App CLI Core
packages/appcli/core owns the reusable Go implementation of the App CLI
protocol contract used by workspace apps.
The package is intentionally limited to protocol-level behavior:
tutti.app.cli.v1manifest reading and validation- command capability construction from a manifest and host-provided app metadata
- manifest input normalization
tutti.app.cli.invoke.v1HTTP invoke envelopes- handler response decoding and output contract validation
- wait-command execution metadata and validated pending continuations
- scope conflict and reserved-scope state calculation
Host products keep their own workspace lookup, durable state, app package
metadata, runtime startup, and user-facing status DTO adapters outside this
module. Tutti daemon integration lives in services/tuttid/service/cli/appcli.
The protocol strings still use the frozen Tutti App CLI contract for backwards compatibility with existing app manifests and handlers. That does not make this module a Tutti daemon business layer; consumers such as TSH can reuse the protocol core while supplying their own host adapters.
Wait commands
An app command that semantically waits for a run, session, or other durable
execution declares execution.mode as wait. Its handler returns an ordinary
final output when the execution reaches a stop point. While the execution is
still active, the handler returns a validated continuation with state
pending and a bounded retryAfterMs delay.
The terminal CLI consumes continuations automatically. One visible command
therefore remains active across multiple handler invocations; callers do not
poll and do not pass a follow flag. The CLI-owned --timeout-ms option is an
optional total wait deadline. When it expires, the command returns a successful
JSON observation with reason: "wait_timeout", timedOut: true, and
executionContinues: true; it never cancels the underlying execution.
Handler timeoutMs remains a per-invocation transport budget. It is not a
workflow or total wait timeout.