tutti-os/tutti
GitHub用于配置、审查和调试通过Tutti App Release工作流发布外部仓库应用的流程。涵盖触发器设置、manifest解析、S3/CloudFront托管、catalog修复及版本管理,确保App Center元数据正确更新。
Install All Skills
npx skills add tutti-os/tutti --all -g -y
More Options
List skills in collection
npx skills add tutti-os/tutti --list
Skills in Collection (5)
.codex/skills/tutti-app-release/SKILL.md
npx skills add tutti-os/tutti --skill tutti-app-release -g -y
SKILL.md
Frontmatter
{
"name": "tutti-app-release",
"description": "Set up, review, run, or debug external repositories that publish a Tutti workspace app through the reusable Tutti App Release GitHub Actions workflow. Use for caller workflows, tutti.app.json manifests, @tutti-os\/app-release-tools, S3\/CloudFront release hosting, latest.json, versions.json, catalog.json, catalog-only repairs, and App Center visibility issues."
}
Tutti App Release
Use this skill when an external app repository publishes a remote Tutti workspace app into App Center release metadata.
The external repository calls the reusable workflow from the Tutti/Tutti repository:
uses: tutti-os/tutti/.github/workflows/publish-tutti-app-release.yml@main
That workflow builds one app package, runs @tutti-os/app-release-tools, uploads immutable release files plus mutable latest.json and versions.json, and can optionally merge that app into the shared catalog.json.
Operating Rules
Inspect before acting:
- Read the caller workflow,
tutti.app.json, package script, and recent GitHub Actions runs. - Confirm whether the user wants a new app release, a catalog refresh, or CI debugging. Do not rerun a release just to repair catalog state.
For catalog publication:
- There are three valid modes. Explain them explicitly when helping a user choose.
- Release only:
publish_catalog: false. This uploads a new app version and updatesapps/<appId>/latest.jsonandversions.json; App Center will see it the next timecatalog.jsonis published. - Release and catalog:
publish_catalog: true. This uploads the app release, then immediately merges that release intocatalog.json. - Catalog only:
catalog_only: true. Use this after a release already succeeded when the user forgot to publish catalog, wants to validate first, or wants to refresh catalog without bumping or uploading a new version. - Do not rerun a full app release just to repair catalog state.
- If the app caller workflow exposes
catalog_only, use that. If it does not, use the Tutti catalog workflow directly or add the caller input when the user wants that repo to support catalog-only dispatch.
For versioning:
- Production releases should be workflow-driven. Run the production caller workflow with
release_bump(patch,minor, ormajor); the reusable workflow calculates the next version from the greater of the packaged manifest version and existing release tags, then creates the tag after the S3 release verifies. - The workflow never bumps or commits app manifest versions. Do not add caller-side release PRs or manifest bump commits to work around protected branches.
- Staging releases should leave
release_bumpempty. The workflow usesmanifest.version+<short git sha>from the packaged manifest and does not create a release tag.
For reusable workflow changes:
- Keep long-lived release behavior in the Tutti reusable workflows and app release tools.
- Keep caller workflows small and stable: app id, package command/dir, runner/tool versions when needed, and environment-specific AWS/CDN values.
- Require callers to declare
min_tutti_versionexplicitly. Use0.0.0only for releases that are safe for every legacy Tutti client. - Avoid requiring app repositories to change for catalog repair behavior. Use an existing catalog-only path for that.
Release Contract
The caller repository must be compatible with pnpm. The reusable workflow runs pnpm install --frozen-lockfile before package_command, so the repository should commit pnpm-lock.yaml and define the package script used by package_command.
The caller repository must commit a source manifest:
tutti.app.json
The generated package directory must contain:
tutti.app.jsonbootstrap.shAGENTS.md- the manifest icon asset, such as
icon.pngoricon.svg - all runtime files and assets
The source and package manifests must use schemaVersion: "tutti.app.manifest.v1". appId must match the workflow app_id input.
The workflow writes release objects under:
apps/<appId>/<version>/
apps/<appId>/latest.json
apps/<appId>/versions.json
For production, the workflow derives the next release version by fetching
existing stable semver tags with the configured release_tag_prefix (default
<appId>-v), reading the packaged manifest version, and applying
release_bump to the greater version. It creates the annotated release tag after
the S3 release has been uploaded and verified. If release_bump is empty, the
workflow uses manifest.version+<short git sha> from the packaged manifest,
which is intended for staging.
Reference Caller Workflow
Use this as the default single-app production caller. Production releases should be workflow-driven so publishing does not need to write version bump commits back to the protected source branch. Keep new app repositories as close to this reference as their package command allows.
name: Publish Tutti App Production
on:
workflow_dispatch:
inputs:
release_bump:
description: Semver bump to publish.
required: true
type: choice
default: patch
options:
- patch
- minor
- major
publish_catalog:
description: Whether to publish the production App Center catalog after this release.
required: false
type: boolean
default: true
catalog_only:
description: Whether to skip app release upload and only publish the existing latest release to catalog.
required: false
type: boolean
default: false
permissions:
contents: write
id-token: write
jobs:
publish:
uses: tutti-os/tutti/.github/workflows/publish-tutti-app-release.yml@main
with:
app_id: your-app-id
min_tutti_version: "REQUIRED_MIN_TUTTI_VERSION"
package_command: pnpm package:tutti
package_dir: build/tutti-app/package
icon_path: build/tutti-app/package/icon.png
release_tag_prefix: your-app-id-v
release_bump: ${{ inputs.release_bump }}
create_release_tag: ${{ !inputs.catalog_only }}
publish_catalog: ${{ inputs.publish_catalog }}
catalog_only: ${{ inputs.catalog_only }}
aws_region: ${{ vars.TUTTI_APP_RELEASES_PRODUCTION_AWS_REGION || vars.TUTTI_APP_RELEASES_AWS_REGION }}
aws_role_arn: ${{ vars.TUTTI_APP_RELEASES_PRODUCTION_AWS_ROLE_ARN || vars.TUTTI_APP_RELEASES_AWS_ROLE_ARN }}
s3_bucket: ${{ vars.TUTTI_APP_RELEASES_PRODUCTION_S3_BUCKET || vars.TUTTI_APP_RELEASES_S3_BUCKET }}
s3_prefix: ${{ vars.TUTTI_APP_RELEASES_PRODUCTION_S3_PREFIX || vars.TUTTI_APP_RELEASES_S3_PREFIX }}
release_assets_base_url: ${{ vars.TUTTI_APP_RELEASES_PRODUCTION_BASE_URL || vars.TUTTI_APP_RELEASES_BASE_URL }}
catalog_cloudfront_distribution_id: ${{ vars.TUTTI_APP_RELEASES_PRODUCTION_CLOUDFRONT_DISTRIBUTION_ID || vars.TUTTI_APP_RELEASES_CLOUDFRONT_DISTRIBUTION_ID || '' }}
Use only workflow_dispatch for staging unless every merge should publish
staging too. Keep staging and production on separate S3 prefixes and base URLs.
Pin the reusable workflow ref only when the caller needs reproducible release behavior:
uses: tutti-os/tutti/.github/workflows/publish-tutti-app-release.yml@<tag-or-commit-sha>
For monorepos that publish multiple apps, keep the caller shape the same but resolve a target matrix from repository config. Each matrix target should expose the same reusable workflow inputs:
app_id: ${{ matrix.target.app_id }}
min_tutti_version: ${{ matrix.target.min_tutti_version }}
package_command: ${{ matrix.target.package_command }}
package_dir: ${{ matrix.target.package_dir }}
icon_path: ${{ matrix.target.icon_path }}
release_tag_prefix: ${{ matrix.target.release_tag_prefix }}
release_bump: ${{ inputs.release_bump }}
create_release_tag: ${{ !inputs.catalog_only }}
Reusable Workflow Inputs
Required release inputs:
app_id: app id, matching the source and packagetutti.app.json.min_tutti_version: minimum compatible Tutti SemVer for a normal release. It has no permissive default; catalog-only repairs read the stored rule fromversions.json.aws_region: AWS region for the release bucket.aws_role_arn: IAM role assumed through GitHub OIDC.s3_bucket: bucket receiving release files.
Conditionally required inputs:
package_command: builds or copies the final package. Required unlesscatalog_onlyis true.package_dir: package directory produced bypackage_command. Required unlesscatalog_onlyis true.release_assets_base_url: public base URL fors3_bucketpluss3_prefix. Required unlesscatalog_onlyis true.
Optional release/version inputs:
icon_path: package-local icon path override. Use when the manifest icon should be resolved from a generated package path.release_tag_prefix: release tag prefix used when calculating and creating production release tags. Defaults to<appId>-v.release_bump: production semver bump. Valid values arepatch,minor, andmajor. Leave empty for staging.create_release_tag: create the annotated release tag after the S3 release verifies. Production callers should set this to true; staging callers should leave it false.
Optional catalog inputs:
publish_catalog: after uploading the app release, merge that release intocatalog.json. Default:false.catalog_only: skip package build, release metadata generation, and app release upload; rebuild the app fromapps/<appId>/versions.jsonintocatalog.json. Default:false.catalog_cloudfront_distribution_id: CloudFront distribution id for invalidating/<s3_prefix>/catalog.jsonafter catalog upload. Default: empty. Caller workflows normally read this fromTUTTI_APP_RELEASES_PRODUCTION_CLOUDFRONT_DISTRIBUTION_IDorTUTTI_APP_RELEASES_CLOUDFRONT_DISTRIBUTION_ID; prefer storing the shared value as an organization variable with selected repository access, and use repository variables only for overrides or when organization variables are unavailable. If neither variable is configured, invalidation is skipped and readers rely on the catalog cache TTL.
Optional runtime/tooling inputs:
runner: GitHub runner label. Default:ubuntu-latest.node_version: Node.js version. Default:24.pnpm_version: pnpm version. Default:10.11.0.release_tools_package: app release tools package spec. Default:@tutti-os/app-release-tools@latest. Pin this only when debugging or when the reusable workflow depends on a version not yet intended for general use.
Catalog Publication
An app release writes apps/<appId>/latest.json and updates apps/<appId>/versions.json. App Center sees it only after the shared catalog includes that app.
Publishing modes:
- Release only: run the app release workflow with
publish_catalog: falseandcatalog_only: false. This updatesapps/<appId>/latest.jsonandversions.json; catalog changes wait until a later catalog publish. - Release and catalog: run the app release workflow with
publish_catalog: true. This publishes the app and then updatescatalog.jsonin the same run. - Catalog only: run with
catalog_only: trueafter a release already exists. This reads the existingapps/<appId>/versions.jsonand updatescatalog.jsonwithout rebuilding, uploading, or bumping a new app version.
Catalog merge semantics:
- App repository release workflows are scoped to their current
app_id.publish_catalog: trueandcatalog_only: truemerge only that app'sapps/<appId>/versions.jsonintocatalog.json. - A release-only app that is not already in
catalog.jsonwill not be picked up by another app's laterpublish_catalog: truerun. - The Tutti catalog workflows can merge one or more explicitly selected app ids through
app_ids. Use that path when refreshing multiple apps, or run each app's catalog-only dispatch separately. - Neither path scans S3 for every published app index. Every app that should be added or refreshed must be the current caller app id or be explicitly listed in
app_ids.
catalog.json keeps schema tutti.app.catalog.v1. Its apps[] array contains the highest active minTuttiVersion: 0.0.0 release for old clients. New clients read the additive compact compatibility.apps frontier. Mutable metadata writes use S3 ETag preconditions because GitHub concurrency groups do not serialize workflows across different repositories.
Catalog-only can be exposed by the app repository caller workflow, or run from the Tutti catalog workflows:
- Production: https://github.com/tutti-os/tutti/actions/workflows/publish-tutti-app-catalog.yml
- Staging: https://github.com/tutti-os/tutti/actions/workflows/publish-tutti-app-catalog-staging.yml
Recommended inputs for refresh/repair:
catalog_mode:mergeapp_ids: the released remote app id, such asvibe-design- Leave AWS, S3, prefix, and CloudFront inputs empty unless overriding organization or repository variables.
Use replace only for deliberate full catalog replacement. Built-in app ids such as automation are not published through the remote catalog workflow.
Catalog writes:
s3://<s3_bucket>/<s3_prefix>/catalog.json
If catalog.json changed but App Center still shows old metadata, check CloudFront invalidation and confirm TUTTI_APP_CATALOG_URL points at the expected staging or production URL.
AWS Requirements
The caller repository needs a GitHub OIDC role that can write release files:
s3://<s3_bucket>/<s3_prefix>/apps/<appId>/<version>/*
s3://<s3_bucket>/<s3_prefix>/apps/<appId>/latest.json
s3://<s3_bucket>/<s3_prefix>/apps/<appId>/versions.json
When publish_catalog or catalog_only is used in the app release workflow, that role also needs catalog read/write access:
s3://<s3_bucket>/<s3_prefix>/catalog.json
CloudFront invalidation requires permission for the matching distribution id. Store shared non-secret configuration such as the CloudFront distribution id in GitHub organization variables with selected repository access when possible; use repository variables only for repository-specific overrides.
Local Validation
Before relying on GitHub Actions, validate the package locally:
pnpm --package @tutti-os/app-release-tools@latest dlx build-tutti-app-release \
--app-id your-app-id \
--package-dir build/tutti-app/package \
--output-dir /tmp/tutti-app-release \
--base-url https://cdn.example.com/tutti-app-releases \
--version 0.1.0+local \
--git-sha local
Expected output:
/tmp/tutti-app-release/apps/<appId>/<version>/<appId>-<version>.zip/tmp/tutti-app-release/apps/<appId>/<version>/release.json/tmp/tutti-app-release/apps/<appId>/latest.json
Normal publishing also creates or updates the remote apps/<appId>/versions.json compatibility index.
Completion Checklist
- Caller workflow uses
tutti-os/tutti/.github/workflows/publish-tutti-app-release.yml. package_commandproducespackage_dir.package_dir/tutti.app.jsonis valid JSON andappIdmatches workflowapp_id.- Package contains
bootstrap.sh,AGENTS.md, icon asset, and runtime files. s3_prefixandrelease_assets_base_urlpoint to the same public release root.- Staging and production use separate prefixes.
- Catalog refresh after an existing successful release uses
catalog_onlyor the Tutti catalog workflow instead of a new release.
Common Failures
manifest appId must match app id: align workflowapp_idand manifestappId.missing tutti.app.json: fix package generation so the package directory contains a manifest.release_bump must be one of major, minor, or patch: production callers must pass a supported bump type.create_release_tag requires release_bump: release tags are only created for workflow-driven production bumps.manifest icon asset missing: include the asset inside the package or passicon_path.- AWS
AccessDenied: check OIDC trust policy, role ARN, bucket policy, region, prefix, and catalog/CloudFront permissions. - Release succeeded but App Center does not show it: publish or refresh the catalog with
catalog_onlyor the Tutti catalog workflow in merge mode.
.codex/skills/tutti-architecture-review/SKILL.md
npx skills add tutti-os/tutti --skill tutti-architecture-review -g -y
SKILL.md
Frontmatter
{
"name": "tutti-architecture-review",
"description": "Review tutti git diffs for project structure, layering, module ownership, and duplicate event-center infrastructure by planning focused architecture review tasks, then having the main agent orchestrate sub-agents for only the changed areas."
}
Tutti Architecture Review
Use this skill when reviewing a tutti change or a named module for repository structure, module ownership, or layering compliance. This is a focused architecture review, not a general bug hunt.
Vocabulary
Use the architecture vocabulary consistently:
- Module: anything with an interface and an implementation.
- Interface: everything a caller must know to use the module correctly.
- Implementation: the code inside a module.
- Depth: leverage at the interface; deep modules hide useful behavior behind a small interface.
- Seam: where an interface lives.
- Adapter: a concrete thing satisfying an interface at a seam.
- Leverage: what callers get from depth.
- Locality: what maintainers get from depth.
Prefer these words in findings. Avoid vague substitutes such as "component", "service", "utility", or "boundary" when a vocabulary term fits.
Workflow
-
Resolve the user's review intent:
- plain
git diffreview for the current change - module-focused diff review when the user names a module inside the current change
- static module review when the user wants a named module inspected even without current diff overlap
Use light natural-language guidance when the request is ambiguous. Do not force the user through a fixed mode menu.
- plain
-
When the user names a module, let the main agent infer a few candidate path keywords and gather candidate paths. Then normalize those paths into a scope file:
node ./.codex/skills/tutti-architecture-review/scripts/build-review-scope.mjs \ --input /tmp/tutti-review-candidates.json \ --output /tmp/tutti-review-scope.jsonCandidate input is agent-produced. The script does not invent module keywords or search the repository itself; it only normalizes candidate paths into a stable scope contract for the planner.
Read
references/scope-contract.mdwhen changing or consuming the candidate input, normalized scope output, or planner scope metadata. -
Run the review planner from the repository root:
pnpm review:architecture:packageFor module-focused review, pass the generated scope file:
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs \ --scope-file /tmp/tutti-review-scope.json \ --format json \ --output-tempThe planner remains
git difffirst. With--scope-file, it reviewsscope ∩ diffwhen there is overlap, and falls back to scoped-file review only when there is no diff overlap.For explicit static module review, force scope-only planning:
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs \ --scope-file /tmp/tutti-review-scope.json \ --scope-mode static-only \ --format json \ --output-temp -
Read the generated JSON task package from
workflowEntry.packagePath. Each task includesriskLevel,spawnRecommendation,summaryForMainAgent,matchedFiles,preflightSignals, and a ready-to-useprompt. -
Spawn
explorersub-agents according tospawnRecommendation:required: spawn unless the user explicitly asked for a narrower reviewrecommended: spawn when the review is not trivially smalloptional: the main agent may review locally
Do not ask sub-agents to edit files. Their job is to inspect the relevant diff and report architecture findings.
-
Continue local work while sub-agents run only if there is non-overlapping review or summarization work. Do not duplicate a sub-agent's assigned scope.
-
Merge sub-agent reports into a code-review style answer:
- findings first, ordered by severity
- cite file paths and line numbers when possible
- explain the violated rule and why it matters for locality, leverage, or dependency direction
- include "No architecture findings" when a reviewer found no issues
Reviewer Expectations
Every sub-agent should:
- read
AGENTS.mdand the closest areaAGENTS.mdfor its changed files - read only the reference files listed in the task package, plus files needed to understand the diff
- inspect the relevant git diff directly instead of relying only on file names
- report only actionable architecture issues, not taste preferences
- distinguish hard rule violations from speculative deepening opportunities
- avoid proposing new interfaces unless the changed code already creates pressure for a real seam
- when eventing, pub-sub, or bidirectional coordination appears, check whether the shared business event stream's
global,desktop, orworkspacescope modules already own the seam before accepting new event-center infrastructure
Task Planner
The planner is deterministic and repository-local:
scripts/plan-review.mjsreadsgit diff, optional untracked files, and an optional normalized scope filescripts/build-review-scope.mjsnormalizes agent-produced candidate paths into a stable scope contractreferences/review-rules.jsondeclares reviewer tasks, path rules, and regex-style preflight signals- the script maps changed paths to architecture reviewer tasks
- it adds lightweight preflight signals for suspicious imports, generated-contract drift, possible hardcoded copy, and cross-area seams
- it assigns task risk and spawn recommendations for the main agent
- it emits JSON or Markdown for the main agent to orchestrate
- it never starts sub-agents itself
Useful options:
pnpm review:architecture
pnpm review:architecture:package
pnpm review:architecture:test
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --format markdown
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --format summary
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --base origin/main
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --staged
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --no-untracked
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --scope-file /tmp/tutti-review-scope.json --format summary
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --scope-file /tmp/tutti-review-scope.json --scope-mode static-only --format summary
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --task desktop-layering --format markdown
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --output /tmp/tutti-review-tasks.json
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --output-temp
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --from-package /tmp/tutti-review-tasks.json --format markdown
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --from-package /tmp/tutti-review-tasks.json --task desktop-layering --format summary
Task Package Entry
A task package file is a stable workflow entrypoint. Prefer creating one before spawning sub-agents, especially for large reviews:
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --format json --output-temp
Then use workflowEntry.packagePath as the source of truth for the review. If the conversation resumes later, reload the same package instead of recomputing the plan:
node ./.codex/skills/tutti-architecture-review/scripts/plan-review.mjs --from-package /tmp/tutti-architecture-review-YYYYMMDDTHHMMSSZ.json --format markdown
Use --format summary before spawning agents when you need a compact orchestration view. Use --task <id> to inspect or rerender one reviewer from either the current diff or an existing task package.
Run the planner self-test after changing task matching, risk rules, output formats, or task-package behavior:
node --test ./.codex/skills/tutti-architecture-review/scripts/plan-review.test.mjs ./.codex/skills/tutti-architecture-review/scripts/build-review-scope.test.mjs
Read references/tutti-layering.md when a task needs the compact project rules.
Read references/scope-contract.md when changing the scope-file contract or the main-agent handoff around module review.
Read docs/architecture/business-event-stream.md when reviewing event-center modules, typed pub-sub, or WebSocket-based product coordination. Do not use the architecture review to enforce generated event-protocol drift; that belongs to pnpm check:event-protocol-generated.
Read or edit references/review-rules.json when changing:
- reviewer task titles, focus, references, or path matching
- simple preflight regex rules
- task assignment for preflight signals
Keep combination logic in scripts/plan-review.mjs, such as cross-cutting trigger reasons, generated-source pairing, risk calculation, spawn recommendations, and output rendering.
Keep module-phrase interpretation in the main agent, not in build-review-scope.mjs or plan-review.mjs. Those scripts should stay deterministic and repository-local.
packages/ui/system/agent/tutti-ui-system/SKILL.md
npx skills add tutti-os/tutti --skill tutti-ui-system -g -y
SKILL.md
Frontmatter
{
"name": "tutti-ui-system",
"description": "Use when working with @tutti-os\/ui-system components, replacing local UI with shared components, querying component ids or metadata, promoting UI into shared base or business components, or maintaining UI-system storyboard inventory."
}
Tutti UI System
Use this skill as the single entrypoint for @tutti-os/ui-system component
reuse, extraction, promotion, metadata, and storyboard work.
Non-Negotiable Standard
Any UI promoted into @tutti-os/ui-system must fully follow the UI-system
design standard before it can be reported as complete.
Treat these as hard requirements, not cleanup suggestions:
- use UI-system semantic tokens and existing shared CSS variables; do not leave
raw
hex,rgb(...),rgba(...), ad hoc gradients, or app-local palette values in promoted components or their storyboard examples unless the source of truth already exposes them as approved tokens - compose existing UI-system
baseprimitives such asCard,Button,Tooltip,Dialog, and related vocabulary before creating custom panel, button, field, or overlay treatments - use icon components from
@tutti-os/ui-system/iconsfor promoted components and storyboard examples. Do not inline SVG/data URI assets, import app-local icon files, or pull third-party icon packages directly from promoted UI. If the source UI depends on an icon that is not in the UI system, promote the source-derived icon intopackages/ui/system/src/iconswith metadata first, then consume the UI-system icon export. - make storyboard examples render the real component surface and states; do not rely on surrounding docs chrome to hide component-level visual drift or to fake the final panel/surface language
- when a consumer is migrated, its final rendered result must also follow the same UI-system visual standard; a temporary bridge may help wiring, but it is not acceptable as the final visual implementation if it keeps a second token system or divergent component styling
If these conditions are not met, report the promotion as incomplete or blocked, not complete.
Source Of Truth
Read these before editing:
- nearest
AGENTS.mdfor the target code - local
AGENTS.mdbundled with this skill - local
ui-system.mdbundled with this skill - component metadata from the first available source:
GET http://127.0.0.1:4100/componentspackages/ui/system/src/metadata/components.json@tutti-os/ui-system/metadatafrom the installed package
Use stable public imports only:
@tutti-os/ui-system@tutti-os/ui-system/components@tutti-os/ui-system/icons@tutti-os/ui-system/metadata@tutti-os/ui-system/styles.css@tutti-os/ui-system/utils
Never deep import @tutti-os/ui-system/src/* or per-file component paths.
Route The Task
Read only the reference file that matches the task.
- Using or querying existing components:
references/use-existing-component.md - Extracting a low-level base primitive:
references/extract-base-component.md - Promoting reusable business UI into a shared component:
references/promote-business-component.md - Maintaining ids, metadata, exports, or storyboard inventory:
references/maintain-inventory.md
Global Boundaries
Keep these outside @tutti-os/ui-system components:
- daemon, Electron, filesystem, router, or host adapter calls
- data fetching, cache mutation, persistence, polling, and global store ownership
- workflow orchestration such as onboarding, workspace registration, install or uninstall flows, confirmation dialogs, queueing, or navigation
- i18n key lookup and business-specific copy derivation unless supplied by props, children, or labels
For any promoted public component, add stable exports, metadata, and storyboard coverage that match the chosen reference workflow.
For promoted base components, storyboard coverage is not satisfied by metadata
alone. The promotion flow must also add or update a real renderable example in
apps/ui-storyboard so the component is visible in navigation and can be
visually reviewed in shared docs immediately after promotion.
For business component promotion, use a copy-first workflow: move the existing business component structure as intact as possible, preserve the real DOM, visual hierarchy, state branches, and interaction layout, then progressively remove host dependencies and standardize the public API. Do not begin by inventing a cleaner abstraction or new visual treatment. The state matrix, props boundary, and candidate source UI define what to copy, what to keep caller-owned, and what to standardize after parity exists.
Treat business component promotion as an iterative migration-review loop, not a single extraction pass:
- migrate the source UI copy-first
- recreate source-backed states in storyboard
- run independent review against the original source and screenshot
- migrate again to close review findings
- repeat review until source/design parity is acceptable
Only after that loop should the API be generalized further. Do not report the component as complete after the first migration if review still shows material DOM, visual, token, state, icon, or storyboard coverage drift.
The promoted UI must follow the original design exactly unless the user explicitly approves a visual change. Do not add new decoration, controls, icons, layout chrome, copy, motion, states, spacing, or visual hierarchy that does not exist in the source UI or provided screenshot. If UI-system token or primitive replacement is needed, it must preserve the observed design and interaction path rather than becoming a redesign.
Copy-first also applies to dependent presentational subcomponents and
third-party-library wrappers used by the candidate UI. Do not copy only the top
level JSX and recreate nested behavior from memory. Trace the dependency tree:
pure display helpers should move with the component; reusable wrappers around
Radix, floating UI, resizable panels, virtualization, or similar libraries
should be promoted or reused as base primitives first; host-coupled children
must be split into caller-owned data, labels, callbacks, or slots before the
business component is considered promoted.
Design Foundation Verification
Every promoted component must comply with
ui-system.md, especially the shared tokens,
theme variables, spacing, radius, typography, surface language, interactive
states, and existing base primitive vocabulary.
Explicitly check and report all of these before completion:
- color and surface styling come from UI-system semantic tokens rather than raw palette values
- panels, rows, controls, and overlays compose existing base primitives where applicable instead of recreating them locally
- storyboard shows the component's real promoted surface rather than only a documentation wrapper
- migrated consumers no longer depend on a separate visual token system for the promoted surface
Run the Tutti promotion review gate before reporting completion. The gate is adapted from frontend design review practice but constrained to Tutti's dense workbench product language:
- Frictionless: the migrated consumer preserves the original task path, keeps a clear action hierarchy, and does not bury primary or recovery actions.
- Quality craft: visual parity evidence is captured for selected states, shared tokens and primitives are used, light/dark and interactive states work, and no unapproved raw palette, spacing, radius, typography, or motion drift remains.
- Trustworthy: empty, loading, disabled, error-like, permission-limited, and AI-generated-content states keep clear labels, actionable recovery, and host-owned policy or provenance outside the shared component.
After promoting a base or business component, start an independent subagent to review design-foundation compliance before reporting completion. Provide the subagent with the promoted files, source usage, selected states, storyboard and metadata entries, and the UI-system guidelines. If subagents are unavailable, state that design-foundation verification is blocked and do not claim full compliance.
Report the gate result with:
- context: source usage, promoted component id/layer, user task, selected states
- status: pass, needs work, or blocked
- pillar assessment: Frictionless, Quality craft, Trustworthy
- issues grouped as blocking, major, and minor
- validation commands and exact results
- remaining risks, uncovered states, or approved visual deltas
API Composition Review
When converting source states into public props, review the API shape before writing the promoted component:
- avoid boolean prop proliferation for rendering modes; mode axes such as
isFoo,showBar, orwithBazmust come from code evidence and usually become a finite variant, discriminated union, explicit component variant, slot, or composed child - keep standard UI booleans such as
disabled,loading,selected,open,required, andinvalidonly when they represent real component state and cannot create impossible combinations - prefer
childrenor named slots for caller-owned visual regions; use render props only when the shared component must pass data back to the caller - use compound components and context only for genuinely complex reusable structures where consumers need to compose subparts without prop drilling
- if shared state is needed, define a narrow context value as
state,actions, andmeta; providers may inject state but must not own daemon, Electron, router, store, query, persistence, or workflow side effects - for new React components in this React 19 codebase, prefer the React 19 API
shape such as
refas a prop; do not churn shadcn or Radix-acquired code only to normalize style when behavior and public API are already sound
Report the API composition decision with the state matrix: which differences became props, variants, slots, children, explicit variants, provider state, or stayed host-owned.
Validation Commands
Run the smallest relevant checks from the selected reference. Common checks are:
node tools/scripts/check-ui-metadata.mjs
pnpm check:ui-boundaries
pnpm --filter @tutti-os/ui-storyboard typecheck
If runtime component code changed, also run the relevant package typecheck or consumer build.
When a base component is promoted, verify both of these conditions before reporting completion:
- the component metadata opts into storyboard visibility when appropriate
apps/ui-storyboardcontains a concrete rendered example for the promoted component states, not just inventory wiring
services/tuttid/service/workspace/agent_workspace_app_reference/SKILL.md
npx skills add tutti-os/tutti --skill tutti-agent-workspace-app -g -y
SKILL.md
Frontmatter
{
"name": "tutti-agent-workspace-app",
"description": "Build or evolve a complex agent-enabled Tutti workspace app repository. Use for Tutti apps with web\/server\/shared monorepos, @tutti-os\/agent-acp-kit local agent runtimes, kit-owned TUTTI_CLI provider\/composer discovery, dynamic provider catalogs, run-scoped MCP tool gateways, app-owned package builders, web-first debugging, i18n harnesses, and production package validation. For simple package creation or repair, use tutti-workspace-app-factory instead."
}
Tutti Agent Workspace App
Use this skill when the task is to create or evolve a full Tutti app repository, not just a final package directory. The target app is usually a local-first web app with a server, shared contracts, optional local agent runtime, and an app-owned scripts/package-tutti-app.mjs.
For the final package contract, defer to $tutti-workspace-app-factory and its references. This skill owns app architecture patterns; the factory skill owns tutti.app.json, tutti.cli.json, bootstrap.sh, runtime env, storage, i18n harness, and static package validation rules.
When To Use
Use this skill for:
- New agent-enabled Tutti app repositories.
- Existing web/server apps being converted into maintainable Tutti app repos.
- Apps that need
@tutti-os/agent-acp-kitfor app-owned local Agent execution and@tutti-os/agent-acp-kit/tuttifor auto CLI-backed/standalone platform context. - App-specific MCP or command gateways that expose domain tools to local agents.
- Multi-package
pnpmworkspaces withapps/web,apps/server, andpackages/shared. - App-owned packaging, smoke tests, i18n enforcement, and CLI/reference endpoints.
- GitHub Actions release workflows for publishing Tutti app releases and staging/production catalogs.
Use $tutti-workspace-app-factory instead for a small standalone package, package repair, or manifest-only validation.
Required References
Read only the references needed for the task:
references/app-architecture.mdfor repository layout, web/server/shared boundaries, and dependency choices.references/agent-acp-kit.mdwhen implementing local agent providers, ACP event mapping, or run-scoped MCP tools.references/dynamic-agent-providers.mdwhen implementing provider catalog/composer endpoints, standalone behavior, provider pickers, default selection, or canonical provider persistence. Read this before hard-coding any provider list.references/package-builder.mdwhen addingscripts/package-tutti-app.mjs,bootstrap.sh, Tutti CLI output docs, or package validation.references/github-actions-release.mdwhen creating or changing.github/workflows/publish-tutti-app.yml,.github/workflows/publish-tutti-app-staging.yml, release variables, or catalog publishing.references/i18n-and-web-debugging.mdwhen changing UI copy, language handling, web-first debug flow, or smoke/e2e checks.
Also read $tutti-workspace-app-factory before changing final package files or package runtime behavior.
Workflow
- Inspect the existing app shape, scripts, runtime dependencies, build output, storage, i18n, and agent surfaces.
- Choose the smallest architecture that can stay maintainable: do not add local agents, WebSocket, MCP, CLI, or background workers unless the product needs them.
- Define shared contracts before wiring web/server calls. Keep domain DTOs, WebSocket messages, CLI-visible shapes, and runtime profile types in
packages/shared. - Build the web UI as the primary development surface. Keep the server as local API/static host and app orchestration layer.
- If agents are needed, add an exact released
@tutti-os/agent-acp-kit, use its default app-owned runtime, call the/tuttiauto facade for catalog/composer/skill context, normalize events, and add a run-scoped tool gateway. Followreferences/dynamic-agent-providers.md: do not pass mode, checkTUTTI_CLI, call Agent catalog HTTP routes, read app ID/token/API environment, parse CLI JSON, or maintain provider aliases. Render every facade provider, keep unavailable entries disabled with their reason, choose one usable default, and never maintain a Codex/Claude-only app catalog. For apps that must run both locally and in cloud/managed Tutti, followreferences/agent-acp-kit.mdexactly: managed credentials come from request headers on the server, never from browser JSB fallback or request body fields. - Add package generation only after the local dev app runs. Package the built web assets, bundled server,
tutti.app.json, optionaltutti.cli.json, executablebootstrap.sh, assets, locales, and package-localAGENTS.md. - If the user asks to connect to the Tutti app ecosystem, treat ecosystem integration as required: expose app capabilities through
tutti.cli.json, make the app callable by other Tutti apps and agents, and useTUTTI_CLIfor any calls to other installed Tutti apps. - For GitHub-hosted app repositories that should publish releases, add staging and production release workflows after the package builder is stable.
- Verify with the repo's targeted checks first, then package checks.
Managed and standalone agent checklist
Keep Tutti-hosted and standalone behavior behind the kit's fixed auto facade while sharing the same runtime execution layer:
- Pin an exact kit version that exports the auto catalog/composer/skill facade and managed header context helper.
- Call
loadTuttiAgentProviderCatalog({ runtime }); do not pass mode or inspectTUTTI_CLI. - Load composer options lazily for one canonical provider and expose only app/domain DTO projections.
- Persist canonical provider IDs; migrate legacy
claudeonce toclaude-code, but keepnexightandtutti-agentdistinct. - Await
createManagedAgentRunContextFromHeaders(...)directly. Do not pre-read credentials or pre-check provider support in app code. - Without a managed header, use an app-owned local cwd. Pass the same canonical provider ID, selected cwd, and optional
managedAgentInvocationinto runtime execution. - Delete raw Agent HTTP/CLI clients, browser credential fallbacks, request-body credential fields, alias maps, and dependency patch scripts.
- Never persist managed credentials or expose managed cwd and credentials through frontend events, logs, status APIs, or stored app state.
- Do not hard-code
/workspace,.agent-runs, orCODEX_HOME; the kit derives managed context. - If instructions arrive over WebSocket, confirm the host injects the managed credential into that route; do not create a second credential channel.
- Package the built server, web assets, MCP/tool entrypoints, and runtime metadata needed by Tutti.
- Test CLI-backed auto, standalone auto, configured CLI failure, canonical IDs, managed/local run context, and secret non-leakage.
Validation
Prefer app-local scripts when they exist:
pnpm check
pnpm test
pnpm typecheck
pnpm check:i18n
pnpm package:tutti
For final package validation, run the validator from $tutti-workspace-app-factory when available:
python3 <factory-skill>/scripts/validate_tutti_app_package.py <generated-package-root>
If the app includes real local agent execution, add or run a smoke check that starts with provider detection before launching a real turn.
services/tuttid/service/workspace/app_factory_reference/SKILL.md
npx skills add tutti-os/tutti --skill tutti-workspace-app-factory -g -y
SKILL.md
Frontmatter
{
"name": "tutti-workspace-app-factory",
"description": "Create, convert, or repair one Tutti workspace app as either a self-contained publishable package under package\/ or a Chrome-style local debug app under .tutti\/dev-app\/. Use for mention:\/\/workspace-app-factory\/create handoffs, mention:\/\/workspace-app-factory handoffs, standalone app generation, adapting existing repositories, Load unpacked repair flows for invalid local project directories, tutti.app.json and tutti.cli.json manifests, bootstrap.sh scripts, package-local AGENTS.md, local HTTP runtimes, TUTTI_APP_* host\/port\/storage rules, healthchecks, app assets, i18n, validation, and optional Tutti CLI integration."
}
Tutti Workspace App Factory
Use this skill to create, convert, or repair one Tutti workspace app. Choose one output mode before editing:
- Publishable package: create a self-contained app under
package/, runnable by the Tutti custom app runtime and safe to copy into a workspace app archive. - Local debug app: create a small
.tutti/dev-app/wrapper that launches the user's existing source tree through the Chrome-style "Load unpacked" flow.
When the user selected a directory in App Center and Tutti reports that it cannot be loaded, treat the task as local debug repair. Adapt the selected project by creating or fixing .tutti/dev-app/; do not create a zip wrapper or copy the repository into package/ unless the user explicitly asks for release packaging.
For a full agent-enabled Tutti app repository with apps/web, apps/server, packages/shared, @tutti-os/agent-acp-kit, kit-owned TUTTI_CLI provider/composer discovery, dynamic local agent runtimes, MCP tool gateways, and an app-owned package builder, use $tutti-agent-workspace-app first. Return to this skill for the final package contract and validation. Do not invent managed-agent credential, cwd, JSB fallback, request-body credential, CODEX_HOME, CLI argv, app ID, token, or provider alias behavior in this factory skill; the agent app skill keeps those concerns in server-side kit calls.
If the user request needs local agent or local LLM execution, Tutti agent providers, or app-owned MCP/tooling, load $tutti-agent-workspace-app and read its references/dynamic-agent-providers.md and references/agent-acp-kit.md. Agent-enabled apps must use a Node server and @tutti-os/agent-acp-kit; do not implement app-owned local agent execution by shelling out to $TUTTI_CLI agent ..., $TUTTI_CLI codex ..., or session polling.
Version Check And Update Reminder
Before generating, repairing, or validating an app package, perform a best-effort freshness check unless the user asks to skip network access or the environment is offline.
-
Fetch the current published skill body:
https://raw.githubusercontent.com/tutti-os/tutti-agent-skills/main/skills/tutti-workspace-app-factory/SKILL.md -
Compare the fetched content with the local
SKILL.mdthat loaded this skill. Prefer a content hash comparison when filesystem access is available. If the local skill path is unavailable, fetch the latest repository commit instead:https://api.github.com/repos/tutti-os/tutti-agent-skills/commits?per_page=1 -
If the published skill differs from the local copy, state this at the start of the reply before doing other work:
This Tutti skill has a newer version available. I can continue with the currently loaded copy, but updating first is recommended so the latest manifest rules and runtime guidance are used. Update the Codex plugin marketplace: codex plugin marketplace upgrade tutti-agent-skills Update the direct skill install: npx --yes skills add tutti-os/tutti-agent-skills -
If the user has explicitly asked to update local installs, or if the current task is itself about keeping the skill current, run the update commands that are available in the environment before continuing. Tell the user that newly installed skill content may take effect only after the next skill reload or new session.
-
If the freshness check fails because network access, GitHub,
codex, ornpxis unavailable, mention the check was skipped or failed briefly and continue the requested Tutti app work.
Required Context
If the current working directory contains context.json, or the task includes mention://workspace-app-factory/create or mention://workspace-app-factory, operate in Tutti factory handoff mode. Read context.json before writing files, then follow its metadata, output rules, workspace context, and constraints exactly. Do not copy the context file into generated app outputs.
If context.json is absent, operate in standalone mode. Treat the current working directory as the app authoring workspace. If the user asks for local debugging, Load unpacked support, or repair of a selected project directory, create or update .tutti/dev-app/. Otherwise, if the directory already contains an app or repository, adapt it into a self-contained Tutti package under package/; if it does not, create a new self-contained package under package/. Infer missing metadata conservatively from the user request.
For publishable packages, the package root is the only generated app output directory; files outside it are scratch or coordination files and will not be published. For local debugging, .tutti/dev-app/ is the generated dev app directory and the surrounding project source remains owned by the user repository.
Mention Contract
Treat a mention://workspace-app-factory/create or mention://workspace-app-factory link as the factory handoff. In handoff mode, use the exact metadata, output rules, workspace context, and constraints from context.json as authoritative.
Before writing files, read these bundled references:
references/manifest-contract.mdfortutti.app.json.references/cli-manifest-contract.mdfortutti.cli.jsonwhen exposing app capabilities to the Tutti ecosystem.references/runtime-env.mdfor runtime environment variables and storage ownership.references/i18n-harness.mdwhen the app has localized metadata, user-facing in-app copy, or an existing localization system.references/tutti-cli-commands.mdwhen the generated app runtime should call, combine, or expose local Tutti CLI capabilities.references/validation-checklist.mdfor completion checks.
Read references/demos/simple-node-static-app/ only when you need a concrete complete package shape. Do not copy its demo app id, display name, description, or tags unless the user explicitly asks for the demo itself.
Output Contract
For a publishable package, create or update these files under output.packageRoot from the context in handoff mode, or under package/ in standalone mode:
tutti.app.json: valid JSON manifest matchingreferences/manifest-contract.md.tutti.cli.json: CLI manifest matchingreferences/cli-manifest-contract.md, required when the user asks to connect the app to the Tutti ecosystem; otherwise create it only whentutti.app.jsondeclarescli.manifest.bootstrap.sh: executable shell entrypoint that starts the app server with no arguments.AGENTS.md: package-local guidance describing layout, runtime command, endpoints, data storage, and modification rules.locales/<locale>/manifest.json: manifest metadata localization files, only when the user asks for localized app metadata.- App-owned locale dictionaries or an i18n helper/harness when the app has user-facing in-app copy in more than one language.
- App implementation files and assets needed for the requested behavior.
For a local debug app, create or update these files under .tutti/dev-app/ instead of package/:
tutti.app.json: local debug manifest.tutti.cli.json: CLI manifest matchingreferences/cli-manifest-contract.md, only when the app exposes capabilities ortutti.app.jsondeclarescli.manifest.bootstrap.sh: executable shell entrypoint that reads the host-injected port and starts the source dev server.AGENTS.md: dev-app guidance describing the project root, dev/watch command, host/port contract, source hot-reload ownership, and how to reload from App Center.- Optional app assets referenced by the manifest.
Keep .tutti/dev-app/ small. It should describe and launch the local app, not copy the whole project. Tutti Desktop can load either the .tutti/dev-app/ directory directly or the project root that contains it.
If the task supplies exact metadata such as appId, version, display name, or description, copy those values exactly into tutti.app.json. If metadata is missing, choose conservative defaults:
schemaVersion:tutti.app.manifest.v1version:0.1.0appId:app_plus a lowercase hyphenated slug from the app name or requestdescription: one concise sentence describing actual app behavioricon: package-local asset, preferably{"type":"asset","src":"icon.svg"}runtime.bootstrap:bootstrap.shruntime.healthcheckPath:/healthzlocalizationInfo: omit unless the user asks for localized app metadata; when needed, followreferences/manifest-contract.mdand create each referenced locale file.
If the user asks to connect the app to the Tutti ecosystem, expose at least one app capability through tutti.cli.json and declare it from tutti.app.json. If the app has a UI, include a business-level open command when there is a meaningful target to open, such as open-project, open-file, open-run, or open-context. The command should own the full self-open flow: accept stable domain identifiers, validate them, map them to an app-owned origin-root route, and request opening this same app through $TUTTI_CLI with an argv list equivalent to --json app open --app-id "$TUTTI_APP_ID" --route .... --json is the CLI machine-readable output flag. Do not return route parameters for a caller or agent to interpret and then call app open; that makes the integration chain too indirect. Do not expose raw frontend route construction as the public contract; callers should invoke the app's business open command without needing to know the app's internal router.
Runtime Rules
Build a small local HTTP app. Default newly generated apps to a Node server. Use Python only when adapting an existing Python project or when the user explicitly requests Python. Agent-enabled apps must use a Node server because @tutti-os/agent-acp-kit is Node-only.
The runtime must:
- Bind
$TUTTI_APP_HOST:$TUTTI_APP_PORT, defaulting the host to127.0.0.1only when the host variable is absent. - Fail startup with a clear error when
$TUTTI_APP_PORTis absent. Do not guess, reserve, or hard-code a fallback port; the daemon owns port allocation. - Serve the manifest healthcheck path with a 2xx response.
- Treat
$TUTTI_APP_PACKAGE_DIRas read-only after startup. - Write durable app data only under
$TUTTI_APP_DATA_DIR. - Write scratch/runtime files only under
$TUTTI_APP_RUNTIME_DIR. - Write logs only under
$TUTTI_APP_LOG_DIRwhen backend/server-side file logs are needed. - Store reusable app-managed binaries only under
$TUTTI_APP_TOOLCHAIN_ROOT. - Prefer
window.tuttiExternal?.logs?.write?.()for browser-side diagnostics in Tutti Desktop; reserve$TUTTI_APP_LOG_DIRfor backend process logs. - Read
$TUTTI_WORKSPACE_ROOTonly when the app needs workspace context. - Launch Python with
$TUTTI_APP_PYTHONand Node with$TUTTI_APP_NODE; use$TUTTI_APP_NPMfor npm install/build work. - When the app exposes an open command, support the routed pages in the app runtime itself: direct navigation to the route must render the intended page, and an already-mounted frontend should handle repeated open intents through
window.tuttiExternal?.workspace?.onLaunchIntent?.(...). - When the generated app calls another local Tutti capability at runtime, use
$TUTTI_CLIand followreferences/tutti-cli-commands.md. - Read the current UI locale from the optional host-injected app context when localized in-app copy is needed. Do not pass locale in the launch URL query.
- Keep localized in-app copy behind stable keys and use the harness pattern in
references/i18n-harness.mdso future edits can check locale parity. - Use CSS
prefers-color-scheme/matchMedia("(prefers-color-scheme: dark)")for dark/light rendering. Do not pass theme in the launch URL query. - When exposing app-owned files through references or generated content, return reference-list
locationobjects scoped toapp-data-relativeorapp-package-relative. Do not emit, persist, or instruct clients to open direct.tutti/.tutti-devapp state paths such as$TUTTI_STATE_DIR/apps/...; the daemon resolves valid locations before desktop clients open files.
Agent Runtime Integration
For a full agent-enabled app repository, prefer $tutti-agent-workspace-app first. When this skill still needs to package or repair an app that already uses @tutti-os/agent-acp-kit, keep the app in control of agent policy:
- Keep the generic
@tutti-os/agent-acp-kitruntime path product-neutral. Tutti-specific provider catalog, composer, and skill discovery stays behind the explicit@tutti-os/agent-acp-kit/tuttisubpath; app code owns only product policy and DTO projection. - Use a Node server for the app host process. Do not start with a Python server and plan to migrate later.
- To give the app's local agent runs access to Tutti's dynamic CLI skills, prefer the
@tutti-os/agent-acp-kit/tuttihelper instead of hand-writing$TUTTI_CLI agent tutti-cli-skill-bundleexecution and response parsing in each app. - Use
loadTuttiAgentSkillContext(...)from the app host process. Pass the selected provider, run id, workspace cwd, and optional Tutti CLI command configuration such ascommandEnvNames. - Pass
tuttiContext.skillManifestintoruntime.run({ ..., skillManifest }), merging it with app-owned skills when needed. - Treat
tuttiContext.recommendedSystemPrompt?.contentas advisory raw prompt content. The app may merge it into its ownsystemPrompt, edit it, place it elsewhere, or ignore it. Do not inject it silently, and do not reintroduce duplicated CLI parsing unless the installed kit lacks the helper. - Keep run-scoped app tools and MCP credentials app-owned. Do not pass broad Tutti daemon credentials or app secrets directly to the agent process.
Agent app main flows must call loadTuttiAgentProviderCatalog and lazy loadTuttiAgentComposerOptions from @tutti-os/agent-acp-kit/tutti. The kit automatically uses TUTTI_CLI inside Tutti and standalone runtime detection when the CLI is absent. App code must not pass a mode, app ID, daemon URL, token, provider alias map, or CLI arguments. Follow $tutti-agent-workspace-app and its references/dynamic-agent-providers.md. Show every returned provider, keep unavailable providers disabled with a reason, and choose a usable default. A configured CLI failure is explicit; never synthesize a fixed provider catalog.
Do not assume a Tutti API token, browser extension, daemon internals, or broad desktop APIs. The only browser-side host surface a generated app may optionally consume is the app context described in references/runtime-env.md.
Dependency Rules
Avoid startup-time package installation. If dependencies or build artifacts are necessary, add an executable prepare.sh and keep bootstrap.sh focused on launching the prepared app. prepare.sh may use $TUTTI_APP_PYTHON, $TUTTI_APP_NODE, and $TUTTI_APP_NPM for install and build steps.
Generated apps must not rely on system python, python3, node, or npm commands. Use the explicit managed runtime environment variables instead.
Keep generated apps small and inspectable. Do not add frameworks, background workers, databases, or network services unless they are required by the user request. Use Node built-ins for small apps; for larger Node servers with many routes, middleware, schemas, streaming, or WebSocket needs, Fastify is a good default and Express is acceptable when it already matches the project. For React/Tailwind UI apps, use shadcn/ui components and Tailwind CSS utilities instead of hand-rolled component markup and ad hoc CSS. Do not migrate a small vanilla app solely to use shadcn/ui unless the user explicitly asks for that frontend stack.
Local Debug Workflow
Use this workflow when the user asks for local app debugging, load-unpacked behavior, or direct development against an existing Next/Vite/Node/Python repository.
- Create
.tutti/dev-app/tutti.app.json,.tutti/dev-app/bootstrap.sh, and.tutti/dev-app/AGENTS.md. - Keep the formal release package path separate: a future release/import package must still be self-contained under
package/. - In
bootstrap.sh, read$TUTTI_APP_HOSTand$TUTTI_APP_PORT; exit with a clear error if the port is missing. The daemon owns port allocation. - If the app server lives in the project root, compute it from the dev app directory, for example
PROJECT_ROOT="$(cd "$TUTTI_APP_PACKAGE_DIR/../.." && pwd)", thencd "$PROJECT_ROOT"before launching. - Translate the project's known dev/watch command explicitly. For example, run Vite with host and port flags, run Next with
-H "$TUTTI_APP_HOST" -p "$TUTTI_APP_PORT", or run backend servers through their watch mode such astsx watch,nodemon,uvicorn --reload,air, orcargo watch. Do not depend on daemon-side framework detection. - Treat source hot-reload as the project dev server's responsibility. The Tutti host does not watch the user's project root and should not be expected to restart on normal frontend or backend source edits. If a server-side project lacks a watch/dev command, add or document a project-owned one such as
dev:tuttirather than adding daemon-side source watching. - Treat
.tutti/dev-app/files as host contract configuration. Changes totutti.app.json,tutti.cli.json,bootstrap.sh, assets, or dev-appAGENTS.mdrequire App Center's local-dev Reload action so the daemon rereads the manifest and restarts the runtime when needed. - Use
$TUTTI_APP_NODEand$TUTTI_APP_NPMfor Node-based dev servers. Do not call systemnode,npm,pnpm, oryarndirectly frombootstrap.shunless the user explicitly owns that dependency and accepts the portability tradeoff. - Document the source project entrypoint, the dev/watch command, which edits hot-reload through the project dev server, which edits require App Center Reload, and the fact that Tutti Desktop loads the project root or
.tutti/dev-app/in.tutti/dev-app/AGENTS.md. - Run
scripts/check_local_dev_app.py <project-root-or-.tutti/dev-app>from this skill after creating or repairing.tutti/dev-app/. Fix every reported failure before saying the local debug repair is complete. - Tell the user to retry App Center's Load unpacked action on the project root or
.tutti/dev-app/. Do not auto-open a Tutti app window.
The old zip/wrapper conversion approach is a fallback for compatibility or release packaging work only. Do not recommend it for normal local debugging; prefer .tutti/dev-app/ plus Load unpacked.
Conversion Workflow
When converting an existing repository into a Tutti workspace app package:
- Inspect the repository shape first: package manifests, lockfiles, source directories, existing start/build scripts, ports, static assets, storage paths, and localization files.
- If the user wants local debugging, use the Local Debug Workflow and generate
.tutti/dev-app/instead of a package wrapper. - For publishable packages, create a self-contained package under
package/that copies the smallest runnable subset of the existing project. Do not reference source files outsidepackage/, and do not rewrite the original repository outsidepackage/unless the user explicitly asks. - Translate the existing start command into
bootstrap.sh. If the project needs install or build work for a publishable package, put that in executableprepare.shand keepbootstrap.shlaunch-only. - Replace hard-coded host, port, data, runtime, and log paths with the Tutti runtime environment variables from
references/runtime-env.md. - If the user asks to connect the app to the Tutti ecosystem, expose stable app capabilities through
tutti.cli.json; otherwise, if the project already exposes commands, convert the stable user-facing commands intotutti.cli.json. - If the project already has localized metadata or UI copy, preserve it using
localizationInfofor manifest metadata and the i18n harness fromreferences/i18n-harness.mdfor in-app copy. - Document the adapted layout, original project entrypoints, runtime command, storage ownership, and any unsupported original features in package
AGENTS.mdor.tutti/dev-app/AGENTS.md. - Validate publishable packages against
references/validation-checklist.md; for.tutti/dev-app/, runscripts/check_local_dev_app.py <project-root-or-.tutti/dev-app>and then validate any project-specific startup behavior manually.
Implementation Workflow
- Read the required reference files.
- Decide the smallest runtime shape that satisfies the requested behavior.
- Write the manifest, bootstrap script, package guidance, and app files.
- Make
bootstrap.shexecutable. - For publishable packages, run
scripts/validate_tutti_app_package.py <package-root>when available, then validate remaining runtime behavior againstreferences/validation-checklist.md. - For local debug apps, run
scripts/check_local_dev_app.py <project-root-or-.tutti/dev-app>from this skill, then validate remaining project-specific startup behavior manually. - Fix any validation failure before finishing.
Repair Workflow
When fixing an existing draft:
- Preserve the existing
appIdunless the user explicitly asks to change it. - Reread the references before changing runtime or manifest behavior.
- Update
AGENTS.mdwhen endpoints, data files, commands, or storage rules change. - Keep reference files out of the package root.


