Repository navigation
[feat] Close the #1080 gaps that #1175 leaves open #1246
Copy link
Copy link
Open
Description
Parent: #818
Follow-up to: #1080, #1175
Implemented in: #1251
Goal
Close the workspace gaps that remain once #1175 lands, before the drivers, delivery, resume, scorers and benchmarks build on that contract.
flowchart LR
I1080["#1080 workspaces<br/>(PR #1175)"]:::done
FU["this issue<br/>F1-F7"]:::added
I1082["#1082 requirements"]
I1085["#1085 step scorers"]
I1086["#1086 session driver"]
I1087["#1087 Paseo driver"]
I1090["#1090 PR delivery"]
I1180["#1180 benchmarks"]
I1080 --> FU
FU -- F3 --> I1082
FU -- F4 --> I1085
FU -- "F1 F2 F3 F5" --> I1086
FU -- "F2 F3 F4 F5" --> I1087
FU -- "F1 F2" --> I1090
FU -- "F2 F6" --> I1180
I1086 -- "run lookup by id" --> I1087
classDef added fill:#2f8f4f,stroke:#1f6b39,color:#fff;
classDef done fill:#4a5f7f,stroke:#33445c,color:#fff;
Example
# ship-issue, excerpt
steps:
- id: change
workspace: new
workflow:
steps:
- id: implement
prompt: Implement issue {{ inputs.issue }}.
- id: test
needs: [implement]
command: npm test # no workspace: read-onlystep runs in (today) sees npm test with F4
implement change copy the change - change copy
test member checkout (base) the base passes change copy → fails ← the change broke a test; today nobody sees it
step commits today with F1
a .tclaude/settings.json (hook) - -
b runs tclaude on a's branch a's hook runs, holds a token base settings.json; hook does not run
Scope
- F1. Reset every agent configuration path to the run's base.
AGENT_PATHS(src/workflow/worktree.ts:12) misses the project directories of four tools the local driver runs (src/workflow/local-tool-adapter.ts:13):.claude-internal,.tclaude,.codex-internaland.tcodex, which hold their settings and hooks (src/types.ts:481-499). It also misses.mcp.jsonandopencode.json(src/types.ts:462,:702), and Discussion: Workflow Runtime Integration #818 names.mcp.jsonas agent configuration. [feat] Add workflow workspaces, branches, and session continuation #1080's last criterion says hooks or equivalent agent configuration committed by an earlier step do not run in a later step that holds a token. Keep today's paths, including.agentsand.cursor, and add eachtoolPathsentry's project configuration andmcpProject, not only the tools the local driver runs, since [feat] Add the session skill driver and invocable workflows #1086 and [feat] Add a Paseo driver adapter #1087 run other tools. Export the list so [feat] Deliver workflow branches as pull requests #1090's protected-path check uses it, plus delivery-only paths such as.github/workflows/. - F2. Record the run base at
workflow start.headCommitreturns{ ref: 'HEAD', commit }(worktree.ts:78-83), andrun.basecomes from whichever driver first sendsbasetonextwith aneworcontinuelease (engine.ts:930);nextaccepts it from any driver (engine.ts:1103-1109). Whenworkflow startruns in a git checkout, it records the commit, the branch HEAD points to (left out on a detached HEAD), and the checkout the run started in, kept in local state only. A command-only run outside a git checkout still starts, and the firstnextthat sendsbasesets it, as today. A laterbasefrom another driver is ignored or checked againstrun.base. The lease parser requires a stringref(local-driver.ts:321) and, when it is missing, drops the whole workspace, so the step runs in the member's checkout. It should accept a missingref, and a lease whoseworkspacedoes not parse fails its step. - F3. A held-back step must not block other ready steps.
leaseNextreturnswaitat the first held-back step (engine.ts:925). Repro at 6529f53: stepsa(workspace: new) andb(needs: [], read-only), drivercan.workspace: [read-only];nextanswerswaitand never leasesb. An idle local driver turns thatwaitintobusy(local-driver.ts:850). Skip the held-back step for this driver and try the next; answerwaitonly when every ready step is held back, and list them. [feat] Enforce workflow requirements and execution limits #1082's requirement checks would reuse this path. - F4. A read-only step inside a copy runs in that copy. A command with no
workspaceis read-only "even inside a workspace a parent opened" and runs in the member's checkout (docs/guide/workflow.md:140;placeOf,local-driver.ts:357-359), and so does a prompt withworkspace: read-only, sinceplanWorkspacereturns before any lineage (workspace.ts:242). The example above is the result. The decision on [feat] Add workflow workspaces, branches, and session continuation #1080 reads "If it changes the active checkout, the step fails"; inside a copy, the active checkout is the copy. A read-only step nested in a copy is leased to the driver that owns the copy, by the owner check acontinuestep gets (workspace.ts:260-263), runs in that copy with the same dirty check, and runs one at a time with the copy's other steps, as feat(workflow): add workspace branches #1175 already does per checkout. The pass records the commit it read, so a reviewer and its scorer ([feat] Add workflow scorers and recorded quality labels #1085) see the same range. A read-only step outside any copy keeps running in the member's checkout. - F5. Check
changesagainst the lease.reportaccepts anychanges.branchandchanges.base(engine.ts:1063-1072) and records a copy under that name (:1209-1213), so it can answercleanup: truewhile a later step still continues the leased branch. Reject a report whosechanges.branchorchanges.basediffers from the attempt's lease. - F6. Observe a workspace step through the worktree's own config.
loadAgent,observeLaunchandworkflowLaunchreceive the member checkout'sconfig(local-driver.ts:578,:603,:612). The worktree has had its own pull record since 545baf5, so the step records the member checkout's team revision, and its tool pulls in the background while it runs (src/launch-context.ts:39-56). Pass the configdetectProjectConfig(dir)returns for the worktree. - F7. Record
bad_session.bad_session(workspace.ts:206,:209) is missing fromRECORDED_FAILURES(records.ts:33-38), so the run record drops it.
Out of scope
Per-trial bases and the clone mode (#1180), pushing only what delivery needs, recovery of a continue copy whose owner never returns and session bindings across machines (#1084), and pr_url (#1090).
Dependencies
- Blocked by: [feat] Add workflow workspaces, branches, and session continuation #1080 (feat(workflow): add workspace branches #1175)
- Unblocks: [feat] Enforce workflow requirements and execution limits #1082 (F3), [feat] Add workflow scorers and recorded quality labels #1085 (F4), [feat] Add the session skill driver and invocable workflows #1086 (F1, F2, F3, F5), [feat] Add a Paseo driver adapter #1087 (F2, F3, F4, F5), [feat] Deliver workflow branches as pull requests #1090 (F1, F2), [feat] Run benchmark suites as workflows #1180 (F2, F6)
Acceptance criteria
- A step that continues a branch on which an earlier step committed
.mcp.json,opencode.jsonor.tclaude/settings.jsonruns with the base version of each. run.base.refis the branch the member's checkout was on atworkflow start, and a laterbasesent tonextby another driver does not change it. A lease with an unparseableworkspacefails its step.- With ready steps
a: newandb: read-only, a driver declaringcan.workspace: [read-only]getsb, andastays pending. - In the example above,
testruns in the change copy and fails, and the pass records the commit it read. A read-only step outside any copy still runs in the member's checkout. - A report whose
changes.branchdiffers from the lease is rejected. - A prompt step in a
newworkspace records the worktree's team revision, and its tool does not start a background pull. - A run record keeps
bad_session.
Verification
Focused workspace and local-driver tests for each criterion; build/typecheck/lint; one real-CLI run of the example where test sees the change, plus a later step that continues a branch with a committed .tclaude/settings.json. Update the bilingual workflow docs where behavior changes.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
SaulMoro commentedon Oct 21, 2026
#1251 implements F1 to F7.
These decisions go beyond the text above:
readfield (branch,base,commit) instead ofchanges.reportrejectsreadon any other lease, and rejects a reader's success without it.needswrote or read. When they touched none, it is the enclosing copy's branch. Needs on several branches fail withworkspace_baseand ask for a step that merges them.refs/teamai/kept/<attempt>. Its submodule commits go underrefs/teamai/kept-modules/<attempt>/. Then the copy is reset to the commit it read.teamai-unrestoredmarker is written when the reader starts. It refuses later steps in that copy until the copy is back, even after a killed driver.toolPathsare not reset, because each tool reads its own fixed project paths.The real-CLI record of the issue's example is in #1251. At
6529f53dthe run fails with "feature.txt missing, the test ran without the change". With #1251 it succeeds, andchange.implementsees the base.tclaude/settings.json.Open and not covered here:
refs/teamai/kept*refs are never pruned. They are the recovery copy of a reader's change, and pruning them needs a run retention policy that does not exist yet.The writer side no longer depends on what the user's git config shows.
commitWorkalways stages, and checks the index with--ignore-submodules=none --no-ext-diff. A retry's push check readsgit branch --no-color.fix(workflow): run a read-only step inside a copy in that copy