@jenga-ai/agent 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +7 -3
  2. package/agents/developer.md +82 -2
  3. package/agents/scrum-master.md +140 -21
  4. package/agents/tester.md +90 -8
  5. package/hooks/on_session_end.sh +171 -20
  6. package/package.json +1 -1
  7. package/scripts/check-permission-level.sh +107 -0
  8. package/scripts/check-publicignore-match.sh +122 -0
  9. package/scripts/check-worktree-liveness.sh +193 -0
  10. package/scripts/generate-rapport-manifest.sh +43 -0
  11. package/scripts/idea_manager.sh +47 -0
  12. package/scripts/install-worktree-commit-guard.sh +134 -0
  13. package/scripts/jenga-permission-level-switch.sh +109 -0
  14. package/scripts/smoke-harness.sh +139 -0
  15. package/scripts/validate-board.sh +62 -0
  16. package/scripts/with-lock.sh +158 -0
  17. package/scripts/worktree-remove-guard.sh +204 -0
  18. package/skills/clearify/SKILL.md +52 -0
  19. package/skills/commit/SKILL.md +13 -4
  20. package/skills/distribute/CONFIG_SCHEMA.md +60 -2
  21. package/skills/do/SKILL.md +48 -11
  22. package/skills/doc-sync/SKILL.md +16 -0
  23. package/skills/doc-sync/assets/doc_targets.md +11 -0
  24. package/skills/idea/SKILL.md +56 -0
  25. package/skills/idea/assets/idea_handoff_template.md +26 -0
  26. package/skills/idea/assets/idea_template.md +3 -0
  27. package/skills/init/SKILL.md +100 -7
  28. package/skills/init/assets/directory_structure.txt +1 -0
  29. package/skills/init/assets/workflow_template.json +1 -1
  30. package/skills/init/scripts/apply-project-visibility.sh +176 -0
  31. package/skills/init/scripts/detect-existing-codebase.sh +166 -0
  32. package/skills/init/scripts/init.sh +30 -1
  33. package/skills/jenga/SKILL.md +160 -17
  34. package/skills/jenga/scripts/board-scan.sh +238 -0
  35. package/skills/jenga/scripts/cascade-resolve.sh +297 -0
  36. package/skills/jenga/scripts/render-confirmation.sh +679 -0
  37. package/skills/jenga/scripts/render-picker.sh +439 -0
  38. package/skills/jenga/scripts/resolve-id.sh +367 -0
  39. package/skills/jenga-permission-level/SKILL.md +81 -0
  40. package/skills/proceed/SKILL.md +1 -1
  41. package/skills/publish/SKILL.md +8 -5
  42. package/skills/publish/assets/ci-contract.md +2 -2
  43. package/skills/publish/assets/ownership-matrix.md +1 -1
  44. package/skills/publish/scripts/finalize_changelog.sh +115 -0
  45. package/skills/publish/scripts/generate_release_notes.sh +475 -28
  46. package/skills/publish/scripts/npm_ci_pipeline.sh +44 -6
  47. package/skills/publish/scripts/publish_deploy.sh +38 -8
  48. package/skills/publish/scripts/run_gates.sh +2 -2
  49. package/skills/reconcile/SKILL.md +117 -5
  50. package/skills/reconcile/scripts/detect-unlinked-code.sh +741 -0
  51. package/skills/skillify/assets/init-new/assets/directory_structure.txt +5 -1
  52. package/skills/spinoff/SKILL.md +12 -7
  53. package/skills/todo/SKILL.md +2 -0
  54. package/skills/uncharted/SKILL.md +711 -0
  55. package/skills/uncharted/assets/SEGMENT_PROPOSAL_TEMPLATE.md +129 -0
  56. package/skills/uncharted/assets/UNDERSTANDING_DOC_TEMPLATE.md +160 -0
  57. package/skills/uncharted/scripts/apply-subsystem-cap.sh +573 -0
  58. package/skills/uncharted/scripts/detect-dependencies.sh +732 -0
  59. package/skills/uncharted/scripts/detect-tests.sh +553 -0
  60. package/skills/uncharted/scripts/discover-subsystems.sh +1029 -0
  61. package/skills/uncharted/scripts/enumerate-target.sh +470 -0
  62. package/skills/uncharted/scripts/import-source.sh +517 -0
  63. package/skills/uncharted/scripts/inspect-provenance.sh +573 -0
  64. package/skills/uncharted/scripts/resolve-segment-target.sh +640 -0
  65. package/skills/uncharted/scripts/run-engine.sh +655 -0
  66. package/skills/uncharted/scripts/validate-proposed-items.sh +125 -0
  67. package/skills/uncharted/scripts/write-backfilled-epics.sh +498 -0
  68. package/skills/wtf/SKILL.md +20 -0
  69. package/templates/CHANGELOG_TEMPLATE.md +13 -0
  70. package/templates/PROBLEM_RAPPORT_TEMPLATE.md +4 -1
  71. package/templates/SCRUM_BOARD_SCHEMA.md +157 -10
  72. package/templates/permission-levels/README.md +73 -0
  73. package/templates/permission-levels/level-1-locked.json +71 -0
  74. package/templates/permission-levels/level-2-guarded.json +64 -0
  75. package/templates/permission-levels/level-3-standard.json +62 -0
  76. package/templates/permission-levels/level-4-elevated.json +60 -0
  77. package/templates/permission-levels/level-5-unrestricted.json +58 -0
  78. package/skills/convert/SKILL.md +0 -124
  79. package/skills/convert/convert_cli.py +0 -235
  80. package/skills/convert/tests/sample.csv +0 -4
  81. package/skills/convert/tests/sample.json +0 -5
  82. package/skills/convert/tests/sample.jsonl +0 -3
  83. package/skills/convert/tests/sample.yaml +0 -18
  84. package/skills/convert/tests/sample_obj.csv +0 -2
  85. package/skills/convert/tests/sample_obj.json +0 -9
  86. package/skills/mirror-public/SKILL.md +0 -237
  87. package/skills/mirror-public/assets/config.json +0 -5
  88. package/skills/mirror-public/scripts/mirror.sh +0 -374
  89. package/skills/self-sync/SKILL.md +0 -73
  90. package/skills/self-sync/scripts/run.js +0 -136
  91. package/skills/strategy/SKILL.md +0 -312
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env bash
2
+ # ---------------------------------------------------------------------------
3
+ # skills/init/scripts/detect-existing-codebase.sh
4
+ #
5
+ # Deterministic front half of the /init "detect existing project state" step.
6
+ # /init currently always scaffolds as though the target directory were empty.
7
+ # That is wrong whenever a directory already carries a Jenga scaffold, or
8
+ # already carries substantial application code that predates Jenga entirely
9
+ # -- in the second case, scaffolding fresh produces an empty board and a stub
10
+ # PROJECT_SUMMARY.md that actively misrepresent the project.
11
+ #
12
+ # This script answers exactly one question -- "what kind of directory is
13
+ # this?" -- and nothing else. It never scaffolds, never prompts, never runs
14
+ # /uncharted, and never modifies anything on disk. Deciding what to DO with
15
+ # the verdict is agent judgement and lives in skills/init/SKILL.md.
16
+ #
17
+ # ---------------------------------------------------------------------------
18
+ # VERDICTS -- exactly one is printed on stdout, nothing else
19
+ # ---------------------------------------------------------------------------
20
+ # empty The target is empty, or contains only boilerplate
21
+ # that does not count as "there is a project here":
22
+ # .git (the directory itself, pruned entirely -- not
23
+ # merely excluded by name), .gitignore, and top-level
24
+ # README*/LICENSE*/LICENCE* files (case-insensitive),
25
+ # plus anything git itself reports as ignored. A repo
26
+ # containing only a README is empty for this purpose.
27
+ # already-scaffolded The target already carries a Jenga scaffold: any one
28
+ # of project/board/, project/PROJECT_SUMMARY.md, or
29
+ # project/configs/workflow.json is present. Checked
30
+ # BEFORE the emptiness scan, so a scaffolded project
31
+ # that also happens to look sparse is never misreported
32
+ # as "empty".
33
+ # existing-codebase The target has real content (source files, configs,
34
+ # docs beyond the boilerplate list above, etc.) and is
35
+ # not already Jenga-scaffolded. This is the case /init
36
+ # currently mishandles: scaffolding fresh here silently
37
+ # discards the fact that pre-existing code exists.
38
+ #
39
+ # ---------------------------------------------------------------------------
40
+ # NOTES ON GITIGNORE HANDLING
41
+ # ---------------------------------------------------------------------------
42
+ # /init runs this check BEFORE `git init` in the fresh-scaffold path, so the
43
+ # target directory is very often not a git work tree yet. Gitignore-based
44
+ # filtering is therefore best-effort: it only runs when the target already
45
+ # has a `.git` directory AND `git` is on PATH. A standalone `.gitignore` file
46
+ # with no repository behind it still counts as boilerplate via the name-based
47
+ # exclusion below -- it just cannot hide any OTHER file, because there is no
48
+ # git to ask "is this ignored".
49
+ #
50
+ # README/LICENSE exclusion applies to TOP-LEVEL entries only. A directory
51
+ # whose only content is a buried `docs/README.md` two levels down is real
52
+ # structure, not boilerplate, and must not be reported as empty.
53
+ #
54
+ # ---------------------------------------------------------------------------
55
+ # Usage
56
+ # ---------------------------------------------------------------------------
57
+ # detect-existing-codebase.sh [target-dir]
58
+ #
59
+ # target-dir Directory to classify. Default: current directory.
60
+ #
61
+ # Options:
62
+ # -h, --help Show this help and exit 0.
63
+ #
64
+ # Exit codes:
65
+ # 0 A verdict was printed on stdout.
66
+ # 1 Usage error (unknown option, more than one positional argument).
67
+ # 2 target-dir does not exist or is not a directory.
68
+ #
69
+ # Requires: bash, find. git is used opportunistically for gitignore
70
+ # filtering when the target is already a git work tree; its absence never
71
+ # causes a failure.
72
+ # ---------------------------------------------------------------------------
73
+
74
+ set -euo pipefail
75
+
76
+ SELF="$(basename "$0")"
77
+
78
+ usage() {
79
+ sed -n '/^# Usage$/,/^# Requires:/p' "$0" | sed -e 's/^# \{0,1\}//' -e '/^-\{10,\}$/d'
80
+ }
81
+
82
+ die_usage() {
83
+ printf '%s: error: %s\n' "$SELF" "$*" >&2
84
+ echo >&2
85
+ usage >&2
86
+ exit 1
87
+ }
88
+
89
+ TARGET_DIR="."
90
+ HAVE_TARGET=0
91
+
92
+ while [ "$#" -gt 0 ]; do
93
+ case "$1" in
94
+ -h|--help) usage; exit 0 ;;
95
+ --)
96
+ shift
97
+ [ "$#" -le 1 ] || die_usage "at most one target directory is allowed"
98
+ if [ "$#" -eq 1 ]; then TARGET_DIR="$1"; HAVE_TARGET=1; fi
99
+ shift $#
100
+ ;;
101
+ -*)
102
+ die_usage "unknown option \"$1\"" ;;
103
+ *)
104
+ [ "$HAVE_TARGET" -eq 0 ] || die_usage "at most one target directory is allowed (got \"$TARGET_DIR\" and \"$1\")"
105
+ TARGET_DIR="$1"; HAVE_TARGET=1; shift ;;
106
+ esac
107
+ done
108
+
109
+ [ -d "$TARGET_DIR" ] || { printf '%s: error: not a directory: %s\n' "$SELF" "$TARGET_DIR" >&2; exit 2; }
110
+
111
+ TARGET_DIR="$(cd -- "$TARGET_DIR" && pwd -P)"
112
+
113
+ # --- already-scaffolded: checked first, independent of emptiness -----------
114
+ if [ -d "$TARGET_DIR/project/board" ] \
115
+ || [ -f "$TARGET_DIR/project/PROJECT_SUMMARY.md" ] \
116
+ || [ -f "$TARGET_DIR/project/configs/workflow.json" ]; then
117
+ echo "already-scaffolded"
118
+ exit 0
119
+ fi
120
+
121
+ # --- enumerate candidate files, pruning .git entirely -----------------------
122
+ ALL_FILES=$(mktemp "${TMPDIR:-/tmp}/detect-existing-codebase.XXXXXX")
123
+ IGNORED_FILES=$(mktemp "${TMPDIR:-/tmp}/detect-existing-codebase-ignored.XXXXXX")
124
+ cleanup() { rm -f "$ALL_FILES" "$IGNORED_FILES"; }
125
+ trap cleanup EXIT
126
+
127
+ find "$TARGET_DIR" -path "$TARGET_DIR/.git" -prune -o -type f -print > "$ALL_FILES"
128
+
129
+ # --- best-effort gitignore filtering ----------------------------------------
130
+ : > "$IGNORED_FILES"
131
+ if [ -d "$TARGET_DIR/.git" ] && command -v git >/dev/null 2>&1; then
132
+ git -C "$TARGET_DIR" check-ignore --stdin < "$ALL_FILES" > "$IGNORED_FILES" 2>/dev/null || true
133
+ fi
134
+
135
+ # --- classify each candidate -------------------------------------------------
136
+ SOURCE_FOUND=0
137
+ while IFS= read -r f; do
138
+ [ -n "$f" ] || continue
139
+
140
+ if [ -s "$IGNORED_FILES" ] && grep -Fxq -- "$f" "$IGNORED_FILES"; then
141
+ continue
142
+ fi
143
+
144
+ rel="${f#"$TARGET_DIR"/}"
145
+ base="$(basename -- "$f")"
146
+ dir_rel="$(dirname -- "$rel")"
147
+
148
+ if [ "$dir_rel" = "." ]; then
149
+ if [ "$base" = ".gitignore" ]; then
150
+ continue
151
+ fi
152
+ base_upper="$(printf '%s' "$base" | tr '[:lower:]' '[:upper:]')"
153
+ case "$base_upper" in
154
+ README*|LICENSE*|LICENCE*) continue ;;
155
+ esac
156
+ fi
157
+
158
+ SOURCE_FOUND=1
159
+ break
160
+ done < "$ALL_FILES"
161
+
162
+ if [ "$SOURCE_FOUND" -eq 1 ]; then
163
+ echo "existing-codebase"
164
+ else
165
+ echo "empty"
166
+ fi
@@ -3,6 +3,25 @@ set -euo pipefail
3
3
 
4
4
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
5
  ASSETS_DIR="$SCRIPT_DIR/../assets"
6
+ VISIBILITY_SCRIPT="$SCRIPT_DIR/apply-project-visibility.sh"
7
+
8
+ # ─── 0. Resolve project_files_visibility ─────────────────────────────────────
9
+ # Defaults to `visible` — the only value that touches nothing on disk — so an
10
+ # unattended run can never silently relocate directories or edit .gitignore.
11
+ VISIBILITY="${JENGA_PROJECT_FILES_VISIBILITY:-visible}"
12
+
13
+ while [[ $# -gt 0 ]]; do
14
+ case "$1" in
15
+ --visibility) VISIBILITY="${2:-}"; shift 2 ;;
16
+ --visibility=*) VISIBILITY="${1#*=}"; shift ;;
17
+ *) echo "Unknown argument: $1" >&2
18
+ echo "Usage: $(basename "$0") [--visibility <visible|ignored>]" >&2
19
+ exit 1 ;;
20
+ esac
21
+ done
22
+
23
+ # Validate before scaffolding so a typo cannot leave a half-initialised project.
24
+ bash "$VISIBILITY_SCRIPT" --check-only "$VISIBILITY"
6
25
 
7
26
  # ─── 1. Initialize git repository ────────────────────────────────────────────
8
27
  echo "→ Initializing git repository..."
@@ -44,7 +63,17 @@ echo "→ Creating docs/STRATEGY.md (strategic brief for investors, partners, an
44
63
  mkdir -p docs
45
64
  cp "$ASSETS_DIR/strategy_stub_template.md" docs/STRATEGY.md
46
65
 
47
- # ─── 10. Initial commit ──────────────────────────────────────────────────────
66
+ # ─── 10. Create CHANGELOG.md ──────────────────────────────────────────────────
67
+ echo "→ Creating CHANGELOG.md from template..."
68
+ cp "$SCRIPT_DIR/../../../templates/CHANGELOG_TEMPLATE.md" CHANGELOG.md
69
+
70
+ # ─── 11. Apply project_files_visibility ──────────────────────────────────────
71
+ # Runs before the commit so the .gitignore entry (ignored) is captured in the
72
+ # initial commit.
73
+ echo "→ Applying project files visibility ($VISIBILITY)..."
74
+ bash "$VISIBILITY_SCRIPT" "$VISIBILITY" "$PWD"
75
+
76
+ # ─── 12. Initial commit ──────────────────────────────────────────────────────
48
77
  echo "→ Staging and committing scaffolded files..."
49
78
  git add -A
50
79
  git commit -m "init: scaffold project structure and workflow config"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jenga
3
- description: Fully automated board orchestrator. Decomposes any unbroken Epics into Stories, any unbroken Stories into Tasks, queues all unqueued Tasks into todo.md, then executes every eligible item — no user prompts — until the board is fully started.
3
+ description: Interactive-by-default board orchestrator with a fully automated escape hatch. Bare `/jenga` renders a picker and confirmation tree before scoping the run; `/jenga <ids>` resolves an explicit fuzzy-ID scope and confirms it; `/jenga *` reproduces the original zero-prompt behavior — decomposing any unbroken Epics into Stories, any unbroken Stories into Tasks, queuing all unqueued Tasks into todo.md, then executing every eligible item with no user prompts — until the board is fully started.
4
4
  keywords:
5
5
  - jenga
6
6
  - orchestrate
@@ -18,7 +18,13 @@ metadata:
18
18
 
19
19
  ## Purpose
20
20
 
21
- `/jenga` is a hands-free "commit to everything on the board" pipeline. It ensures the entire board is fully decomposed, fully queued, and fully executing — without any user interaction. It runs in four phases: **decompose → queue → execute → loop**.
21
+ `/jenga` is interactive by default — it never silently commits to the whole board without showing the user what it's about to run and letting them scope or edit that selection first. It has three entry modes:
22
+
23
+ - **Bare `/jenga`** (no argument) — renders a numbered picker of the full board, then an editable confirmation tree, before anything executes.
24
+ - **`/jenga <ids>`** (explicit comma-separated scope) — resolves the given IDs via the fuzzy-ID grammar, skipping the picker, then still shows the same editable confirmation tree before executing.
25
+ - **`/jenga *`** (literal wildcard) — the explicit escape hatch. Skips both the picker and the confirmation step entirely and reproduces the original hands-free "commit to everything on the board" pipeline: the entire board is fully decomposed, fully queued, and fully executing — without any user interaction, no user prompts. This is the only path where `/jenga` runs with no user prompts at all.
26
+
27
+ Once a run's scope is established (by confirmation, or unconditionally under `*`), `/jenga` runs the same underlying phases against that scope: **entry mode resolution → decompose → queue → execute → loop**.
22
28
 
23
29
  ## Instructions
24
30
 
@@ -46,36 +52,165 @@ Extract the following named values for use throughout this skill:
46
52
 
47
53
  These values must be read fresh on each invocation. Never use hardcoded fallbacks.
48
54
 
55
+ ### Phase 0.5 — Pre-flight Validation
56
+
57
+ Before accepting any task for decomposition or execution, the executing agent must validate the task's scope fields. The threshold values loaded in Phase 0 may be referenced in error messages for context, but are not required for the core validation rules below.
58
+
59
+ For each task read from the board, apply the following checks in order:
60
+
61
+ #### Rule 1 — Valid execution_scope value
62
+
63
+ If the task frontmatter contains an `execution_scope` field, its value must be one of: `task`, `story`, `epic`, `inline`.
64
+
65
+ If the value is anything else, halt immediately with:
66
+
67
+ ```
68
+ VALIDATION ERROR [<task_id>]: execution_scope "<value>" is not a valid scope. Allowed: task, story, epic, inline.
69
+ ```
70
+
71
+ Do not proceed with this task.
72
+
73
+ #### Rule 2 — scope_rationale must contain a measurable claim
74
+
75
+ If `execution_scope` is present, `scope_rationale` must also be present and must contain at least one digit (0–9) or the word "file" (case-insensitive).
76
+
77
+ If `scope_rationale` is absent, or present but contains no digit and does not contain the word "file", halt with:
78
+
79
+ ```
80
+ VALIDATION ERROR [<task_id>]: scope_rationale is missing or lacks a numeric/file-count claim. Provide a rationale that includes a digit (e.g. "touches 2 files") or the word "file".
81
+ ```
82
+
83
+ Do not proceed with this task.
84
+
85
+ #### Rule 3 — epic scope requires explicit human approval
86
+
87
+ If `execution_scope` is `"epic"`, the task must also have `epic_scope_approval: true` set explicitly in its frontmatter. A missing `epic_scope_approval` field and a value of `false` are both rejection conditions.
88
+
89
+ If `epic_scope_approval` is absent or is not exactly `true`, halt with:
90
+
91
+ ```
92
+ VALIDATION ERROR [<task_id>]: execution_scope=epic requires epic_scope_approval: true (set by human operator). This field must be added manually — it is never assigned autonomously.
93
+ ```
94
+
95
+ Do not proceed with this task.
96
+
97
+ #### Rule 4 — crucial_level: locked forces execution_scope: inline
98
+
99
+ If the task frontmatter contains `crucial_level: locked` (per `templates/SCRUM_BOARD_SCHEMA.md`'s Crucial Flag Fields), `execution_scope` for that task MUST be `inline` — only the current foreground/inline session can pause mid-run for a live confirmation; a backgrounded subagent has no live channel back to the user.
100
+
101
+ This rule **auto-corrects and continues**; unlike Rules 1-3, it never halts.
102
+
103
+ - If `execution_scope` is present and its value is anything other than `inline`, correct it to `inline` directly in the task file, and record a logged note of the correction by appending to that task's `override_justification` frontmatter field (the auditable mechanism for this rule — do not use `events.json` or any other location) a line of the form:
104
+
105
+ ```
106
+ override_justification: "Rule 4 auto-correction <date>: execution_scope forced from '<previous_value>' to 'inline' because crucial_level: locked."
107
+ ```
108
+
109
+ Then emit (non-fatally — do not halt):
110
+
111
+ ```
112
+ AUTO-CORRECTION [<task_id>]: crucial_level=locked requires execution_scope=inline; corrected from "<previous_value>" to "inline".
113
+ ```
114
+
115
+ - If `execution_scope` is absent entirely, set it to `inline` directly in the task frontmatter. Do **not** fall through to the Backward-compatibility default of `execution_scope: task` documented immediately below — a `locked` item overrides that default even when no other execution-scope fields are present. No `override_justification` note is required in this case, since there is no prior value being overridden.
116
+
117
+ Proceed to the next rule (or the next phase, if this was the last applicable rule) after applying the correction.
118
+
119
+ #### Backward compatibility — legacy tasks
120
+
121
+ If the task frontmatter contains **none** of `execution_scope`, `scope_rationale`, `needs_docs`, `jenga_assigned`, or `override_justification`, treat the task as a legacy task:
122
+
123
+ - Assume `execution_scope: task`
124
+ - Assume `needs_docs: true`
125
+ - Skip all three rules above and proceed without error.
126
+
127
+ #### Validation success
128
+
129
+ If all applicable rules pass (or the task is a legacy task), proceed to the next phase for that task without any error output.
130
+
131
+ ---
132
+
133
+ ### Phase 0.75 — Entry Mode Resolution
134
+
135
+ This phase determines **how `/jenga` was invoked** and, for two of the three entry modes, produces a **scoped set** — a confirmed list of board IDs (epics/stories/tasks) that Phases 1-4 must restrict themselves to. All board scanning, ID parsing, cascade expansion, and rendering used by this phase already live in `skills/jenga/scripts/` per this repo's "Scripts Over Inline Logic" principle — this phase never re-implements any of that logic inline. The executing agent's job here is limited to: invoking the right script with the right arguments, relaying its STDOUT verbatim to the user when the contract calls for that, capturing the `STATE_FILE:` line from STDERR for the next turn, and forwarding the user's raw reply back into the next invocation unmodified.
136
+
137
+ **Determine the invocation form** from the raw argument (if any) passed to `/jenga`:
138
+
139
+ - No argument at all → **bare branch**.
140
+ - The argument is the literal string `*` → **wildcard branch**.
141
+ - Any other non-empty argument → **scoped branch** (treat the whole argument as the comma-separated raw ID list).
142
+
143
+ #### Wildcard branch (`/jenga *`)
144
+
145
+ Skip both the picker and the confirmation step entirely. There is no scoped set — proceed to Phase 1 unrestricted, exactly as `/jenga` behaved before this phase existed.
146
+
147
+ #### Bare branch (`/jenga`)
148
+
149
+ 1. Invoke `skills/jenga/scripts/render-picker.sh` with no arguments (start mode). Relay its STDOUT (the numbered checklist) to the user verbatim — no summarizing, no reformatting. Capture the `STATE_FILE:` path from STDERR.
150
+ 2. Wait for the user's chat reply, then invoke `skills/jenga/scripts/render-picker.sh <state_file> "<raw_reply>"` (continue mode).
151
+ - **Error turn** (plain text on STDOUT, state file retained) — relay verbatim and return to step 2 for another reply.
152
+ - **Cancellation** — relay the cancellation acknowledgement and halt the entire `/jenga` run; do not proceed to any later phase.
153
+ - **Resolved** (JSON object on STDOUT, state file removed) — extract `resolved_ids_csv` and continue to the shared confirmation step below.
154
+
155
+ #### Scoped branch (`/jenga <ids>`)
156
+
157
+ 1. Invoke `skills/jenga/scripts/resolve-id.sh "<raw argument>"` directly — the picker is skipped entirely in this branch.
158
+ 2. Parse the JSON array response, one object per comma-delimited input segment.
159
+ - If **every** segment has `status: "resolved"`, collect their `resolved_id` values into a comma-separated list and continue to the shared confirmation step below.
160
+ - If **any** segment has `status: "rejected"`, halt this phase (do not proceed to confirmation or Phase 1) and report each rejected segment's `input` and `reason` to the user verbatim, per `resolve-id.sh`'s own contract — a partial or ambiguous ID is never guessed. The user must re-invoke `/jenga <ids>` with corrected input.
161
+
162
+ #### Shared confirmation step (bare and scoped branches only)
163
+
164
+ 1. Invoke `skills/jenga/scripts/render-confirmation.sh "<comma-separated resolved ids from whichever branch above>"` (start mode). Relay STDOUT (the confirmation tree) to the user verbatim. Capture the `STATE_FILE:` path from STDERR.
165
+ 2. Wait for the user's chat reply, then invoke `skills/jenga/scripts/render-confirmation.sh <state_file> "<raw_reply>"` (continue mode).
166
+ - **Toggle or error turn** (plain text on STDOUT, state file retained) — relay verbatim and return to step 2 for another reply.
167
+ - **Cancellation** — relay the cancellation acknowledgement and halt the entire `/jenga` run; do not proceed to any later phase.
168
+ - **Confirmed** (JSON object on STDOUT, state file removed) — this is the final **scoped set**. Take `resolved_ids` (or `resolved_ids_csv`) as the exact set of board IDs Phases 1-4 restrict themselves to for the rest of this run.
169
+ 3. **Handoff to cascade resolution** — do not invoke `cascade-resolve.sh` again here. `render-confirmation.sh` already invoked it internally to build the tree, and the CONFIRMED JSON's own `undecomposed` field is that same result already scoped down to the checked-only set. Use that `undecomposed` field directly to identify which epics/stories in the scoped set still need Phase 1/2 decomposition.
170
+
171
+ After this phase completes (bare and scoped branches via confirmation, wildcard branch immediately), proceed to Phase 1.
172
+
173
+ ---
174
+
49
175
  ### Phase 1 — Decompose Epics into Stories
50
176
 
51
- Read all files in `project/board/epics/`. For each Epic that has no corresponding story files in `project/board/stories/` (i.e. no files whose name starts with that Epic's ID), invoke `/do` via a **scrum-master sub-agent** to break it down into Stories.
177
+ If Phase 0.75 produced a scoped set, restrict this phase to epics that are members of that set (directly selected, or flagged in its `undecomposed` list). Under `/jenga *`, this phase is unrestricted, exactly as before.
178
+
179
+ Read all files in `project/board/epics/`. For each in-scope Epic that has no corresponding story files in `project/board/stories/` (i.e. no files whose name starts with that Epic's ID), invoke `/do` via a **scrum-master sub-agent** to break it down into Stories.
52
180
 
53
- Repeat until every Epic has at least one Story on the board.
181
+ Repeat until every in-scope Epic has at least one Story on the board.
54
182
 
55
183
  ### Phase 2 — Decompose Stories into Tasks
56
184
 
57
- Read all files in `project/board/stories/`. For each Story that has no corresponding task files in `project/board/tasks/` (i.e. no files whose name starts with that Story's ID), invoke `/do` via a **scrum-master sub-agent** to break it down into Tasks.
185
+ If Phase 0.75 produced a scoped set, restrict this phase to stories that are members of that set (directly selected, expanded from an in-scope epic, or flagged in its `undecomposed` list). Under `/jenga *`, this phase is unrestricted, exactly as before.
58
186
 
59
- Repeat until every Story has at least one Task on the board.
187
+ Read all files in `project/board/stories/`. For each in-scope Story that has no corresponding task files in `project/board/tasks/` (i.e. no files whose name starts with that Story's ID), invoke `/do` via a **scrum-master sub-agent** to break it down into Tasks.
188
+
189
+ Repeat until every in-scope Story has at least one Task on the board.
60
190
 
61
191
  ### Phase 3 — Queue all Tasks into `todo.md`
62
192
 
63
- Read all files in `project/board/tasks/`. For every Task not already listed in `project/todo.md`, append its ID (and title as a comment) to `project/todo.md`.
193
+ If Phase 0.75 produced a scoped set, restrict this phase to tasks that are members of that set (directly selected, or expanded from an in-scope epic/story). Under `/jenga *`, this phase is unrestricted, exactly as before.
194
+
195
+ Read all files in `project/board/tasks/`. For every in-scope Task not already listed in `project/todo.md`, append its ID (and title as a comment) to `project/todo.md`.
64
196
 
65
- After this phase, `todo.md` reflects the full set of work on the board.
197
+ After this phase, `todo.md` reflects the full set of in-scope work (or the full board, under `*`).
66
198
 
67
199
  ### Phase 3.5 — Story-bundle detection
68
200
 
69
201
  Before dispatching individual tasks in Phase 4, check each story for bundle eligibility. This phase runs once after Phase 3 completes.
70
202
 
71
- For each story that has one or more tasks listed in `todo.md`:
203
+ If Phase 0.75 produced a scoped set, restrict this phase to stories that are members of that set (directly selected, or expanded from an in-scope epic) — a story with tasks sitting in `todo.md` from an earlier, differently-scoped run but that is **not** a member of the current run's scoped set is skipped entirely by this phase (not considered for bundling, and not dispatched via the bundle path) so that Phase 4's own scoped-set exclusion is never bypassed by a bundle call issued here. Under `/jenga *`, this phase is unrestricted, exactly as before.
204
+
205
+ For each in-scope story that has one or more tasks listed in `todo.md`:
72
206
 
73
207
  1. **Read the story file** — parse the `tasks:` frontmatter array to get the ordered list of task IDs.
74
208
  2. **Guard: empty task list** — if the `tasks:` list is empty (zero entries), this story is **not** eligible for the bundle path. Skip to per-task dispatch in Phase 4.
75
209
  3. **Read each task file** — for every task ID in the `tasks:` list, read the corresponding task file from `project/board/tasks/`.
76
210
  4. **Collect `execution_scope`** — extract the `execution_scope` field from each task's YAML frontmatter. If the field is absent or has any value other than `story`, treat that task as **not** story-scoped.
77
- 5. **Apply the all-or-nothing rule** — a story qualifies for the bundle path **only if every task** in its `tasks:` list has `execution_scope: story`. A single task with a different scope (or a missing field) disqualifies the entire story.
78
- 6. **Route bundle candidates** — if all tasks in the story are `execution_scope: story` and the list is non-empty:
211
+ 5. **Guard: locked-task disqualifier (defense-in-depth)** — for each task file already read in step 3, also read `crucial_level` (per `templates/SCRUM_BOARD_SCHEMA.md`'s Crucial Flag Fields). If **any** task in the story's `tasks:` list has `crucial_level: locked`, this story is **not** eligible for the bundle path — skip to per-task dispatch in Phase 4 for this story, **regardless of that task's `execution_scope` value**, even if it already reads `inline`. This check is defense-in-depth alongside Phase 0.5's Rule 4 (which forces a locked task's own `execution_scope` to `inline` when Rule 4 processes it): it exists for the race window where Rule 4 hasn't (yet) corrected the task — e.g. the task was added to the story's `tasks:` list after Rule 4 last ran, or the file was edited by hand after validation. It is not a replacement for Rule 4.
212
+ 6. **Apply the all-or-nothing rule** — a story qualifies for the bundle path **only if every task** in its `tasks:` list has `execution_scope: story`. A single task with a different scope (or a missing field) disqualifies the entire story.
213
+ 7. **Route bundle candidates** — if all tasks in the story are `execution_scope: story` and the list is non-empty:
79
214
  a. Emit:
80
215
  ```
81
216
  BUNDLE DETECTED: story <E##_S##> — <N> story-scoped tasks will execute as a bundle.
@@ -83,17 +218,19 @@ For each story that has one or more tasks listed in `todo.md`:
83
218
  where `<E##_S##>` is the story ID and `<N>` is the count of tasks in the list.
84
219
  b. Call `/do <E##_S##>` once (with the story ID, not individual task IDs). This invokes the bundle execution path in `/do` (implemented in E32_S05_T02), which runs all tasks sequentially in one shared worktree.
85
220
  c. **Mark these tasks as bundled** — record their task IDs so Phase 4 skips individual dispatch for them.
86
- 7. **Non-bundle stories** — stories with a mixed scope, a zero-length task list, or any task missing `execution_scope: story` use the normal per-task dispatch in Phase 4 without any change.
221
+ 8. **Non-bundle stories** — stories with a mixed scope, a zero-length task list, any task missing `execution_scope: story`, or any task with `crucial_level: locked` (step 5) use the normal per-task dispatch in Phase 4 without any change.
87
222
 
88
223
  ### Phase 4 — Execute
89
224
 
90
225
  Loop through `todo.md` and execute all eligible items, running independent ones in parallel. Use the threshold values loaded in Phase 0 (`inline_max_files`, `inline_max_lines`, `story_max_files`, `bundle_lock_ttl_minutes`) when applying execution-scope logic to each task. **Skip any task that was bundled in Phase 3.5** — those tasks will be handled by the `/do` story-bundle call already issued.
91
226
 
92
- 1. **Collect eligible items** — from `todo.md`, find all items whose board file has `status: Pending` and no unresolved dependencies, **excluding tasks already dispatched as part of a story bundle in Phase 3.5**. A dependency is resolved if the blocking item's status is at least `Running` or `Passed`.
227
+ 1. **Collect eligible items** — from `todo.md`, find all items whose board file has `status: Pending` and no unresolved dependencies, **excluding tasks already dispatched as part of a story bundle in Phase 3.5**. If Phase 0.75 produced a scoped set, also exclude any item not a member of that set — execution never runs outside the confirmed/resolved scope. Under `/jenga *`, no such exclusion applies. A dependency is resolved if the blocking item's status is at least `In Progress` or `Passed`.
93
228
  2. **Group by parallelism** — items with no shared dependencies and no overlapping output files can run concurrently. Items that depend on each other must be sequenced.
94
229
  3. **Invoke `/do` in parallel** — launch each independent item as a **background sub-agent** simultaneously. Do not wait for one to finish before starting another if they are independent.
95
- 4. **Mark Running** — update `status: Running` in each launched item's board file (YAML front-matter) immediately after launch.
96
- 5. **Wait and loop** — once all active background agents have completed, return to step 1 of this phase to pick up any newly unblocked items.
230
+ 4. **Mark In Progress** — update `status: In Progress` in each launched item's board file (YAML front-matter) immediately after launch.
231
+ 5. **Wait, drain, and loop** — once all active background agents in the wave have completed:
232
+ a. **Drain the scrum triggers queue** — invoke the `## Drain Scrum Triggers Queue` procedure from `agents/scrum-master.md` against `project/queue/scrum_triggers.jsonl`. `/jenga`'s orchestrating agent is the scrum-master, and this is the same session-start procedure applied mid-run: process any `rapport_review`, `status_review`, and `story_rollup` triggers written by the tester sub-sessions that just completed, then clear the file. This ensures rollups become visible on the board (story/epic status updates) before the next wave is collected, instead of sitting unprocessed until some future scrum-master session start.
233
+ b. **Return to step 1** of this phase to pick up any newly unblocked items — including items unblocked by the rollups just processed in (a).
97
234
 
98
235
  ### Exit condition
99
236
 
@@ -108,10 +245,16 @@ When no eligible candidates remain in Phase 4, exit and output:
108
245
  - **Epic with no stories after breakdown** — log a warning and continue to the next Epic; do not block the pipeline.
109
246
  - **Story with no tasks after breakdown** — log a warning and continue to the next Story.
110
247
  - **Task already in `todo.md`** — skip; do not duplicate.
111
- - **All tasks in `todo.md` already Running/Passed** — exits cleanly with the completion message.
112
- - **Unresolved dependencies** — item is skipped in Phase 4 until its blockers are at least `Running`.
248
+ - **All tasks in `todo.md` already In Progress/Passed** — exits cleanly with the completion message.
249
+ - **Unresolved dependencies** — item is skipped in Phase 4 until its blockers are at least `In Progress`.
113
250
  - **`/do` failure (background agent)** — treated as a skip; mark the item's status back to `Pending` and continue the loop with remaining candidates.
114
251
  - **Story with zero tasks (empty `tasks:` list)** — does not enter the bundle path in Phase 3.5; tasks (if any appear in `todo.md` independently) are dispatched normally in Phase 4.
115
252
  - **Story with mixed `execution_scope` values** — falls back entirely to per-task dispatch in Phase 4; no partial bundling occurs.
116
253
  - **Task file missing `execution_scope` field** — treated as not story-scoped; the containing story is disqualified from the bundle path.
254
+ - **Story containing a `crucial_level: locked` task** — disqualified from the bundle path at Phase 3.5 step 5, independent of that task's `execution_scope`; falls back to per-task dispatch in Phase 4, where `/do` Section 4.2's locked-task dispatch guard (E39_S03_T04) provides the second enforcement layer before any worktree or subagent is created.
117
255
  - **Bundle `/do` call failure** — treated as a skip for the entire bundle; mark all bundled tasks' status back to `Pending` and continue Phase 4 with remaining non-bundled candidates.
256
+ - **Picker cancelled (bare branch)** — the entire `/jenga` run halts immediately after relaying the cancellation acknowledgement; no phase past 0.75 runs, and nothing on the board is modified.
257
+ - **Confirmation cancelled (bare or scoped branch)** — same as picker cancellation: the entire `/jenga` run halts immediately; no scoped set is produced and no later phase runs.
258
+ - **`resolve-id.sh` rejects one or more segments (scoped branch)** — the whole invocation halts at Phase 0.75 with the rejected segments' reasons reported verbatim; no partial scope is assembled from the segments that did resolve, and no fallback guess is made for the rejected ones. The user must re-invoke `/jenga <ids>` with corrected input.
259
+ - **`/jenga *` (wildcard branch)** — never produces a scoped set; Phases 1-4 run fully unrestricted over the entire board, identical to `/jenga`'s behavior before Phase 0.75 existed.
260
+ - **Stale out-of-scope story queued in `todo.md` from an earlier run (scoped run only)** — Phase 3.5's scoped-set guard skips it entirely (not considered for bundling), so it cannot be dispatched via a bundle `/do <E##_S##>` call that would otherwise bypass Phase 4's own scoped-set exclusion; it remains untouched in `todo.md` until a future run's scope includes it.