forge-orkes 0.37.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/create-forge.js +66 -1
- package/package.json +1 -1
- package/template/.claude/skills/chief-of-staff/SKILL.md +8 -0
- package/template/.claude/skills/forge/SKILL.md +19 -2
- package/template/.claude/skills/upgrading/SKILL.md +37 -1
- package/template/.forge/FORGE.md +3 -1
- package/template/.forge/adapters/codex-generation.md +90 -0
- package/template/.forge/migrations/0.41.0-generated-codex-adapter.md +81 -0
package/bin/create-forge.js
CHANGED
|
@@ -68,7 +68,7 @@ function compareVersions(a, b) {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// Template-only: reference templates Forge controls
|
|
71
|
-
const TEMPLATE_ONLY_DIRS = ['.forge/templates', '.forge/migrations'];
|
|
71
|
+
const TEMPLATE_ONLY_DIRS = ['.forge/templates', '.forge/migrations', '.forge/adapters'];
|
|
72
72
|
|
|
73
73
|
// Settings file gets smart-merge (overwrite forge.* keys, preserve user hooks)
|
|
74
74
|
const SETTINGS_FILE = '.claude/settings.json';
|
|
@@ -357,6 +357,9 @@ async function install() {
|
|
|
357
357
|
}
|
|
358
358
|
|
|
359
359
|
console.log(`\n Forge v${pkgVersion} is ready. Start with: /forge\n`);
|
|
360
|
+
|
|
361
|
+
// Presence-gated: if a Codex adapter is present, note it may need regeneration.
|
|
362
|
+
noticeCodexAdapter();
|
|
360
363
|
}
|
|
361
364
|
|
|
362
365
|
/**
|
|
@@ -652,6 +655,68 @@ async function upgrade() {
|
|
|
652
655
|
// Pass the version captured BEFORE upgradeSettings() stamped the new one, so the
|
|
653
656
|
// migration range is (installed, source] against the freshly-synced guides.
|
|
654
657
|
runPostUpgradeMigrationChecks(installedVersion);
|
|
658
|
+
|
|
659
|
+
// Presence-gated advisories (no generation, no rebase — notices only).
|
|
660
|
+
noticeCodexAdapter();
|
|
661
|
+
noticeWorktreeLag();
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Presence-gated Codex-adapter staleness notice. The bin has no LLM, so it can
|
|
666
|
+
* only NOTICE that a Codex adapter (.agents/ / .codex/) may be stale after a
|
|
667
|
+
* .claude/ sync and point to the regeneration route (/upgrading Step 4b). It
|
|
668
|
+
* never generates, never writes .agents/, never adds .agents to
|
|
669
|
+
* FRAMEWORK_OWNED_DIRS. Silent when no Codex adapter is present.
|
|
670
|
+
*/
|
|
671
|
+
function noticeCodexAdapter() {
|
|
672
|
+
const hasCodex =
|
|
673
|
+
fs.existsSync(path.join(targetDir, '.agents')) ||
|
|
674
|
+
fs.existsSync(path.join(targetDir, '.codex'));
|
|
675
|
+
if (!hasCodex) return;
|
|
676
|
+
console.log(' Codex adapter detected (.agents/ / .codex/).');
|
|
677
|
+
console.log(' It may now be stale relative to the .claude/ source just synced.');
|
|
678
|
+
console.log(' This installer does not regenerate it (no LLM). To refresh it,');
|
|
679
|
+
console.log(' run the `/upgrading` skill — its Codex step offers regeneration');
|
|
680
|
+
console.log(' from .forge/adapters/codex-generation.md.\n');
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Presence-gated worktree-lag notice (paired with /upgrading Step 8). An upgrade
|
|
685
|
+
* run touches only this checkout; live forge/m-* worktrees keep their
|
|
686
|
+
* branch-point framework files until rebased. The bin only NOTICES — it never
|
|
687
|
+
* rebases (a rebase can conflict). Silent when there are no live forge worktrees
|
|
688
|
+
* or this is not a git repo.
|
|
689
|
+
*/
|
|
690
|
+
function noticeWorktreeLag() {
|
|
691
|
+
let out;
|
|
692
|
+
try {
|
|
693
|
+
out = execSync('git worktree list --porcelain', {
|
|
694
|
+
cwd: targetDir,
|
|
695
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
696
|
+
}).toString();
|
|
697
|
+
} catch {
|
|
698
|
+
return; // not a git repo / git unavailable
|
|
699
|
+
}
|
|
700
|
+
const lagging = [];
|
|
701
|
+
let curPath = null;
|
|
702
|
+
for (const line of out.split('\n')) {
|
|
703
|
+
if (line.startsWith('worktree ')) curPath = line.slice('worktree '.length).trim();
|
|
704
|
+
else if (line.startsWith('branch ')) {
|
|
705
|
+
const br = line.slice('branch '.length).trim();
|
|
706
|
+
if (/^refs\/heads\/forge\/m-/.test(br) && curPath) {
|
|
707
|
+
lagging.push({ path: curPath, branch: br.replace('refs/heads/', '') });
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (!lagging.length) return;
|
|
712
|
+
console.log(` ${lagging.length} live Forge worktree(s) lag this upgrade:`);
|
|
713
|
+
for (const w of lagging) {
|
|
714
|
+
console.log(` ${w.path} (${w.branch})`);
|
|
715
|
+
}
|
|
716
|
+
console.log(' They keep their branch-point framework files until rebased.');
|
|
717
|
+
console.log(' Pick up this upgrade in each: git -C <path> rebase main');
|
|
718
|
+
console.log(' (Gitignored carve-outs like .mcp.json / experimental hooks do not');
|
|
719
|
+
console.log(' rebase — re-run the experimental installer if the upgrade changed them.)\n');
|
|
655
720
|
}
|
|
656
721
|
|
|
657
722
|
// --- Entry point ---
|
package/package.json
CHANGED
|
@@ -160,6 +160,14 @@ existing M10 state.
|
|
|
160
160
|
`{orchestration.worktree_root or ../<repo>-worktrees}/{anchor}` — rather
|
|
161
161
|
than assuming the experimental `orchestrating` skill's internal default.
|
|
162
162
|
Confirm the resolved path with `git worktree list` before recording it.
|
|
163
|
+
**If a path *is* recorded, validate it before honoring it** (don't trust it
|
|
164
|
+
blind — that is the gap a recorded-but-wrong path slips through): compare its
|
|
165
|
+
parent dir to the resolved convention root (`orchestration.worktree_root`,
|
|
166
|
+
else `{repo-basename}-worktrees`). Mismatch → advisory warn *"recorded
|
|
167
|
+
worktree path `{path}` is not under the convention root `{root}` — a manual or
|
|
168
|
+
pre-convention `git worktree add`; `git worktree move` it and update the
|
|
169
|
+
record."* Adopt the recorded path as-is regardless (advisory, never a block;
|
|
170
|
+
honors `orchestration.worktree_root`).
|
|
163
171
|
- `runtime.worker_sessions` with the M10 session / claim ids
|
|
164
172
|
- `ownership.owned_surfaces`, `shared_surfaces`, and `read_only_surfaces`
|
|
165
173
|
as empty lists if unknown
|
|
@@ -32,8 +32,10 @@ git worktree list --porcelain 2>/dev/null \
|
|
|
32
32
|
- Surfacing continues to Rollup + selection — but it is **no longer purely informational**. Enforcement is deferred to **1.1a**, which fires only for the *selected* milestone (booting from main to work an unrelated milestone stays free). Record which worktrees were reported here so 1.1a can match the selection against them. (See FORGE.md State Ownership for the full taxonomy.)
|
|
33
33
|
|
|
34
34
|
**If `in_main_checkout: false`** (this session is itself a worktree) AND `forge.worktree_rebase_check: true` in `.forge/project.yml` (default `false` — opt-in):
|
|
35
|
-
- Diff
|
|
36
|
-
-
|
|
35
|
+
- Diff this worktree's `HEAD` against `origin/main` (or `main` if no remote) across **two** surfaces:
|
|
36
|
+
- **(a) shared `.forge/` state** — the **shared-mutable** + **stable-shared** files per the FORGE.md taxonomy: `context.md`, `refactor-backlog.yml`, `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `requirements/m{N}.yml`, `FORGE.md`.
|
|
37
|
+
- **(b) framework surface** — `.claude/skills/`, `.claude/agents/`, `.forge/FORGE.md` — the files a `/upgrading` run changes. This catches a **framework upgrade that landed on main after this worktree branched**: `upgrading` Step 8's producer-side offer is the primary path, but a worktree created (or forgotten) since the upgrade only finds out here. (Gitignored framework files — `.mcp.json`, experimental hooks — won't show in the diff; they propagate via the experimental installer, not git.)
|
|
38
|
+
- Any differ → surface: *"`{file}` has changed on main since this worktree branched. Pull just this file (`git restore --source main -- {file}`), rebase, or skip?"* — operator decides. For a framework-surface (b) hit, lead with rebase (a partial restore of skills/agents is rarely what you want).
|
|
37
39
|
- Setting absent or `false` → no-op.
|
|
38
40
|
|
|
39
41
|
**Integration flag check (consumer — worktree only).** When `in_main_checkout: false`, check whether a checkpoint publish has landed work on main that this worktree should pull (FORGE.md → Stream Integration Checkpoints). Event-driven, not polled — read the flag first; act only if it is set:
|
|
@@ -45,6 +47,13 @@ git worktree list --porcelain 2>/dev/null \
|
|
|
45
47
|
|
|
46
48
|
Cross-machine note: the flag file is machine-local, so a worktree on another laptop relies on the opt-in `forge.worktree_rebase_check` / a periodic fetch instead — eventual, not instant.
|
|
47
49
|
|
|
50
|
+
**Worktree path convention check (advisory — main or worktree).** A recorded worktree path is trusted *verbatim* everywhere (FORGE.md → "Recorded path is authoritative"), so a path created **outside** the convention — a manual `git worktree add ../forge-worktrees/m115`, or pre-convention state — is honored unchallenged by the 1.1a gate and by `chief-of-staff` adoption. This check surfaces that drift. It never blocks and never moves anything.
|
|
51
|
+
|
|
52
|
+
- Resolve the convention root: `orchestration.worktree_root` from `project.yml` (relative → against the **repo root**; absolute / leading-`~` honored verbatim); if unset, `{repo-parent}/{repo-basename}-worktrees`.
|
|
53
|
+
- For each recorded worktree path in play this boot — `lifecycle.worktree_path` of any surfaced live milestone, plus any stream `runtime.worktree` — compare its **parent dir** to the resolved root.
|
|
54
|
+
- Mismatch → one advisory line: *"recorded worktree path `{path}` for m{id} is not under the convention root `{root}` — likely a manual `git worktree add` or pre-convention state. Fix: `git worktree move {path} {root}/{anchor}` then update the recorded path. (Advisory; honors `orchestration.worktree_root`.)"*
|
|
55
|
+
- Parent dir under the root, or no recorded path → silent. An explicit `orchestration.worktree_root` is honored by construction (the override **is** the root compared against), so a deliberately relocated root never false-warns.
|
|
56
|
+
|
|
48
57
|
**Stream Rollup (active.yml is derived).** If `.forge/streams/` has any stream files, regenerate `.forge/streams/active.yml` from them + active milestones per FORGE.md → Stream Rollup, the same way step 1.0 regenerates `index.yml`. `active.yml` is derived — never read it as authoritative without rolling up first, and never hand-edit it. Runs in the main checkout (worktrees never write `active.yml`). No `streams/` dir → skip.
|
|
49
58
|
|
|
50
59
|
**Ready-to-merge nudge (main checkout / streams without checkpoints).** From the just-regenerated `active.yml`, scan for streams with `coordination: ready` or a non-empty `merge_queue` **that are not auto-publishing via checkpoints**. Any present → one line: *"{N} stream(s) ready to merge — run `/chief-of-staff` (merge safe) to integrate."* Pointer only — the cadence logic lives in the Chief's Merge Cadence Check; `forge` never merges. Nothing pending → silent.
|
|
@@ -65,6 +74,8 @@ Rollup procedure (deterministic + idempotent):
|
|
|
65
74
|
|
|
66
75
|
Output is a pure function of the milestone files, so two sessions regenerating it produce identical bytes — it never needs a hand-merge. **Only the main/orchestrator session runs rollup; worktree agents never write `index.yml`** (they edit only their own `milestone-{id}.yml`).
|
|
67
76
|
|
|
77
|
+
**Enforced, not optional — a boot must not read a stale registry.** The rollup *is* the reconcile step; skipping it silently lets `index.yml` drift from the milestone files — e.g. a worktree sets `current.status: complete` and merges to main, but `index.yml` stays `active` until some later boot happens to regenerate by hand (observed twice for m-CLOUDS01). So every boot **runs** steps 1–4. Before rewriting, diff each milestone's *derived* status against its current `index.yml` entry; any mismatch → emit one loud line — *"index.yml was stale vs {N} milestone file(s) ({ids}) — regenerated."* — then write. Identical (the common case) → the rewrite is a no-op by bytes; stay silent. The rollup is idempotent, so running it on every boot is free.
|
|
78
|
+
|
|
68
79
|
### 1.1 Milestone Selection
|
|
69
80
|
|
|
70
81
|
Check state files:
|
|
@@ -113,6 +124,12 @@ Single-owner-mutable state must be written by exactly one checkout. When this se
|
|
|
113
124
|
|
|
114
125
|
Resolve the worktree path from the recorded `lifecycle.worktree_path` / `runtime.worktree`, or — if absent — from the base **Worktree Convention** (FORGE.md).
|
|
115
126
|
|
|
127
|
+
**Completed milestone + live worktree → finalize, not gate (precedence).** The gate assumes the live worktree holds *in-progress, owned* work. A worktree whose milestone file is already `current.status: complete` — it set complete and merged to main, then a fresh main boot lands here — needs the **opposite** of a write-block: it needs wrapping up. So when the selected milestone is `complete` **and** still has a live worktree, do **not** raise the four-option ownership gate. Surface the finalize offer instead: *"m{id} is complete but its worktree `{path}` (`{branch}`) is still live — roll up `index.yml` and tear down the worktree + branch? [yes / keep]"*.
|
|
128
|
+
- **yes** → confirm, then `git worktree remove {path}`, delete the branch, clear `lifecycle.worktree_*` on the milestone, and run **Rollup (1.0)**. (Never auto-remove without the explicit yes.)
|
|
129
|
+
- **keep** → leave it; impose no write-block — a `complete` milestone has no live cursor left to fork.
|
|
130
|
+
|
|
131
|
+
The gate (below) and this finalize path are mutually exclusive on `current.status`: `complete` → finalize; any other status with a live worktree → gate.
|
|
132
|
+
|
|
116
133
|
**When it does NOT trigger** (no-op — continue to routing): no live worktree for the selected milestone; or this session **is** the owning worktree (`in_main_checkout: false` and the branch anchors to this milestone); or the milestone has a recorded, still-current `lifecycle.ownership_override` (see option 4).
|
|
117
134
|
|
|
118
135
|
**When it triggers — STOP. Do not route** to `planning`, `executing`, `verifying`, `reviewing`, `quick-tasking` against this milestone, and do not write any of:
|
|
@@ -81,12 +81,28 @@ For each skill dir present in the project's `.claude/skills/` but **absent from
|
|
|
81
81
|
|
|
82
82
|
## Step 4: Sync Template-Only Files
|
|
83
83
|
|
|
84
|
-
Same process as Step 3 for `.forge/templates
|
|
84
|
+
Same process as Step 3 for `.forge/templates/**`, `.forge/migrations/**`, and `.forge/adapters/**`. (Matches the npm bin's template-only dirs — keeps migration guides installed so the Step 7 pointers resolve via the in-Claude sync route, not just `npx forge-orkes upgrade`. `.forge/adapters/**` ships the platform-adapter generation protocols, e.g. `codex-generation.md`, so the Step 4b Codex step can hand it to `quick-tasking`.)
|
|
85
85
|
|
|
86
86
|
**Also sync the forge gitignore:** the source ships it as `.forge/gitignore` (npm strips files literally named `.gitignore` from a published tarball). Copy/refresh the source's `.forge/gitignore` into the project as `.forge/.gitignore` (overwrite — it is framework-owned). Report added/updated/unchanged like any template-only file.
|
|
87
87
|
|
|
88
88
|
**Sync the framework prose file `.forge/FORGE.md`** (framework-owned single file — it holds the `# Forge` prose, formerly embedded in CLAUDE.md). Copy/refresh `{source}/packages/create-forge/template/.forge/FORGE.md` → `.forge/FORGE.md` (overwrite when different; report added/updated/unchanged). **Run this BEFORE the Step 5 CLAUDE.md pass** so a migrated import line never points at a missing file.
|
|
89
89
|
|
|
90
|
+
## Step 4b: Codex Adapter (presence-gated — detect + offer, never auto)
|
|
91
|
+
|
|
92
|
+
Forge ships a **Codex/AGENTS adapter** (`.agents/skills/` + `.codex/` wiring) for projects run on Codex. It is a *derived translation* of the canonical `.claude/` skills (ADR-014) and drifts whenever core moves — but `upgrading` syncs only `.claude/`, so the Codex adapter would silently rot. This step makes that staleness visible and one-keystroke-fixable, **without** ever generating it here (only an agent-as-Codex can author it natively).
|
|
93
|
+
|
|
94
|
+
1. **Presence gate.** Glob the project root for `.agents/` and `.codex/`. **Neither exists → skip silently** — no prose, no prompt (Claude-only / greenfield projects are unaffected).
|
|
95
|
+
2. **Either exists → report + offer.** The Codex adapter is present and may be stale relative to the `.claude/` source just synced in Steps 3–4. Offer regeneration:
|
|
96
|
+
```
|
|
97
|
+
Codex adapter detected (.agents/ / .codex/). It may be stale vs the .claude/
|
|
98
|
+
source just synced. Regenerate it now? (yes / no)
|
|
99
|
+
```
|
|
100
|
+
- **yes** → invoke `quick-tasking`, handing it `.forge/adapters/codex-generation.md` as the task definition (the **same delegation pattern as Step 7 migrations**). The protocol instructs an agent-as-Codex to author `.agents/` + `.codex/` from source using native primitives; a human reviews the diff before commit. `upgrading` itself **never** writes `.agents/` and never performs the translation.
|
|
101
|
+
- **no** → record `Codex adapter: stale, declined` for the Step 6 report.
|
|
102
|
+
3. **Report line.** Add a `Codex adapter:` line to the Step 6 report — one of `regenerated` / `stale, declined` / `not present`.
|
|
103
|
+
|
|
104
|
+
Presence-gated, never auto-runs, regeneration is agent-run via `quick-tasking`. The protocol doc itself reaches the project via the Step 4 `.forge/adapters/**` sync.
|
|
105
|
+
|
|
90
106
|
## Step 5: Handle Import-Managed + Merge-Owned Files
|
|
91
107
|
|
|
92
108
|
**`CLAUDE.md` (import-managed — one-pass auto-migration, no prompt):** mirror the npm bin's `ensureClaudeMdImport()` case-for-case. The framework prose lives in `.forge/FORGE.md` (synced in Step 4) — never write prose into CLAUDE.md, and never modify user content outside a legacy forge section.
|
|
@@ -125,6 +141,8 @@ Experimental skills: {N}
|
|
|
125
141
|
- orchestrating (from experimental/m10) — updated [or: unchanged / STALE, declined]
|
|
126
142
|
- ...
|
|
127
143
|
|
|
144
|
+
Codex adapter: regenerated [or: stale, declined / not present]
|
|
145
|
+
|
|
128
146
|
Removed from template: {N} files
|
|
129
147
|
- .claude/agents/old-agent.md (still in your project)
|
|
130
148
|
- ...
|
|
@@ -175,3 +193,21 @@ Migrate now? (yes/no/show guide)
|
|
|
175
193
|
### Why there is no bookkeeping
|
|
176
194
|
|
|
177
195
|
Recording "crossed" guides is implicit in the range. Once Step 5 stamps `forge.version` to `source`, a later run's range `(new installed, source]` excludes every guide already crossed — so nothing re-detects, with **no ledger or marker file**. The range also closes the install-run blind spot: detection keys off the guides **freshly synced this run** (Step 4) plus the **pre-stamp installed version**, so the run that installs new detection behavior uses the new guides, not this skill's own pre-sync prose.
|
|
196
|
+
|
|
197
|
+
## Step 8: Propagate to Live Worktrees (offer, never auto)
|
|
198
|
+
|
|
199
|
+
The sync lands framework files (`.claude/skills/`, `.claude/agents/`, `.forge/FORGE.md`, templates) in **this checkout only**. A live Forge worktree keeps running its branch-point copies until it pulls main in — and nothing else surfaces this: the integration flag (`.git/forge/integration-pending`) fires only on a verified **work** checkpoint, never on an upgrade, and `forge.worktree_rebase_check` is opt-in. So close the loop here, where the upgrade actually happened.
|
|
200
|
+
|
|
201
|
+
1. **Main checkout only.** `git rev-parse --git-dir` == `--git-common-dir` → main; differ → this session **is** a worktree, so skip (run `/upgrading` from main to propagate). No remote/not a git repo → skip.
|
|
202
|
+
2. **Commit the sync first** — a worktree can only rebase onto committed history, so uncommitted synced files won't propagate. If the sync is unstaged, prompt: *"Commit this upgrade on main before propagating? (e.g. `chore(forge): upgrade to v{new}`)"* and wait.
|
|
203
|
+
3. **Enumerate live worktrees:** `git worktree list --porcelain`, branches matching `refs/heads/forge/m-*` (same scan as the `forge` boot preflight). None → done, silent.
|
|
204
|
+
4. **Offer — never auto** (a rebase can conflict and needs human judgment):
|
|
205
|
+
```
|
|
206
|
+
{N} live worktree(s) lag this upgrade (v{old} → v{new}):
|
|
207
|
+
- {path} ({branch})
|
|
208
|
+
Pick up v{new} in each: git -C {path} rebase main
|
|
209
|
+
Rebase now? (each / list-only / skip)
|
|
210
|
+
```
|
|
211
|
+
- **each** → run `git -C {path} rebase main` per worktree; on conflict, **stop that one**, report it, and move on — never force, never auto-resolve.
|
|
212
|
+
- **list-only / skip** → print the commands; the operator runs them when each worktree is at a safe stopping point.
|
|
213
|
+
5. **Gitignored carve-outs don't rebase.** `.mcp.json`, experimental hooks (e.g. M10 `forge-claim-check*.sh`), and anything else gitignored is **not** carried by a rebase. If the upgrade changed them (e.g. an experimental skill was re-synced in Step 3b), each worktree must re-run the experimental installer (`experimental/{pkg}/install.sh`) — a rebase alone leaves them stale. Surface this line whenever Step 3b reported an experimental re-sync.
|
package/template/.forge/FORGE.md
CHANGED
|
@@ -63,6 +63,8 @@ Worktrees are a **base concern** — Chief/Streams creates and references them w
|
|
|
63
63
|
|
|
64
64
|
**Fallback when no path was recorded.** A worktree created outside `orchestrating` (a manual `git worktree add`, an adopted stream) may have no recorded path. Resolve it from this convention — `{worktree_root}/{anchor}` — rather than assuming the experimental skill's internal default. Chief/Streams uses this fallback; `orchestrating` (when installed) implements the same scheme for the worktrees it creates.
|
|
65
65
|
|
|
66
|
+
**Validated against the convention (advisory).** "Authoritative" means *honored*, not *unchecked*: `forge` boot (Step 1 preflight) and `chief-of-staff` adoption compare a recorded path's parent dir to the resolved `worktree_root` and **warn** — never block, never move — when it sits outside. This catches a manual `git worktree add ../forge-worktrees/m115` or pre-convention state that the verbatim-trust rule would otherwise sail past (the convention was a *fallback resolver* only, never a *validator*). The warning honors an explicit `orchestration.worktree_root`. Fix with `git worktree move` + update the recorded path.
|
|
67
|
+
|
|
66
68
|
## Workflow Tiers
|
|
67
69
|
|
|
68
70
|
Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
|
|
@@ -249,7 +251,7 @@ with the work it describes. Every artifact has a sharing class:
|
|
|
249
251
|
| **Derived** | `state/index.yml`, `streams/active.yml` | Never hand-edited. Regenerated by rollup from their sources (`index.yml` ← `milestone-*.yml` via Rollup 1.0; `active.yml` ← per-stream files + active milestones via the Stream Rollup). Only the main/orchestrator session (and `chief-of-staff` for `active.yml`) runs rollup. |
|
|
250
252
|
| **Append-only shared** | `releases.yml` (version reservations), `state/desire-paths/*` (one file per observation) | Many writers OK; structure prevents collision. `releases.yml` uses the Version Reservation Protocol (append + commit + push before depending on the slot); desire-paths use distinct filenames so two writers never touch the same file. |
|
|
251
253
|
| **Shared mutable** | `context.md`, `refactor-backlog.yml`, `requirements/m{N}.yml` (ID space `FR-`/`DEF-`/`NFR-` is globally shared even though each milestone owns its file) | Write only to your milestone/stream block. Within a block, append-only; strike through instead of rewriting. |
|
|
252
|
-
| **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md
|
|
254
|
+
| **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md`, `.claude/skills/`, `.claude/agents/` | Rarely changes except via `/upgrading`. Canonical on main; worktrees lag until they rebase. An upgrade run touches **only the checkout it runs in**, so after upgrading in main, live worktrees keep their branch-point framework files — `upgrading` **Step 8** enumerates live `forge/m-*` worktrees and offers to rebase each (never auto), and the opt-in `forge.worktree_rebase_check` watches these files as a boot-time safety net. Gitignored carve-outs (`.mcp.json`, experimental hooks) don't rebase — re-run the experimental installer if the upgrade changed them. |
|
|
253
255
|
|
|
254
256
|
Cross-tree edits land on the current branch and are invisible to other worktrees
|
|
255
257
|
until they pull/rebase. `forge` surfaces live worktrees at boot **and enforces
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Codex/AGENTS Adapter — Generation Protocol
|
|
2
|
+
|
|
3
|
+
**You are an agent running AS the Codex runtime.** Your job: (re)generate Forge's
|
|
4
|
+
Codex/AGENTS adapter from the canonical source skills, using **Codex's own native
|
|
5
|
+
primitives**. This is a *native authoring* task, not a find-replace — a swapped-nouns
|
|
6
|
+
copy of the Claude adapter is wrong (FORGE.md Principle 2: adapter-native). Output is a
|
|
7
|
+
**derived product**; the source below is the spec.
|
|
8
|
+
|
|
9
|
+
Run via `quick-tasking` (handed this file by `/upgrading` Step 4b). A human reviews your
|
|
10
|
+
output before commit. Regenerating *this* Forge repo's own `.agents/` is **DEF-040** —
|
|
11
|
+
not your job unless explicitly asked.
|
|
12
|
+
|
|
13
|
+
## 1. Source spec → output
|
|
14
|
+
|
|
15
|
+
| Source of truth (the spec) | You author (the derived adapter) |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `.claude/skills/<name>/*.md` | `.agents/skills/<name>/*.md` |
|
|
18
|
+
| `.claude/agents/<name>.md` (if present) | `.agents/agents/<name>.md` |
|
|
19
|
+
| `.claude/hooks/*.sh` + settings hooks | `.codex/hooks/*.sh` + `.codex/hooks.json` |
|
|
20
|
+
| `CLAUDE.md` | `AGENTS.md` (keep the `@.forge/FORGE.md` import) |
|
|
21
|
+
|
|
22
|
+
Source = `.claude/` for now. The platform-neutral core (M16) is **DEF-041 deferred**; when
|
|
23
|
+
it lands, only this "source" pointer changes. `.forge/` protocol state is shared, **not**
|
|
24
|
+
translated — never fork it.
|
|
25
|
+
|
|
26
|
+
## 2. Layout deltas — cosmetic, always-true (apply mechanically)
|
|
27
|
+
|
|
28
|
+
- skill dir `.claude/skills/` → `.agents/skills/`
|
|
29
|
+
- agent dir `.claude/agents/` → `.agents/agents/`
|
|
30
|
+
- hook dir `.claude/hooks/` → `.codex/hooks/`
|
|
31
|
+
- config file `CLAUDE.md` → `AGENTS.md`
|
|
32
|
+
- settings `.claude/settings.json` → Codex's settings equivalent
|
|
33
|
+
- `Reviewer: Claude` → `Reviewer: Codex`; `Claude Code <X>` → `Codex <X>`
|
|
34
|
+
|
|
35
|
+
**WARN — do NOT produce `.Codex` (capital C).** The real directories are lowercase
|
|
36
|
+
`.agents/` (skills/agents) and `.codex/` (hooks). A `.Codex` token is the exact bug this
|
|
37
|
+
protocol exists to kill — it must appear **nowhere** in your output.
|
|
38
|
+
|
|
39
|
+
**Do NOT rewrite Claude *model ids*** (`claude-opus-*`, `claude-sonnet-*`, `claude-haiku-*`,
|
|
40
|
+
`claude-fable-*`) — those are literal API identifiers, not branding. Leave them verbatim.
|
|
41
|
+
|
|
42
|
+
## 3. Coupled mechanisms — handle with JUDGMENT, not substitution
|
|
43
|
+
|
|
44
|
+
These four skills (`executing`, `forge`, `orchestrating`, `planning`) reference Claude-only
|
|
45
|
+
runtime mechanics. A noun-swap corrupts them. For each, translate to Codex's real surface or
|
|
46
|
+
drop the moot part:
|
|
47
|
+
|
|
48
|
+
- **`EnterPlanMode`** (forge, planning). A Claude-native tool. → Map to Codex's plan/approval
|
|
49
|
+
convention if it has one; else **DROP** the "never use EnterPlanMode" prohibition (moot on
|
|
50
|
+
Codex) and keep the positive rule: *planning = invoke the planning skill*.
|
|
51
|
+
- **ADR-007 session-id / file-claim identity / `forge-session-id.sh` SessionStart hook**
|
|
52
|
+
(orchestrating). → Translate to Codex's actual session concept; if Codex has none, mark
|
|
53
|
+
**N/A** — the claim layer degrades to single-session, which `orchestrating` already
|
|
54
|
+
tolerates.
|
|
55
|
+
- **Native Task tools** (`TaskCreate`/`TaskUpdate`/`TaskList`, executing in-session UI). →
|
|
56
|
+
Map to Codex's equivalent; if none, note they were a Claude-only UI nicety and the
|
|
57
|
+
`.forge/state/` files remain the cross-session source of truth.
|
|
58
|
+
|
|
59
|
+
## 4. `.codex/` wiring
|
|
60
|
+
|
|
61
|
+
Author the hook scripts + `.codex/hooks.json` for Codex's real hook surface (its
|
|
62
|
+
PreToolUse/PostToolUse analogs), preserving the **active-skill gate** behavior the
|
|
63
|
+
`.claude/hooks/` versions enforce. If Codex exposes no hook surface, say so explicitly and
|
|
64
|
+
have the skills self-enforce in prose instead of silently dropping the gate. Pre-existing
|
|
65
|
+
`.codex/hooks/README.md` cleanup (stale "Claude Code PreToolUse" wording) is **DEF-042** —
|
|
66
|
+
separate.
|
|
67
|
+
|
|
68
|
+
## 5. Invariants — PRESERVE verbatim across adapters
|
|
69
|
+
|
|
70
|
+
Translate **mechanics** (tool names, hook surface, paths, config filenames), **never the
|
|
71
|
+
protocol**. These must read identically in `.agents/` and `.claude/`, so a regeneration is
|
|
72
|
+
diffable for fidelity:
|
|
73
|
+
|
|
74
|
+
- skill routing tables + workflow tiers (Quick / Standard / Full)
|
|
75
|
+
- gate semantics — verification gates, the **Human Verification Gate** (close precondition)
|
|
76
|
+
- state-ownership rules (single-owner / derived / append-only / shared classes)
|
|
77
|
+
- the **Version Reservation Protocol** and atomic-commit rules
|
|
78
|
+
- desire-path capture, milestone lifecycle, context size gates
|
|
79
|
+
|
|
80
|
+
If a translation forces a change to any of these, you have over-reached — stop and flag it;
|
|
81
|
+
the protocol does not move to fit a platform.
|
|
82
|
+
|
|
83
|
+
## 6. How this runs
|
|
84
|
+
|
|
85
|
+
1. `/upgrading` Step 4b detects `.agents/` or `.codex/` and offers regeneration; on **yes**
|
|
86
|
+
it hands you this file via `quick-tasking`.
|
|
87
|
+
2. You author the adapter per §1–5 using native primitives.
|
|
88
|
+
3. A human reviews the diff for fidelity (invariants intact, no `.Codex`, coupled mechanisms
|
|
89
|
+
handled) **before** anything is committed. `/upgrading` never writes `.agents/` itself.
|
|
90
|
+
4. Output is the derived adapter; the source skills are untouched.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Migration Guide: Agent-Regenerated Codex Adapter (Forge 0.41.0)
|
|
2
|
+
|
|
3
|
+
Applies to projects that have a **Codex/AGENTS adapter** (`.agents/` and/or `.codex/`).
|
|
4
|
+
Claude-only and greenfield projects are unaffected — this guide is silent for them.
|
|
5
|
+
|
|
6
|
+
Forge 0.41.0 (ADR-014) stops treating `.agents/` as a hand-maintained or find-replaced
|
|
7
|
+
second source. The Codex adapter is now a **derived translation** of the `.claude/` skills,
|
|
8
|
+
**regenerated by an agent acting as the Codex runtime** from a shipped protocol
|
|
9
|
+
(`.forge/adapters/codex-generation.md`), using Codex's native primitives. This kills the
|
|
10
|
+
`.Codex`-token corruption an earlier naive find-replace produced and fixes the silent drift
|
|
11
|
+
where `.agents/` rotted while `.claude/` advanced. Regeneration is **offered, never
|
|
12
|
+
auto-applied** — `/upgrading` Step 4b hands the protocol to `quick-tasking`, and a human
|
|
13
|
+
reviews the diff before commit.
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
1. On the 0.41.0 framework files — run `npx forge-orkes upgrade` (or the `/upgrading` skill)
|
|
18
|
+
first, so `.forge/adapters/codex-generation.md` is present.
|
|
19
|
+
2. Working tree clean or changes committed — regeneration rewrites `.agents/` + `.codex/`.
|
|
20
|
+
|
|
21
|
+
## Detection
|
|
22
|
+
|
|
23
|
+
Prints `MIGRATE` when a Codex adapter exists but is missing the protocol, carries the broken
|
|
24
|
+
`.Codex` token, or is older than the `.claude/` source. Silent + exit 0 otherwise (including
|
|
25
|
+
Claude-only projects).
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Codex adapter present but stale/broken → regenerate via the protocol.
|
|
29
|
+
{ [ -d .agents ] || [ -d .codex ]; } || exit 0 # Claude-only → nothing to do
|
|
30
|
+
|
|
31
|
+
# (a) generation protocol not installed yet
|
|
32
|
+
if [ ! -f .forge/adapters/codex-generation.md ]; then
|
|
33
|
+
echo "MIGRATE — Codex adapter present but the generation protocol is missing; sync framework files then regenerate"
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# (b) broken: the .Codex corruption token anywhere in the adapter trees
|
|
38
|
+
if grep -rqF '.Codex' .agents .codex 2>/dev/null; then
|
|
39
|
+
echo "MIGRATE — Codex adapter contains the broken .Codex token; regenerate from the protocol"
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# (c) stale: newest source skill newer than newest adapter skill
|
|
44
|
+
newest_src=$(ls -t .claude/skills/*/SKILL.md 2>/dev/null | head -1)
|
|
45
|
+
newest_adapter=$(ls -t .agents/skills/*/SKILL.md 2>/dev/null | head -1)
|
|
46
|
+
if [ -n "$newest_src" ] && [ -n "$newest_adapter" ] && [ "$newest_src" -nt "$newest_adapter" ]; then
|
|
47
|
+
echo "MIGRATE — Codex adapter is older than the .claude/ source; regenerate from the protocol"
|
|
48
|
+
exit 0
|
|
49
|
+
fi
|
|
50
|
+
exit 0
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Migration steps
|
|
54
|
+
|
|
55
|
+
The migration is **never auto-applied**. In Claude Code it runs via the `quick-tasking`
|
|
56
|
+
skill, which `/upgrading` Step 4b hands the protocol to on "yes".
|
|
57
|
+
|
|
58
|
+
### 1. Ensure the protocol is present
|
|
59
|
+
`.forge/adapters/codex-generation.md` ships with 0.41.0 — confirm `npx forge-orkes upgrade`
|
|
60
|
+
(or `/upgrading`) has synced it.
|
|
61
|
+
|
|
62
|
+
### 2. Regenerate (Codex-run, agent-authored)
|
|
63
|
+
Run the regeneration **as the Codex runtime**, following `.forge/adapters/codex-generation.md`:
|
|
64
|
+
author `.agents/skills/` + `.codex/` wiring from the `.claude/` source using native
|
|
65
|
+
primitives. Do **not** find-replace; handle the coupled mechanisms (EnterPlanMode, ADR-007
|
|
66
|
+
session-id/claim hook, native Task tools) with judgment per the protocol §3.
|
|
67
|
+
|
|
68
|
+
### 3. Human review before commit
|
|
69
|
+
Review the diff for fidelity: invariants intact (routing tables, tiers, gate semantics,
|
|
70
|
+
state-ownership, version-reservation, atomic commits), **no `.Codex` token**, coupled
|
|
71
|
+
mechanisms handled. Commit only after review. Lossy steps are confirmed first.
|
|
72
|
+
|
|
73
|
+
## Validation
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# No .Codex token survives anywhere in the regenerated adapter
|
|
77
|
+
grep -rqF '.Codex' .agents .codex 2>/dev/null && echo "FAIL: .Codex token still present" || echo "OK: no .Codex token"
|
|
78
|
+
# Every source skill has a corresponding adapter skill dir
|
|
79
|
+
for d in .claude/skills/*/; do n=$(basename "$d"); [ -d ".agents/skills/$n" ] || echo "MISSING adapter skill: $n"; done
|
|
80
|
+
echo "validation complete"
|
|
81
|
+
```
|