engineering-memory 1.11.9 → 1.11.11

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.
Files changed (35) hide show
  1. package/dispatcher/sections.mjs +7 -2
  2. package/install/codex-approval.mjs +457 -0
  3. package/install/files.mjs +5 -1
  4. package/install/installer.mjs +24 -1
  5. package/package.json +1 -1
  6. package/runtime/build.json +1 -1
  7. package/runtime/dist/src/config.js +2 -0
  8. package/runtime/dist/src/git/git-inspector.js +114 -4
  9. package/runtime/dist/src/git/verification-gate.js +30 -17
  10. package/runtime/dist/src/mcp/onboarding-tools.js +110 -16
  11. package/runtime/dist/src/mcp/questionnaire-tools.js +99 -15
  12. package/runtime/dist/src/mcp/tool-annotations.js +112 -0
  13. package/runtime/dist/src/mcp/tool-definitions.js +150 -29
  14. package/runtime/dist/src/mcp/worktree-tools.js +395 -236
  15. package/runtime/dist/src/project/repository.js +26 -8
  16. package/runtime/dist/src/runtime/active-context-store.js +3 -0
  17. package/runtime/dist/src/runtime/api-client.js +1 -0
  18. package/runtime/dist/src/runtime/branch-preferences.js +0 -19
  19. package/runtime/dist/src/runtime/bridge-service.js +1320 -246
  20. package/runtime/dist/src/runtime/offline-outbox.js +33 -158
  21. package/runtime/dist/src/runtime/phase-timer.js +26 -0
  22. package/runtime/dist/src/runtime/privacy-detector.js +263 -0
  23. package/runtime/dist/src/runtime/questionnaire-store.js +210 -49
  24. package/runtime/dist/src/runtime/recovery-error.js +3 -1
  25. package/runtime/dist/src/runtime/runtime-entry.js +8 -0
  26. package/runtime/dist/src/runtime/runtime-host.js +1 -3
  27. package/runtime/dist/src/runtime/task-branch-store.js +17 -1
  28. package/runtime/dist/src/runtime/task-start.js +281 -0
  29. package/runtime/dist/src/runtime/worktree-pool.js +374 -26
  30. package/runtime/dist/src/utilities/process.js +1 -0
  31. package/skill/SKILL.md +3 -3
  32. package/skill/references/lifecycle.md +59 -19
  33. package/skill/references/memory-updates.md +9 -3
  34. package/skill/references/project-onboarding.md +19 -2
  35. package/skill/references/questionnaires.md +86 -15
@@ -6,13 +6,21 @@ Sign-in decides nothing beyond who the user is. The organization and the project
6
6
 
7
7
  Use the binding returned by `session.entry` as the authority. The bridge stores the selected project and repository identity under `~/.engineering-memory/origins/<api-hash>/project-bindings/`, outside the installed runtime and working tree. It imports a legacy `.engineering-memory/project.json` once, preserving its schema and exact backend fingerprint for existing tasks and receipts. It leaves that file unchanged; after migration the file is optional and may be removed through the repository's normal Git workflow. New bindings never create it. A checkout that never imported the marker still finds a project bound under the older identity: the bridge presents that identity alongside the current one and stores whichever the backend confirms. Never infer a selection from a directory or remote, and never edit binding records by hand. Separate clones or a changed remote require a new explicit selection; worktrees of the same checkout share the local binding.
8
8
 
9
+ A project is not tied to one repository forever. When its code moves — to another host, under a new remote, into a history that starts again from one commit — the project moves with it and keeps everything: tasks, memory, work items, open sessions, the local state of every checkout. The old repository stays in the project's history. Recognise the three shapes this takes and never answer any of them by creating a second project:
10
+
11
+ - Binding the selected project is refused with recovery `project.move_repository`. The project lives in another repository and the user is one of its owners. Call `project.move_repository` with the project id; it opens one native form that names both repositories and what stays with the project, and on approval moves the project and binds this checkout. A declined form changes nothing.
12
+ - The same refusal arrives with recovery `project.member_list`. Moving needs project-owner authority, which the organization owner also holds. Check the roles, say that an owner has to run the move from a checkout of the new repository, and continue only work that does not need the binding. Do not name a person.
13
+ - `session.entry`, `project.resolve` or bootstrap reports `projectMoved`, or bootstrap refuses with "Project moved". This checkout still points at a repository the project has left; the message names where it lives now. Tasks already open here can be resumed and finished. New work starts from the new repository: the user points this checkout's origin at it, or clones it, and selects the project again. An owner calls `project.move_repository` from here only when the code truly lives in this repository again.
14
+
15
+ After a move nothing else changes for the agent. The binding keeps reporting the identity the project has always had, so resume, verification, receipts and the commit gate behave as they did before.
16
+
9
17
  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
18
 
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, pinned revisions, project profile, engineering rules, prior task documents, quality gates, and current deviations.
19
+ 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
20
 
13
- Before a new write or scaffold task, read `session.entry` and the project Git preferences. If `canManage` is true, ask only the unanswered development/production/test preferences through native forms and save them with `project.set_git_preferences`. 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.
21
+ 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
22
 
15
- Call `task.branch` with the stable `externalTaskId` and `repoRoot`. Its native forms show configured branch names, the current commit, another branch, and the explicit keep-current option. New branches always use a separate managed worktree. Configured remote bases are fetched and their exact commits pinned; after a fetch failure select an explicit local source through a new native decision, never silently use a cached branch. Existing task decisions survive retries and restarts. Resume their recorded branch rather than recreating or resetting it.
23
+ 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
24
 
17
25
  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
26
 
@@ -20,7 +28,7 @@ Renew `task.heartbeat` using the exact returned task, path and ownership generat
20
28
 
21
29
  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
30
 
23
- `task.close` retains a managed checkout while changes or delivery remain pending. Complete only the delivery the user authorized, then use `worktree.release` with `delivered:true` and the current generation. 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. Legacy reservations and already-open unmanaged tasks keep their original lifecycle; they are not forcibly moved.
31
+ `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
32
 
25
33
  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
34
 
@@ -30,7 +38,7 @@ A task nobody is going to finish is abandoned rather than inherited. Ask the use
30
38
 
31
39
  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
40
 
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.
41
+ 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
42
 
35
43
  ## Discovery
36
44
 
@@ -85,6 +93,12 @@ Do not pull history for everything. Pull it for the records the task actually to
85
93
 
86
94
  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
95
 
96
+ 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.
97
+
98
+ 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.
99
+
100
+ 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.
101
+
88
102
  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
103
 
90
104
  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 +171,7 @@ reopening the task and abandoning it.
157
171
 
158
172
  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
173
 
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. Every deferred resource is still required: read it with `memory.query` before touching the path it governs, because verification checks the read receipt and will fail without it. Prefer several small leases over one wide one.
174
+ 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
175
 
162
176
  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
177
 
@@ -189,9 +203,15 @@ A project-specific correction is offered as task-only or permanent for this proj
189
203
 
190
204
  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
205
 
192
- Record `task.self_review` naming the resources reviewed and, for every conflict found, the file, the rule, what was wrong and what was done about it. A review that found nothing records an empty finding list, which is a claim about the work rather than a formality.
206
+ `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:
193
207
 
194
- An area the task worked in that the coverage map marks as having no rule is recorded as a finding too, naming the area and what was decided in its absence. 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.
208
+ - `follows`: the file does what the rule says.
209
+ - `fixed`: it did not, and you changed it; record what was wrong and what you changed.
210
+ - `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`.
211
+
212
+ 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.
213
+
214
+ 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
215
 
196
216
  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
217
 
@@ -201,19 +221,25 @@ Before validation begins, declare the discretion the task used. Send it as `deci
201
221
 
202
222
  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
223
 
204
- 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 returned by the bridge or required by the changed paths. 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.
224
+ 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.
225
+
226
+ 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.
227
+
228
+ `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
229
 
206
230
  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
231
 
208
- 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, resolve the reported gap and verify again. 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.
232
+ 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.
233
+
234
+ 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
235
 
210
236
  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
237
 
212
238
  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
239
 
214
- Call `task.close` only after verification and only when the current diff still matches. The Git hook performs a fresh authenticated commit-gate check against the closed task, current membership, repository fingerprint, diff hash, and knowledge revisions. A local receipt alone never authorizes commit. Closing a task does not authorize commit, push, publish, deploy, tag, or merge.
240
+ 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
241
 
216
- Closing is not the end of the turn either. `task.close` returns the delivery question, and it is asked every time: commit, commit and push, commit and push with a draft pull request, or commit and push with a pull request. The two pull request options take the base branch from the user. Do exactly the one chosen and nothing more.
242
+ 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
243
 
218
244
  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
245
 
@@ -238,8 +264,13 @@ current. Select linkedSources explicitly by accessible project id, commit and tr
238
264
  do not guess the counterpart's source from this repository's branch. Unselected or unknown linked
239
265
  sources are not verified endpoint contracts.
240
266
 
241
- After the already-authorized commit is created, call memory.publish_task with the closed task id
242
- and repoRoot. The bridge proves the resulting commit has the task's base parent and exactly its
267
+ If task.close reported sourcePublication.applicable, call memory.publish_task after the
268
+ already-authorized commit is created, with the closed task id and repoRoot; otherwise there is
269
+ nothing to publish, for one of two distinct reasons publish_task's reason field names: a project
270
+ with no inspected source snapshot at all has legacy-unverified coverage, while a source-aware task
271
+ whose commit and tree were never resolved to an inspected snapshot has unknown coverage.
272
+ publish_task itself reports {published:false, reason} rather than refusing in either case. The bridge
273
+ proves the resulting commit has the task's base parent and exactly its
243
274
  verified files, blobs, modes and deletions. Backend publication rechecks the task, current access
244
275
  and immutable source identity and atomically saves the approved overlay for the resulting commit.
245
276
  It never publishes dirty worktree contents. Repeating the same result is idempotent. If merging,
@@ -257,12 +288,14 @@ An unexpired cached context pack may be used for implementation. The bridge reco
257
288
 
258
289
  ## Reuse before allocating another directory
259
290
 
260
- Before starting a write task, call `worktree.list` with the bound repository. It reconciles managed
261
- Git checkouts with local records. Then let `task.branch` choose the smallest safe slot; do not guess
262
- a new worktree number or create a directory yourself. Allocation also performs discovery when the
263
- caller omitted the listing. Old unregistered managed checkouts count toward the limit and remain
291
+ `task.branch` reconciles managed Git checkouts with local records and chooses the smallest safe
292
+ slot itself, so do not call `worktree.list` before it, guess a new worktree number or create a
293
+ directory yourself. Use `worktree.list` when the pool is full or the user asks about old folders:
294
+ it shows which checkouts are protected and why. Old unregistered managed checkouts count toward the limit and remain
264
295
  protected because their previous ownership and delivery are unknown. A clean checkout alone is
265
- insufficient proof of availability.
296
+ insufficient proof of availability. Slots outside the managed root appear as retired and are never
297
+ reused or counted toward the limit; offer `worktree.reconcile` with `retireLegacy:true` only when
298
+ the user wants the old folders gone.
266
299
 
267
300
  When prior work has finished, call `worktree.reconcile` on that checkout with `releaseUnowned:true`
268
301
  and the conversation language. Its native question binds the decision to the checkout, source and
@@ -270,6 +303,13 @@ ownership generation. Cancellation leaves it protected. Git reservation, dirty f
270
303
  Git operations and pending work are checked again before release. A changed source requires a new
271
304
  inspection and answer. This recovery never deletes files or branches or interrupts another agent.
272
305
 
306
+ When a recorded checkout is gone or can no longer be read as a Git worktree — its `.git` was
307
+ deleted, or the repository it was linked to was removed — `worktree.list` names `worktree.reconcile`
308
+ with `forgetUnreadable` and that task's `externalTaskId`, called from a working checkout of the same
309
+ project. After its own native approval Engineering Memory only stops tracking that entry, so it
310
+ stops counting toward the limit; no file in the folder is moved or deleted, the branch and the task
311
+ stay, and a readable checkout is still freed with `worktree.release`.
312
+
273
313
  If the running client predates the pool tools, inspect `git worktree list` and the existing task
274
314
  reservations before any explicit allocation. Do not treat an unavailable tool or an empty registry
275
315
  as an empty filesystem. Preserve uncertain checkouts and report the client limitation.
@@ -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. It remains inactive for the configured product release principal to review; waiting in that platform queue does not prevent the contributor's task from verifying or closing.
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
- 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 the reason, the current and base revision numbers, and whether the proposal now needs a rebase. Pass a single `proposalId` to read that proposal's 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 summary alone. Approval makes the current context lease stale. Call `context.refresh`, reread the changed rule, prepare a new change lease, and rerun affected validation.
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})`, then use the current session with
174
- `memory.read_revisions` for the exact revision IDs needed by the task. Do not assume the core pack is
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
- 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.
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
- For branch preferences, each role remains a separate decision bound to the exact preference
28
- value and expectedVersion. A combined "yes to all branches" from a different question cannot
29
- be relayed into three independent forms. Finish each original role question, then retry
30
- project.set_git_preferences with its original arguments. The backend applies the group only
31
- when every supplied role is approved and the version and authority still match. A concurrent
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.
@@ -74,6 +119,8 @@ Once the organization is chosen, call `project.list` and offer that organization
74
119
 
75
120
  The normal list omits archived projects. If repository entry, setup, binding or task open reports `project.restore`, use the project id and expected version returned with that refusal and restore it before continuing. If it reports `project.member_list`, the current member cannot restore the project: call that operation to check the available roles and explain that the versioned restore requires project-owner authority. Do not identify a person, reconstruct an identity from an account identifier or disclose contact details. If an owner does not yet have the project id and expected version, call `project.list` with `includeArchived: true` and let them select the archived project. Archive state never authorizes creating a duplicate project.
76
121
 
122
+ When the user picks an existing project and binding it is refused because the project lives in another repository, do not offer to create a new project for the same code. An owner is asked once, through the form `project.move_repository` opens, whether the project moves to this repository; the form already says which repository it leaves, which one it joins and how many tasks, memory records and work items stay with it, so add no second question of your own. Anyone else is told that a project owner runs the move, and is not asked anything.
123
+
77
124
  Ask both questions again whenever a chat starts in a repository whose binding you have not confirmed in this session.
78
125
 
79
126
  ## Switching Organization or Project
@@ -129,7 +176,7 @@ Ask for the registered email and intended role. Show owner, maintainer, member,
129
176
 
130
177
  ## Branch
131
178
 
132
- Ask once for every new write or scaffold task, on any branch, and before a read-only task transitions to writing. Offer a new or existing task branch, or explicitly continuing on the current branch; use the naming convention from the returned rules. When another task owns the worktree, offer a separate directory and branch for parallel work. Pass the exact `externalTaskId` and either `name` or `keepCurrent` to `task.branch`; for a separate worktree also supply `worktreePath`. Continue in the returned `repoRoot`. Retries and handoffs reuse the stored choice. Read-only analysis does not create a branch or consume another task's answer.
179
+ 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
180
 
134
181
  ## Flow Entry and Exit
135
182
 
@@ -182,7 +229,7 @@ Ask this in the same reply that delivers the fix, every time, including correcti
182
229
 
183
230
  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
231
 
185
- For any permanent option, show the old rule, proposed rule, reason, affected areas, and regression evidence. Create a proposal but do not approve it until the user explicitly confirms the proposal review.
232
+ 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
233
 
187
234
  ## Work Across Both Sides
188
235
 
@@ -206,15 +253,19 @@ finished.
206
253
 
207
254
  ## Delivery
208
255
 
209
- After `task.close`, and every time, ask the user what to do with the finished work. Nothing has been committed at this point and nothing may be until they answer. Offer exactly these:
256
+ 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
257
 
211
258
  - Commit
212
259
  - Commit and push
213
260
  - Commit, push and open a **draft** pull request
214
261
  - Commit, push and open a pull request
215
262
 
263
+ 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.
264
+
216
265
  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
266
 
267
+ 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.
268
+
218
269
  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
270
 
220
271
  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 +297,14 @@ project.rework_plan confirms an exact approved target and phase digest after lea
246
297
  reviewAttempt distinguishes a new requested review from a retry of a previously deferred batch. Do not
247
298
  turn defer into approve or loop new attempts without the user's intent to reconsider.
248
299
 
300
+ task.verify with `waivers` asks, for each one, whether the required UI check may be skipped for the
301
+ exact changed paths and reason; pass language and repeat the same call to resume it. A require answer
302
+ keeps the check required and verifies nothing.
303
+
249
304
  The initial context pack may be budgeted. If it reports `additionalMemory`, use
250
305
  `memory.catalog({projectId, includeLinked: true, afterId, limit})` to page all authorized linked
251
- resource headers, then call `memory.read_revisions` with the current session for the exact revisions
252
- needed. Never assume that the core pack contains every linked record. Source inspection should begin
306
+ resource headers, passing each page's `nextAfterId` as the next `afterId` until it is null, then call
307
+ `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
308
  with the bounded orientation summary from `project.inspect`; use paged committed-source reads for the
254
309
  units being learned.
255
310
 
@@ -281,15 +336,24 @@ withdrawing it. Language changes never broaden the approved source, mode or prev
281
336
 
282
337
  ## Worktree and branch decisions
283
338
 
284
- `task.branch` owns native selection of the starting source and branch. Confirmed decisions bind the external task identifier, selected source and branch; fetch resolves the exact immutable commit. A cancelled or dismissed question allocates nothing. Repeat the same call to resume its form. Do not select a different source to recover a timeout. On a remote failure offer an explicit local commit in another native decision. Show actual names from project.git_preferences, never infer develop/test/prod meaning from a branch name.
339
+ `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
340
 
286
- Shared preferences use separate native decisions for development, production and test. Explicitly absent production/test values are answers. Members without canManage receive a task-specific branch choice, never an administrator question they cannot apply. The same task's accepted decision stays valid across Codex/Claude handoff after pause; return to session.resume and the recorded repoRoot.
341
+ Shared preferences are confirmed in one native form: `project.set_git_preferences` asks every
342
+ supplied role (development, production, test) as its own question in a single multi-question
343
+ record, then saves every role answered "save this choice" in one PUT at `expectedVersion`. A
344
+ role answered "leave unchanged" is simply not included in that PUT; it stays exactly as it was
345
+ and unanswered, and reconsidering it later is a plain retry with a new `decisionAttempt`, not a
346
+ separate on-hold state. Explicitly absent production/test values are still answers. Members
347
+ without canManage receive a task-specific branch choice, never an administrator question they
348
+ cannot apply. The same task's accepted decision stays valid across Codex/Claude handoff after
349
+ pause; return to session.resume and the recorded repoRoot.
287
350
 
288
351
  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
352
 
290
353
  ## Legacy worktree availability
291
354
 
292
- Use `worktree.list` before deciding another directory is needed. An unregistered legacy checkout
355
+ `task.branch` reuses a safe slot before creating another directory; `worktree.list` explains which
356
+ checkouts stay protected when the pool is full. An unregistered legacy checkout
293
357
  has unknown prior ownership and delivery, even if Git reports clean. `worktree.reconcile` with
294
358
  `releaseUnowned:true` and `language` opens the native availability question for that exact checkout,
295
359
  source commit and generation. The user confirms prior work and delivery have finished; current Git
@@ -297,5 +361,12 @@ safety checks still decide whether reuse is possible. Cancellation or choosing t
297
361
  release it. Resume the same form via the same operation. A changed source/generation needs a fresh
298
362
  decision, and an old answer cannot release a newly owned task.
299
363
 
364
+ A checkout that is gone, or that can no longer be read as a Git worktree, is left with
365
+ `worktree.reconcile` and `forgetUnreadable: {"externalTaskId": "..."}` from a working checkout of the
366
+ same project: its native question names the task and the folder name, says that Engineering Memory
367
+ only stops tracking it and touches no file, and warns when that task closed with its delivery
368
+ unsettled. Cancelling or keeping it leaves it tracked, and a readable checkout is refused there and
369
+ freed with `worktree.release` instead.
370
+
300
371
  If the user later reconsiders a preserved legacy checkout, repeat `worktree.reconcile` with a new
301
372
  `decisionAttempt`; never reinterpret the previous preserve answer as approval.