engineering-memory 1.11.9 → 1.11.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dispatcher/sections.mjs +6 -2
- package/install/codex-approval.mjs +457 -0
- package/install/files.mjs +5 -1
- package/install/installer.mjs +24 -1
- package/package.json +1 -1
- package/runtime/build.json +1 -1
- package/runtime/dist/src/config.js +1 -0
- package/runtime/dist/src/git/git-inspector.js +82 -3
- package/runtime/dist/src/git/verification-gate.js +30 -17
- package/runtime/dist/src/mcp/onboarding-tools.js +3 -16
- package/runtime/dist/src/mcp/questionnaire-tools.js +99 -15
- package/runtime/dist/src/mcp/tool-annotations.js +111 -0
- package/runtime/dist/src/mcp/tool-definitions.js +148 -28
- package/runtime/dist/src/mcp/worktree-tools.js +323 -236
- package/runtime/dist/src/project/repository.js +11 -5
- package/runtime/dist/src/runtime/active-context-store.js +3 -0
- package/runtime/dist/src/runtime/branch-preferences.js +0 -19
- package/runtime/dist/src/runtime/bridge-service.js +1131 -220
- package/runtime/dist/src/runtime/offline-outbox.js +33 -158
- package/runtime/dist/src/runtime/phase-timer.js +26 -0
- package/runtime/dist/src/runtime/privacy-detector.js +263 -0
- package/runtime/dist/src/runtime/questionnaire-store.js +210 -49
- package/runtime/dist/src/runtime/recovery-error.js +3 -1
- package/runtime/dist/src/runtime/runtime-entry.js +8 -0
- package/runtime/dist/src/runtime/runtime-host.js +1 -3
- package/runtime/dist/src/runtime/task-branch-store.js +17 -1
- package/runtime/dist/src/runtime/task-start.js +281 -0
- package/runtime/dist/src/runtime/worktree-pool.js +334 -24
- package/runtime/dist/src/utilities/process.js +1 -0
- package/skill/SKILL.md +3 -3
- package/skill/references/lifecycle.md +44 -19
- package/skill/references/memory-updates.md +9 -3
- package/skill/references/project-onboarding.md +19 -2
- package/skill/references/questionnaires.md +77 -15
|
@@ -8,11 +8,11 @@ Use the binding returned by `session.entry` as the authority. The bridge stores
|
|
|
8
8
|
|
|
9
9
|
An archived project is recoverable state, not a missing or conflicting binding. When an owner receives `project.restore`, use the `projectId` and `expectedVersion` in its data and call that operation before retrying. A non-owner receives `project.member_list` instead: check the available roles and explain that project-owner authority is required to restore this exact project before retrying. Do not name a person or disclose contact details. Use `project.list` with `includeArchived: true` when an owner must first select the archived project. Never create or bind a replacement project to escape archive state.
|
|
10
10
|
|
|
11
|
-
For a bound repository, call `session.bootstrap` before producing a plan or changing files. Supply the current repository root, project ID, task ID or stable local task slug, objective, task kind, task mode, and current Git diff hash. Use `read_only` for review, diagnosis, planning, or reporting without write authority; use `scaffold` when the task applies organization architecture templates to a new project; use `write` when the request authorizes repository changes. The bridge records the read-only Git diff hash as the immutable task baseline, including a pre-existing dirty worktree. Use the returned task ID, task version, context session ID,
|
|
11
|
+
For a bound repository, call `session.bootstrap` before producing a plan or changing files. Supply the current repository root, project ID, task ID or stable local task slug, objective, task kind, task mode, and current Git diff hash. `externalTaskId`, `objective`, `taskKind` and `workItemKey` are each one line with a fixed maximum length (160/240/80/120 characters); the bridge refuses an over-length or multi-line value locally, in milliseconds, before any Git or backend work, and names the limit in the refusal — put detail that does not fit in checkpoints, not in the objective. Use `read_only` for review, diagnosis, planning, or reporting without write authority; use `scaffold` when the task applies organization architecture templates to a new project; use `write` when the request authorizes repository changes. The bridge records the read-only Git diff hash as the immutable task baseline, including a pre-existing dirty worktree. Use the returned task ID, task version, context session ID, project profile, engineering rules, prior task documents, quality gates, and current deviations; `deferredResources` names what did not fit, each with the `revisionId` to read it by.
|
|
12
12
|
|
|
13
|
-
Before a new write or scaffold task, read `session.entry` and the project Git preferences. If `canManage` is true,
|
|
13
|
+
Before a new write or scaffold task, read `session.entry` and the project Git preferences. If `canManage` is true, and any of development/production/test is still unanswered, ask them through one native form and save them with `project.set_git_preferences` — the tool asks every supplied role as its own question in that single form, then saves the approved roles together in one PUT. Development needs a branch; production/test may explicitly be absent. Their answered flags prevent repeated questions. Other members choose only a task-specific base and continue without changing shared preferences. A later request to change a base updates future tasks only. Branch preferences never label memory sources or change commit/tree applicability.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Start new write or scaffold work with `task.branch`, before `session.bootstrap`, passing the stable `externalTaskId` and `repoRoot`. It opens one native form: where the branch starts (the configured project branches, this folder's branch and commit, or another remote branch), the new branch's name with a suggested default, and the folder: a separate managed worktree, this folder as a new branch when it is clean (moving out an unfinished task that holds it, which that option names), this folder on its current branch, or not now. Pass `base` or `name` only when the user has already said them; those questions then drop out of the form. Show the whole form in as few native control calls as the host allows, relay every answer together, then call `task.branch` again with the same arguments, which is the `retry` the relay returns. That call allocates exactly what was answered, fetches a remote base and pins its commit, and returns the `repoRoot` to bootstrap in. When the fetch fails it asks once whether to continue from the local commit; never select a cached branch silently. "Not now" returns `status: 'deferred'` with nothing created, reserved or saved: say so in one line, continue only read-only work, and call the returned `reconsider` exactly as given once the user asks to start it. A refusal that names a new `decisionAttempt`, such as a branch name that already exists, asks the form again under that attempt. Existing task decisions survive retries and restarts; resume a recorded branch rather than recreating or resetting it.
|
|
16
16
|
|
|
17
17
|
Use the returned `repoRoot` for **every** file read/write, terminal, context, validation and Git/delivery operation. The user-local pool is shared by Codex and Claude. Managed directories live under `engineering_memory/worktrees/<stable-project-folder>/<folder>_worktreeN`, at the root of the system drive on Windows (`C:\engineering_memory\worktrees\...`) and in the home directory elsewhere, or under the absolute directory named by `worktree-root.json` in the user-level API state directory when that file exists; `worktree.list` reports the effective root, and worktrees created by earlier clients under the Documents folder keep working where they are. Do not supply arbitrary `worktreePath` values or create ad-hoc siblings. Independent clones cannot reuse each other's worktrees. `worktree.list` explains which slots are active, inactive but protected, or safely reusable. The versioned backend policy defaults to 50 directories per project/computer, 30-second heartbeats and 10-minute inactivity. Protected inactive directories still count toward the limit. Only a global admin changes `worktree.set_policy`; it is not an environment setting.
|
|
18
18
|
|
|
@@ -20,7 +20,7 @@ Renew `task.heartbeat` using the exact returned task, path and ownership generat
|
|
|
20
20
|
|
|
21
21
|
Use `task.pause` when work stops or is handed to another client. It preserves task state and files, invalidates the old owner, and allows safe clean directories to be reused. It is not `task.abandon`. Resume reacquires the original directory when possible or uses the retained task branch in another safe directory. `worktree.reconcile` recovers interrupted allocation and validated local ownership records against Git. Never edit the registry, force checkout, stash/reset/clean, remove branches, kill a client or delete a worktree to bypass a refusal.
|
|
22
22
|
|
|
23
|
-
`task.close` retains a managed checkout while changes or delivery remain pending.
|
|
23
|
+
`task.close` retains a managed checkout while changes or delivery remain pending. After delivery, release with `deliveryOutcome:'delivered'` and the current generation. When the user decides not to deliver, call `worktree.release` with `deliveryOutcome:'cancelled'`; the product asks what happens to the folder and saves any changes to a ref. Never run `git restore` or `git clean` yourself to free a worktree, and never report a delivery that did not happen. Dirty/staged/untracked files, pending outbox/intents and unfinished Git operations prevent release. An old release cannot affect a reused directory. User-owned existing directories are never added to automatic cleanup. When the user wants to work in the main folder, they answer that in `task.branch`'s start form; when an open task holds the folder, that option names the task that would move out. A closed or abandoned task stops holding the folder by itself; a task still running in another client keeps it until it is paused there. Never edit or delete the reservation ref by hand.
|
|
24
24
|
|
|
25
25
|
Read-only tasks allocate no worktree. If the user authorizes writing, settle `task.branch` for that same externalTaskId, use the allocated repoRoot, then call `context.prepare_change` with `transitionToWrite`. Its pinned source must still match; choosing a different source requires a new task, never rewriting the original task's source identity. Existing lease, discipline, source-memory, verify and commit gates remain mandatory.
|
|
26
26
|
|
|
@@ -30,7 +30,7 @@ A task nobody is going to finish is abandoned rather than inherited. Ask the use
|
|
|
30
30
|
|
|
31
31
|
If an existing task is identified or execution resumes after compaction, call `session.resume`. Reconcile backend sequence, local outbox, Markdown projections, current Git diff, pinned revisions, and the active lease before any further action.
|
|
32
32
|
|
|
33
|
-
Reconcile pending questions too. A required question remains unanswered across a timeout, dismissed form, interruption or restart. Use `questionnaire.resume` for its recorded identifier and wait for an explicit valid response before dependent work. Follow `questionnaires.md`; do not create a replacement async prompt or consume an unrelated task's answer.
|
|
33
|
+
Reconcile pending questions too. A required question remains unanswered across a timeout, dismissed form, interruption or restart. Use `questionnaire.resume` for its recorded identifier and wait for an explicit valid response before dependent work. Follow `questionnaires.md`; do not create a replacement async prompt or consume an unrelated task's answer. A question belongs to the task the chat was working on when it was asked. `pendingQuestionnaires` lists this chat's own questions and those that belong to no task in full; another task's appear under `otherTasksPendingQuestionnaires` as a one-line summary naming that task. Resume one of those only when this chat is working on the task it names.
|
|
34
34
|
|
|
35
35
|
## Discovery
|
|
36
36
|
|
|
@@ -85,6 +85,12 @@ Do not pull history for everything. Pull it for the records the task actually to
|
|
|
85
85
|
|
|
86
86
|
Send calls that do not feed each other in one batch rather than one at a time: reads of any kind, and proposals for different records. Proposal drafting, submission and pending approval do not block independent task work. Use host-authorized background agents or concurrent tools and continue the next independent unit; do not immediately wait for the worker. If concurrency is unavailable, checkpoint the pending draft and defer submission until an operation needs it. Follow `references/memory-updates.md` for ownership, delivery tracking and recovery. Reconcile every record the task touched in a single `task.reconcile` call with `entries`, not one call per record.
|
|
87
87
|
|
|
88
|
+
That is a rule for work that can run beside the task, not for the checks that steer it. A check whose answer decides the next action — delivery preconditions such as the commit hook, the remote and the branch; whether verification or close can pass; what a waiver allows — is run by the agent that takes that action, in its own turn. Hand work to another agent only when you have other real work to do while it runs, and never take the action a delegated check gates before its answer is back: a report that arrives after the commit it should have stopped is worth nothing. Work another agent checked is neither the user's approval nor task verification.
|
|
89
|
+
|
|
90
|
+
Size delegation to what the task actually needs: a one- or two-file change carries no discovery a single agent cannot finish itself, and a multi-agent workflow on it adds a wait without adding an answer. Once work is delegated, wait for its real completion signal — a task notification, a returned result — never a sleep loop polling its journal or log, and never a blocking wait on its output; keep doing the next independent piece of lifecycle work and collect the delegated result when it actually arrives.
|
|
91
|
+
|
|
92
|
+
Order blocking questions the same way: finish everything that does not depend on the answer — the models, the services, the parts of the implementation the answer cannot change — before opening one, so a user who is away comes back to progress instead of an untouched task. Ask at the point where the answer is actually needed, not at the start of discovery merely because that is where the question first came up.
|
|
93
|
+
|
|
88
94
|
Checkpoints, recorded corrections, reconciliations, self-reviews and scaffold application receipts return before the backend has them, reporting `deliveryStatus: 'pending'` with the task version they will occupy. The local recording call is complete; backend delivery remains pending and is already under way. Do not wait for it, poll it, or send it again before a dependent operation. Collect a proposal's identifiers when its approval or reconciliation needs them, and an approved revision before work that depends on its changed contract. A prepared lease, required synchronization and verification must succeed before the operations that require them; unrelated proposal work is never a prerequisite for continuing this task.
|
|
89
95
|
|
|
90
96
|
Temporary code written to reach or force a path — a pinned state, a fixed service response, a jump straight to the screen — is allowed and expected, carries the marker `ENGINEERING-MEMORY-TEMPORARY` immediately followed by a colon and its reason, and is removed before verification. `task.verify` refuses while any marker is in the tree and names every line, and the commit gate refuses while one is staged.
|
|
@@ -157,7 +163,7 @@ reopening the task and abandoning it.
|
|
|
157
163
|
|
|
158
164
|
Skip change preparation for a read-only task. Do not request an edit lease, send changed paths, record `pre_edit`, or reconcile code resources in that mode. If the user later authorizes a change, call `context.prepare_change` with `transitionToWrite: true`, the bridge-owned current task version, intended paths, and current baseline diff. Continue only after the bridge returns the updated write task and lease.
|
|
159
165
|
|
|
160
|
-
Keep the path set narrow. A lease covering most of the repository returns more knowledge than one response can carry, and the resources that do not fit come back as `deferredResources` instead of content.
|
|
166
|
+
Keep the path set narrow. A lease covering most of the repository returns more knowledge than one response can carry, and the resources that do not fit come back as `deferredResources` instead of content. Read a deferred record with `memory.read_revisions` and the `revisionId` its entry carries before touching the path it governs; skip the ones that govern nothing you are changing. Prefer several small leases over one wide one.
|
|
161
167
|
|
|
162
168
|
For a write task, list the precise relative paths likely to change and call `context.prepare_change`. It must return a change lease and read receipts for every matched required resource. Read the full returned screen, component, service, navigation, localization, storage, or state record before editing its matched path.
|
|
163
169
|
|
|
@@ -189,9 +195,15 @@ A project-specific correction is offered as task-only or permanent for this proj
|
|
|
189
195
|
|
|
190
196
|
Before validation, read the changed code back against the rules that govern it. Not from memory: reread the returned records for the paths that changed, including anything the context pack deferred, and read the diff as the next person to open the file would. The restraint document is the first thing to hold it against.
|
|
191
197
|
|
|
192
|
-
|
|
198
|
+
`context.prepare_change` returns `governingRules`: for each changed path, the rules its role in the project profile binds it to. Record `task.self_review` with one entry per changed file (deleted files excepted) that names every one of those rules, and for a file the profile maps to no role, the engineering rules you actually read it against. Each rule gets one outcome:
|
|
199
|
+
|
|
200
|
+
- `follows`: the file does what the rule says.
|
|
201
|
+
- `fixed`: it did not, and you changed it; record what was wrong and what you changed.
|
|
202
|
+
- `user_accepted_deviation`: it does not follow the rule and the user decided to keep it that way. Record the rule's `resourceKey` and the issue; `task.self_review` asks the user the rule-deviation question natively and records the deviation only on their approval. If they choose to change the code, change it and record the rule as `fixed`.
|
|
193
203
|
|
|
194
|
-
|
|
204
|
+
There is no fourth outcome. Keeping code because the surrounding code already does it, or because the rule seemed not to fit, is a deviation the user has not approved, and verification refuses it. A rule conflict is a question for the user, and the right moment to ask it is before the code is written; existing code is evidence of what was done, not authority for what to do.
|
|
205
|
+
|
|
206
|
+
An area the task worked in that the coverage map marks as having no rule is named in the handoff, with what was decided in its absence, and proposed as a rule when a real task had to improvise there. That is how the product learns which rule to write next: an area nothing has needed yet can wait, and one a real task just had to improvise in cannot.
|
|
195
207
|
|
|
196
208
|
This applies to a write task. A read-only task changed nothing, so there is nothing to read back against the rules and `task.self_review` is refused for it; go straight to verification. `task.verify` refuses a write task without a self review of the current diff. Editing after the review invalidates it, which is the point: the last thing that happens to the code is that someone read it against the rules. This exists because a task once shipped code that broke rules it had been given — the rules were present and correct, and nothing in the lifecycle ever asked whether the result matched them.
|
|
197
209
|
|
|
@@ -201,19 +213,25 @@ Before validation begins, declare the discretion the task used. Send it as `deci
|
|
|
201
213
|
|
|
202
214
|
Record `validation_before`, run proportionate format, generation, static analysis, tests, security scans, and design checks, then record `validation_after` with command results and hashes. Each `task.verify` validation entry must contain the backend validation ID, the exact command, a successful result, and the SHA-256 hash of its sanitized output. Never invent a validation result or reuse a placeholder hash.
|
|
203
215
|
|
|
204
|
-
|
|
216
|
+
Run each required validation once, after the last edit, capturing and hashing its output in the same command. A rerun that follows no further code change adds no new evidence — the hash already on file still stands. Run the tests for the changed unit; run the whole suite at most once, and only when the change actually touched shared infrastructure the whole suite exercises. Run a code generator in its plain incremental form, which already rebuilds only what changed; never narrow it with a filter such as `build_runner`'s `--build-filter`, which makes it crawl for far longer and adds no evidence. Bind every test, build and search command to a timeout. Resolve a pinned dependency's path from its lockfile before searching it, and never grep an entire package cache or the home directory.
|
|
217
|
+
|
|
218
|
+
Available validation IDs are `format`, `static_analysis`, `tests`, `build`, `codegen`, `localization`, `ui`, `network`, `structure`, `diff_check`, `privacy_scan`, `dependency_audit`, `deploy_smoke`, and `read_only_integrity`. Use the exact set in the `requirements` that `context.prepare_change` and `session.resume` return: the required and optional validations with the paths that call for each and the command shapes each accepts, plus the history reads, memory mappings, reconciliations and checkpoints verification will ask for. Produce all of them before `task.verify`, so what verification wants is known up front rather than discovered one refusal at a time. A command is matched by the tool it runs, so a full path to `dart.exe`, `flutter.bat` or `flutter_tools.snapshot`, PowerShell's `&` and quotes all read as that tool. `memory.history` with `required: true` reads every record verification will ask about in one call; a path no record covers comes back in `uncoveredPaths` with the kind verification will want a record of. A handwritten-code task cannot substitute a generic command for analysis or tests. Dependency manifests, lockfiles, build configuration, and deployment configuration require their additional audit or smoke evidence. Read-only tasks require repository-integrity and privacy evidence without a change lease.
|
|
219
|
+
|
|
220
|
+
`ui` evidence must render or exercise the changed widget or screen: a widget, golden or screenshot test of that surface. A command that only matches the pattern without exercising the change is not UI evidence. When the user decides the UI check is not needed for this change, pass `waivers` to `task.verify` with their reason; the tool asks them in a native form and records the answer on the task. Never infer a waiver from prose, and never waive tests, static analysis or format — only `ui` can be waived. `task.close` and `session.resume` return the recorded waivers; name each one and its reason in the delivery summary.
|
|
205
221
|
|
|
206
222
|
For each changed screen or component, call `task.reconcile` with an approved proposal ID or a reasoned `no_semantic_memory_change` result. In a scaffold task, reconcile each applied template resource with a reasoned `scaffold_applied` result instead; files that still match their recorded scaffold hash need no per-file proposal, and every other changed path follows the normal rules. New screens and components require a memory proposal. Changed project contracts, service contracts, Figma mappings, or engineering rules require the corresponding proposal when their semantics changed.
|
|
207
223
|
|
|
208
|
-
|
|
224
|
+
When `context.prepare_change`'s `requirements` list a path under `mappings`, draft that proposal as soon as the lease is prepared — in the background if the host allows it, otherwise as the very next independent step — so its approval runs alongside validation instead of opening for the first time inside the verify loop.
|
|
225
|
+
|
|
226
|
+
Record `handoff_before`, then call `task.verify`. For a write task, verify the exact changed paths, current diff hash, validations, session, and lease. For a read-only task, send no changed paths, lease, or write baseline; the bridge supplies the current Git diff hash and the backend compares it with the baseline captured at bootstrap while also verifying bootstrap, discovery, validation-before, validation-after, handoff, pinned read receipts, and synchronized outbox evidence. If verification fails, the refusal lists every unmet requirement at once; resolve all of them, then verify again. When `session.resume` reports `context_refresh_required`, call `context.refresh`, then `context.prepare_change` for the same paths; resume alone never reactivates a stale session, and the task baseline does not change. `context.refresh` sends in full only the revisions that changed since the session pinned them and lists the rest in `unchangedResources`; reread one of those with `memory.read_revisions` only when its text is no longer in view. Do not state that the task is complete while verification is failing, and do not carry on writing code with the failure unaddressed — a task that never verifies never closes, and everything that depends on closing, including the commit gate, silently never happens.
|
|
209
227
|
|
|
210
228
|
When a task adds a structure the system did not have — a cache, a broker, a read replica, a second deployable, a projection, an event store — name it in `introducedStructures` at verification. The backend refuses any the project profile has not recorded under `architecture.adopted`, with the pressure it relieves, and refuses with the stated reason any the project recorded as deliberately declined. Recording it is a project profile revision like any other: propose, have the user approve, reconcile. Do not reach for the structure first and record it afterwards — the point of the record is that somebody decided.
|
|
211
229
|
|
|
212
230
|
A new screen or component fails verification until its memory exists, which takes four steps in order: `memory.propose_revision` for each new path, the user's explicit approval, `memory.review_proposal`, then `task.reconcile`. The error names the paths. Walk the chain rather than retrying the same verification.
|
|
213
231
|
|
|
214
|
-
Call `task.close` only after verification and only when the current diff still matches.
|
|
232
|
+
Call `task.close` only after verification and only when the current diff still matches. Where the Engineering Memory pre-commit hook was installed, it performs a fresh authenticated commit-gate check against the closed task, current membership, repository fingerprint, diff hash, and knowledge revisions. Without that hook nothing checks the commit; never say a hook confirmed the closure. A local receipt alone never authorizes commit. Closing a task does not authorize commit, push, publish, deploy, tag, or merge.
|
|
215
233
|
|
|
216
|
-
Closing is not the end of the turn either. `task.close` returns the delivery question
|
|
234
|
+
Closing is not the end of the turn either. `task.close` returns the delivery question — commit, commit and push, commit and push with a draft pull request, or commit and push with a pull request — and names the branch, remote and URL the work would go to. It is settled every time — by the user's own message when that already chose one, otherwise by asking. The two pull request options take the base branch from the user. Do exactly the one chosen and nothing more. When the host has to approve the push, follow the Delivery section of `questionnaires.md`; an Engineering Memory form is never the way past a host's denial.
|
|
217
235
|
|
|
218
236
|
When a pull request has been opened, keep going: check whether it merges cleanly, report the result with the link, and if it conflicts, name the files and ask whether to resolve them. Never end the turn on a pull request whose mergeability was never checked, and never resolve a conflict without being told to.
|
|
219
237
|
|
|
@@ -238,8 +256,13 @@ current. Select linkedSources explicitly by accessible project id, commit and tr
|
|
|
238
256
|
do not guess the counterpart's source from this repository's branch. Unselected or unknown linked
|
|
239
257
|
sources are not verified endpoint contracts.
|
|
240
258
|
|
|
241
|
-
|
|
242
|
-
|
|
259
|
+
If task.close reported sourcePublication.applicable, call memory.publish_task after the
|
|
260
|
+
already-authorized commit is created, with the closed task id and repoRoot; otherwise there is
|
|
261
|
+
nothing to publish, for one of two distinct reasons publish_task's reason field names: a project
|
|
262
|
+
with no inspected source snapshot at all has legacy-unverified coverage, while a source-aware task
|
|
263
|
+
whose commit and tree were never resolved to an inspected snapshot has unknown coverage.
|
|
264
|
+
publish_task itself reports {published:false, reason} rather than refusing in either case. The bridge
|
|
265
|
+
proves the resulting commit has the task's base parent and exactly its
|
|
243
266
|
verified files, blobs, modes and deletions. Backend publication rechecks the task, current access
|
|
244
267
|
and immutable source identity and atomically saves the approved overlay for the resulting commit.
|
|
245
268
|
It never publishes dirty worktree contents. Repeating the same result is idempotent. If merging,
|
|
@@ -257,12 +280,14 @@ An unexpired cached context pack may be used for implementation. The bridge reco
|
|
|
257
280
|
|
|
258
281
|
## Reuse before allocating another directory
|
|
259
282
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
283
|
+
`task.branch` reconciles managed Git checkouts with local records and chooses the smallest safe
|
|
284
|
+
slot itself, so do not call `worktree.list` before it, guess a new worktree number or create a
|
|
285
|
+
directory yourself. Use `worktree.list` when the pool is full or the user asks about old folders:
|
|
286
|
+
it shows which checkouts are protected and why. Old unregistered managed checkouts count toward the limit and remain
|
|
264
287
|
protected because their previous ownership and delivery are unknown. A clean checkout alone is
|
|
265
|
-
insufficient proof of availability.
|
|
288
|
+
insufficient proof of availability. Slots outside the managed root appear as retired and are never
|
|
289
|
+
reused or counted toward the limit; offer `worktree.reconcile` with `retireLegacy:true` only when
|
|
290
|
+
the user wants the old folders gone.
|
|
266
291
|
|
|
267
292
|
When prior work has finished, call `worktree.reconcile` on that checkout with `releaseUnowned:true`
|
|
268
293
|
and the conversation language. Its native question binds the decision to the checkout, source and
|
|
@@ -51,7 +51,7 @@ always-running worker. Background execution must use the host's permitted facili
|
|
|
51
51
|
|
|
52
52
|
## Revision scope and review
|
|
53
53
|
|
|
54
|
-
Knowledge is layered. `scope: product` proposes a change to the shared engineering core that every organization reads, `scope: organization` proposes one that only this organization reads and which hides the product text for that key, and `scope: project` proposes a record for this project alone. The nearest layer wins when context is delivered. A product-scope proposal is the way a developer improves the product itself from inside their own project, and it requires nothing but the skill.
|
|
54
|
+
Knowledge is layered. `scope: product` proposes a change to the shared engineering core that every organization reads, `scope: organization` proposes one that only this organization reads and which hides the product text for that key, and `scope: project` proposes a record for this project alone. The nearest layer wins when context is delivered. A product-scope proposal is the way a developer improves the product itself from inside their own project, and it requires nothing but the skill. Product rules change only through a product release, never by approving a proposal in a chat, so a product-scope proposal stays inactive as input for the next release; it never blocks the contributor's task from verifying or closing. A shipped product release that republishes or withdraws the resource closes the proposals still waiting on it as superseded, with a note naming the release.
|
|
55
55
|
|
|
56
56
|
An architecture template is organization-scoped source, not prose. When a task establishes or changes a shared architecture structure that the templates carry, the template is stale and needs its own revision. Its manifest and content must stay in step: one `files[]` entry per `## file:` block, same path, byte count, SHA-256 and order. See `scaffolding.md`.
|
|
57
57
|
|
|
@@ -61,7 +61,13 @@ When a revision changes which stacks receive the resource, send the complete sel
|
|
|
61
61
|
|
|
62
62
|
Permanent proposals remain inactive until an authorized user explicitly approves them. Call `memory.review_proposal` only after receiving that decision through the native questionnaire.
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
An approval response carries `revisionId`, `resourceId`, `revisionNumber` and, when the proposal belongs to a task, `reconcileEntry`. After approval, pass `reconcileEntry` straight to `task.reconcile` rather than searching catalog or read_revisions for the revision that was just created; `revisionId` on the entry is optional and is resolved from the approved proposal when left out.
|
|
65
|
+
|
|
66
|
+
`memory.propose_revision` and `memory.list_proposals` report `reviewableByCaller` for each proposal. Ask the user for approval only when it is true. When it is false, the user in front of you cannot approve it, so do not ask: report the proposal as submitted, with its id, to the `reviewPath` it names — `product_release` for the product release, `organization_owner` for an owner of the organization, `project_maintainer` for an owner or maintainer of the project — and carry on with the task.
|
|
67
|
+
|
|
68
|
+
`metadata` on a proposal carries only the structured fields the resource kind defines, such as a project profile's `pathRoles`, `architecture` and `resourceDiscovery`, `appliesToStacks`, or an architecture template's manifest. `classification`, `containsPii`, `containsSecrets` and `resourceDescriptor` are computed by the server; sending them back from a served revision is harmless and they are ignored.
|
|
69
|
+
|
|
70
|
+
A proposal created in an earlier session, or created by a bundle import, is found with `memory.list_proposals`. It reports every proposal still waiting for review that this project or its organization can reach, with a `reasonPreview`, the current and base revision numbers, and whether the proposal now needs a rebase. Narrow a long list with `taskId`, `scope` or `status` (defaults to pending); page through the rest with `limit` and `afterId`, set to the response's `nextAfterId` to continue — `null` means nothing more is waiting. Pass a single `proposalId` to read that proposal's full `reason` and proposed text before putting the decision to the user. Never present a decision the user cannot see the content of, and never approve on the strength of the preview alone. Approval makes the current context lease stale. Call `context.refresh`, reread the changed rule, prepare a new change lease, and rerun affected validation.
|
|
65
71
|
|
|
66
72
|
A flow record is canonical in the same way a screen record is, and covers what no single screen knows: what the flow is for, every entry point with the screen or route it starts from, the ordered steps each naming its screen record and the Figma node it came from, the tracker that owns it and exactly what data that tracker carries or one sentence on why no tracker is needed, the branch points and what decides them, where the flow returns when it finishes, what happens when the user abandons it halfway, and the questions still open.
|
|
67
73
|
|
|
@@ -69,7 +75,7 @@ A `figma_reference` record is JSON, not prose: the current file key, the file UR
|
|
|
69
75
|
|
|
70
76
|
Screen logic is canonical in the backend. A screen revision should cover purpose, route, entry point, inputs, outputs, viewmodel observables, actions and computed values, tracker and global state, services and business codes, loading, empty and error behavior, Figma frames and components, localization keys, navigation, tests, constraints, selectors, and evidence.
|
|
71
77
|
|
|
72
|
-
Component mappings should cover the Flutter symbol and path, public API, purpose, states, design tokens, responsive behavior, Figma file and exact node IDs, assets, usage guidance, tests, selectors, and evidence. Mark missing or partial Figma evidence instead of inventing node IDs.
|
|
78
|
+
Component mappings should cover the Flutter symbol and path, public API, purpose, states, design tokens, responsive behavior, Figma file and exact node IDs, assets, usage guidance, tests, selectors, and evidence. Mark missing or partial Figma evidence instead of inventing node IDs. A `component_mapping` record is for the project's actual shared component area — something a second screen really imports. A widget that lives inside a screen's own `widgets` folder is part of that screen's `screen_logic` record instead, however much behaviour it carries; do not open a permanent component record for it.
|
|
73
79
|
|
|
74
80
|
A backend project records three kinds instead of screens and components, and which kinds a project has is declared in its project profile rather than assumed.
|
|
75
81
|
|
|
@@ -116,6 +116,21 @@ authentication, runtime/toolchain and cross-module/end-to-end flows. Record sour
|
|
|
116
116
|
behavior, inference and unknown historical reasons separately. Never fabricate historical tasks,
|
|
117
117
|
prior developer decisions or reasons the code cannot establish.
|
|
118
118
|
|
|
119
|
+
Adoption and refresh also record, in the project profile, the conventions the engineering rules
|
|
120
|
+
leave to the project: which layer shows a failure's message and whether transport failures are
|
|
121
|
+
handled centrally, which presenters show sheets, dialogs and toasts (static entry points on the
|
|
122
|
+
shared presenter), where typed request and response models live, and the folders that hold enums,
|
|
123
|
+
extensions and other shared
|
|
124
|
+
kinds. Record `metadata.pathRoles` as well: a map from each role the shipped rules govern (view,
|
|
125
|
+
state-object, service, transfer-object, enum, extension, presenter, component, flow, localization,
|
|
126
|
+
style, test) to the repository globs that hold it. `context.prepare_change` binds each changed path to
|
|
127
|
+
the rules of its roles through this map, so a path no glob maps is reviewed only against the rules the
|
|
128
|
+
agent names. A screen's own `widgets` folder carries the view role of the screen it belongs to, not
|
|
129
|
+
the component role; the component role, and the `component_mapping` kind in `resourceDiscovery`, are
|
|
130
|
+
for the project's actual shared component area, wherever the architecture places it — never for a
|
|
131
|
+
widget only one screen imports. A refresh rechecks the map and the conventions against the current
|
|
132
|
+
tree and proposes a profile revision when either has drifted.
|
|
133
|
+
|
|
119
134
|
1. `memory.sync_start` opens a durable native confirmation bound to the mode, committed source hash
|
|
120
135
|
and previousRunId/rework behavior. Only acceptance starts the run. It snapshots the selected HEAD
|
|
121
136
|
or explicit ref, uploads every manifest page with exclusion reasons and seals the inventory.
|
|
@@ -170,8 +185,10 @@ remaining units and decisions durably.
|
|
|
170
185
|
|
|
171
186
|
The core pack is intentionally bounded. Linked contracts remain inline while they fit the budget; when
|
|
172
187
|
the response reports `additionalMemory`, read the full authorized catalogue with
|
|
173
|
-
`memory.catalog({projectId, includeLinked: true, afterId, limit})`,
|
|
174
|
-
|
|
188
|
+
`memory.catalog({projectId, includeLinked: true, afterId, limit})`, passing each page's `nextAfterId`
|
|
189
|
+
as the next `afterId` until it comes back null, then use the current session with
|
|
190
|
+
`memory.read_revisions` for the exact revision IDs needed by the task; it returns what fits one
|
|
191
|
+
response and names the rest in `remainingRevisionIds`. Do not assume the core pack is
|
|
175
192
|
exhaustive. `memory.catalog` is the paging surface for linked project memory; it does not grant access
|
|
176
193
|
or change project links.
|
|
177
194
|
|
|
@@ -12,7 +12,17 @@ Fixed-choice answers can be replayed from the local receipt. Free text is return
|
|
|
12
12
|
|
|
13
13
|
Read pending questions returned by `session.entry` and `session.resume`. Call `questionnaire.resume` for the question belonging to this work. Do not silently adopt a pending question from another task. Resuming uses the original question; do not rewrite its options under the same identifier.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
A question belongs to the task the chat was working on when it was asked. That covers the forms
|
|
16
|
+
`task.branch` and `project.set_git_preferences` open and every `questionnaire.ask` made after
|
|
17
|
+
`session.bootstrap` or `session.resume` in the same folder. `pendingQuestionnaires` holds only the
|
|
18
|
+
current task's own questions and any question with no task owner (a project-level decision, or
|
|
19
|
+
one asked before any task started). Every other task's question appears under
|
|
20
|
+
`otherTasksPendingQuestionnaires` as a one-line summary naming its task: enough to recognise,
|
|
21
|
+
never enough to answer here. Resume it only in the chat working on that task.
|
|
22
|
+
|
|
23
|
+
Only an explicit, valid accepted response answers a question. A timeout, dismissed form, empty response, invalid response, connection loss or ended turn is not an answer. These events leave the decision pending. Never substitute the recommended choice or treat silence as consent. The form's cancel or decline button dismisses the form; if abandoning the work is a meaningful decision, offer it as an explicit answer in the question. A question left pending this way stays pending; show it again once, on the user's next message, and then wait rather than re-asking on every following turn.
|
|
24
|
+
|
|
25
|
+
State the decision and one concrete example directly in the question's `message`, in the language the user is writing in. Never put a resource key, hash, task ID or other internal identifier in a question's text — it explains nothing to the person answering and only makes the question harder to read.
|
|
16
26
|
|
|
17
27
|
Never use request_user_input_async for a required decision: it does not wait for an answer. Do not end a turn while a required native form is still awaiting the user. Work that does not depend on the answer may continue. If the host removes the form or interrupts the tool call, retain the pending decision and resume that same question when the user returns. Do not automatically reopen dismissed forms in a loop, or use repeated sleeps to claim that a host timer has been disabled.
|
|
18
28
|
|
|
@@ -24,12 +34,11 @@ Never replace the questionnaire with a chat instruction such as 'type this', 're
|
|
|
24
34
|
|
|
25
35
|
When a durable MCP form cannot be displayed, read its `hostFallback` or call `questionnaire.resume` with `presentation: host_native` to get the original question without reopening the MCP form. Display the same question, all choices and notices through a blocking native control only if the host permits that control for this decision. After an actual native answer, call `questionnaire.answer_from_host` with the unchanged questionnaireId, requestKey and contentHash, the hostTool name and the returned choice/text. This is an agent-reported relay, not MCP transport attestation. Then retry the owning operation; its authority, content and version checks still apply. Never relay prose consent, a default, an asynchronous response or a cancelled/declined/missing answer. Decline alone is not proof that the host cannot display forms. Keep the decision pending if no permitted native control can represent it.
|
|
26
36
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
edit requires reading current preferences and fresh decisions for the new version.
|
|
37
|
+
Branch preferences are one form bound to the exact supplied values and expectedVersion. Relay
|
|
38
|
+
its answers once, keyed by role, then make the returned retry; the save applies only while the
|
|
39
|
+
version and authority still match. An answer to some other question, such as a prose "yes to
|
|
40
|
+
all branches", is never relayed into it. A concurrent edit requires reading current preferences
|
|
41
|
+
and a fresh form for the new version.
|
|
33
42
|
|
|
34
43
|
Map the native result to the original option id only when the selected label identifies it
|
|
35
44
|
unambiguously; never substitute or omit choices to fit a host limit. If all choices and required
|
|
@@ -44,6 +53,42 @@ clients must restart after an upgrade to read the new relay receipt field; old r
|
|
|
44
53
|
readable by the new client. No server or SDK can independently prove an agent's claim that a
|
|
45
54
|
host-native form was shown; agents must use only the actual native result they observed.
|
|
46
55
|
|
|
56
|
+
Claude Code declines the MCP form today, so each attempt costs several seconds for nothing.
|
|
57
|
+
After the first decline in this session, pass `presentation: host_native` on `questionnaire.ask`
|
|
58
|
+
and on any owning tool that opens a question (`task.branch`, `project.set_git_preferences`) to
|
|
59
|
+
go straight to `hostFallback`. This is a per-session choice, not a permanent verdict on the
|
|
60
|
+
host: offer the MCP form again in a fresh session, since decline alone is not proof the host
|
|
61
|
+
cannot display one.
|
|
62
|
+
|
|
63
|
+
Some forms carry several related questions in one durable record. The `task.branch` start form
|
|
64
|
+
asks where the task works, which branch it starts from and the branch name; the
|
|
65
|
+
`project.set_git_preferences` form asks one question per role. Their `hostFallback` carries a
|
|
66
|
+
`questions` array instead of a single `options` array. AskUserQuestion takes at most 4
|
|
67
|
+
questions per call, so show them in as few calls as needed and relay every answer together in
|
|
68
|
+
one `questionnaire.answer_from_host` call, as `answers` keyed by each question's id. A choice
|
|
69
|
+
that needs text, such as a custom branch name, carries it as that answer's `text`. A record can
|
|
70
|
+
also declare `terminalChoices`: picking one of those answers (for example "Not now") makes
|
|
71
|
+
every other question in that form optional.
|
|
72
|
+
|
|
73
|
+
A relayed answer that resolves an owner-bound question (one opened by `task.branch` or
|
|
74
|
+
`project.set_git_preferences`) returns `retry: {tool, arguments}`: the exact call that reaches
|
|
75
|
+
the same decision again, with its authority and version checks intact. Make that call next
|
|
76
|
+
instead of re-deriving its arguments.
|
|
77
|
+
|
|
78
|
+
## Deferred decisions
|
|
79
|
+
|
|
80
|
+
"Not now" is not a normal answer: it is an explicit, resumable on-hold state, never replayed as
|
|
81
|
+
if the user had approved something. A deferred `task.branch` question returns
|
|
82
|
+
`{status: 'deferred', allocated: false, reconsider}`: nothing was created, reserved or saved.
|
|
83
|
+
Say in one line that starting that task is on hold, continue only read-only work, and call
|
|
84
|
+
`reconsider` exactly as given — not a hand-typed retry — only once the user actually asks to
|
|
85
|
+
start it; it carries a fresh `decisionAttempt` and asks the form again. Never reopen the same
|
|
86
|
+
deferred question in the same turn on your own initiative.
|
|
87
|
+
|
|
88
|
+
`session.entry` lists recent on-hold task starts under `deferredTaskStarts`, each with its own
|
|
89
|
+
`reconsider` call. Mention one only if the user brings up that task; a deferred start sitting
|
|
90
|
+
there is not itself a reason to interrupt other work.
|
|
91
|
+
|
|
47
92
|
## Authentication
|
|
48
93
|
|
|
49
94
|
When no Engineering Memory session exists, ask whether to sign in, create an account, or skip Engineering Memory for this task. Explain that skip is permitted only for an unbound repository. After sign in or sign up is selected, let the bridge open the browser authentication flow. Never ask for a password in the native questionnaire or chat. If a browser link is expired, rejected, already used, or otherwise unusable, call `auth.signin_browser` with `restart: true` and present only the newly returned URL.
|
|
@@ -129,7 +174,7 @@ Ask for the registered email and intended role. Show owner, maintainer, member,
|
|
|
129
174
|
|
|
130
175
|
## Branch
|
|
131
176
|
|
|
132
|
-
|
|
177
|
+
Call `task.branch` once for every new write or scaffold task, on any branch, and before a read-only task transitions to writing. Do not ask these questions yourself first: its one form asks where the task works (a separate managed worktree, this folder when it is clean, this folder after the task holding it moves out, or the branch already checked out), which branch it starts from, and the branch name, with a suggestion that follows the returned naming convention. Pass the exact `externalTaskId`. Pass `name`, `base` or `keepCurrent` only when the user already stated them, so the form skips that question; never pass a `worktreePath`. A task whose branch already exists resumes its recorded task instead of starting a new one. Continue in the returned `repoRoot`. Retries and handoffs reuse the stored answer. Read-only analysis does not create a branch or consume another task's answer.
|
|
133
178
|
|
|
134
179
|
## Flow Entry and Exit
|
|
135
180
|
|
|
@@ -182,7 +227,7 @@ Ask this in the same reply that delivers the fix, every time, including correcti
|
|
|
182
227
|
|
|
183
228
|
Offer the product option whenever the classification supports it, and say plainly that it changes the shared engineering core every organization reads, because that is a wider decision than an organization revision. It is raised with `memory.propose_revision` at `scope: product` and needs no access to the product's own repository. Never choose between organization and product on the user's behalf.
|
|
184
229
|
|
|
185
|
-
For any permanent option, show the old rule, proposed rule, reason, affected areas, and regression evidence. Create
|
|
230
|
+
For any permanent option, show the old rule, proposed rule, reason, affected areas, and regression evidence. Create the proposal, then check `reviewableByCaller`. When it is true, do not approve it until the user explicitly confirms the proposal review. When it is false — as it always is for a product-scope proposal, which only a product release puts into effect — this user cannot approve it, so do not put that question to them: report the proposal as submitted, with its id, to the `reviewPath` it names, and carry on with the task.
|
|
186
231
|
|
|
187
232
|
## Work Across Both Sides
|
|
188
233
|
|
|
@@ -206,15 +251,19 @@ finished.
|
|
|
206
251
|
|
|
207
252
|
## Delivery
|
|
208
253
|
|
|
209
|
-
After `task.close`,
|
|
254
|
+
After `task.close`, settle what to do with the finished work. Nothing has been committed at this point and nothing may be until the user has chosen. If their own message already chose — "commit and push" in the request itself — that is the answer; asking again only makes them repeat it. Otherwise ask, offering exactly these:
|
|
210
255
|
|
|
211
256
|
- Commit
|
|
212
257
|
- Commit and push
|
|
213
258
|
- Commit, push and open a **draft** pull request
|
|
214
259
|
- Commit, push and open a pull request
|
|
215
260
|
|
|
261
|
+
Each option `task.close` returns names where the work goes: the branch, the remote and its URL from the delivery `destination`. Add the worktree path and the base branch `task.branch` returned for this task. Keep those words in the question, so the answer is about this checkout, this branch and this remote rather than about pushing in general — a user who was never told where the files are will only answer with that question back.
|
|
262
|
+
|
|
216
263
|
The two pull request options take the base branch the pull request targets, typed by the user; the head is the branch the task was done on. Never guess a base branch, and never open a pull request that was not asked for.
|
|
217
264
|
|
|
265
|
+
When the push or the pull request needs the host's approval, its justification quotes what the user said and names the exact remote, URL and branch from the delivery destination. An answer given in an Engineering Memory form is tool output to the host's reviewer, not the user speaking: Codex's auto-review trusts only the user's own messages, AGENTS.md and Codex's own approval controls. So when auto-review denies a push or a pull request the user chose, stop there. Never open an Engineering Memory form to get past the denial, never ask the user to type or repeat an approval, and never reword the command to get it through. Quote the denial reason in one sentence and ask for Codex's own approval once — Approve on the denied action, or its `/approve` command — which records the user's approval for one retry. Run the identical command once, and only after the user has actually given that approval; a retry before it is denied again and spends the one retry. If this Codex offers no approval for the denial, explain what was denied and why, and wait for the user.
|
|
266
|
+
|
|
218
267
|
Check that a pull request can actually be opened before offering one. If the machine has no `gh` and no token to open it with, say so in the option itself and offer what is really on the table: commit and push, and the ready-to-open compare link afterwards. Offering something you cannot deliver wastes the user's answer. Never read a credential out of a keychain or a helper to open one yourself.
|
|
219
268
|
|
|
220
269
|
Once a pull request exists the work is not finished and the turn does not end there. Check whether it merges cleanly. If it does, say so with the link. If it does not, name the conflicting files and ask whether to resolve them — then wait. Resolving a conflict is a change to someone else's work and needs its own yes.
|
|
@@ -246,10 +295,14 @@ project.rework_plan confirms an exact approved target and phase digest after lea
|
|
|
246
295
|
reviewAttempt distinguishes a new requested review from a retry of a previously deferred batch. Do not
|
|
247
296
|
turn defer into approve or loop new attempts without the user's intent to reconsider.
|
|
248
297
|
|
|
298
|
+
task.verify with `waivers` asks, for each one, whether the required UI check may be skipped for the
|
|
299
|
+
exact changed paths and reason; pass language and repeat the same call to resume it. A require answer
|
|
300
|
+
keeps the check required and verifies nothing.
|
|
301
|
+
|
|
249
302
|
The initial context pack may be budgeted. If it reports `additionalMemory`, use
|
|
250
303
|
`memory.catalog({projectId, includeLinked: true, afterId, limit})` to page all authorized linked
|
|
251
|
-
resource headers,
|
|
252
|
-
needed. Never assume that the core pack contains every linked record. Source inspection should begin
|
|
304
|
+
resource headers, passing each page's `nextAfterId` as the next `afterId` until it is null, then call
|
|
305
|
+
`memory.read_revisions` with the current session for the exact revisions needed. Never assume that the core pack contains every linked record. Source inspection should begin
|
|
253
306
|
with the bounded orientation summary from `project.inspect`; use paged committed-source reads for the
|
|
254
307
|
units being learned.
|
|
255
308
|
|
|
@@ -281,15 +334,24 @@ withdrawing it. Language changes never broaden the approved source, mode or prev
|
|
|
281
334
|
|
|
282
335
|
## Worktree and branch decisions
|
|
283
336
|
|
|
284
|
-
`task.branch` owns
|
|
337
|
+
`task.branch` owns the native start form. Its answer binds the external task identifier, the folder, the selected source and the branch name, and a fetch pins the exact commit. A cancelled or dismissed form allocates nothing; repeat the same call to resume it. If the folder, its commit or the task holding it changed in the meantime, the same call asks a fresh form, because the earlier answer was given about something else. Do not select a different source to recover a timeout. When the chosen remote branch cannot be fetched, `task.branch` itself asks whether to continue from the local commit. A custom branch name that already exists or is not a valid Git name is refused without creating anything, with the `decisionAttempt` that asks the form again. Show actual names from project.git_preferences, never infer develop/test/prod meaning from a branch name.
|
|
285
338
|
|
|
286
|
-
Shared preferences
|
|
339
|
+
Shared preferences are confirmed in one native form: `project.set_git_preferences` asks every
|
|
340
|
+
supplied role (development, production, test) as its own question in a single multi-question
|
|
341
|
+
record, then saves every role answered "save this choice" in one PUT at `expectedVersion`. A
|
|
342
|
+
role answered "leave unchanged" is simply not included in that PUT; it stays exactly as it was
|
|
343
|
+
and unanswered, and reconsidering it later is a plain retry with a new `decisionAttempt`, not a
|
|
344
|
+
separate on-hold state. Explicitly absent production/test values are still answers. Members
|
|
345
|
+
without canManage receive a task-specific branch choice, never an administrator question they
|
|
346
|
+
cannot apply. The same task's accepted decision stays valid across Codex/Claude handoff after
|
|
347
|
+
pause; return to session.resume and the recorded repoRoot.
|
|
287
348
|
|
|
288
349
|
For task.branch and project.set_git_preferences, retries keep the same decisionAttempt (omit it on the first attempt). When the user explicitly reconsiders an answered deferral, use a new positive decisionAttempt to open a fresh native decision. Never reinterpret the old deferral as consent.
|
|
289
350
|
|
|
290
351
|
## Legacy worktree availability
|
|
291
352
|
|
|
292
|
-
|
|
353
|
+
`task.branch` reuses a safe slot before creating another directory; `worktree.list` explains which
|
|
354
|
+
checkouts stay protected when the pool is full. An unregistered legacy checkout
|
|
293
355
|
has unknown prior ownership and delivery, even if Git reports clean. `worktree.reconcile` with
|
|
294
356
|
`releaseUnowned:true` and `language` opens the native availability question for that exact checkout,
|
|
295
357
|
source commit and generation. The user confirms prior work and delivery have finished; current Git
|