arcane-cli 0.20.2 → 0.21.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.
@@ -275,8 +275,9 @@ If an agent encounters a situation outside its defined parameters, it should:
275
275
 
276
276
  4. **Push the branch** to origin (after rebase).
277
277
 
278
- 5. **Merge or queue** based on your power level:
279
- - **Magus+ power level:** self-merge via `git merge --ff-only`, push main, delete branch.
278
+ 5. **Merge or queue** based on your power level — and merge by the mechanism your isolation primitive allows (ARC-028 R1):
279
+ - **Magus+ power level, in the primary checkout:** self-merge via `git merge --ff-only`, push main, delete branch.
280
+ - **Magus+ power level, in a linked worktree or a clone:** self-merge through the platform's PR merge instead. The authority is identical; only the mechanism changes, because a local ff-merge requires checking out `main` and another working tree already holds it. Power level decides *whether* you may merge without review; the isolation primitive decides *how*.
280
281
  - **Below Magus:** push the branch, report the branch name, and queue for human merge.
281
282
 
282
283
  6. **Delete the branch** (local and remote) after merge.
@@ -286,7 +287,7 @@ If an agent encounters a situation outside its defined parameters, it should:
286
287
  - The agent-slug prefix makes ownership obvious and prevents naming collisions.
287
288
  - Use standard commit types: `feat`, `fix`, `docs`, `refactor`, `chore`, etc.
288
289
 
289
- **What happens if ff-only fails:** Another actor merged to main first. This should not happen if you followed step 3. If it does, rebase and retry:
290
+ **What happens if ff-only fails:** Another actor merged to main first. This should not happen if you followed step 3. If it does, rebase and retry — **from the primary checkout**, since this block checks out `main`:
290
291
 
291
292
  ```bash
292
293
  git fetch origin
@@ -295,6 +296,8 @@ git checkout main
295
296
  git merge --ff-only {your-slug}/type/short-description
296
297
  ```
297
298
 
299
+ From a linked worktree or a clone, stop after the rebase and merge through the platform's PR instead (ARC-028 R1). `git checkout main` there fails with `fatal: 'main' is already used by worktree at '<path>'`.
300
+
298
301
  ### Multi-Agent Concurrency Rules
299
302
 
300
303
  When more than one agent may work in the same repository simultaneously:
@@ -204,7 +204,7 @@ type/short-description
204
204
  sessions/YYYY-MM-DD-topic-slug
205
205
  ```
206
206
 
207
- Create the session branch as the **first action** of any session, before any file edits or commits. All session commits land on this branch. At close, push and open a PR. After merge, return to `main`.
207
+ Create the session branch as the **first action** of any session, before any file edits or commits. All session commits land on this branch. At close, push and open a PR. After merge, return to `main` — **in the primary checkout only** (ARC-028 R8). A session running in a linked worktree ends with push → PR → worktree removal instead; it must not check out `main`, because the primary checkout already holds it and Git will refuse the second checkout.
208
208
 
209
209
  **Examples:**
210
210
 
@@ -257,7 +257,9 @@ The agent slug prefix makes branch ownership obvious in `git branch -r` output a
257
257
  ```bash
258
258
  git push origin docs/my-topic
259
259
  ```
260
- 4. **Merge to main via fast-forward** when done:
260
+ 4. **Merge to main via fast-forward** when done. **This step is primary-checkout work** (ARC-028 R1)
261
+ — it checks out `main`, which a linked worktree cannot do while the primary holds it. From a
262
+ worktree or a clone, open a PR and merge through the platform instead:
261
263
  ```bash
262
264
  git checkout main
263
265
  git pull origin main
@@ -266,7 +268,7 @@ The agent slug prefix makes branch ownership obvious in `git branch -r` output a
266
268
  git branch -d docs/my-topic
267
269
  git push origin --delete docs/my-topic
268
270
  ```
269
- 5. **If ff-only fails** (someone else merged first), rebase and retry:
271
+ 5. **If ff-only fails** (someone else merged first), rebase and retry — **primary checkout only**, same as step 4:
270
272
  ```bash
271
273
  git checkout docs/my-topic
272
274
  git rebase main
@@ -295,7 +297,11 @@ The agent slug prefix makes branch ownership obvious in `git branch -r` output a
295
297
  stale divergence. Resolve conflicts locally — never push a branch with known merge conflicts.
296
298
  4. **Push the branch to origin** (after rebase).
297
299
  5. **Merge or queue for review** based on power level:
298
- - **Magus+ agents:** self-merge via `git merge --ff-only`, then push main
300
+ - **Magus+ agents, working in the primary checkout:** self-merge via `git merge --ff-only`, then push main
301
+ - **Magus+ agents, working in a linked worktree or a clone:** self-merge through the platform's PR
302
+ merge instead (ARC-028 R1). The authority is the same; only the mechanism changes, because a
303
+ local ff-merge requires checking out `main` and the primary checkout already holds it. Power
304
+ level decides *whether* you may merge without review; the isolation primitive decides *how*.
299
305
  - **Below Magus:** push the branch, report branch name, and queue for human merge
300
306
  6. **Delete the branch** after merge.
301
307
 
@@ -354,16 +360,35 @@ Commit execution rights depend on the interaction context:
354
360
 
355
361
  ### Post-Merge Cleanup
356
362
 
357
- After every PR merge or local fast-forward merge, **always return to main and prune the branch**. Failing to do this leaves you on a stale branch where new work gets committed to the wrong place or stays unpushed.
363
+ After every PR merge or local fast-forward merge, **from the primary checkout, always return to main and prune the branch** (ARC-028 R8 — the worktree procedure is below, and differs). Failing to do this leaves you on a stale branch where new work gets committed to the wrong place or stays unpushed.
358
364
 
359
365
  ```bash
360
- # After PR merges on remote:
366
+ # After PR merges on remote — from the primary checkout:
361
367
  git checkout main
362
368
  git pull origin main
363
369
  git branch -d type/old-topic # delete local branch
364
370
  git push origin --delete type/old-topic # delete remote branch (safety net; ignore 'does not exist' errors if already auto-deleted)
365
371
  ```
366
372
 
373
+ **From a linked worktree, do not run the block above** (ARC-028 R8). `git checkout main` fails with
374
+ `fatal: 'main' is already used by worktree at <path>` when the primary checkout holds it, and
375
+ `git branch -d` fails with `error: cannot delete branch '<branch>' used by worktree at <path>` for
376
+ any branch still attached to a worktree — including your own, from inside it. Those are the exact
377
+ messages; recognising them is the point, because neither is a malfunction. A worktree session cleans
378
+ up like this instead:
379
+
380
+ ```bash
381
+ # From the worktree: push and let the PR merge land.
382
+ git push origin type/old-topic
383
+ # Then, from the PRIMARY checkout (R7 — a worktree cannot remove itself safely):
384
+ git worktree remove <path> # after the same-vantage-point check below
385
+ git fetch --prune origin # drops the remote-tracking ref
386
+ git push origin --delete type/old-topic # if the platform did not auto-delete
387
+ ```
388
+
389
+ Neither failure is an obstacle to work around: Git refusing to double-check-out a branch, and
390
+ refusing to delete a worktree-attached one, are the enforcement ARC-028 R3/R7 rely on.
391
+
367
392
  This applies to all actors — humans, interactive tools (Copilot, Claude), and autonomous agents. The `spell-commit-work` and `spell-close-session` prompts enforce this check.
368
393
 
369
394
  ### Same-Vantage-Point Check (EF-33 / ARC-028 R7)
@@ -423,7 +448,9 @@ az repos pr reviewer list --id <PR_ID> --org https://dev.azure.com/<org>
423
448
  # Allowed merge strategies: Merge (no fast forward) or Rebase+fast-forward
424
449
  az repos pr update --id <PR_ID> --org https://dev.azure.com/<org> --status completed --delete-source-branch true --squash false
425
450
 
426
- # 8. Pull merge commit and clean up (worktree-safe)
451
+ # 8. Pull merge commit and clean up — PRIMARY CHECKOUT ONLY (ARC-028 R8).
452
+ # From a linked worktree, `git checkout main` fails first and the rest of
453
+ # this block never runs; see Post-Merge Cleanup for the worktree procedure.
427
454
  git checkout main
428
455
  git pull origin main
429
456
  git branch -d <branch> # delete local branch (skip if branch is attached to an active worktree)
@@ -49,7 +49,8 @@ See also: [Hardening Checklist](hardening-checklist.md), [Authentication Strateg
49
49
  | Network exposure on the agent host | **Mitigated** | Gateway bound to loopback only. An encrypted tunnel/VPN is the only remote-access path. No ports open on the LAN. |
50
50
  | Supply chain (package installs) | **Mitigated** | Global package installs use a user-owned directory, not a system directory. No `sudo` during install. |
51
51
  | Inter-machine communication | **Mitigated** | Encrypted mesh tunnel/VPN. No direct unencrypted LAN communication. |
52
- | Token/credential exposure | **Mitigated** | Token stored as an env var in a `.env` file. Config uses a secret reference, not plaintext. State directory is mode `700`. |
52
+ | Token/credential exposure (at rest) | **Mitigated** | Token stored as an env var in a `.env` file. Config uses a secret reference, not plaintext. State directory is mode `700`. |
53
+ | Credential committed to version control | **Not mitigated** | Storage conventions are documented (secret references, `.gitignore` entries for `.env`/`*.pem`/`*.key`) but **no detection exists** — no scanner runs on the commit path, the push path, or in CI, and nothing verifies the conventions were followed. `spell-security-review`'s secrets step is an on-demand agent read, not a control. Treat every credential that reaches a commit as compromised and rotate it — history, existing clones, and remote backups all survive deleting the file (EF-35). |
53
54
 
54
55
  ---
55
56
 
@@ -151,11 +151,30 @@ Rules:
151
151
  - Skip this entire step for local-only and read-only sessions.
152
152
  - Resolve `<remote>` and `<trunk>` from observed Git/provider state: use the usable authenticated remote selected in step 9 and the merged PR's target branch (falling back to that remote's default branch). Never assume `origin` or `main`.
153
153
  - Verify through the detected provider that the PR is merged before changing branches.
154
+ - **Determine the isolation primitive first (ARC-028 R8).** Run both of these and compare:
155
+ ```bash
156
+ git rev-parse --path-format=absolute --git-common-dir
157
+ git rev-parse --path-format=absolute --git-dir
158
+ ```
159
+ Equal → **primary checkout**. Different → **linked worktree**, and the two paths below diverge. `spell-open-session` should already have named the primitive; re-derive it here rather than trusting the handoff, because the session may have moved.
160
+
161
+ **`--path-format=absolute` is required, not decorative.** Without it, `--git-dir` returns an absolute path while `--git-common-dir` stays relative whenever the current directory is *below* the repository root — so a plain comparison reports the primary checkout as a linked worktree from any subdirectory, which is most of the time. If your git predates `--path-format` (2.31), use `git rev-parse --git-dir` and test whether the result contains `/worktrees/` instead.
162
+
163
+ **Primary checkout (the default path):**
154
164
  - Run `git switch <trunk>` followed by `git pull --ff-only <remote> <trunk>`. Do not end a remote-backed session on a topic branch.
155
- - Delete the local topic branch: `git branch -d <branch>` — if the repository or its linked worktrees might be reached through more than one filesystem view, run the same-vantage-point check first (EF-33 / ARC-028 R7, [governance/git-conventions.md](../../.arcane/governance/git-conventions.md) Same-Vantage-Point Check section).
165
+ - Delete the local topic branch: `git branch -d <branch>` — if the repository or its linked worktrees might be reached through more than one filesystem view, run the same-vantage-point check first (EF-33 / ARC-028 R7, [governance/git-conventions.md](../../.arcane/governance/git-conventions.md) Same-Vantage-Point Check section).
156
166
  - Verify `git log --oneline -3` shows the merged change at HEAD.
157
- - If stale local branches exist (merged or older than 7 days), list them and suggest cleanup.
158
- - See [governance/git-conventions.md](../../.arcane/governance/git-conventions.md) Post-Merge Cleanup section.
167
+
168
+ **Linked worktree:**
169
+ - First establish whether any working tree currently holds `<trunk>`: run `git worktree list` and look for `[<trunk>]`. That, not the mere fact of being in a worktree, is what determines the two rules below — a **bare** repository with worktrees attached (a common agent-fleet layout: one bare clone, one worktree per agent) usually has no checkout holding `<trunk>` at all, and there `git switch <trunk>` and `git branch -d` both succeed normally. Verified: they do.
170
+ - **If a working tree holds `<trunk>`, do not run `git switch <trunk>`.** It will fail — Git refuses to check out one branch in two worktrees (`fatal: '<trunk>' is already used by worktree at '<path>'`). Ending on the session branch is correct here, not a lapse; the branch is already merged and the worktree is about to be removed.
171
+ - **Do not run `git branch -d <branch>` while this worktree is attached to it.** It will fail (`error: cannot delete branch '<branch>' used by worktree at '<path>'`), from inside the worktree and from the primary alike. Both refusals are the guardrail ARC-028 R3/R7 leans on, not an obstacle to work around — never reach for `-D`, `--force`, or manual deletion of `.git/worktrees/<name>` to get past them. (`-D` does not bypass this either; the refusal is about attachment, not about merge state.)
172
+ - Report the worktree path and the branch name, and name **where** removal must happen: `git worktree remove <path>` then `git fetch --prune <remote>`, run after the same-vantage-point check from a checkout that is not this one. A worktree cannot safely remove itself. If `git worktree list` shows a working tree holding `<trunk>`, that is the vantage point; if the repository is **bare**, run it from the bare repository itself (`git -C <bare> worktree remove <path>`) — do not report the work as belonging to a "primary checkout" that does not exist.
173
+ - If this worktree was created with `--detach` there is no branch to name; report the path and the detached HEAD sha instead.
174
+ - Verify the merge landed with `git log --oneline -3 <remote>/<trunk>` (the remote-tracking ref), since local `<trunk>` is not checked out here to fast-forward.
175
+
176
+ - Common to both: if stale local branches exist (merged or older than 7 days), list them and suggest cleanup.
177
+ - See [governance/git-conventions.md](../../.arcane/governance/git-conventions.md) Post-Merge Cleanup section.
159
178
 
160
179
  11. **Return a concise closure report.**
161
180
 
@@ -107,6 +107,12 @@ Execute the `spell-implement` workflow:
107
107
  git checkout main && git pull --ff-only
108
108
  ```
109
109
  If `pull --ff-only` fails, halt and report — manual rebase is needed.
110
+
111
+ **In a linked worktree, do not run the `checkout main` line** (ARC-028 R1/R8). It fails with `fatal: 'main' is already used by worktree at '<path>'` when another working tree holds `main`, and the halt instruction above only covers a `pull` failure — so an agent that runs it there has no branch to take. This matters especially here: the R4 rule below sends genuinely disjoint epics into parallel worktrees, so this pipeline reaches that state by design. Sync the remote-tracking ref instead:
112
+ ```bash
113
+ git fetch --prune origin # origin/main is now current
114
+ ```
115
+ and branch from `origin/main` in step 1. Check which primitive you are in with `git rev-parse --path-format=absolute --git-common-dir` vs `--git-dir` — equal means primary checkout. `--path-format=absolute` is required, or every primary checkout looks like a worktree from any subdirectory.
110
116
  1. Create the topic branch from `stories.json.branchName` (format: `{agent}/type/description`).
111
117
  2. Loop:
112
118
  a. Pick the next story where `passes: false`, ordered by priority.
@@ -200,3 +206,6 @@ After each phase completes, output a brief status line:
200
206
  - **Branch discipline.** All work on topic branches, never on main. Per ADR-048.
201
207
  - **Fresh context per story.** Do not carry assumptions between stories during Phase 3.
202
208
  - **Epic checkpointing.** When this spell is run as one epic in a multi-epic plan, recommend running `spell-commit-work` before starting the next epic.
209
+ - **Multi-epic runs serialize by default (ARC-028 R4).** Before running two or more epics concurrently in separate worktrees, compare their footprints: the file and directory globs each will touch, plus any **shared sequence** — database migration numbers, generated indexes and manifests, lockfiles, fixture IDs, anything where correctness depends on what another epic picked. If the footprints overlap on either axis, run the epics **sequentially in one workspace**, or re-scope them to disjoint footprints first. State the comparison and the resulting decision in the run's opening report; "they seemed unrelated" is not a footprint comparison.
210
+
211
+ This is a default derived from evidence, not caution for its own sake. A four-epic run with three executing in parallel isolated worktrees produced two epics independently claiming the same migration sequence number and two adding conflicting imports to the same file region — none of it visible until a human reached merge review. A three-epic re-run, strictly serialized in one workspace, produced zero collisions. Isolation prevents epics from *disturbing* each other; it does nothing to stop them *agreeing on the same answer* to a question neither knew the other was asking, and it delays the discovery until the most expensive moment. Serialization stays the default until re-derivation tooling exists (fresh-pull sequence re-derivation, shared numbering locks) — parallelism is available for genuinely disjoint footprints, and should be used there.
@@ -33,6 +33,13 @@ Workflow (loop until all stories pass):
33
33
  ```
34
34
  If `pull --ff-only` fails, halt and report — manual rebase is needed.
35
35
 
36
+ **In a linked worktree, do not run the `checkout main` line** (ARC-028 R1/R8). It fails with `fatal: 'main' is already used by worktree at '<path>'` when another working tree holds `main`, and the halt instruction above only covers a `pull` failure — so an agent that runs it there has no branch to take. Sync the remote-tracking ref instead, which is all this step actually needs:
37
+ ```bash
38
+ git fetch --prune origin # origin/main is now current
39
+ git rebase origin/main # or branch from origin/main directly in step 1
40
+ ```
41
+ Check with `git rev-parse --path-format=absolute --git-common-dir` vs `--git-dir`: equal means primary checkout, different means linked worktree. `--path-format=absolute` is required — without it the two differ from any subdirectory and every primary checkout looks like a worktree.
42
+
36
43
  1. **Load stories.json** — locate the feature folder from the current branch:
37
44
  ```bash
38
45
  # Derive feature folder from branch name (works for lafayette/feat/541-phase-2a or lafayette/feat/phase-2a)
@@ -71,6 +71,13 @@ Then produce output in this exact structure:
71
71
  Before anything else, check:
72
72
 
73
73
  - **Current branch:** Run `git branch --show-current` and `git worktree list`. Report the current state; do not switch during this read-only check. Branch creation/switching is owned by the lazy Mutation Guard. **Caveat (EF-33):** if this repository or its linked worktrees might be reached through more than one filesystem view (a bridged/remote mount, a container bind-mount), `git worktree list` can truthfully report a live, healthy worktree as `prunable` when read from a vantage point that can't resolve its registered path — this is a read-only report, not a reason to act; never run a destructive worktree/branch command on its output alone (see git-conventions.md's Same-Vantage-Point Check section before any such command elsewhere in this or later sessions).
74
+ - **Isolation primitive (ARC-028 R1–R5):** name where this session will run *before* the Mutation Guard creates anything, and state it in the session output. Every unit of work lives in exactly one of three primitives — the **primary checkout**, a **linked worktree**, or a **full clone**. Select from what the previous bullet's `git worktree list` and `git status` already showed, in this order:
75
+ - **Managing repository state** — reconciling uncommitted files, pruning branches, fast-forwarding `main`, cutting a release, or any `git worktree` lifecycle operation → **primary checkout** (R1). These are the only operations that require holding `main`, and only one working tree can.
76
+ - **The primary checkout is occupied** — another session's branch is checked out there, or it holds uncommitted work that is not yours → **linked worktree** (R3). At most one actor occupies the primary checkout at a time. Create it with `git worktree add <path> -b <session-branch>`; never switch or delete a branch attached to a worktree you are not in.
77
+ - **Unattended/automated git operations** (cron, daemon fleets, anything pulling or pushing without a human present) → **full clone** (R5). Linked worktrees share one physical `.git`, so concurrent unattended operations contend on the same locks.
78
+ - **Otherwise** → **primary checkout on a session branch** (R2). This is the default and it is deliberately the do-nothing path: one actor, one checkout, no new tooling.
79
+ - **Footprint overlap overrides the choice (R4).** If this session's work touches the same files or the same shared sequence (migration numbers, generated indexes, lockfiles) as work already running in another primitive, do **not** isolate it — serialize instead: wait, or re-scope to a disjoint footprint first. Isolation does not prevent those collisions, it hides them until merge review.
80
+ - Working in a linked worktree changes two things later in the session and nothing else: `spell-close-session` must not check out `main` (see git-conventions.md's Post-Merge Cleanup section), and the worktree contains no untracked tooling state — budget for `npm install` or equivalent in a code repo. Branch naming, attribution, and the PR gate are identical from every primitive (R8).
74
81
  - **Session branch naming compliance:** Branch names must be human-readable and policy-compliant:
75
82
  - Interactive session default: `sessions/YYYY-MM-DD-<topic-slug>` (kebab-case topic from current task/session objective).
76
83
  - Disallow random adjective-noun generator names (example: `ideal-disco`) as session defaults.
@@ -91,6 +91,7 @@ Workflow:
91
91
  - Tag release if applicable.
92
92
 
93
93
  9. **Post-merge branch cleanup** (after the PR merges) — the merge was the human gate, so cleanup is automatic:
94
+ - **First, which primitive are you in?** `git rev-parse --path-format=absolute --git-common-dir` vs `--git-dir` — equal means primary checkout, different means linked worktree. (`--path-format=absolute` is required; without it the two differ from any subdirectory and every primary checkout reads as a worktree.) **In a linked worktree, skip the two steps below** (ARC-028 R1/R8): `git checkout main` fails when another working tree holds `main`, and it fails *first*, so the rest of this cleanup block never runs and the remote branch deletion below is left half-done. Report the worktree path for removal from another vantage point instead, and go straight to the remote-branch and prune steps.
94
95
  - Switch to the main branch (e.g. `git checkout main`).
95
96
  - Pull the latest (e.g. `git pull`).
96
97
  - Delete the merged topic branch locally (e.g. `git branch -d <branch>`) — if the repository or its linked worktrees might be reached through more than one filesystem view, run the same-vantage-point check first (EF-33 / ARC-028 R7, [governance/git-conventions.md](../../.arcane/governance/git-conventions.md) Same-Vantage-Point Check section).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-cli",
3
- "version": "0.20.2",
3
+ "version": "0.21.0",
4
4
  "description": "Arcane framework CLI — scaffold and manage governance files in consuming repositories",
5
5
  "keywords": [
6
6
  "arcane",