源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
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
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
This commit is contained in:
@@ -0,0 +1,631 @@
|
||||
# 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 `ActionableItem`s. 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:
|
||||
|
||||
```text
|
||||
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:
|
||||
|
||||
```text
|
||||
<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
|
||||
|
||||
```text
|
||||
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 `ActionableItem`s. 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.
|
||||
Reference in New Issue
Block a user