@jenga-ai/agent 1.1.0 → 1.2.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/README.md +7 -3
- package/agents/developer.md +82 -2
- package/agents/scrum-master.md +140 -21
- package/agents/tester.md +90 -8
- package/hooks/on_session_end.sh +171 -20
- package/package.json +1 -1
- package/scripts/check-permission-level.sh +107 -0
- package/scripts/check-publicignore-match.sh +122 -0
- package/scripts/check-worktree-liveness.sh +193 -0
- package/scripts/generate-rapport-manifest.sh +43 -0
- package/scripts/idea_manager.sh +47 -0
- package/scripts/install-worktree-commit-guard.sh +134 -0
- package/scripts/jenga-permission-level-switch.sh +109 -0
- package/scripts/smoke-harness.sh +139 -0
- package/scripts/validate-board.sh +62 -0
- package/scripts/with-lock.sh +158 -0
- package/scripts/worktree-remove-guard.sh +204 -0
- package/skills/clearify/SKILL.md +52 -0
- package/skills/commit/SKILL.md +13 -4
- package/skills/distribute/CONFIG_SCHEMA.md +60 -2
- package/skills/do/SKILL.md +48 -11
- package/skills/doc-sync/SKILL.md +16 -0
- package/skills/doc-sync/assets/doc_targets.md +11 -0
- package/skills/idea/SKILL.md +56 -0
- package/skills/idea/assets/idea_handoff_template.md +26 -0
- package/skills/idea/assets/idea_template.md +3 -0
- package/skills/init/SKILL.md +100 -7
- package/skills/init/assets/directory_structure.txt +1 -0
- package/skills/init/assets/workflow_template.json +1 -1
- package/skills/init/scripts/apply-project-visibility.sh +176 -0
- package/skills/init/scripts/detect-existing-codebase.sh +166 -0
- package/skills/init/scripts/init.sh +30 -1
- package/skills/jenga/SKILL.md +160 -17
- package/skills/jenga/scripts/board-scan.sh +238 -0
- package/skills/jenga/scripts/cascade-resolve.sh +297 -0
- package/skills/jenga/scripts/render-confirmation.sh +679 -0
- package/skills/jenga/scripts/render-picker.sh +439 -0
- package/skills/jenga/scripts/resolve-id.sh +367 -0
- package/skills/jenga-permission-level/SKILL.md +81 -0
- package/skills/proceed/SKILL.md +1 -1
- package/skills/publish/SKILL.md +8 -5
- package/skills/publish/assets/ci-contract.md +2 -2
- package/skills/publish/assets/ownership-matrix.md +1 -1
- package/skills/publish/scripts/finalize_changelog.sh +115 -0
- package/skills/publish/scripts/generate_release_notes.sh +475 -28
- package/skills/publish/scripts/npm_ci_pipeline.sh +44 -6
- package/skills/publish/scripts/publish_deploy.sh +38 -8
- package/skills/publish/scripts/run_gates.sh +2 -2
- package/skills/reconcile/SKILL.md +117 -5
- package/skills/reconcile/scripts/detect-unlinked-code.sh +741 -0
- package/skills/skillify/assets/init-new/assets/directory_structure.txt +5 -1
- package/skills/spinoff/SKILL.md +12 -7
- package/skills/todo/SKILL.md +2 -0
- package/skills/uncharted/SKILL.md +711 -0
- package/skills/uncharted/assets/SEGMENT_PROPOSAL_TEMPLATE.md +129 -0
- package/skills/uncharted/assets/UNDERSTANDING_DOC_TEMPLATE.md +160 -0
- package/skills/uncharted/scripts/apply-subsystem-cap.sh +573 -0
- package/skills/uncharted/scripts/detect-dependencies.sh +732 -0
- package/skills/uncharted/scripts/detect-tests.sh +553 -0
- package/skills/uncharted/scripts/discover-subsystems.sh +1029 -0
- package/skills/uncharted/scripts/enumerate-target.sh +470 -0
- package/skills/uncharted/scripts/import-source.sh +517 -0
- package/skills/uncharted/scripts/inspect-provenance.sh +573 -0
- package/skills/uncharted/scripts/resolve-segment-target.sh +640 -0
- package/skills/uncharted/scripts/run-engine.sh +655 -0
- package/skills/uncharted/scripts/validate-proposed-items.sh +125 -0
- package/skills/uncharted/scripts/write-backfilled-epics.sh +498 -0
- package/skills/wtf/SKILL.md +20 -0
- package/templates/CHANGELOG_TEMPLATE.md +13 -0
- package/templates/PROBLEM_RAPPORT_TEMPLATE.md +4 -1
- package/templates/SCRUM_BOARD_SCHEMA.md +157 -10
- package/templates/permission-levels/README.md +73 -0
- package/templates/permission-levels/level-1-locked.json +71 -0
- package/templates/permission-levels/level-2-guarded.json +64 -0
- package/templates/permission-levels/level-3-standard.json +62 -0
- package/templates/permission-levels/level-4-elevated.json +60 -0
- package/templates/permission-levels/level-5-unrestricted.json +58 -0
- package/skills/convert/SKILL.md +0 -124
- package/skills/convert/convert_cli.py +0 -235
- package/skills/convert/tests/sample.csv +0 -4
- package/skills/convert/tests/sample.json +0 -5
- package/skills/convert/tests/sample.jsonl +0 -3
- package/skills/convert/tests/sample.yaml +0 -18
- package/skills/convert/tests/sample_obj.csv +0 -2
- package/skills/convert/tests/sample_obj.json +0 -9
- package/skills/mirror-public/SKILL.md +0 -237
- package/skills/mirror-public/assets/config.json +0 -5
- package/skills/mirror-public/scripts/mirror.sh +0 -374
- package/skills/self-sync/SKILL.md +0 -73
- package/skills/self-sync/scripts/run.js +0 -136
- package/skills/strategy/SKILL.md +0 -312
|
@@ -26,7 +26,7 @@ project/
|
|
|
26
26
|
developer_triggers.jsonl Trigger queue for developer agent
|
|
27
27
|
tester_triggers.jsonl Trigger queue for tester agent
|
|
28
28
|
project_summary_updates.jsonl Proposed PROJECT_SUMMARY.md edits
|
|
29
|
-
|
|
29
|
+
handoffs/ Per-session transient handoffs (written by agent, consumed by on_session_end.sh) — see `handoffs/` below
|
|
30
30
|
rapports/
|
|
31
31
|
problems/ Problem rapports from developer and tester
|
|
32
32
|
analysis/ Analysis rapports from tester
|
|
@@ -65,6 +65,8 @@ All status fields must use one of the following exact strings:
|
|
|
65
65
|
| `Failed` | Tests did not pass |
|
|
66
66
|
| `Rejected` | Deliberately rejected — not a test failure |
|
|
67
67
|
| `Blocked` | Cannot proceed; human intervention required |
|
|
68
|
+
| `Backlog` | Epic-level only; queued but not yet prioritized for work |
|
|
69
|
+
| `Done` | Epic-level only; all child stories/tasks closed out |
|
|
68
70
|
|
|
69
71
|
Only the **tester agent** may write status values to story and task files. Only the **scrum master** may write status values to epic files and may update story status as part of rollup.
|
|
70
72
|
|
|
@@ -87,6 +89,7 @@ reopened_on: # comma-separated list, e.g. 2026-02-01, 2026-04-10
|
|
|
87
89
|
reopened_reason: # comma-separated list, e.g. "Scope expanded", "Bug found post-release"
|
|
88
90
|
docs: [] # optional list of repo-relative documentation paths, e.g. ["README.md", "docs/API.md"]
|
|
89
91
|
epic_scope_approval: false # set to true by the human operator only when any task in this epic has execution_scope: epic
|
|
92
|
+
provenance: # optional; only valid value is `backfilled` (epic reverse-engineered from pre-existing code by `/uncharted onboard`). Omit for normally-authored epics.
|
|
90
93
|
stories:
|
|
91
94
|
- E##_S##
|
|
92
95
|
- E##_S##
|
|
@@ -119,6 +122,11 @@ dates_previously_completed: # comma-separated list, e.g. 2026-01-15, 2026-03-22
|
|
|
119
122
|
reopened_on: # comma-separated list, e.g. 2026-02-01, 2026-04-10
|
|
120
123
|
reopened_reason: # comma-separated list, e.g. "Scope expanded", "Bug found post-release"
|
|
121
124
|
docs: [] # optional list of repo-relative documentation paths, e.g. ["README.md", "docs/API.md"]
|
|
125
|
+
crucial_level: # optional; advisory | gated | locked; absence means no elevated caution
|
|
126
|
+
crucial_set_by: # required when crucial_level is set; user | scrum-master | <agent>-escalation
|
|
127
|
+
crucial_note: # required when crucial_level is set; free-text justification
|
|
128
|
+
crucial_declined: # optional; true only; absence means no declined proposal is on record
|
|
129
|
+
crucial_declined_note: # required when crucial_declined: true; free-text: heuristic matched, proposed tier, date declined
|
|
122
130
|
tasks:
|
|
123
131
|
- E##_S##_T##
|
|
124
132
|
- E##_S##_T##
|
|
@@ -159,6 +167,11 @@ scope_rationale: "" # required when execution_scope is set; must cont
|
|
|
159
167
|
jenga_assigned: true # boolean; true = machine-assigned, false = human override
|
|
160
168
|
override_justification: "" # required when jenga_assigned: false
|
|
161
169
|
epic_scope_approval: false # required (as true) when execution_scope: epic; set by human operator only
|
|
170
|
+
crucial_level: # optional; advisory | gated | locked; absence means no elevated caution
|
|
171
|
+
crucial_set_by: # required when crucial_level is set; user | scrum-master | <agent>-escalation
|
|
172
|
+
crucial_note: # required when crucial_level is set; free-text justification
|
|
173
|
+
crucial_declined: # optional; true only; absence means no declined proposal is on record
|
|
174
|
+
crucial_declined_note: # required when crucial_declined: true; free-text: heuristic matched, proposed tier, date declined
|
|
162
175
|
---
|
|
163
176
|
|
|
164
177
|
# Task: <Title>
|
|
@@ -175,6 +188,21 @@ epic_scope_approval: false # required (as true) when execution_scope: epic;
|
|
|
175
188
|
|
|
176
189
|
> **Backward compatibility:** Tasks that omit all six new fields (`execution_scope`, `needs_docs`, `scope_rationale`, `jenga_assigned`, `override_justification`, `epic_scope_approval`) are treated as `execution_scope: task` / `needs_docs: true` and are processed without error. Agents must not reject board files that lack these fields.
|
|
177
190
|
|
|
191
|
+
### Runtime-written task fields
|
|
192
|
+
|
|
193
|
+
These four fields are **not authored by hand**. They are appended to a task's frontmatter after execution and are absent from any task that has not yet run. They are listed here so that tooling — in particular `scripts/validate-board.sh` — recognises them as valid rather than unknown.
|
|
194
|
+
|
|
195
|
+
| Field | Written by | Meaning |
|
|
196
|
+
|---|---|---|
|
|
197
|
+
| `actual_files_changed` | `/close-story` | Count of files changed by the task, extracted from its EST-tagged commits |
|
|
198
|
+
| `actual_lines_delta` | `/close-story` | Net line delta for the task, from the same extraction |
|
|
199
|
+
| `scope_divergence_flag` | `/close-story` | Set when actual diff stats exceed the thresholds that justified the assigned `execution_scope` |
|
|
200
|
+
| `divergence_flag` | `/do` | Set to `true` by the intent-vs-diff check when a `needs_docs: false` task touched unregistered files |
|
|
201
|
+
|
|
202
|
+
All four are advisory and non-blocking — they record evidence for later review and never change a task's Passed/Failed outcome.
|
|
203
|
+
|
|
204
|
+
> `task_changed_files` is **not** a frontmatter field despite the similar name. It lives in the bundle manifest at `project/queue/bundle-<E##_S##>.json`, keyed by task ID.
|
|
205
|
+
|
|
178
206
|
---
|
|
179
207
|
|
|
180
208
|
## Story Format Standards
|
|
@@ -183,6 +211,14 @@ epic_scope_approval: false # required (as true) when execution_scope: epic;
|
|
|
183
211
|
|
|
184
212
|
**`dates_previously_completed`, `reopened_on`, `reopened_reason`** — These fields are **only populated when a previously completed item is being reopened and modified**. Leave them blank on first-run items. Each value is a comma-separated list to support multiple reopen cycles.
|
|
185
213
|
|
|
214
|
+
## Planning Fields
|
|
215
|
+
|
|
216
|
+
**`priority`** (stories, optional) — Relative planning priority, e.g. `P0`, `P2`, or a range such as `P0-P1`. Advisory only; no agent behaviour keys off it.
|
|
217
|
+
|
|
218
|
+
**`depends_on`** (stories and tasks, optional) — Board IDs this item depends on, e.g. `E19_S02`. Advisory only.
|
|
219
|
+
|
|
220
|
+
> **Deprecated spellings.** `epic:`, `story:`, `date_added:`, `dependencies:`, and `reopens:` were used on older board files and are **not** valid. Use `epic_id`, `story_id`, `date_created`, `depends_on`, and the reopen tracking fields respectively. All existing files were normalised on 2026-08-19; `scripts/validate-board.sh` rejects the old spellings so the drift cannot reappear.
|
|
221
|
+
|
|
186
222
|
## Documentation Provenance Field
|
|
187
223
|
|
|
188
224
|
**`docs`** — Optional YAML list of documentation files affected by the board item. Use repo-relative paths such as `README.md` or `docs/API.md`.
|
|
@@ -192,6 +228,32 @@ epic_scope_approval: false # required (as true) when execution_scope: epic;
|
|
|
192
228
|
- Optionality: existing board files remain valid when `docs` is omitted.
|
|
193
229
|
- Format: use a YAML list. Inline (`docs: ["README.md"]`) and expanded list styles are both valid.
|
|
194
230
|
|
|
231
|
+
## Epic Provenance Field
|
|
232
|
+
|
|
233
|
+
**`provenance`** (epics only, optional) — Records how the epic came to exist: whether it was
|
|
234
|
+
planned through the normal Jenga workflow or reverse-engineered from code that already existed.
|
|
235
|
+
|
|
236
|
+
- **Valid values:** `backfilled` — the only recognised value.
|
|
237
|
+
- **`provenance: backfilled`** means the epic was generated by `/uncharted onboard` from a
|
|
238
|
+
pre-existing codebase, rather than authored through the normal planning flow (`/pi-plan`,
|
|
239
|
+
`/brainstorm`, `/todo`, or the Scrum Master breaking down a user request).
|
|
240
|
+
- **Absence means normally-authored.** An epic with no `provenance` field was authored through
|
|
241
|
+
the standard planning flow. There is no explicit value for this — omission *is* the signal.
|
|
242
|
+
- **Optional and backward compatible.** Every existing epic omits `provenance` and remains valid.
|
|
243
|
+
`scripts/validate-board.sh` accepts the key when present and never requires it.
|
|
244
|
+
- **Scope:** epics only. Stories and tasks do not carry `provenance`; a backfilled epic's children
|
|
245
|
+
are identified by their parent, not by a marker of their own.
|
|
246
|
+
|
|
247
|
+
### What `backfilled` implies
|
|
248
|
+
|
|
249
|
+
A backfilled epic describes **code that already exists**. Its Purpose section documents a
|
|
250
|
+
subsystem that was discovered, not a capability to be built. Consequently its stories and tasks
|
|
251
|
+
describe **understanding and integration work** — documenting behaviour, adding missing tests,
|
|
252
|
+
identifying risk areas, bringing the subsystem under board provenance — and **not original
|
|
253
|
+
construction**. Agents and humans reading the board should not treat a backfilled epic's
|
|
254
|
+
Definition of Done as a build plan, and should not assume that an incomplete-looking backfilled
|
|
255
|
+
epic represents unbuilt functionality.
|
|
256
|
+
|
|
195
257
|
## Execution Scope Fields (Task)
|
|
196
258
|
|
|
197
259
|
These six fields control the execution footprint of a task within the `/jenga` and `/do` workflows. They are **optional** — omitting all six is valid and equivalent to `execution_scope: task` / `needs_docs: true`.
|
|
@@ -232,6 +294,52 @@ These six fields control the execution footprint of a task within the `/jenga` a
|
|
|
232
294
|
|
|
233
295
|
These rules apply to every story file written or amended by the **Scrum Master**. They are enforced at write time by `scripts/validate-story-format.sh`.
|
|
234
296
|
|
|
297
|
+
## Crucial Flag Fields (Story, Task)
|
|
298
|
+
|
|
299
|
+
These three fields let a story or task declare an elevated caution tier — a signal that the item carries more risk than usual and should be handled with extra care during execution and review. They are **optional** — omitting all three is valid and means no elevated caution applies.
|
|
300
|
+
|
|
301
|
+
**`crucial_level`**
|
|
302
|
+
- Valid values: `advisory` | `gated` | `locked`
|
|
303
|
+
- When required: optional; absence means no elevated caution (same "absence is the signal" convention used by `provenance` and the execution-scope fields)
|
|
304
|
+
- Description: declares the item's caution tier.
|
|
305
|
+
- `advisory` — proceed as normal but flag the elevated risk for reviewers
|
|
306
|
+
- `gated` — requires explicit confirmation before execution proceeds
|
|
307
|
+
- `locked` — execution is blocked until the tier is downgraded or cleared by an authorised party
|
|
308
|
+
|
|
309
|
+
**`crucial_set_by`**
|
|
310
|
+
- Valid values: `user` | `scrum-master` | `<agent>-escalation` (e.g. `developer-escalation`, `tester-escalation`)
|
|
311
|
+
- When required: required when `crucial_level` is set
|
|
312
|
+
- Description: records who or what set the caution tier — a human operator, the scrum-master during planning, or an agent escalating mid-execution.
|
|
313
|
+
|
|
314
|
+
**`crucial_note`**
|
|
315
|
+
- Valid values: any non-empty string
|
|
316
|
+
- When required: required whenever `crucial_level` is set (same required-when-present pattern as `scope_rationale`)
|
|
317
|
+
- Description: a free-text justification explaining why the item was assigned this caution tier. Validators reject a blank value when `crucial_level` is present.
|
|
318
|
+
|
|
319
|
+
**Scope: stories and tasks only.** Epics do not carry these fields — an epic's risk gating is already handled by `epic_scope_approval` (see Execution Scope Fields above). A story or task's `crucial_level` is independent of any execution-scope value on the same item.
|
|
320
|
+
|
|
321
|
+
**Backward compatibility.** Existing board files that omit all three fields (`crucial_level`, `crucial_set_by`, `crucial_note`) remain valid, exactly like the `docs` field and the execution-scope fields. Agents must not reject board files that lack them.
|
|
322
|
+
|
|
323
|
+
## Declined Crucial Proposal Fields (Story, Task)
|
|
324
|
+
|
|
325
|
+
These two fields record that a scrum-master heuristic proposed a `crucial_level` for this specific item (per the "Crucial Level Heuristic Proposal" step in `agents/scrum-master.md`) and the user explicitly declined it in-session. This is the **authoritative decline-tracking mechanism** — `agents/scrum-master.md`'s breakdown step checks it before evaluating the heuristic list again, so a declined proposal is not silently re-surfaced on a later breakdown pass over the same item. They follow the same "optional field, absence is the signal, backward compatible" convention already used by `docs`, `provenance`, and the execution-scope fields, and the same required-when-present pairing already used by `crucial_level`/`crucial_note`.
|
|
326
|
+
|
|
327
|
+
**`crucial_declined`**
|
|
328
|
+
- Valid values: `true` (the only recognised value)
|
|
329
|
+
- When required: optional; absence means no declined proposal is on record for this item — same "absence is the signal" convention used by `provenance`. There is no `false` state to write: an item either has a recorded decline or it doesn't.
|
|
330
|
+
- Description: a boolean marker, deliberately separate from free text, so the scrum-master breakdown step can check a single unambiguous field before re-proposing rather than parsing prose for intent.
|
|
331
|
+
|
|
332
|
+
**`crucial_declined_note`**
|
|
333
|
+
- Valid values: any non-empty string
|
|
334
|
+
- When required: required when `crucial_declined: true` (same required-when-present pattern as `crucial_note`)
|
|
335
|
+
- Description: free-text record of which heuristic(s) matched (from the fixed list in `agents/scrum-master.md`'s "Crucial Level Heuristic Proposal" section), the `crucial_level` tier that was proposed, and the date the user declined it — e.g. `"Declined 2026-08-27: matched 'schema/frontmatter contracts' heuristic, proposed advisory tier; user declined without further reason."` Validators reject a blank value when `crucial_declined` is present.
|
|
336
|
+
|
|
337
|
+
**Scope: stories and tasks only** — same scope as the Crucial Flag Fields above.
|
|
338
|
+
|
|
339
|
+
**Relationship to `crucial_level`.** `crucial_declined` and `crucial_level` are mutually exclusive in the normal flow: if the user *confirms* a proposal, the item gets `crucial_level`/`crucial_set_by: scrum-master`/`crucial_note` and no decline is recorded; if the user *declines*, the item gets `crucial_declined: true`/`crucial_declined_note` and none of the three `crucial_level` fields are set. A human operator may still set `crucial_level` directly on an item that also carries a recorded decline (e.g. deciding later, independent of the scrum-master's proposal, that the item should be flagged) — the fields are not validated as exclusive, only documented as normally following one path or the other.
|
|
340
|
+
|
|
341
|
+
**Backward compatibility.** Existing board files that omit both fields remain valid — no item has ever had a decline recorded before this convention existed, so every pre-existing file is trivially compliant.
|
|
342
|
+
|
|
235
343
|
### Acceptance Criteria (`## Acceptance Criteria`)
|
|
236
344
|
|
|
237
345
|
- **Required** — the section must exist in every story file.
|
|
@@ -248,7 +356,7 @@ These rules apply to every story file written or amended by the **Scrum Master**
|
|
|
248
356
|
|
|
249
357
|
Run `scripts/validate-story-format.sh <path-to-story-file>` to verify a story file meets these requirements. The script exits 0 on success and non-zero with a descriptive error message on failure.
|
|
250
358
|
|
|
251
|
-
Run `scripts/validate-board.sh <path-to-board-file>` to validate epic, story, or task frontmatter keys. The helper accepts optional `docs` annotations and remains backward compatible with existing board files that omit
|
|
359
|
+
Run `scripts/validate-board.sh <path-to-board-file>` to validate epic, story, or task frontmatter keys. The helper accepts optional `docs` and (on epics) `provenance` annotations, and remains backward compatible with existing board files that omit them.
|
|
252
360
|
|
|
253
361
|
---
|
|
254
362
|
|
|
@@ -264,12 +372,28 @@ Run `scripts/validate-board.sh <path-to-board-file>` to validate epic, story, or
|
|
|
264
372
|
|
|
265
373
|
## File Locking (Concurrency Control)
|
|
266
374
|
|
|
267
|
-
|
|
375
|
+
Board file writes (task/story/epic frontmatter updates) are enforced through `scripts/with-lock.sh`, not through agents manually implementing a check-wait-retry convention. The earlier prose-only protocol ("check for a `<filename>.lock` file, wait, retry, then create/delete it yourself") was purely advisory — nothing stopped two writers from both deciding the lock was free at the same instant. `scripts/with-lock.sh` closes that gap with a real mutual-exclusion primitive.
|
|
376
|
+
|
|
377
|
+
**Usage:**
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
scripts/with-lock.sh <target-file> -- <command> [args...]
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
The script acquires an exclusive lock keyed to `<target-file>`, runs `<command> [args...]` only once the lock is held, and always releases the lock afterward — on success, on failure, and on `INT`/`TERM` signals. Agents (scrum-master, tester) MUST wrap every board file write through this script rather than reading/writing a `.lock` file by hand.
|
|
384
|
+
|
|
385
|
+
**Lock primitive.** The script uses `mkdir "<target-file>.lock.d"` as the exclusivity check, not `flock`. `flock` is a Linux-only (`util-linux`) utility and is not available by default on macOS/BSD — this repo runs on Darwin, so a `flock`-only implementation would silently not work for every contributor on macOS. `mkdir` is atomic on every POSIX platform this project targets: when multiple processes race to create the same directory, exactly one succeeds and every other caller fails immediately (`EEXIST`) — there is no window where two callers can both believe they hold the lock.
|
|
386
|
+
|
|
387
|
+
**Waiting and failure behavior.** If the lock is already held, the script polls (default every 0.2s, `WITH_LOCK_POLL_SECONDS`) until either the lock is released or a timeout elapses (default 30s, `WITH_LOCK_TIMEOUT_SECONDS`). If the timeout elapses first, the script exits `2` **without ever running the wrapped command** — a fail-safe abort, never a silent overwrite. A lock still held after `WITH_LOCK_STALE_SECONDS` (default 60s) is treated as abandoned (e.g. a crashed holder) and reclaimed; reclamation only clears the lock directory, it does not itself grant the lock, so simultaneous reclaim attempts by multiple waiters still cannot let more than one of them proceed — the next `mkdir` in each waiter's loop remains the sole arbiter.
|
|
388
|
+
|
|
389
|
+
**Example — a status write wrapped in the lock:**
|
|
268
390
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
391
|
+
```bash
|
|
392
|
+
scripts/with-lock.sh project/board/tasks/E01_S02_T03_example.md -- \
|
|
393
|
+
bash -c 'update_task_status project/board/tasks/E01_S02_T03_example.md Passed'
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
If a caller cannot acquire the lock within the timeout, treat it the same as the old protocol's "still locked after retry" case: abort the write and write a problem rapport rather than bypassing the script.
|
|
273
397
|
|
|
274
398
|
---
|
|
275
399
|
|
|
@@ -282,6 +406,17 @@ Before writing to any board file, agents must:
|
|
|
282
406
|
| `security_concern` | developer | `project/rapports/problems/` |
|
|
283
407
|
| `test_failure` | tester | `project/rapports/problems/` |
|
|
284
408
|
| `analysis` | tester | `project/rapports/analysis/` |
|
|
409
|
+
| `crucial_escalation` | developer, tester | `project/rapports/problems/` |
|
|
410
|
+
|
|
411
|
+
### `crucial_escalation` — concrete-reason requirement
|
|
412
|
+
|
|
413
|
+
A `crucial_escalation` rapport is filed mid-task when developer or tester discovers something that changes an item's risk profile and warrants raising its `crucial_level` (see E39 — Crucial Flag). It is routed through the same rapport/trigger queue as every other rapport type (`on_session_end.sh` → `scrum_triggers.jsonl`), since no synchronous interrupt exists for a backgrounded subagent.
|
|
414
|
+
|
|
415
|
+
The rapport's reason **must include at least one concrete, checkable fact** — a specific file/path, an exact error message, a reproduction count, or a quantifiable impact (e.g. "affects 12 downstream tasks", "data loss observed on 2 of 2 reproduction attempts"). A subjective statement alone (e.g. "this seems risky", "this feels important") is **not** acceptable.
|
|
416
|
+
|
|
417
|
+
This is the same numeric-claim bar already established for `scope_rationale` in `agents/scrum-master.md` (see its "scope_rationale — Mandatory Population Rules" section) — reused here deliberately so the concrete-reason standard is consistent across the codebase rather than a new one-off rule invented for this rapport type. Enforcing this rule (rejecting generic text) is scrum-master's responsibility when it reviews the rapport, not something checked at write time.
|
|
418
|
+
|
|
419
|
+
A `crucial_escalation` rapport must also name the target item's ID (`E##`, `E##_S##`, or `E##_S##_T##`) whose `crucial_level` is being escalated. No new field is introduced for this — it uses the rapport's existing "Related Epic" / "Related Story" / "Related Task" header fields (see `templates/PROBLEM_RAPPORT_TEMPLATE.md`).
|
|
285
420
|
|
|
286
421
|
---
|
|
287
422
|
|
|
@@ -308,9 +443,21 @@ Before writing to any board file, agents must:
|
|
|
308
443
|
|-------------------|---------------------|-------------------------------------------------|
|
|
309
444
|
| `test_assignment` | on_session_end.sh (from developer handoff) | Implementation complete; run tests against worktree |
|
|
310
445
|
|
|
311
|
-
###
|
|
446
|
+
### `handoffs/` — per-session transient handoffs, consumed by on_session_end.sh
|
|
447
|
+
|
|
448
|
+
**Directory:** `project/queue/handoffs/`
|
|
449
|
+
|
|
450
|
+
Replaces the earlier single-slot `project/queue/.session_handoff.json` file (E37_S01_T01). The single fixed path allowed two sessions ending close together — an in-session tester invocation, or concurrent `/jenga` dispatch running multiple developer/tester pairs at once — to both write the same file before either write was consumed; the second write silently clobbered the first, and the loser's handoff (and, in the worst case, the task it represented) was lost with no error. Live incidents are recorded in `PROJECT_SUMMARY.md`'s E37 section.
|
|
451
|
+
|
|
452
|
+
**Filename convention:** `project/queue/handoffs/<agent>-<session_id>-<task_id>.json`
|
|
453
|
+
|
|
454
|
+
- `<agent>` — `scrum-master`, `developer`, or `tester` (matches the handoff body's own `agent` field).
|
|
455
|
+
- `<session_id>` — the writing session's id, verbatim. This alone already makes the path collision-free, since each session has a unique id and writes its terminal handoff exactly once (the "last action of its session").
|
|
456
|
+
- `<task_id>` — the primary task ID (`E##_S##_T##`) this handoff concerns, included for human-readability/debugging. For the scrum-master's batched `task_ids` array, use the first entry, or the literal string `batch` if the array is empty.
|
|
457
|
+
|
|
458
|
+
Each file is written by an agent as the **last action** of its session, and is single-use: consumed and deleted by `on_session_end.sh` (per-file, immediately after routing — see `hooks/on_session_end.sh` section 4) once that session's `SessionEnd` hook fires. A file must not persist once it has been consumed. `project/queue/handoffs/*.json` is git-ignored (E37_S01_T02) precisely to enforce this structurally — the directory itself is kept via `.gitkeep`, but individual handoff files must never become durable git artifacts, since a committed one can no longer be told apart from a live pending signal by inspection alone.
|
|
312
459
|
|
|
313
|
-
|
|
460
|
+
**Staleness guard (E37_S01_T02):** before routing a `developer` or `tester` handoff, `on_session_end.sh` checks whether the file's `task_id` is already in a terminal board status (`Passed`, `Passed with remarks`, `Rejected`, `Done`, or `Blocked`). If so, the file is deleted without routing — it is treated as a stale leftover (e.g. one that predates this consumer logic, or one that slipped past the git-ignore rule above) rather than a live signal for already-completed work. This closed a real regression found during testing: `project/queue/handoffs/` had accumulated ~25 committed files for already-`Passed` work before this consumer logic existed to clean them up, and a bare generic glob would have resurrected all of them as fresh `test_assignment`/`story_rollup` triggers on the first `SessionEnd` run after this feature landed. The check is not applied to `scrum-master`'s batched `task_ids` handoffs (a `planning_complete` handoff's tasks are freshly created and cannot already be terminal in practice).
|
|
314
461
|
|
|
315
462
|
| Field | Required by | Notes |
|
|
316
463
|
|---------------|----------------------|------------------------------------------|
|
|
@@ -337,7 +484,7 @@ Located at `project/configs/workflow.json`. Scaffolded by `/init` and owned by t
|
|
|
337
484
|
|
|
338
485
|
```json
|
|
339
486
|
{
|
|
340
|
-
"statuses": ["Pending", "In Progress", "Passed", "Passed with remarks", "Failed", "Rejected", "Blocked"],
|
|
487
|
+
"statuses": ["Pending", "In Progress", "Passed", "Passed with remarks", "Failed", "Rejected", "Blocked", "Backlog", "Done"],
|
|
341
488
|
"rapport_types": ["conflict", "implementation_blocker", "security_concern", "test_failure", "analysis"],
|
|
342
489
|
"paths": {
|
|
343
490
|
"board": "project/board",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Permission Level Templates
|
|
2
|
+
|
|
3
|
+
> **Distribution note:** This directory is mirrored automatically — no additional wiring is needed. `/self-sync` (`skills/self-sync/scripts/run.js`, `COPY_SET`) and `/distribute` (`distribute.config.json`, `distribute.include`) both already list `templates` as a top-level entry, and both copy that directory recursively, so `templates/permission-levels/` (including this README and all five level JSON files) rides along automatically with every sync/distribute run.
|
|
4
|
+
|
|
5
|
+
This directory holds the five canonical `settings.json` permission templates that back the `/jenga-permission-level` session-switchable permission system: **Locked (1)**, **Guarded (2)**, **Standard (3)**, **Elevated (4)**, and **Unrestricted (5)**.
|
|
6
|
+
|
|
7
|
+
Each level is a full `settings.json` file — `level-1-locked.json` through `level-5-unrestricted.json`. Two fields vary between them: `permissions.deny` and `autoMode.allow`. This table exists so a maintainer can see, at a glance, what each level allows and denies without diffing all 5 JSON files by hand.
|
|
8
|
+
|
|
9
|
+
## Level Matrix
|
|
10
|
+
|
|
11
|
+
| Level | Name | `permissions.deny` | Rationale |
|
|
12
|
+
|---|---|---|---|
|
|
13
|
+
| 1 | Locked | `rm *`<br>`rmdir *`<br>`dd *`<br>`mkfs *`<br>`shred *`<br>`truncate *`<br>`git push *`<br>`git reset --hard *`<br>`git clean *`<br>`chmod *`<br>`chown *`<br>`sudo *`<br>`su *`<br>`git commit *`<br>`git add *`<br>`git stash *`<br>`npm install *`<br>`npm publish *`<br>`git branch -D *`<br>`git tag *` | Maximum safety. Blocks all destructive file/git ops plus every git *write* op (commit, add, stash, branch delete, tag) and package publish/install — suitable for read-only exploration or highly sensitive sessions. |
|
|
14
|
+
| 2 | Guarded (**permanent default**) | `rm *`<br>`rmdir *`<br>`dd *`<br>`mkfs *`<br>`shred *`<br>`truncate *`<br>`git push *`<br>`git reset --hard *`<br>`git clean *`<br>`chmod *`<br>`chown *`<br>`sudo *`<br>`su *` | Safe default for normal agentic work. Blocks destructive file ops, destructive/history-rewriting git ops, and permission/ownership changes, but allows normal git commit/add/stash and package installs. |
|
|
15
|
+
| 3 | Standard | `dd *`<br>`mkfs *`<br>`shred *`<br>`truncate *`<br>`git push *`<br>`git reset --hard *`<br>`git clean *`<br>`chmod *`<br>`chown *`<br>`sudo *`<br>`su *` | Adds `rm *` / `rmdir *` back (Guarded minus those two) for normal file cleanup during active development, while still blocking pushes and history-rewriting git ops. |
|
|
16
|
+
| 4 | Elevated | `dd *`<br>`mkfs *`<br>`shred *`<br>`truncate *`<br>`chmod *`<br>`chown *`<br>`sudo *`<br>`su *` | Adds `git push *` / `git reset --hard *` / `git clean *` back (Standard minus those three) for active development workflows that need to push and reset branches. |
|
|
17
|
+
| 5 | Unrestricted | `dd *`<br>`mkfs *`<br>`shred *`<br>`truncate *`<br>`sudo *`<br>`su *` | Adds `chmod *` / `chown *` back (Elevated minus those two). Only the non-negotiable always-blocked set (see below) remains denied. |
|
|
18
|
+
|
|
19
|
+
## `autoMode.allow` by Level
|
|
20
|
+
|
|
21
|
+
`autoMode.allow` lists commands that are auto-approved **without a prompt** when the session is running in auto mode. It is a *friction* dial, not a *capability* dial — `permissions.deny` always wins over it — with one important exception described below.
|
|
22
|
+
|
|
23
|
+
| Level | `autoMode.allow` |
|
|
24
|
+
|---|---|
|
|
25
|
+
| 1 · Locked | `$defaults` |
|
|
26
|
+
| 2 · Guarded | `$defaults` |
|
|
27
|
+
| 3 · Standard | `$defaults` |
|
|
28
|
+
| 4 · Elevated | `$defaults`<br>`Bash(bash skills/mirror-public/scripts/mirror.sh*)` |
|
|
29
|
+
| 5 · Unrestricted | `$defaults`<br>`Bash(bash skills/mirror-public/scripts/mirror.sh*)` |
|
|
30
|
+
|
|
31
|
+
### Why mirror.sh is gated to level 4+
|
|
32
|
+
|
|
33
|
+
`permissions.deny` matches the command string the agent invokes — it does **not** see what that command spawns in a subprocess. `skills/mirror-public/scripts/mirror.sh` internally runs `git reset --hard origin/<branch>` and `git push origin <branch>` against the public repo. Auto-approving the script by name therefore grants an unprompted push of repository content to a **public** repo that the deny list cannot intercept. (The push itself is a plain fast-forward `git push` — the script's `--force` flag only overrides a pre-flight safety abort, it does not force-push. The risk here is disclosure, not history loss.)
|
|
34
|
+
|
|
35
|
+
Levels 1–3 deny `git push *` and `git reset --hard *`. Auto-approving `mirror.sh` at those levels would silently defeat that intent. Level 4 (Elevated) is the first tier where `git push *` and `git reset --hard *` are permitted directly, so it is the first tier where auto-approving a script that performs them is consistent.
|
|
36
|
+
|
|
37
|
+
**Rule for adding future entries:** before adding a command to `autoMode.allow` at level *n*, check what it executes internally. If it performs an operation that `permissions.deny` blocks at level *n*, it belongs at a higher level instead.
|
|
38
|
+
|
|
39
|
+
### Every template must carry an `autoMode` key
|
|
40
|
+
|
|
41
|
+
Even the levels that only grant `$defaults` declare the block explicitly. A level switch is a **whole-file overwrite** of `.claude/settings.json` and `.agents/settings.json` — any top-level key present in the destination but absent from the template is silently dropped. A template that omitted `autoMode` would wipe the destination's block on every switch.
|
|
42
|
+
|
|
43
|
+
## Always Blocked
|
|
44
|
+
|
|
45
|
+
The following commands are **never removed from `permissions.deny` at any level, including level 5 (Unrestricted)**:
|
|
46
|
+
|
|
47
|
+
- `dd *`
|
|
48
|
+
- `mkfs *`
|
|
49
|
+
- `shred *`
|
|
50
|
+
- `truncate *`
|
|
51
|
+
- `sudo *`
|
|
52
|
+
- `su *`
|
|
53
|
+
|
|
54
|
+
These are disk-destructive or privilege-escalation commands with no legitimate use case in an agentic coding session. No permission level — not even Unrestricted — removes them.
|
|
55
|
+
|
|
56
|
+
## Fields That Never Vary
|
|
57
|
+
|
|
58
|
+
Across all 5 templates:
|
|
59
|
+
|
|
60
|
+
- `defaultMode` stays `"acceptEdits"` at every level.
|
|
61
|
+
- `permissions.allow` stays `["Bash(*)"]` at every level.
|
|
62
|
+
- `env` and `hooks` (`WorktreeCreate`, `WorktreeRemove`, `SessionEnd`) are identical across all 5 files.
|
|
63
|
+
|
|
64
|
+
**Only `permissions.deny` and `autoMode.allow` vary between levels.** Every template is otherwise byte-identical to root `settings.json`, and root `settings.json` matches `level-2-guarded.json` exactly — Guarded being the permanent default.
|
|
65
|
+
|
|
66
|
+
> **Superseded (2026-08-23):** epic E33 originally settled on "`autoMode` is never used at any level" and "only `permissions.deny` varies". That decision was revisited after it emerged that auto-approving `mirror.sh` by script name bypasses the `git push *` deny at levels 1–3 (see the section above). `autoMode.allow` is now a second, deliberately tiered axis.
|
|
67
|
+
|
|
68
|
+
## Guarded (Level 2) Is the Permanent Default
|
|
69
|
+
|
|
70
|
+
There is no separate "default level" config number. Level 2 (Guarded) is conceptually always the project's permanent default.
|
|
71
|
+
|
|
72
|
+
- To change the **permanent, project-wide default**, a maintainer edits `templates/permission-levels/level-2-guarded.json` directly.
|
|
73
|
+
- Running `/jenga-permission-level <n>` only changes the **current session's** active level (by copying the matching template into `.claude/settings.json` and `.agents/settings.json` and recording the level in `.jenga-permission-level.json`) — it does not modify the permanent default, and the scrum-master resets a session back to Guarded at the start of every session it starts.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"defaultMode": "acceptEdits",
|
|
3
|
+
"env": {
|
|
4
|
+
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
|
|
5
|
+
},
|
|
6
|
+
"autoMode": {
|
|
7
|
+
"allow": [
|
|
8
|
+
"$defaults"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"permissions": {
|
|
12
|
+
"allow": [
|
|
13
|
+
"Bash(*)"
|
|
14
|
+
],
|
|
15
|
+
"deny": [
|
|
16
|
+
"Bash(rm *)",
|
|
17
|
+
"Bash(rmdir *)",
|
|
18
|
+
"Bash(dd *)",
|
|
19
|
+
"Bash(mkfs *)",
|
|
20
|
+
"Bash(shred *)",
|
|
21
|
+
"Bash(truncate *)",
|
|
22
|
+
"Bash(git push *)",
|
|
23
|
+
"Bash(git reset --hard *)",
|
|
24
|
+
"Bash(git clean *)",
|
|
25
|
+
"Bash(chmod *)",
|
|
26
|
+
"Bash(chown *)",
|
|
27
|
+
"Bash(sudo *)",
|
|
28
|
+
"Bash(su *)",
|
|
29
|
+
"Bash(git commit *)",
|
|
30
|
+
"Bash(git add *)",
|
|
31
|
+
"Bash(git stash *)",
|
|
32
|
+
"Bash(npm install *)",
|
|
33
|
+
"Bash(npm publish *)",
|
|
34
|
+
"Bash(git branch -D *)",
|
|
35
|
+
"Bash(git tag *)"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"hooks": {
|
|
39
|
+
"WorktreeCreate": [
|
|
40
|
+
{
|
|
41
|
+
"hooks": [
|
|
42
|
+
{
|
|
43
|
+
"type": "command",
|
|
44
|
+
"command": "NAME=$(jq -r '.name')\n. \"$(git rev-parse --show-toplevel)/lib/resolve-project-dir.sh\"\nDIR=\"$JENGA_PROJECT_DIR/.claude/worktrees/$NAME\"\ngit worktree add \"$DIR\" -b \"$NAME\" 2>&1\necho \"$DIR\"\n"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"WorktreeRemove": [
|
|
50
|
+
{
|
|
51
|
+
"hooks": [
|
|
52
|
+
{
|
|
53
|
+
"type": "command",
|
|
54
|
+
"command": "\"$(git rev-parse --show-toplevel)/scripts/worktree-remove-guard.sh\"\n"
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"SessionEnd": [
|
|
60
|
+
{
|
|
61
|
+
"hooks": [
|
|
62
|
+
{
|
|
63
|
+
"type": "command",
|
|
64
|
+
"async": true,
|
|
65
|
+
"command": ". \"$(git rev-parse --show-toplevel)/lib/resolve-project-dir.sh\" && \"$JENGA_PROJECT_DIR\"/.claude/hooks/on_session_end.sh"
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"defaultMode": "acceptEdits",
|
|
3
|
+
"env": {
|
|
4
|
+
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
|
|
5
|
+
},
|
|
6
|
+
"autoMode": {
|
|
7
|
+
"allow": [
|
|
8
|
+
"$defaults"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"permissions": {
|
|
12
|
+
"allow": [
|
|
13
|
+
"Bash(*)"
|
|
14
|
+
],
|
|
15
|
+
"deny": [
|
|
16
|
+
"Bash(rm *)",
|
|
17
|
+
"Bash(rmdir *)",
|
|
18
|
+
"Bash(dd *)",
|
|
19
|
+
"Bash(mkfs *)",
|
|
20
|
+
"Bash(shred *)",
|
|
21
|
+
"Bash(truncate *)",
|
|
22
|
+
"Bash(git push *)",
|
|
23
|
+
"Bash(git reset --hard *)",
|
|
24
|
+
"Bash(git clean *)",
|
|
25
|
+
"Bash(chmod *)",
|
|
26
|
+
"Bash(chown *)",
|
|
27
|
+
"Bash(sudo *)",
|
|
28
|
+
"Bash(su *)"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"hooks": {
|
|
32
|
+
"WorktreeCreate": [
|
|
33
|
+
{
|
|
34
|
+
"hooks": [
|
|
35
|
+
{
|
|
36
|
+
"type": "command",
|
|
37
|
+
"command": "NAME=$(jq -r '.name')\n. \"$(git rev-parse --show-toplevel)/lib/resolve-project-dir.sh\"\nDIR=\"$JENGA_PROJECT_DIR/.claude/worktrees/$NAME\"\ngit worktree add \"$DIR\" -b \"$NAME\" 2>&1\necho \"$DIR\"\n"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"WorktreeRemove": [
|
|
43
|
+
{
|
|
44
|
+
"hooks": [
|
|
45
|
+
{
|
|
46
|
+
"type": "command",
|
|
47
|
+
"command": "\"$(git rev-parse --show-toplevel)/scripts/worktree-remove-guard.sh\"\n"
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"SessionEnd": [
|
|
53
|
+
{
|
|
54
|
+
"hooks": [
|
|
55
|
+
{
|
|
56
|
+
"type": "command",
|
|
57
|
+
"async": true,
|
|
58
|
+
"command": ". \"$(git rev-parse --show-toplevel)/lib/resolve-project-dir.sh\" && \"$JENGA_PROJECT_DIR\"/.claude/hooks/on_session_end.sh"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"defaultMode": "acceptEdits",
|
|
3
|
+
"env": {
|
|
4
|
+
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
|
|
5
|
+
},
|
|
6
|
+
"autoMode": {
|
|
7
|
+
"allow": [
|
|
8
|
+
"$defaults"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"permissions": {
|
|
12
|
+
"allow": [
|
|
13
|
+
"Bash(*)"
|
|
14
|
+
],
|
|
15
|
+
"deny": [
|
|
16
|
+
"Bash(dd *)",
|
|
17
|
+
"Bash(mkfs *)",
|
|
18
|
+
"Bash(shred *)",
|
|
19
|
+
"Bash(truncate *)",
|
|
20
|
+
"Bash(git push *)",
|
|
21
|
+
"Bash(git reset --hard *)",
|
|
22
|
+
"Bash(git clean *)",
|
|
23
|
+
"Bash(chmod *)",
|
|
24
|
+
"Bash(chown *)",
|
|
25
|
+
"Bash(sudo *)",
|
|
26
|
+
"Bash(su *)"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"hooks": {
|
|
30
|
+
"WorktreeCreate": [
|
|
31
|
+
{
|
|
32
|
+
"hooks": [
|
|
33
|
+
{
|
|
34
|
+
"type": "command",
|
|
35
|
+
"command": "NAME=$(jq -r '.name')\n. \"$(git rev-parse --show-toplevel)/lib/resolve-project-dir.sh\"\nDIR=\"$JENGA_PROJECT_DIR/.claude/worktrees/$NAME\"\ngit worktree add \"$DIR\" -b \"$NAME\" 2>&1\necho \"$DIR\"\n"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"WorktreeRemove": [
|
|
41
|
+
{
|
|
42
|
+
"hooks": [
|
|
43
|
+
{
|
|
44
|
+
"type": "command",
|
|
45
|
+
"command": "\"$(git rev-parse --show-toplevel)/scripts/worktree-remove-guard.sh\"\n"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"SessionEnd": [
|
|
51
|
+
{
|
|
52
|
+
"hooks": [
|
|
53
|
+
{
|
|
54
|
+
"type": "command",
|
|
55
|
+
"async": true,
|
|
56
|
+
"command": ". \"$(git rev-parse --show-toplevel)/lib/resolve-project-dir.sh\" && \"$JENGA_PROJECT_DIR\"/.claude/hooks/on_session_end.sh"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"defaultMode": "acceptEdits",
|
|
3
|
+
"env": {
|
|
4
|
+
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
|
|
5
|
+
},
|
|
6
|
+
"autoMode": {
|
|
7
|
+
"allow": [
|
|
8
|
+
"$defaults",
|
|
9
|
+
"Bash(bash skills/mirror-public/scripts/mirror.sh*)"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"permissions": {
|
|
13
|
+
"allow": [
|
|
14
|
+
"Bash(*)"
|
|
15
|
+
],
|
|
16
|
+
"deny": [
|
|
17
|
+
"Bash(dd *)",
|
|
18
|
+
"Bash(mkfs *)",
|
|
19
|
+
"Bash(shred *)",
|
|
20
|
+
"Bash(truncate *)",
|
|
21
|
+
"Bash(chmod *)",
|
|
22
|
+
"Bash(chown *)",
|
|
23
|
+
"Bash(sudo *)",
|
|
24
|
+
"Bash(su *)"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"hooks": {
|
|
28
|
+
"WorktreeCreate": [
|
|
29
|
+
{
|
|
30
|
+
"hooks": [
|
|
31
|
+
{
|
|
32
|
+
"type": "command",
|
|
33
|
+
"command": "NAME=$(jq -r '.name')\n. \"$(git rev-parse --show-toplevel)/lib/resolve-project-dir.sh\"\nDIR=\"$JENGA_PROJECT_DIR/.claude/worktrees/$NAME\"\ngit worktree add \"$DIR\" -b \"$NAME\" 2>&1\necho \"$DIR\"\n"
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"WorktreeRemove": [
|
|
39
|
+
{
|
|
40
|
+
"hooks": [
|
|
41
|
+
{
|
|
42
|
+
"type": "command",
|
|
43
|
+
"command": "\"$(git rev-parse --show-toplevel)/scripts/worktree-remove-guard.sh\"\n"
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"SessionEnd": [
|
|
49
|
+
{
|
|
50
|
+
"hooks": [
|
|
51
|
+
{
|
|
52
|
+
"type": "command",
|
|
53
|
+
"async": true,
|
|
54
|
+
"command": ". \"$(git rev-parse --show-toplevel)/lib/resolve-project-dir.sh\" && \"$JENGA_PROJECT_DIR\"/.claude/hooks/on_session_end.sh"
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|