@open-agent-toolkit/cli 0.3.36 → 0.3.38

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 (38) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/provider-sync/pilot-with-a-team.md +6 -6
  3. package/assets/docs/provider-sync/providers.md +1 -0
  4. package/assets/docs/reference/cli-reference.md +3 -3
  5. package/assets/docs/reference/project-artifacts.md +12 -3
  6. package/assets/docs/reference/what-oat-writes.md +14 -11
  7. package/assets/docs/skills/repo-improve.md +23 -19
  8. package/assets/docs/workflows/advanced/workflow-gates.md +7 -1
  9. package/assets/docs/workflows/projects/closeout/closeout-skills.md +3 -1
  10. package/assets/docs/workflows/projects/lifecycle.md +3 -1
  11. package/assets/public-package-versions.json +4 -4
  12. package/assets/skills/oat-project-brief/SKILL.md +1 -1
  13. package/assets/skills/oat-project-brief/references/brief-contract.md +32 -9
  14. package/assets/skills/oat-project-implement/SKILL.md +1 -1
  15. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +14 -4
  16. package/assets/skills/oat-project-pr-progress/SKILL.md +23 -12
  17. package/assets/skills/oat-repo-knowledge-index/SKILL.md +226 -131
  18. package/dist/commands/project/closeout-check/index.d.ts.map +1 -1
  19. package/dist/commands/project/closeout-check/index.js +4 -8
  20. package/dist/commands/project/delivery/check.d.ts.map +1 -1
  21. package/dist/commands/project/delivery/check.js +32 -14
  22. package/dist/commands/project/delivery/evidence.d.ts +39 -0
  23. package/dist/commands/project/delivery/evidence.d.ts.map +1 -1
  24. package/dist/commands/project/delivery/evidence.js +163 -17
  25. package/dist/commands/project/delivery/refresh.d.ts.map +1 -1
  26. package/dist/commands/project/delivery/refresh.js +13 -16
  27. package/dist/commands/project/journal-check/index.d.ts +2 -0
  28. package/dist/commands/project/journal-check/index.d.ts.map +1 -1
  29. package/dist/commands/project/journal-check/index.js +78 -1
  30. package/dist/commands/project/journal-check/types.d.ts +1 -1
  31. package/dist/commands/project/journal-check/types.d.ts.map +1 -1
  32. package/dist/providers/codex/codec/config-merge.d.ts +5 -1
  33. package/dist/providers/codex/codec/config-merge.d.ts.map +1 -1
  34. package/dist/providers/codex/codec/config-merge.js +111 -62
  35. package/dist/providers/codex/codec/config-toml-edit.d.ts +8 -0
  36. package/dist/providers/codex/codec/config-toml-edit.d.ts.map +1 -0
  37. package/dist/providers/codex/codec/config-toml-edit.js +718 -0
  38. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "oatVersion": "0.3.36"
3
+ "oatVersion": "0.3.38"
4
4
  }
@@ -177,12 +177,12 @@ inside the working tree. Remove it with `oat init --scope project --no-hook`.
177
177
 
178
178
  ## Mixed tools
179
179
 
180
- | Provider | What OAT generates in the repository | What the team should know |
181
- | ----------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
182
- | Claude Code | A relative link per skill in `.claude/skills/` and per agent in `.claude/agents/`; rules as generated copies in `.claude/rules/` | The only provider with skill views, so a new skill reaches Claude Code only after sync |
183
- | Cursor | No skill files: it reads `.agents/skills`. A link per agent in `.cursor/agents/`; rules as `.cursor/rules/*.mdc` files | Its `.cursor/skills/` folder is not managed; skills found there are reported as strays |
184
- | Codex | No skill files: it reads `.agents/skills`. A generated `.codex/agents/<name>.toml` per agent, registered in `.codex/config.toml` | Sync merges into an existing `.codex/config.toml`: it adds OAT's tables, turns on `multi_agent` and raises `max_depth` to at least 2, and keeps your other settings |
185
- | Gemini | Nothing; it reads skills and agents from `.agents/` directly | Nothing to commit |
180
+ | Provider | What OAT generates in the repository | What the team should know |
181
+ | ----------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
182
+ | Claude Code | A relative link per skill in `.claude/skills/` and per agent in `.claude/agents/`; rules as generated copies in `.claude/rules/` | The only provider with skill views, so a new skill reaches Claude Code only after sync |
183
+ | Cursor | No skill files: it reads `.agents/skills`. A link per agent in `.cursor/agents/`; rules as `.cursor/rules/*.mdc` files | Its `.cursor/skills/` folder is not managed; skills found there are reported as strays |
184
+ | Codex | No skill files: it reads `.agents/skills`. A generated `.codex/agents/<name>.toml` per agent, registered in `.codex/config.toml` | Sync merges into an existing `.codex/config.toml`: it adds OAT's tables, turns on `multi_agent` and raises `max_depth` to at least 2, and keeps your other settings and comments |
185
+ | Gemini | Nothing; it reads skills and agents from `.agents/` directly | Nothing to commit |
186
186
 
187
187
  If OAT's own implementer and reviewer agents are installed in the repository,
188
188
  sync also generates one file per supported model for each of them, in
@@ -58,6 +58,7 @@ description: 'Provider-specific path mappings for Claude, Cursor, Copilot, Gemin
58
58
  - Canonical markdown agents in `.agents/agents/*.md` are exported to Codex runtime roles:
59
59
  - `.codex/agents/<role>.toml`
60
60
  - `.codex/config.toml` (`[features] multi_agent = true`, `[agents.<role>]` upserts)
61
+ - Sync and direct materialization edit `config.toml` in place. They change only `features.multi_agent`, `agents.max_depth`, and the `description` and `config_file` keys of managed `[agents.<role>]` tables, and remove stale managed role tables. Comments (including other tools' ownership markers), blank lines, table order, and other keys stay byte for byte, and the file is not rewritten when nothing managed changed. Removing a stale role deletes its whole table, including comments inside it; comments above or after the table stay. Dotted keys and inline tables are edited where they are defined. New keys and tables are never added between another tool's `# BEGIN <label>` and `# END <label>` comments: a key goes before the block, and a table that cannot sit next to its related tables outside the block goes at the end of the file. If `features`, `agents`, or a managed role is not a table, or a key can only be added inside such a block, sync stops with an error instead of rewriting the file.
61
62
  - Codex role files include OAT managed provenance headers and are regenerated by `oat sync --scope project|user|all`
62
63
  - Project sync writes and maintains the version-controlled supported catalogue: GPT-6.1 Sol and GPT-6 Luna, Sol, and Astra at `low`, `medium`, `high`, `xhigh`, and `max`; GPT-5.6 Luna and Terra through `xhigh`; and GPT-5.6 Sol through `max`. Both `oat-phase-implementer` and `oat-reviewer` receive each supported pair (66 pinned variants). Sync writes files; it does not create a Git commit.
63
64
  - Custom targets follow configuration provenance: user-config targets write only under `~/.codex`; shared, repo-local, and active-project targets write under the project's tracked `.codex` view.
@@ -205,8 +205,8 @@ Notable commands introduced in the current CLI surface:
205
205
  - `oat review latest --json` - find the newest review artifact by `oat_generated_at`, scanning the active or specified project's `reviews/` and `reviews/archived/` directories plus ad-hoc review locations. Same-time candidates use target priority, then lifecycle recency (`final` > higher phase/task > lower phase/task). The JSON contract returns `path`, `scope`, `generatedAt`, `kind` (`project` or `adhoc`), `archived`, and `actionable`, with `null` values when no review exists. Archived project reviews remain discoverable as history but return `actionable: false`.
206
206
  - `oat project list --json` - summary state for tracked projects under the configured projects root
207
207
  - `oat project closeout-check <project-path> [--autonomous] [--json]` - read-only check of the closeout invariant: a closeout that must snapshot its post-implementation sequence cannot reach terminal completion until its `oat_post_implement_sequence` snapshot exists, every stored step is recorded complete, approval is recorded, and the snapshot reached `status: complete`. A snapshot is required when the effective layered `workflow.postImplementSequence` is configured, when the closeout is autonomous (`--autonomous`, or `OAT_AUTONOMOUS=1` in the environment even without the flag), or when `oat_workflow_mode` is `lite`. Once a snapshot exists its recorded state is authoritative and current configuration is not consulted. JSON output reports `status` (`complete`, `not_required`, or `incomplete`), the missing `invariant` (`snapshot_missing`, `snapshot_malformed`, `sequence_failed`, `pre_approval_step_pending`, `approval_pending`, `post_approval_step_pending`, or `sequence_not_complete`), `route` (`oat-project-implement` when incomplete), `nextOwner` (the next stored step and its skill, or the approval), and the evaluated `inputs`. An incomplete or malformed result exits 1. For a goal project (`oat_workflow_mode: goal`) the goal boundary is checked first and read-only: it requires `oat_goal_status: declared_met`, a valid exhaustive `oat_goal_outcome_audit`, resolved extractions, a successful `gh pr view` observation of every terminal delivery member, and delivery coverage of every accepted phase (each in a terminal delivery's effective scope with a passed, fresh integrated review and its persisted `exit_gate`); refusals report `goal_inputs_unreadable`, `goal_not_declared`, `goal_audit_invalid`, `goal_extraction_unresolved`, `goal_observation_failed`, or `goal_coverage_incomplete`, and `nextOwner` is `{ kind: "goal", skill, reasons }`, where each reason is `{ code, message, subject? }` and `skill` is the owner of the first reason: for example `not-declared` and `audit-invalid` route to `oat-project-goal`, `review-not-fresh` to `oat-project-review-provide`, `exit-carrier-not-fresh` to `oat-project-implement`, delivery and endpoint reasons such as `endpoint-unmet` to `oat-project-pr-progress`, and `phase-uncovered` to `oat-project-pr-final`. A goal snapshot may record its `pr` step as satisfied by delivery coverage (`satisfied_by: { pr: delivery-coverage }`) only once `pr` is in the completed prefix.
208
- - `oat project delivery refresh --project <path> [--json]` - goal only. Observes every registered delivery member with `gh pr view <url> --json state,headRefOid,baseRefOid` and persists, in `state.md`, only the observations (`observed_head`, `observed_base`, member `status`), the delivery `status` (`open` or `at_endpoint`), the first observed `endpoint_attainment`, and derived staleness (`integrated_review.disposition: stale`, the milestone exit carrier's `freshness: stale` with `freshness_reason`). It never rewrites a reviewed revision, a member base, or the first endpoint attainment, never writes `oat_milestone_status` or `oat_goal_recovery`, and never manufactures a passed review or a fresh carrier. `oat-project-pr-progress` and `oat-project-goal` run it before registration and re-alignment.
209
- - `oat project delivery check --project <path> --subject <mNN|dNN> [--json]` - goal only, read-only. Reports whether a milestone (before registration, against the branch head) or a registered delivery (against its observed member revisions) is deliverable: a passed integrated review that is still fresh under the bookkeeping-successor rule and an allowed, fresh milestone exit carrier (reported as `exit.source: milestone-carrier`; the closeout boundary judges each delivery's persisted `exit_gate` instead). Evidence reviewed at R covers a later head only when every intervening commit changes permitted bookkeeping in this project's tracking files (`state.md`, `plan.md`, `implementation.md`, `project-log.md`, `summary.md`) and review artifacts (including those of deliveries sharing the same member pull request); any change to `summary.md` is bookkeeping because it is derived memory, never the authority for the brief's content; code changes, edits to approved brief content, and a substantive change followed by its revert fail. JSON output carries `status` (`ok` or `undeliverable`), the subject, its ordered `scope`, `publishedHeads`, `review`, `exit`, and `deliverable`; an undeliverable subject exits 1 with the full report. A stale `review` or `exit` result carries a `reason` that starts with a code, such as `review-missing`, `review-scope-narrow`, `member-unobserved`, `base-changed`, `bound-revision-mismatch` (a bound revision differs from its member's set-once `reviewed_head`), `subject-changed`, `configuration-changed`, or a bookkeeping-successor failure: `missing-revision`, `missing-object`, `not-ancestor`, `inspection-failed`, `disallowed-path`, or `substantive-change`.
208
+ - `oat project delivery refresh --project <path> [--json]` - goal only. Observes every registered delivery member with `gh pr view <url> --json state,headRefOid,baseRefOid` and persists, in `state.md`, only the observations (`observed_head`, `observed_base`, member `status`), the delivery `status` (`open` or `at_endpoint`), the first observed `endpoint_attainment`, and derived staleness (`integrated_review.disposition: stale`, the milestone exit carrier's `freshness: stale` with `freshness_reason`). It never rewrites a reviewed revision, a member base, or the first endpoint attainment, never writes `oat_milestone_status` or `oat_goal_recovery`, and never manufactures a passed review or a fresh carrier. For `kind: stack`, members are ordered base to tip. A configured code carrier bound to a reviewed head is judged at the tip, and each lower observed head must be an ancestor of the tip; null carriers are skipped, and unreviewed-resolution carriers (`no_gate`, `project_disabled`) are evaluated exactly as for `kind: pr`. `oat-project-pr-progress` and `oat-project-goal` run it before registration and re-alignment.
209
+ - `oat project delivery check --project <path> --subject <mNN|dNN> [--json]` - goal only, read-only. Reports whether a milestone (before registration, against the branch head) or a registered delivery (against its observed member revisions) is deliverable: a passed integrated review that is still fresh under the bookkeeping-successor rule and an allowed, fresh milestone exit carrier (reported as `exit.source: milestone-carrier`; the closeout boundary judges each delivery's persisted `exit_gate` instead). For `kind: stack`, `publishedHeads` still reports every member head. For a registered delivery subject (`--subject dNN`), a configured code carrier bound to a reviewed head is judged against the tip after verifying each lower head is its ancestor (`stack-order` otherwise); null carriers and unreviewed-resolution carriers (`no_gate`, `project_disabled`) are evaluated exactly as for `kind: pr`. A milestone subject (`--subject mNN`) keeps branch-head carrier evaluation. Evidence reviewed at R covers a later head only when every intervening commit changes permitted bookkeeping in this project's tracking files (`state.md`, `plan.md`, `implementation.md`, `project-log.md`, `summary.md`) and review artifacts (including those of deliveries sharing the same member pull request). A gate-produced code-review artifact under `reviews/` also counts as permitted bookkeeping when its Reviews row has Invocation `gate` and Reviewed Head equal to the carrier's `reviewed_head`; it remains shared evidence, never integrated-review evidence or a delivery's own evidence. Any change to `summary.md` is bookkeeping because it is derived memory, never the authority for the brief's content; code changes, edits to approved brief content, and a substantive change followed by its revert fail. JSON output carries `status` (`ok` or `undeliverable`), the subject, its ordered `scope`, `publishedHeads`, `review`, `exit`, and `deliverable`; an undeliverable subject exits 1 with the full report. A stale `review` or `exit` result carries a `reason` that starts with a code, such as `review-missing`, `review-scope-narrow`, `member-unobserved`, `base-changed`, `bound-revision-mismatch` (a bound revision differs from its member's set-once `reviewed_head`), `subject-changed`, `configuration-changed`, `stack-order`, or a bookkeeping-successor failure: `missing-revision`, `missing-object`, `not-ancestor`, `inspection-failed`, `disallowed-path`, or `substantive-change`.
210
210
  - `oat project complete-state <project-path> [--archived] [--autonomous]` - apply the canonical completed-state mutation to a project's `state.md`; used by `oat-project-complete` during lifecycle closeout. It first evaluates the same closeout invariant as `oat project closeout-check` and refuses, with the same message and without writing, a configured, autonomous, or lite closeout whose snapshot is absent, malformed, or incomplete. A project whose implementation finished before closeout snapshots existed recovers by running `oat-project-implement`, which persists the snapshot (`completion-and-closeout.md` Step 15) and completes its stored steps; there is no override flag. An unconfigured, interactive, non-lite closeout without a snapshot completes as before. A goal project is also refused, without writing, by the goal boundary that `closeout-check` describes. When the project has an `implementation.md`, `complete-state` then runs the final journal evaluator (`oat project journal check --at completion`) on the same bytes immediately before its write, and refuses with the evaluator's reasons, writing nothing, when the journal does not hold its terminal shape; an override line covers only its eligible gap and never the closeout invariant. A project with a `plan.md` but no `implementation.md` is refused with `journal-missing`; only a plan-less project completes on the closeout invariant alone.
211
211
  - `oat project archive [project-path] [--project-recap-run <project-relative-path>] [--no-commit] [--new-generation <reason>]` - archive a tracked project through the same local move, summary export, and configured S3 upload path used by completion. When omitted, the project path falls back to the active project. The optional recap path must identify a `project-recap` run inside the project's `explainers/` directory. Archive verifies the complete selected package and every immutable file byte, then atomically exports one self-contained `.oat/repo/reference/project-recaps/<YYYYMMDD-project-slug>.html` page before deleting the active project. The full original package remains in the archived project. JSON `projectRecapExport` identifies `runId`, `page.sourceRelativePath`, `page.originalSha256`, `page.exportedSha256`, `verifiedArtifactCount`, and the flat `exportRoot`. No tracked sidecar is created. Matching dated pages are adopted on retry; conflicting destinations, incomplete inventory coverage, stale bytes, path escapes, and recipe mismatches fail without removing the active project. Summary and PR links point to the tracked page. For synced projects, a configured S3 upload must succeed before terminal cleanup. Successful closeout makes `refs/oat/completed/<project>` authoritative, deletes the tracked JSON record and nested checkout, and leaves archive metadata sufficient for an idempotent recordless retry. With `--json`, the terminal receipt reports `completedRef`, `verifiedSourceSha`, whether `activeAliasDisposition` was `retained` or `removed`, whether `recordRetired` completed, and the parent `lifecycleCommit`. `--no-commit` is a manual/library-only option: for a synced project it still removes the checkout but deliberately leaves `lifecycleCommit` null. Never pass it through `oat-project-complete`, which requires that receipt. Retry identity: one read-only evaluator, shared by apply and `--dry-run`, resolves the archive before any write. An identical retry (the project's retained-artifact manifest matches exactly one same-scope archive) reuses that snapshot's local path, dated export identity (summary export file and S3 key) and receipt on any later date, and a source-absent retry resumes the single same-scope archive; changed content, several matching archives, or an unverifiable non-empty directory at the archive path refuse before export, copy, overwrite or S3 upload, with follow-up-project guidance. The dry-run reports the identity the apply would use. `.oat-archive-source.json` records `manifestHash` and `generation` beside the project name, scope, snapshot and synced source SHA. The exported summary rewrites `oat-project:<project>#<entry-id>` locators to `oat-archive:<snapshot>#<entry-id>` and turns relative `project-log.md` or `oat-execution-learnings.md` links into plain text; see [Archive identity](project-artifacts.md#archive-identity). `--new-generation <reason>` archives reopened work of a shared or local project as the next generation instead of refusing it: it requires a non-empty single-line reason and exactly one latest generation of the same project and scope as predecessor (otherwise it refuses), never overwrites that predecessor, and persists the new generation (`<project>-gN` locally, `<YYYYMMDD>-<project>-gN` as export identity; when the same project's archive from another scope already holds that path or identity, both carry the scope: `<project>-gN-<scope>` and `<YYYYMMDD>-<project>-gN-<scope>`) with its predecessor, reason and `generationRequest` id before any export, copy or S3 side effect, so a retry reuses it. Replaying the same predecessor and content resolves to the same generation; synced projects refuse the option. JSON adds `generation` and `predecessorSnapshot`, and `--dry-run` reports the proposed generation without writing it.
212
212
  - `oat repo archive sync [project-name]` - hydrate archived project snapshots from the configured repo-scoped S3 archive into `.oat/projects/archived/`. A name resolves as an exact snapshot, then a full generation name such as `demo-g2`, then the project (or `<project>-<scope>` family), restoring its latest generation and then its latest date; see [Project Artifacts](project-artifacts.md) for the `<project>[-gN][-<scope>]` naming contract. The old `oat project archive sync` path remains as a deprecated shim.
@@ -214,7 +214,7 @@ Notable commands introduced in the current CLI surface:
214
214
  - `oat project dispatch record --event-file <json-file-or-dash> --format line [--dispatch-stamp <line>]` - print the one-line journal run record for the same validated, redacted record and event (projection `run/v1`), and write nothing; standard input still works. The line is `run/v1` followed by named fields in a fixed order, joined by a space-padded `·`: `request`, `scope`, `action`, `role`, configured `target`, `model` and `effort`, `stamp` (the formal `Dispatch:` stamp passed verbatim through `--dispatch-stamp`; a stamp without the canonical prefix is refused), `launch` (`planned`, `accepted`, or `blocked-before-start`), the raw child `outcome`, `terminal` (`yes` or `no`) and its `class` (`completed`, `terminal-stop`, `blocked-before-start`, `live`, or `unrecognized`), `continuation` references, and the optional `observed` identity with its `match`, which never replaces the configured fields. Inside a value, `\\` is a literal backslash and `\·`, `\~`, `\n`, and `\r` escape the delimiter, a tilde, a newline, and a carriage return; a bare `~` is null. Terminality comes from one producer-to-outcome mapping: a successful completion (`completed`, `DONE`, `DONE_WITH_CONCERNS`), a terminal stop (`BLOCKED`, `failed`, `cancelled`, `INVALID_RUN_ABORT`) and `blocked-before-start` are terminal; `planned`, `running`, `pending`, and `NEEDS_CONTEXT` with its handle still open are not, and an outcome outside the mapping is `unrecognized`, never success. The owning skill writes one line per request id under `## Orchestration Runs` and updates it in place. `--json` keeps `status: validated-only`, the record and `runtimeIdentity`, and adds `runLine` (`version`, `line`, `fields`, `classification`, `terminal`).
215
215
  - `oat project dispatch canonical-role --role <name> --request-id <id> --skill-dir <dir> [--json]` - resolve a canonical role through the loaded, user (`$HOME/.agents`), and project (`<repo>/.agents`) tiers and print the `canonical-role-resolution` event that `oat project dispatch record` accepts unchanged: redacted `canonicalPath` and `selectedPath` in the form `<loaded|user|project>/agents/<name>.md`, the role's `contentDigest`, and `candidateMisses`. `--skill-dir` is required because the loaded tier is derived from the loaded skill's directory; a missing or invalid directory exits 1 with a redacted error. An unknown role prints `missing` evidence with its recovery commands. Read-only; the dependency is the `workflows` pack.
216
216
  - `oat project validate-plan --project-path <path>` - validates `oat_plan_parallel_groups` metadata in `plan.md`; exits non-zero on invalid. Lite plans must contain exactly one phase, declare no parallel groups, and give every Validation Criteria bullet either a backticked command or a `manual:` instruction. Brief plans (`oat_workflow_mode: brief`) are validated with the brief profile: phases need non-empty `**Intent:**` and `**Exit evidence:**`, a `**Provisional:**` value of `yes` or `no`, unique IDs, and a concrete first phase; `### Task` headings in a brief are reported as a warning, and taskless parallel groups are valid. Goal plans add the goal profile: `oat_plan_source: goal`, a valid `## Milestones` table (`goal-milestones-missing`, `goal-milestones-malformed`, `goal-duplicate-milestone`, `goal-milestone-empty`, `goal-milestone-unknown-phase`, `goal-phase-in-multiple-milestones`, `goal-phase-without-milestone`), no parallel group spanning milestones (`goal-group-crosses-milestone`), canonical persisted phase IDs (`goal-noncanonical-phase-id`), and no change to a shipped milestone or a registered delivery's frozen scope (`goal-shipped-milestone-changed`, `goal-delivered-scope-changed`); phases the journal marks `extracted` need no milestone. See [Implementation Execution](../workflows/projects/execution/implementation-execution.md#parallel-phase-groups).
217
- - `oat project journal check --at <implement-preflight|review|completion> [--project <path>] [--scope pNN[,pNN]] [--json]` - read-only journal evaluator: it reads `plan.md`, `implementation.md`, and `state.md` and writes nothing. `implement-preflight` is implement's call before its Step 16: it validates the accepted task and phase evidence while the terminal headers and pointers Step 16 owns may still be unwritten. `review` requires an explicit `--scope` of phases the plan declares and ignores future phases; a live run line warns there instead of refusing. `completion` (oat-project-complete, before roll-up, seal, or any lifecycle write) also requires the terminal journal shape: journal `oat_status: complete` and a cleared `oat_current_task_id`, `state.md` `oat_phase_status` `complete` or `pr_open` and a cleared `oat_current_task`. Task modes read journal records through the shared heading-only reader (fenced and indented code excluded, a block ends at the next heading of equal or higher level): every plan task heading is unique and sits under its own phase (`plan-task-duplicate`, `plan-task-misplaced`, routed to the plan owner and never override-eligible), and every plan task has exactly one journal block in its phase with exactly one owned `**Status:** completed` and one owned `**Commit:**` SHA; tables and checklists are never completion evidence, and overview totals must match. Brief and goal read phase units: an accepted phase carries its `**Head:**`, execution records close as `completed` with a commit or as `failed`, `cancelled`, or `no-change` without one, an extracted goal phase and a phase the goal outcome audit defers or retires stay valid and incomplete. Everywhere: `## References` is last, review receipts sit in their phase or `## Reviews and Gates`, deferrals in `## Deferred Findings`, dispatch payloads are refused unless marked `quoted-evidence`, every run line parses as `run/v1` under `## Orchestration Runs`, carries a valid `request` identifier, and is terminal at implement-preflight and completion, and no template placeholder survives, including one left in an inline-code slot such as ``- `{path}` - …`` unless the line is marked `quoted-evidence`. An override is one line under `## Deviations from Plan / Design`: `**Override:** <scope-disposition-approved|evidence-lost|operator-accepted-gap> · **Authorized by:** <decision id> · **Scope:** <pNN-tNN|pNN> · <reason>`; it covers only a missing task block, an incomplete task, missing commit evidence, or (for `scope-disposition-approved`) an unaccepted phase within its scope, and a malformed or misplaced override is refused. Output is `{ status: ok | refused, reasons: [{ code, path, line, owner, message }], warnings, overrides }`; a refusal exits 1. Delivery coverage and the post-implementation sequence stay with `closeout-check`.
217
+ - `oat project journal check --at <implement-preflight|review|completion> [--project <path>] [--scope pNN[,pNN]] [--json]` - read-only journal evaluator: it reads `plan.md`, `implementation.md`, and `state.md` and writes nothing. `implement-preflight` is implement's call before its Step 16: it validates the accepted task and phase evidence while the terminal headers and pointers Step 16 owns may still be unwritten. `review` requires an explicit `--scope` of phases the plan declares and ignores future phases; a live run line warns there instead of refusing. In goal projects, those two boundaries also compare working `implementation.md` with its committed `HEAD` version and refuse each removed or rewritten recorded line as `journal-line-rewritten`; append-only additions, mutable progress fields, and new extraction markers do not trigger that reason. The comparison base is `HEAD`, so a rewrite that is already committed is left to `delivery check`. Unparseable committed journal frontmatter refuses as `journal-frontmatter-malformed` and must be repaired and committed before re-running. An untracked journal or unborn `HEAD` has no committed version to compare, while other Git inspection failures are command errors. `completion` does not run this comparison and instead requires the terminal journal shape: journal `oat_status: complete` and a cleared `oat_current_task_id`, `state.md` `oat_phase_status` `complete` or `pr_open` and a cleared `oat_current_task`. Task modes read journal records through the shared heading-only reader (fenced and indented code excluded, a block ends at the next heading of equal or higher level): every plan task heading is unique and sits under its own phase (`plan-task-duplicate`, `plan-task-misplaced`, routed to the plan owner and never override-eligible), and every plan task has exactly one journal block in its phase with exactly one owned `**Status:** completed` and one owned `**Commit:**` SHA; tables and checklists are never completion evidence, and overview totals must match. Brief and goal read phase units: an accepted phase carries its `**Head:**`, execution records close as `completed` with a commit or as `failed`, `cancelled`, or `no-change` without one, an extracted goal phase and a phase the goal outcome audit defers or retires stay valid and incomplete. Everywhere: `## References` is last, review receipts sit in their phase or `## Reviews and Gates`, deferrals in `## Deferred Findings`, dispatch payloads are refused unless marked `quoted-evidence`, every run line parses as `run/v1` under `## Orchestration Runs`, carries a valid `request` identifier, and is terminal at implement-preflight and completion, and no template placeholder survives, including one left in an inline-code slot such as ``- `{path}` - …`` unless the line is marked `quoted-evidence`. An override is one line under `## Deviations from Plan / Design`: `**Override:** <scope-disposition-approved|evidence-lost|operator-accepted-gap> · **Authorized by:** <decision id> · **Scope:** <pNN-tNN|pNN> · <reason>`; it covers only a missing task block, an incomplete task, missing commit evidence, or (for `scope-disposition-approved`) an unaccepted phase within its scope, and a malformed or misplaced override is refused. Output is `{ status: ok | refused, reasons: [{ code, path, line, owner, message }], warnings, overrides }`; a refusal exits 1. Delivery coverage and the post-implementation sequence stay with `closeout-check`.
218
218
  - `oat project log append|check|synthesize|rollup` - manage the optional append-only project observation log: append validated judgment or structural entries, inspect grammar and synthesis status, complete end-of-run synthesis, and roll observations into `summary.md` plus the configured repository ledger. See [Project Log](../workflows/projects/execution/project-log.md).
219
219
  - `oat project log append --category <category> --source <id> [--origin <producer>]` - record a learning on a judgment entry. The category is one of `gotcha`, `efficiency`, `documentation-gap`, `candidate-skill-content`, `decision`, or `environment-limited`; any other value, `--category` without `--source`, a `--source` containing whitespace, and these flags on a `--structural` entry are refused. The flags write a `**Category:**`, `**Source:**`, `**Origin:**`, `**Recorded:**` body head above the body; the heading grammar is unchanged and an entry without them is stored as before. Passing the source id as `--idempotency-key` makes a retry report `already-appended` and write nothing.
220
220
  - `oat project log check` - JSON adds `learnings`: `legacy` when the project still has `oat-execution-learnings.md`, which summary and retro read after the log, and `none` otherwise, in every status.
@@ -112,19 +112,28 @@ goal fields:
112
112
  its milestone, frozen phase scope, agreed endpoint, status, member pull
113
113
  requests and their observed revisions, the integrated review it was
114
114
  delivered on, its exit-gate binding and the first observed endpoint
115
- attainment. A delivery's `status` is `registering`, `open`, `at_endpoint`,
115
+ attainment. A delivery's `kind` is `pr` for one pull request or `stack` for
116
+ an existing gh-stack, whose members are recorded base to tip; a stack's
117
+ configured code exit carrier is judged at the tip member, and every lower
118
+ member's observed head must be an ancestor of the tip (`stack-order`
119
+ otherwise). A delivery's `status` is `registering`, `open`, `at_endpoint`,
116
120
  or `superseded`, and its agreed `endpoint` is `open` or `merged`. A
117
121
  replacement delivery names its one direct predecessor in `covers_scope_of`,
118
122
  and the predecessor's `superseded_by` points back; only a delivery that never
119
123
  reached its agreed endpoint may be replaced. A correction of a delivery that
120
124
  did reach it is additive (`corrects_delivery_id`, new phase IDs, no inherited
121
125
  coverage). `oat_pr_status` and `oat_pr_url` project the latest member pull
122
- request.
126
+ request, which is the tip member for a stack.
123
127
 
124
128
  Delivery evidence stays fresh across later commits that change only bookkeeping:
125
129
  `state.md`, `plan.md` (outside its approved content), `implementation.md`,
126
130
  `project-log.md` appends, `summary.md`, and the review artifacts of the
127
- delivery and of any delivery sharing its pull request.
131
+ delivery and of any delivery sharing its pull request. In evidence scopes built
132
+ for an exit carrier, the gate's own artifact also counts as bookkeeping if its
133
+ `## Reviews` row has Type `code`, Invocation `gate` and a non-placeholder
134
+ Reviewed Head equal to the carrier's `reviewed_head`, and the artifact is under `reviews/`
135
+ (including `reviews/archived/`). That artifact is never integrated-review
136
+ evidence and never one of a delivery's own review artifacts.
128
137
 
129
138
  A delivery's evidence identity is set once: its `exit_gate`, its
130
139
  `integrated_review` identity (`artifact`, `scope`, `bound_revisions`), and each
@@ -45,10 +45,13 @@ agents, templates and scripts that `oat tools install` adds.
45
45
  ## What each command writes
46
46
 
47
47
  Where a file already existed, OAT appended its own marked block instead of
48
- replacing it. This held for `.gitignore`, `.gitattributes`, an existing
49
- `pre-commit` hook and the other settings in an existing `.codex/config.toml`
50
- (OAT does change `multi_agent` and `max_depth` there; see the
51
- [provider table](#syncing-provider-views)). A pre-existing
48
+ replacing it. This held for `.gitignore`, `.gitattributes` and an existing
49
+ `pre-commit` hook. From version 0.3.37, an existing `.codex/config.toml` is
50
+ edited in place: OAT changes only `multi_agent`, `max_depth` and its own
51
+ `[agents.<name>]` tables, and comments, blank lines, table order and your other
52
+ settings stay as they were (see the
53
+ [provider table](#syncing-provider-views)). Earlier versions rewrote the whole
54
+ file and dropped its comments. A pre-existing
52
55
  `~/.claude/settings.json` was left untouched.
53
56
 
54
57
  ### Setting up
@@ -82,13 +85,13 @@ views OAT manages. A provider does not have to be enabled: an existing
82
85
  `.claude/` directory in the repository, or `~/.claude/` in your home directory,
83
86
  is enough for `oat sync` to create Claude views.
84
87
 
85
- | Provider | Repository views created by `oat sync --scope project` |
86
- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
87
- | Claude | `.claude/skills/<name>` and `.claude/agents/<name>.md`, relative symlinks into `.agents/` |
88
- | Cursor | `.cursor/agents/`: relative symlinks for agents, plus generated model-variant files marked `# oat-managed: true` |
89
- | Copilot | `.github/agents/`, relative symlinks |
90
- | Codex | `.codex/agents/*.toml` and `.codex/config.toml`, generated files. In an existing `config.toml`, OAT adds its `[agents.<name>]` tables and sets `[features] multi_agent = true` and `[agents] max_depth` to at least 2, changing those two values if you had set them lower; your other settings stay. |
91
- | Gemini | Nothing |
88
+ | Provider | Repository views created by `oat sync --scope project` |
89
+ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
90
+ | Claude | `.claude/skills/<name>` and `.claude/agents/<name>.md`, relative symlinks into `.agents/` |
91
+ | Cursor | `.cursor/agents/`: relative symlinks for agents, plus generated model-variant files marked `# oat-managed: true` |
92
+ | Copilot | `.github/agents/`, relative symlinks |
93
+ | Codex | `.codex/agents/*.toml` and `.codex/config.toml`, generated files. In an existing `config.toml`, OAT adds its `[agents.<name>]` tables and sets `[features] multi_agent = true` and `[agents] max_depth` to at least 2, changing those two values if you had set them lower; your other settings and comments stay byte for byte (0.3.37 and later). |
94
+ | Gemini | Nothing |
92
95
 
93
96
  OAT creates skill views only for Claude. It reports the other providers' skill
94
97
  support as `native-read` and creates no skill views for them. No generated
@@ -209,15 +209,22 @@ explicitly save a report before asking another workflow to consume its path.
209
209
  so use the slash or `$` form rather than relying on the agent to pick it. It
210
210
  does not require a project name or an active-project pointer.
211
211
 
212
- **Prerequisites:** A Git repository, the OAT CLI, and the ability to dispatch
213
- the `oat-codebase-mapper` subagent. A preflight checks whether background
214
- agents can write files and switches to a read-only fallback if they cannot.
215
- Needs an active OAT project: no. If a knowledge directory already exists,
216
- choose whether to refresh it or skip the run. Refresh removes only regular
217
- Markdown files marked `oat_generated: true` and regenerates the eight named
218
- outputs. Hand-written notes survive; an unmarked expected-output collision
219
- stops the run before deletion so you can decide how to preserve it. Symlinked
220
- knowledge directories and output collisions are refused.
212
+ **Prerequisites:** A Git repository, the OAT CLI, the utility-pack dispatch
213
+ skills, and an installed `oat-codebase-mapper` provider projection. Before
214
+ changing knowledge on either a first generation or a refresh, the skill
215
+ resolves `oat-dispatch-subagents` and `subagent-orchestration`, then checks that
216
+ the active Claude, Codex, or Cursor provider can launch its mapper projection.
217
+ A missing dispatch skill reports the utility-pack install/update commands; a
218
+ missing mapper projection reports the workflows-pack commands or `oat sync`.
219
+ An unsupported host or declined authorization reports that limitation without
220
+ irrelevant install advice. Every failure stops before cleanup, thin-index
221
+ creation, or a write probe. Needs an active OAT project: no. If a knowledge
222
+ directory already exists, choose whether to refresh it or skip the run.
223
+ Refresh removes only regular Markdown files marked `oat_generated: true` and
224
+ regenerates the eight named outputs. Hand-written notes survive; an unmarked
225
+ expected-output collision stops the run before deletion so you can decide how
226
+ to preserve it. Symlinked knowledge directories and output collisions are
227
+ refused.
221
228
 
222
229
  **Example scenario:** A new teammate needs to understand which packages own
223
230
  the CLI, how shared configuration reaches applications, and which test
@@ -232,16 +239,13 @@ index is an onboarding and retrieval aid, not a declaration that all
232
239
  architecture concerns have been fixed or that every future question is
233
240
  answered.
234
241
 
235
- **What it does without asking:** The only question is refresh-or-skip when
236
- knowledge files already exist. Otherwise it creates `.oat/repo/knowledge/`,
237
- starts a test subagent and then four `oat-codebase-mapper` subagents in the
238
- background, and writes the knowledge files. It then runs
239
- `oat internal commit-paths` on your current branch with the exact generated
240
- output/deletion paths and enabled hooks. Unrelated staged and unstaged work
241
- remains intact.
242
- Afterwards it records the run in `.oat/tracking.json` and regenerates the
243
- `.oat/state.md` dashboard with `oat state refresh`; those two files are not
244
- part of the commit. It does not push.
242
+ **What it does without asking:** The run resolves a usable mapper route before
243
+ changing knowledge and may ask once for authorization covering the write probe
244
+ and four mapper lanes. It offers read-only fallback only after a launched probe
245
+ verifies that writes are blocked. It preserves manual notes while preparing and
246
+ generating the eight owned outputs. It commits only the exact owned paths with
247
+ hooks enabled, leaving unrelated staged and unstaged work intact, then updates
248
+ the tracking dashboard without pushing.
245
249
 
246
250
  **Expected output:** Eight files under `.oat/repo/knowledge/`:
247
251
  `project-index.md`, `stack.md`, `architecture.md`, `structure.md`,
@@ -299,7 +299,13 @@ milestone's `plan` carrier, `oat_milestone_gates[mNN].plan`, written with
299
299
  for a re-alignment amendment it is the only approval evidence. The implement
300
300
  exit gate at milestone closeout writes `oat_milestone_gates[mNN].exit` (never
301
301
  `oat_implement_exit_gate`, which goal uses only at terminal closeout). It runs
302
- before the milestone's integrated review and runs again after queued fixes.
302
+ the configured command verbatim with `--review-scope final`, before the
303
+ milestone's integrated review, and runs again after queued fixes. Its own
304
+ Type `code`, Invocation `gate` Reviews row and artifact count as bookkeeping
305
+ only when the row's non-placeholder Reviewed Head equals the carrier's
306
+ `reviewed_head` and the artifact's project-relative path is under `reviews/`
307
+ (including `reviews/archived/`). That row never serves as the integrated review
308
+ or unlocks delivery fields, and no placeholder row is required before the gate runs.
303
309
  `oat project delivery check` reports the exit carrier's freshness, and
304
310
  `oat project delivery refresh` marks it stale when delivery evidence no longer
305
311
  holds.
@@ -143,7 +143,9 @@ deliveries exist and registers only when
143
143
  `oat project delivery check --subject <mNN|dNN>` reports `status: ok`. It
144
144
  commits a `registering` registry entry before creating anything, then creates
145
145
  the PR, or on resume attaches the single PR that `gh pr list` finds for the
146
- head branch (more than one match stops at `oat-project-reconcile`). It then
146
+ head branch (more than one match stops at `oat-project-reconcile`). For a
147
+ stacked milestone, registration instead records `kind: stack` and attaches its
148
+ existing layer pull requests base to tip; it never creates a stack. It then
147
149
  records the member, `status: open`, and `oat_milestone_status: delivered`, and
148
150
  appends one structural project-log entry. Stale review or exit-gate evidence
149
151
  stops before registration: for the active milestone the skill writes
@@ -612,7 +612,9 @@ from a first–last range. `oat-project-pr-progress` registers a delivery only
612
612
  when `oat project delivery check --subject <mNN|dNN>` reports `status: ok`,
613
613
  writing the `oat_deliveries` entry (`registering`) before it creates the pull
614
614
  request so an interrupted run resumes by `gh pr list` instead of opening a
615
- duplicate.
615
+ duplicate. For a stacked milestone, registration instead records `kind: stack`
616
+ and attaches its existing layer pull requests base to tip; it never creates a
617
+ stack.
616
618
 
617
619
  **Freshness.** Evidence keeps the revision actually reviewed. Commits after it
618
620
  count as bookkeeping only when they touch the project's tracking files in
@@ -1,6 +1,6 @@
1
1
  {
2
- "cli": "0.3.36",
3
- "docs-config": "0.3.36",
4
- "docs-theme": "0.3.36",
5
- "docs-transforms": "0.3.36"
2
+ "cli": "0.3.38",
3
+ "docs-config": "0.3.38",
4
+ "docs-theme": "0.3.38",
5
+ "docs-transforms": "0.3.38"
6
6
  }
@@ -7,7 +7,7 @@ disable-model-invocation: true
7
7
  user-invocable: true
8
8
  allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion, Task
9
9
  metadata:
10
- version: 1.0.3
10
+ version: 1.0.4
11
11
  ---
12
12
 
13
13
  # Brief Project
@@ -531,7 +531,8 @@ root commits shared routing, registry, gate and acceptance records.
531
531
 
532
532
  `oat_deliveries` entries carry `delivery_id` (`dNN`, unique), `milestone`, a
533
533
  `scope` frozen on registration, the agreed `endpoint` (`open | merged`),
534
- `kind: pr`, `status` (`registering | open | at_endpoint | superseded`), the
534
+ `kind: pr | stack`, `status`
535
+ (`registering | open | at_endpoint | superseded`), the
535
536
  supersession links `superseded_by` and `covers_scope_of`, an additive
536
537
  `corrects_delivery_id`, persisted `lookup` keys (`repository`, `head_branch`,
537
538
  `head_sha_at_registration`), `members` (`url`, `base`, `reviewed_head`,
@@ -540,12 +541,26 @@ supersession links `superseded_by` and `covers_scope_of`, an additive
540
541
  binding `exit_gate`, and the first observed `endpoint_attainment`.
541
542
 
542
543
  - **Idempotent registration.** The registration owner writes the entry with
543
- `status: registering` and its `lookup` keys and commits before creating the
544
- pull request, then records the URL and `status: open`. A `registering` entry
545
- on resume runs `gh pr list --repo <repository> --head <head_branch> --state
546
- all --json url,headRefOid`: exactly one match is attached without creating a
547
- duplicate; zero matches create once; more than one stops and routes to
548
- `oat-project-reconcile`.
544
+ `status: registering` and its `lookup` keys. For `kind: pr`, it commits
545
+ before creating the pull request, then records the URL and `status: open`; on
546
+ resume, `gh pr list --repo <repository> --head <head_branch> --state all
547
+ --json url,headRefOid` attaches exactly one match, creates once for zero
548
+ matches, and stops for more than one. For `kind: stack`, registration is
549
+ attach-only: the `registering` write records every existing member URL in
550
+ base-to-tip order, and resume re-checks each URL rather than creating a
551
+ stack. For a PR lookup, more than one stops and routes to
552
+ `oat-project-reconcile`; a missing, closed-unmerged or re-targeted stack
553
+ layer follows the same stop-and-route.
554
+ - **Stacked deliveries.** A stack records members base to tip. For a configured
555
+ code carrier bound to a reviewed head, the exit carrier is judged against
556
+ the tip member's observed head, and every lower member's observed head must
557
+ be an ancestor of the tip (`stack-order` otherwise). Null carriers and
558
+ unreviewed-resolution carriers (`no_gate`, `project_disabled`) are evaluated
559
+ exactly as for `kind: pr`; the integrated review remains per member.
560
+ Post-review bookkeeping lands on the tip member's branch, because a commit
561
+ on a lower layer changes upper members' bases and stales their review. A stack
562
+ that fails the configured-carrier order check is never repaired in place:
563
+ replace it through supersession with `covers_scope_of`.
549
564
  - **Prerequisites.** Before registration the owner runs
550
565
  `oat project delivery refresh --project <path>` and
551
566
  `oat project delivery check --project <path> --subject <mNN|dNN> --json`; it
@@ -562,7 +577,8 @@ all --json url,headRefOid`: exactly one match is attached without creating a
562
577
  share their member pull request (`gh` allows one open pull request per head
563
578
  and base), so one member URL may appear in several deliveries. Coverage
564
579
  judges each delivery's own frozen scope and bound evidence, never the shared
565
- member alone; `oat_pr_url` and `oat_pr_status` project the latest member.
580
+ member alone; `oat_pr_url` and `oat_pr_status` project the latest member,
581
+ which is the tip member for a stack.
566
582
  - **Evidence capture.** The exit-gate result accepted for the delivery is
567
583
  persisted as its `exit_gate` with the delivery evidence; overwriting the
568
584
  milestone's working carrier for a correction never relabels another
@@ -600,7 +616,14 @@ changes only permitted bookkeeping:
600
616
  the evidence being recorded or archived, and, for a delivery whose member
601
617
  pull request is shared (12.7, Shared members), the review artifacts recorded
602
618
  for the deliveries that share it; each delivery is still judged on its own
603
- frozen scope, reviewed revisions and `exit_gate`. `summary.md` is derived
619
+ frozen scope, reviewed revisions and `exit_gate`. The artifact of a Reviews
620
+ row with Type `code`, Invocation `gate`, and a non-placeholder Reviewed Head
621
+ equal to the judged carrier's `reviewed_head` is also admitted in evidence
622
+ scopes built for that carrier (its review and exit evaluations), provided
623
+ its project-relative artifact path is under `reviews/` (including
624
+ `reviews/archived/`). The gate row is never integrated-review evidence and
625
+ its artifact never joins a delivery's own review-artifact set, so it cannot
626
+ unlock set-once fields. `summary.md` is derived
604
627
  institutional memory, never the authority for outcomes, approach,
605
628
  constraints, decisions or endpoint, which live in the brief; any change to
606
629
  it is bookkeeping. Path membership alone is insufficient for the other
@@ -7,7 +7,7 @@ disable-model-invocation: false
7
7
  user-invocable: true
8
8
  allowed-tools: Read, Write, Bash(git:*), Bash(oat:*), Bash(oat project log:*), Glob, Grep, AskUserQuestion, Task
9
9
  metadata:
10
- version: 2.3.22
10
+ version: 2.3.23
11
11
  ---
12
12
 
13
13
  # Implementation Phase
@@ -59,10 +59,20 @@ recovery owner for that carrier:
59
59
  1. **Exit gate before the integrated review.** Resolve and run the configured
60
60
  implement exit gate exactly as Step 14 does (`oat gate resolve
61
61
  oat-project-implement --project "$PROJECT_PATH" --json`, canonical
62
- `oat --json gate review`, receive eligibility, `onFailure`, `maxAttempts`),
63
- scoped to the milestone's ordered phase set. The goal ladder exception
64
- applies: this gate precedes the integrated delivery review, and queued
65
- fixes require it to run again.
62
+ `oat --json gate review`, receive eligibility, `onFailure`, `maxAttempts`).
63
+ Run the configured command verbatim, including its
64
+ `--review-scope final`; do not rewrite that argument to the milestone's
65
+ phase IDs. The carrier subject still records the milestone's ordered phase
66
+ set. The goal ladder exception applies: this gate precedes the integrated
67
+ delivery review, and queued fixes require it to run again. The gate's own
68
+ Reviews row is admitted as carrier bookkeeping only when it has Type
69
+ `code`, Invocation `gate`, and a non-placeholder Reviewed Head equal to the
70
+ carrier's `reviewed_head`; its non-placeholder artifact is admitted with
71
+ that row only when its project-relative path is under `reviews/` (including
72
+ `reviews/archived/`). This row never serves as the milestone or delivery
73
+ integrated review and never joins a delivery's own evidence artifacts, so
74
+ it cannot unlock set-once delivery fields. Do not create a placeholder
75
+ Reviews row before the gate runs.
66
76
  2. **Write the milestone carrier.** Record `oat_milestone_gates[mNN].exit`
67
77
  with the gate approval record core, `resolution` (`configured`, `no_gate`,
68
78
  or `project_disabled`), `subject: { kind: code, scope: [ordered phase
@@ -5,7 +5,7 @@ disable-model-invocation: true
5
5
  user-invocable: true
6
6
  allowed-tools: Read, Write, Bash(awk:*), Bash(gh:*), Bash(git:*), Bash(mktemp:*), Bash(oat:*), Bash(rm:*), Glob, Grep, AskUserQuestion
7
7
  metadata:
8
- version: 1.3.5
8
+ version: 1.3.6
9
9
  ---
10
10
 
11
11
  # Progress PR
@@ -399,9 +399,14 @@ entry is not registered yet and resumes at item 5.
399
399
  non-superseded registered delivery (item 3a), allocate the next unused
400
400
  `dNN` and write its entry with `status: registering`: `milestone`, the
401
401
  frozen `scope` (the ordered set), the agreed `endpoint` from the brief's
402
- Delivery endpoint and authority, `kind: pr`, the persisted `lookup` keys
403
- (`repository` from `gh repo view --json nameWithOwner`, `head_branch`,
404
- `head_sha_at_registration` from `git rev-parse HEAD`), the
402
+ Delivery endpoint and authority, `kind: pr` for one pull request or
403
+ `kind: stack` when the milestone is delivered as an existing gh-stack, and
404
+ the persisted `lookup` keys (`repository` from
405
+ `gh repo view --json nameWithOwner`, `head_branch`,
406
+ `head_sha_at_registration` from `git rev-parse HEAD`). For a stack,
407
+ `lookup.head_branch` names the tip layer's branch and this same
408
+ `registering` write records every existing layer's `url` in base-to-tip
409
+ member order. Also record the
405
410
  `integrated_review` (`artifact`, `scope`, `bound_revisions`,
406
411
  `disposition: passed`) and the accepted `exit_gate` copied from the
407
412
  milestone's current exit carrier, so the gate result is captured with the
@@ -409,16 +414,22 @@ entry is not registered yet and resumes at item 5.
409
414
  and the predecessor's `superseded_by: <dNN>` in the same write; an additive
410
415
  correction writes `corrects_delivery_id` instead. Commit this registration
411
416
  record before creating anything.
412
- 5. **Create or attach.** Generate the PR description (Steps 2–5), push the
413
- branch, and create the pull request with the Step 6 commands. On resume
414
- with a `registering` entry, first run
417
+ 5. **Create or attach.** For `kind: pr`, generate the PR description (Steps
418
+ 2–5), push the branch, and create the pull request with the Step 6 commands.
419
+ On resume, first run
415
420
  `gh pr list --repo <repository> --head <head_branch> --state all --json url,headRefOid`:
416
421
  exactly one match is attached without creating a duplicate; zero matches
417
- create once; more than one stops and routes to `oat-project-reconcile`.
418
- 6. **Record.** Write the member (`url`, `base`, `reviewed_head`),
419
- `status: open`, `oat_milestone_status: delivered` for the active milestone,
420
- `oat_pr_status: open`, `oat_pr_url`, and `oat_phase_status: pr_open`;
421
- commit this registration bookkeeping.
422
+ create once. For `kind: stack`, attach the already-created pull requests;
423
+ never create a stack. On resume, re-check every recorded member URL with
424
+ `gh pr view`. For a PR lookup, more than one stops and routes to
425
+ `oat-project-reconcile`; a missing, closed-unmerged, or re-targeted stack
426
+ layer follows the same stop-and-route.
427
+ 6. **Record.** For a stack, fill every member's `base` and `reviewed_head`;
428
+ for one pull request, write its member (`url`, `base`, `reviewed_head`).
429
+ Then write `status: open`, `oat_milestone_status: delivered` for the active
430
+ milestone, `oat_pr_status: open`, `oat_pr_url` (projected from the tip
431
+ member for a stack), and `oat_phase_status: pr_open`; commit this
432
+ registration bookkeeping.
422
433
  7. **Log.** After that registration commit, append exactly one structural
423
434
  entry and commit it in this same step:
424
435
  `oat project log append --project "$PROJECT_PATH" --structural --producer oat-project-pr-progress --ref <dNN> --idempotency-key "<goal-slug>-register-<dNN>" --body "Registered <dNN> for <mNN> (<ordered phase ids>) at <url>; <goal-slug>-register-<dNN>"`.