Files
tutti/docs/architecture/workspace-workflows.md
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

42 KiB

Tutti Mode Activation And Workspace Workflows

This document describes the Tutti-owned activation and workflow models used by Tutti Mode Plan. It covers the daemon business core, the Agent CLI boundary, AgentGUI projection, and Issue materialization.

Ownership Boundary

Tutti Mode is a Tutti-owned host preference, not a provider-native Agent mode or a capability granted to the Agent. Agent sessions and turns provide association, isolation, and provenance, but they do not own the Tutti activation, proposal, user decision, or resulting Issue. Tutti CLI availability is a separate runtime capability and never derives from the activation badge.

Ownership is split as follows:

  • services/tuttid/biz/tuttimodeactivation defines the durable activation and immutable revision vocabulary.
  • services/tuttid/service/tuttimodeactivation owns activation transitions, submission snapshots, and post-commit publication.
  • services/tuttid/biz/workspaceworkflow defines the durable workflow entities and state vocabulary.
  • services/tuttid/service/tuttimodeplan validates Markdown revisions, enforces transitions, projects executable work, and coordinates downstream operations.
  • services/tuttid/biz/tuttimodeexecution defines the durable Tutti execution aggregate and checkpoint vocabulary.
  • services/tuttid/service/tuttimodeexecution owns Tutti execution materialization and later orchestration commands.
  • services/tuttid/data/workspace stores workflow metadata in SQLite. Plan content is kept in immutable files under the Tutti state directory.
  • services/tuttid/service/cli/providers/tuttimodeplan exposes Agent-callable propose, revise, and get commands. It deliberately exposes no decision command and no wait/poll command: the agent's turn ends after propose or revise, and the user's review decision reaches the agent as a new user message.
  • packages/agent/gui/workspaceWorkflow renders the daemon snapshot and sends user decisions through the desktop runtime adapter. It contains no workflow business state machine.
  • Workspace Issue Manager owns the Issue and task graph after an accepted task-graph revision is materialized.

Provider-native Plan mode remains independent. /plan may enable a provider's planning behavior, while /tutti creates or advances a Tutti-owned TuttiModeActivation. The badges are compatible, and removing either badge only disables that modifier. The Tutti badge creates durable activation state, not a workflow; a workflow begins only when the Agent invokes the Tutti CLI. Workflow CLI capabilities remain discoverable when activation is inactive, but their mutation paths require the user-controlled activation to be active. The Agent has no CLI or service mutation that can change this state; it must ask the user to turn Tutti Mode on manually. The persisted agent_command source is retained only so revisions written by older builds remain readable.

Durable And Derived Entities

Entity Persistence Purpose and relations
TuttiModeActivation SQLite Tutti-owned session-associated activation root. It points to the current immutable activation revision; Agent Session exposes only an independent read projection.
ActivationRevision SQLite Append-only active or inactive transition. A submitted Turn uses one exact revision so later badge changes cannot rewrite running or historical work.
WorkspaceAgentSubmitClaim SQLite Generic idempotency record from clientSubmitId to one preallocated canonical Turn ID. A prepared claim is retained when delivery is ambiguous, so a retry reconciles or reports unknown instead of dispatching again.
TuttiModeTurnSnapshot SQLite First-write-wins link from one canonical Turn to the exact activation revision observed before provider dispatch. Same-Turn guidance reuses it instead of reading current state.
WorkspaceWorkflow SQLite Tutti-owned lifecycle root. It belongs to one workspace, records its source Agent session and any trusted turn/tool-call provenance available at creation, and points to the current revision.
TuttiModePlan SQLite Type-specific one-to-one marker for a WorkspaceWorkflow. It does not contain plan text.
PlanRevision SQLite metadata plus immutable Markdown file Append-only version of the proposal. Metadata records sequence, schema, path, SHA-256, and producing turn.
WorkflowCheckpoint SQLite A user-owned decision gate bound to exactly one revision. The task review is the only active checkpoint kind; the configuration-review kind survives solely as legacy vocabulary on retired workflows.
WorkflowTurnLink SQLite Optional provenance link from a workflow to source, decomposition, revision, or feedback turns.
WorkflowOperation SQLite Idempotent record of a downstream side effect such as generating a task graph, creating a revision, or creating an Issue. A successful Issue operation stores the Issue ID.
WorkflowMutation SQLite Durable caller mutation ledger for propose/revise response-loss recovery. Its scoped request ID is the identity; the input SHA-256 detects conflicting reuse, and the row points to the committed workflow/revision/checkpoint result.
ActionableItem Derived only Read-only projection of a task from the accepted current task-graph revision. It is never a second task store.
Workspace Issue and Task SQLite in Issue Manager Reusable Issue graph materialized from accepted ActionableItems. It links back through sourceSessionId; the workflow operation links forward through issueId.
Tutti execution SQLite Tutti-owned orchestration authority for one accepted workflow and Issue. Initial status is awaiting_schedule at graph revision 1.
Execution checkpoint SQLite Ordered durable orchestration gate. Materialization creates one active initial_schedule checkpoint and no Issue Run; every terminal Run later appends one deterministic settlement checkpoint.
Execution mutation SQLite Source-session-scoped mutation ledger for exact checkpoint/revision graph changes. It provides replay/conflict detection and records the incremented graph revision.

The relation is:

clientSubmitId --- WorkspaceAgentSubmitClaim --- canonical Agent Turn
                                                     |
                                                     v
Agent Session 1 ----- 0..1 TuttiModeActivation
                              |
                              +--- * ActivationRevision
                              |          |
                              |          +--- * TuttiModeTurnSnapshot ---+

Agent Session / Turn / Tool Call (workflow provenance)
                  |
                  v
         WorkspaceWorkflow 1 --- 1 TuttiModePlan
                  |
                  +--- * PlanRevision --- 1 immutable Markdown file
                  |          |
                  |          +--- * WorkflowCheckpoint
                  |
                  +--- * WorkflowTurnLink --- Agent Turn
                  |
                  +--- * WorkflowOperation --- 0..1 Workspace Issue
                  |
                  +--- * WorkflowMutation --- committed revision/checkpoint result
                                  ^
                                  |
          accepted current task-graph revision
                  -> ActionableItem projection
                  -> Workspace Issue + Tasks
                  -> Tutti execution + initial_schedule checkpoint

ActionableItem exists only when the current revision is a task_graph, its bound checkpoint is accepted, and that revision is still current. Pending, rejected, superseded, and stale revisions project no executable work.

TuttiModeActivation and WorkspaceWorkflow are independent roots. Activating the badge does not create a workflow, and invoking the CLI without an active badge may still create a workflow. A workflow reaches an activation revision only indirectly through its source Turn provenance; it never changes the badge.

The Agent CLI runtime context supplies AgentSessionID as the workflow association and isolation key. plan revise and plan get require the same caller session as the workflow's sourceSessionId; a mismatch is deliberately reported as not found. This is a local capability boundary, not a claim that an environment variable is a malicious-client authentication credential. The daemon host is responsible for constructing the CLI runtime context. Agent plan proposal and revision commands require the exact active Turn ID from that context and fail closed when it is unavailable. The plan service resolves that Turn through the activation service and verifies the document's explicit execution.effect and execution.speed equal its frozen snapshot before writing an immutable revision or workflow mutation. It never substitutes the mutable current Session preferences. sourceToolCallId remains empty until a trusted tool-call seam exists; App CLI ParentCommandID is nested-command context and must never be recorded as an Agent tool-call ID.

The same caller authority applies after Issue materialization. Generic Issue Manager mutations cannot modify a tutti_mode_plan graph; they return tutti_issue_managed with recommendedAction = open_source_session. The source Agent uses tutti plan issue mutate and supplies the active execution checkpoint and expected graph revision. Admission validates all operations and the resulting dependency graph in one SQLite transaction, advances the graph revision, rebinds the checkpoint, and cancels stale prepared/dispatched Goal Review state and reviewer wakes. Logical supersession preserves obsolete task/Run/output history while removing that task from the active projection; running tasks must settle before they can be superseded.

Activation And Turn Snapshot Flow

Before a Session exists, AgentGUI keeps the /tutti choice as an engine-owned pending activation intent. Session creation carries that intent explicitly; the daemon persists the Activation before starting the initial submission and returns the independent read projection. Existing-session badge changes use a revision-checked, idempotent activation command.

For every initial submission or ordinary Turn, the daemon allocates the canonical Turn ID before provider dispatch. When a clientSubmitId is present, the generic submit claim durably reserves that exact ID first. The daemon then persists a TuttiModeTurnSnapshot under the same ID before calling the runtime. A persistence failure therefore cannot start provider work. The runtime must accept and return that exact ID; it may not replace it with a runtime-generated one. Same-Turn guidance reads the already-bound snapshot instead of observing the current badge. A missing snapshot for an existing Turn fails closed rather than being reinterpreted as inactive. Removing the badge appends an inactive revision: it cannot alter an in-flight Turn, while the next new Turn receives the inactive snapshot. An explicit inactive revision retains its activation identity; a Session that has never been activated uses the canonical unconfigured inactive snapshot.

Runtime acceptance has three explicit outcomes. A definite pre-dispatch rejection abandons the prepared snapshot and submit claim. The API maps clientSubmitId into typed create/send input, and the service passes it through typed runtime input instead of recovering it from diagnostics metadata. After Exec reports provider acceptance, the Agent service explicitly invokes the required RuntimeController.DurablyReportSubmitProvenance method before any snapshot or claim promotion. The runtime adapter only maps and delegates this typed call. Because it occurs after Exec releases the Session lifecycle lock, the controller can wait on an uncoalesced FIFO durability barrier: the ordinary submitted report must already have created the canonical Turn, then one SQLite transaction writes the enriched Session projection and stable clientSubmitId user message against that exact Turn. After the barrier succeeds, the service accepts the bound snapshot, then reads the exact message provenance back before accepting the submit claim; retry reconciliation repeats both promotions idempotently. A barrier failure, or an accepted response with a different Turn ID, retains the claim, Session, activation, and snapshot. A retry with the same clientSubmitId first reconciles the preallocated Turn only against durable per-submit provenance and never performs a second provider dispatch while delivery remains unknown. A live runtime Turn, an accepted activation snapshot, or a matching Turn ID without that submit provenance is not enough evidence—especially because multiple guidance submissions may target the same Turn. This is an intentional at-most-once safety boundary; ambiguity is surfaced rather than guessed away. A crash after claim reservation but before the barrier commits leaves a prepared—not accepted—claim conservatively unknown. A crash after the barrier commits is deterministically reconciled from the stable message without another provider dispatch. Same-Turn guidance uses one distinct message per clientSubmitId, so multiple guidance submissions remain independently recoverable without rewriting the active Turn lifecycle.

The runtime derives a canonical Tutti-owned Host Context only from that exact snapshot. It does not derive instructions from capabilityRefs, user Prompt text, transcript markers, or arbitrary metadata. Provider adapters use the strongest host seam they expose. Codex uses developer instructions when its collaboration-mode contract is available; Codex without that negotiated seam and standard ACP use a provider-transport-only synthetic prompt block; Claude uses a coordinator-owned synthetic message. These fallbacks are transport details, not user-authored messages: Tutti's visible user message, prompt preview, and activity transcript remain unchanged. The context explicitly distinguishes Tutti activation from provider Default/Plan mode and reasoning effort. Reusing an existing provider Session does not weaken that boundary: each new Turn receives the current immutable activation snapshot before dispatch. The snapshot's state is the sole authority for reporting Tutti Mode status; provider Default/Plan mode and workflow existence are independent facts that cannot override it. A clear plan request still enters the Tutti proposal workflow instead of returning a chat-only plan. An active snapshot is a directive, not a suggestion: the Agent must not execute the user's request directly in that turn. It first asks focused clarifying questions when the request is ambiguous or missing key constraints, then submits one complete tutti-mode-plan/v1 document through a single run of the tutti plan propose shell command and then ends the turn immediately — there is no wait command, and the user's review decision always arrives as a new user message. Because providers repeatedly misread the bare directive as a built-in tool they lack and fall back to provider planning surfaces (update_plan, TodoWrite, chat-only Markdown plans), the active context also carries one worked example per workflow step: the resolved CLI executable name (tutti-dev on development installs), the exact plan propose / plan revise command lines, and a minimal valid plan document showing the frontmatter task graph. The guide requires a complete launch configuration on every task — agentTargetId, model, and permissionModeId copied from agent composer-options output, never invented — plus explicit execution.effect / execution.speed preference snapshots. The existing v1 reasoningIntensity and orchestrationIntensity fields retain their provider-reasoning and Issue-orchestration meanings; speed is never encoded into orchestrationIntensity. It routes model assignment through the injected $tutti-model-allocation skill so C0-C3 task requirements, the effect floor, speed ranking, hard capabilities, and effect-scaled validation are applied consistently. The skill ranks joint Agent/model candidates across every plausible target: the planning Agent, current provider/model, and provider defaults receive no affinity bonus, while an equally qualified non-planning target wins the tie for safely independent work so the planner remains available for coordination and final integration. Unless the user asks for supervised execution, the guide directs agents to the permission mode whose semantic is full-access (codex full-access, claude-code bypassPermissions): the user's approval happens once at plan review, so accepted tasks must not stall on mid-task approval prompts. The same resolved CLI name is used by the plan-revision feedback prompt. Read-only investigation is allowed while writing the plan; provider-native planning modes must not substitute for the Tutti plan workflow. Activation still does not gate tool availability—Tutti CLI capabilities remain available whether the state is active or inactive—but executing work the user has not accepted through plan review goes against the user's intent.

Markdown Revision Contract

Every proposal file uses the tutti-mode-plan/v1 schema: YAML frontmatter followed by a non-empty Markdown body. The flow is single-shot: every revision is one complete document containing the plan narrative (body) plus the full task graph (tasks frontmatter, at least one task, acyclic). phase may be omitted and defaults to task_graph. phase: configuration remains parseable only so legacy revision files stay readable; new configuration-phase proposals and revisions are rejected. Rejected revisions are replaced by a new complete immutable revision.

The frontmatter owns:

  • title and workspace topic ID;
  • sequential or parallel execution mode — parallel mirrors the Issue Manager's honest-parallelism gate at propose/revise ingress: every task must carry its own unique absolute execution directory, or the document is rejected while the agent can still fix it (never after acceptance, where the failed create_issue operation would strand an accepted workflow);
  • Issue-level reasoning and orchestration intensity; Tutti Host Context compiles the explicit speed preference into a 1-4 upper parallel target while the durable scheduler still enforces dependency, isolation, budget, and workspace-capacity limits;
  • explicit effect and speed values copied from the producing Turn's immutable activation snapshot; both fields are required for Agent CLI proposals and revisions, and either a missing snapshot or an unequal value rejects the mutation before revision-file persistence;
  • auto or fixed token budget and quota waterline (the token limit is dormant and no longer surfaced in UI);
  • task IDs, content, priority, assignment (agent target, model plan, model, permission mode, reasoning effort), execution directory, and dependencies.

Files live under:

<state-dir>/tutti-mode-plans/<workflow-id>/revisions/<sha256>.md

The globally unique workflow ID is the opaque file scope; workspace IDs never appear in state-directory segments. Publishing uses an atomic link. If the same content-addressed target already contains the same digest, a retry is an idempotent success; a mismatch fails closed. Reads verify the stored SHA-256 before parsing. Multiple intentional revisions may reference the same content-addressed file; revision ID and per-workflow sequence remain unique, while document path is not revision identity. The OpenAPI response includes parsed document data for clients; renderers do not read the state directory directly.

State And Decision Flow

Agent: tutti plan propose --file <plan.md> --request-id <stable-id>
  (plan.md = complete narrative + full task graph in one document)
  -> daemon validates effect/speed against the exact producing Turn snapshot
  -> daemon commits workflow + revision + the single pending task review
  -> daemon publishes workspace.workflow.updated
  -> AgentGUI pulls the authoritative session-scoped pending snapshot
  -> Agent's turn ends with the propose response (nextAction "stop")
  -> user accepts (optionally with per-task assignment overrides),
     rejects with feedback, or cancels through HTTP; turning Tutti mode
     off with a review still pending cancels the checkpoint the same way
  -> the decision reaches the Agent as a new user message when follow-up
     work is needed; there is no agent-side wait

review rejected ("request changes")
  -> the rejection commits durably with its create_revision operation
  -> the daemon dispatches a feedback turn to the source Agent session
     containing the feedback and revise instructions, idempotent through a
     checkpoint-scoped clientSubmitId and linked back as a feedback turn
     (best-effort; the committed rejection never depends on dispatch)
  -> Agent appends a complete replacement plan with tutti plan revise
  -> daemon validates the replacement against that revision Turn's snapshot
  -> revision append atomically completes that exact pending operation
  -> the panel refreshes onto the new pending review

review accepted
  -> the decision durably records any per-task assignment overrides
  -> daemon derives ActionableItems (document values merged with overrides)
  -> deterministic create_issue operation atomically materializes one Issue,
     its tasks, one Tutti execution, and one active initial_schedule checkpoint
  -> materialization creates no Run and invokes no task launcher
  -> operation succeeds with issueId and CLI reports issue_created

Legacy two-phase workflows are retired at daemon startup: a one-shot scan cancels every non-terminal workflow whose current pending checkpoint is a configuration review (actor tutti). Historical accepted configuration checkpoints may still advance to a task-graph revision, but new configuration-phase revisions are rejected.

The user-facing HTTP decision endpoint is the sole approval boundary. Agent CLI commands can observe a decision but cannot approve their own proposal. Rejection requires feedback. Repeating the same decision is idempotent; attempting a different decision or deciding a stale checkpoint fails closed. The decision compare-and-set includes the current workflow revision and status, so a concurrent revision cannot be overwritten by a late decision. Revision append likewise compares source session, current revision, workflow status, checkpoint identity, and checkpoint status in its final SQLite transaction. This prevents either side of a revise/decide race from reviving stale state.

Proposal and revision writes have a separate durable mutation ledger. Its unique key is (workspace, source session, mutation kind, workflow scope, request ID): proposal scope is empty, and revision scope is the workflow ID. The caller must reuse the request ID when retrying the same mutation after a timeout or lost response. The same key and Markdown SHA-256 returns the original workflow/revision/checkpoint result without another mutation; the same key with different bytes fails as a conflict. A new request ID is an explicit new mutation even when the Markdown bytes are identical, so content hashes are never treated as user intent or idempotency identity. The CLI reports both requestId and replayed.

Operations use deterministic identities derived from workflow, checkpoint, and operation kind. The Issue ID is also deterministic for the workflow. Its reserved namespace and identity constructor live in the daemon-owned workspaceworkflow business model; the reusable workspace Issue package only validates generic Issue semantics and does not know Tutti workflow identity. This allows retries to converge on the existing operation or Issue instead of duplicating a side effect. A failed create_issue operation is requeued through a compare-and-set transition to the same pending operation when decide is replayed. The retry clears stale error and completion fields; the idempotent Issue materializer then converges on the same Issue ID.

For a new decision, the checkpoint, resulting workflow status, and deterministic operation are one SQLite transaction. If operation insertion fails, the entire decision rolls back. Once that transaction commits, downstream materialization failure does not turn an accepted checkpoint into an apparent approval error: the response carries the committed checkpoint and durable failed operation. Only failure to record the operation outcome is returned as an execution error. If a decision response is lost, replaying the same decision finds the same checkpoint and deterministic operation; a succeeded operation is not executed again. During daemon composition, after the workflow and Issue services exist but before the public daemon service graph is returned, a one-shot recovery scan resumes accepted task graphs with pending or failed create_issue operations against the same deterministic Issue identity. Successful rows leave the recovery set, and a later plan wait or decision replay remains a secondary idempotent repair path. Revision read/parse and other operation-local failures are recorded on that operation and do not block recovery of later workflows; startup fails only when the scan fails or a durable operation outcome cannot be written. No background workflow worker is started.

The workflow service owns the transition policy. The single active checkpoint kind is the task review; the configuration-review row below is legacy-only (retired at startup, cancel remains valid):

Checkpoint Decision Durable result Agent next action
Task review Accept workflow becomes accepted; overrides recorded; create_issue operation issue_created after successful materialization
Task review Reject workflow remains in progress; feedback stored; feedback turn dispatched to source revise the complete plan
Task review Cancel workflow becomes canceled stop
Configuration review (legacy) Cancel workflow becomes canceled stop

Source Agent Session deletion is guarded at the Agent Host boundary against the entire canonical deletion closure. Before Host closes a runtime or mutates persistence, the daemon records one durable deletion admission for that exact closure. Any execution whose source Session is in the closure and whose status is not completed or archived rejects the whole request with tutti_execution_active plus the complete protected Issue set. This applies equally to single deletion, batch deletion, and workspace clear. Materialization checks the same durable admission in its creation transaction, so a new execution cannot race an admitted source deletion.

After admission, Host owns runtime closure and delegates canonical Session, activation snapshot, and Turn deletion to the daemon store in one SQLite transaction. Host reports terminal success or failure so the admission becomes finalized or superseded; a replan must pass admission again. At daemon startup, admissions left admitted by a previous process are superseded before Host serves requests. This keeps the source deletion guard on the provider- neutral lifecycle path instead of pre-closing runtimes in an adapter.

Stopping Tutti Mode is an archive saga, not source Session deletion. The archive request atomically changes the execution to archiving, pauses Issue dispatch, cancels pending checkpoints, wakes, reviewer work, and prepared launches, and records a durable idempotent operation with actor and reason. The service then cancels every running Issue Run through the exact-run coordinator and waits for authoritative settlement. Only after no Run remains running may the execution become archived with archived_at, archived_by, and archive_reason. Cancellation failure leaves a durable failed operation and the execution fenced; startup recovery retries each incomplete archive independently. There is no force-archive path.

HTTP, Events, And Recovery

The schema-first HTTP surface is:

  • GET /v1/workspaces/{workspaceID}/agent-sessions/{agentSessionID}/tutti-mode-activation returns the independent activation projection, including null before the first activation;
  • PUT /v1/workspaces/{workspaceID}/agent-sessions/{agentSessionID}/tutti-mode-activation appends an idempotent, revision-checked active or inactive revision;
  • GET /v1/workspaces/{workspaceID}/workflows?sourceSessionId=... lists every workflow for one Agent Session; adding checkpointStatus=pending narrows the result to workflows with a pending checkpoint. The hand-written client exposes these as listWorkspaceWorkflows and listPendingWorkspaceWorkflows respectively;
  • GET /v1/workspaces/{workspaceID}/workflows/{workflowID} returns one full authoritative snapshot;
  • POST /v1/workspaces/{workspaceID}/workflows/{workflowID}/checkpoints/{checkpointID}/decision records a user decision.
  • POST /v1/workspaces/{workspaceID}/tutti-executions/{issueID}/cancel-execution pauses dispatch and cancels active Runs for a proven Tutti-owned Issue without archiving the execution;
  • POST /v1/workspaces/{workspaceID}/tutti-executions/{issueID}/archive starts or replays the durable archive saga;
  • GET /v1/workspaces/{workspaceID}/tutti-executions/{issueID}/archive?operationId=... returns its authoritative operation state.

workspace.tuttimode.updated and workspace.workflow.updated are advisory invalidation events. The former identifies the changed Session and activation revision; the latter carries workflow, source Session, checkpoint, and change kind. Clients re-pull their authoritative HTTP or Session projection. Event loss is safe because committed SQLite and revision-file state remains authoritative. Every event-stream connected transition, including automatic reconnect, invalidates every currently subscribed workspace scope. AgentGUI then lists pending workflows for the active workspace and source Session again; the new request sequence invalidates any list result that began before the connection transition. Activation independently comes from the Session projection. The desktop adapter never opens a panel from transcript text or a model-authored marker. Renderer state carries the same workspace and source-session scope key. A scope change immediately hides the previous snapshot and invalidates in-flight list or decision results before they can mutate the newly selected Session.

Every daemon service response containing an Agent Session passes through one canonical response projection seam. That seam joins persisted Protocol v2 Turn state and the independent TuttiModeActivation read projection for create, resume/get, settings, title, visibility, pin, and list paths. A mutation must not return a hand-built partial Session, because an authoritative client upsert would otherwise interpret an omitted activation as removal and clear the badge.

The GUI panel displays only the current revision and its single pending task review. Before acceptance it exposes every Issue materialization input in that revision: execution mode, reasoning and orchestration intensity, quota waterline (the token limit is dormant and hidden), plus each task's ID, content, priority, execution directory, and dependency IDs. Each task's assignment (Agent target, model plan, model, permission mode, reasoning effort) is editable in place through host-supplied option catalogs; the edits travel with the accept decision as per-task overrides and are durably recorded on the checkpoint. Accept, reject, and cancel post the decision to the daemon; rejection feedback is mandatory. Closing the app does not discard the review: the next mount reconstructs it from the daemon snapshot.

Desktop assignment catalogs load provider composer options through the same activity-core target-scoped cache used by the main Composer. The workflow adapter may join that canonical snapshot with the workspace Agent directory and compatible model-plan catalog, but it does not create a second provider-options transport path. Model and reasoning entries retain their canonical value/label metadata end to end: task overrides persist the opaque provider value, while editable and read-only review surfaces render the label and fall back to the value only for an unknown historical selection.

The Tutti activation additionally carries a session-scoped orchestration intensity (0-100, default 50). The composer's Tutti Budget popup persists it as a new activation revision; each turn's frozen snapshot copies it, and the Tutti Host Context exposes it so the planning Agent chooses decomposition granularity from it.

Issue Projection

Accepting a current task graph synchronously asks the daemon-owned Issue materializer to create an Issue from the derived ActionableItems. One SQLite transaction creates the Issue, tasks, Tutti execution aggregate at awaiting_schedule/graph revision 1, and its active initial_schedule checkpoint. It maps the Markdown execution profile, budget, assignments, model choices, directories, and dependency graph into the Issue Manager contract and records planningSource = tutti_mode_plan.

Materialization is inert: it creates no Run and calls no task launcher. The source Agent must later schedule an explicit task set through the checkpoint- and-revision-fenced Tutti execution command surface. Existing autoAccept values remain readable migration metadata but have no dispatch authority for Tutti-owned executions. Manual and traditional_plan Issues keep the generic Issue Manager dispatch behavior.

plan issue schedule derives source authority from the trusted invoke context. While holding the Issue mutation lock, the daemon validates the entire requested set, including isolation. One SQLite transaction revalidates the durable caller, active checkpoint, graph revision, task/dependency state, budget, and workspace capacity. Fixed-budget admission reserves one estimated allowance for every same-Issue active Run before evaluating the requested set. The transaction then creates every Run, task-running projection, and durable launch intent while resolving that checkpoint. Any rejection leaves the execution and Issue graph unchanged.

Agent launch happens after commit. The launch-intent row is the source of truth for clientSubmitId; delivery workers claim it with a durable lease and pass that stored value unchanged into Agent Host. The active worker renews the lease throughout worktree creation and Agent delivery. Ordinary recovery never steals a leased intent, and startup recovery requeues only an expired lease, so a second daemon replica starting while the first launch is live cannot enter the launcher. Response-loss recovery retries the same deterministic issue-run:<runID> identity, allowing Host to converge on the existing canonical Turn rather than creating a second one. Tutti settlement, reconciliation, and cancellation resolve this persisted identity from the launch intent; only generic Issue Runs derive the deterministic default. The existing Issue Run reconciliation queue also requeues expired launch ownership and recovers prepared intents on every pass. A daemon that restarts before the previous owner's last lease expires therefore retries immediately after that expiry instead of leaving the Run stranded until its hard timeout.

A definite launch failure is terminal only when the adapter can prove that no canonical Turn exists. An empty create result alone is insufficient: the adapter also checks Host by the exact persisted clientSubmitId. A found Turn, a lookup error, ErrSubmitDeliveryUnknown, or a create error carrying a Turn ID remains recoverable. Only a clean Host not-found permits terminalization. That write is one owner-fenced SQLite transaction: the currently leased launch intent, Run, Task, Issue projection, and deterministic task_failed checkpoint either commit together or all roll back. An expired owner therefore cannot settle a Run after another daemon has reclaimed its lease.

Every terminal Issue Run (completed, failed, or canceled) creates one ordered deterministic checkpoint. Completion remains pending_acceptance/agent_claimed until the source Agent reviews that checkpoint. The Agent may resolve the checkpoint by scheduling an exact next task set, or acknowledge it when another Run is active or a later settlement is already queued. Acknowledge accepts a successful task, promotes the next pending checkpoint, and never invokes the generic dispatch frontier. Failed and canceled checkpoints preserve their terminal task projection. Settlement repair runs at startup and on the periodic Issue reconciliation cadence, so a crash after Run persistence cannot lose the review gate.

When every task is terminal and every terminal Run has its settlement checkpoint, the execution appends one ordered all_tasks_terminal checkpoint with requiresGoalReview. Promoting it moves the execution to pending_goal_review; the generic acknowledge command deliberately cannot resolve this boundary. If a graph mutation adds or reworks tasks while that terminal checkpoint is still pending, the mutation supersedes the stale terminal boundary. After the replacement work settles, the same deterministic terminal checkpoint is rearmed at the current graph revision and moved behind the new settlement checkpoint. This preserves one terminal identity while ensuring the final settlement can always promote a current Goal Review. The settlement recovery scan applies the same readiness check to persisted executions whose replacement Run had already settled before this invariant was enforced, so daemon recovery repairs the stranded terminal backlog without weakening acknowledge fences.

After acceptance the source conversation embeds a live "issue panel view" (board/list) of the materialized Issue, fed by the same workspace issue events the Issue Manager consumes. The embed surfaces the durable task structure and execution state; Tutti-owned scheduling, mutation, and completion authority comes from the source conversation rather than generic Issue mutation or automatic dispatch.

The embedded panel's task-level accept and rework controls are source-Agent prompt actions. They append a localized instruction with the exact Task mention to the source conversation draft, preserve existing draft content, and require an explicit user send. The renderer does not translate them into generic Task status writes. After submission, the source Agent reads canonical execution state and uses the existing checkpoint/revision-fenced command path. Direct daemon-owned commands such as execution cancellation remain commands rather than prompts.

The workflow remains the review and provenance record; the Issue remains the task/run evidence graph; and the Tutti execution is the orchestration authority. No renderer or Agent turn recreates the graph, and no Agent is instructed to issue a second create call. If materialization fails, the create_issue operation records a durable failure code and message, and the authoritative workflow snapshot remains inspectable through tutti plan get and the HTTP detail endpoint. Startup recovery, replaying the accepted decision, or observing it through tutti plan wait retries the same durable operation; it never asks the Agent to create the Issue separately.

The Agent-facing issue create-from-plan command accepts only traditional_plan provenance. It rejects tutti_mode_plan; that provenance can be written only by the daemon workflow materializer after the matching checkpoint is durably accepted.

Validation Boundaries

  • Change the OpenAPI source before generated HTTP clients.
  • Change the event protocol definition before generated event types.
  • Keep workflow transitions and Issue materialization decisions in tuttid.
  • Keep AgentGUI as a snapshot projector and decision client.
  • Do not infer workflow state from provider Plan cards, transcript ordering, Markdown markers in messages, or the /tutti badge.
  • Do not infer activation state from historical capabilityRefs; they are submission provenance only.
  • Do not persist ActionableItem separately from the accepted revision.
  • Do not expose Agent-callable accept or reject CLI commands.