@jenga-ai/agent 1.3.0 → 2.0.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.
Files changed (76) hide show
  1. package/README.md +97 -92
  2. package/agents/developer.md +9 -8
  3. package/agents/scrum-master.md +57 -23
  4. package/agents/tester.md +51 -5
  5. package/hooks/on_session_end.sh +13 -1
  6. package/lib/generate-agent-context.js +18 -1
  7. package/lib/generate-copilot-instructions.js +18 -1
  8. package/lib/generate-skill-allow-list.js +191 -0
  9. package/lib/skill-allow-list.json +43 -0
  10. package/package.json +18 -4
  11. package/scripts/apply-j-prefix.sh +230 -0
  12. package/scripts/consume-context-digest.sh +103 -0
  13. package/scripts/postinstall.js +25 -0
  14. package/scripts/sweep-stale-context-digests.sh +132 -0
  15. package/scripts/validate-board.sh +5 -0
  16. package/scripts/write-context-digest.sh +230 -0
  17. package/skills/brainstorm/SKILL.md +1 -1
  18. package/skills/btw/SKILL.md +1 -1
  19. package/skills/clearify/SKILL.md +1 -1
  20. package/skills/close-story/SKILL.md +78 -6
  21. package/skills/close-story/scripts/check-privatized.sh +345 -0
  22. package/skills/commit/SKILL.md +1 -1
  23. package/skills/continue/SKILL.md +1 -1
  24. package/skills/deep-dive/SKILL.md +1 -1
  25. package/skills/dev-done/SKILL.md +1 -1
  26. package/skills/distribute/SKILL.md +1 -1
  27. package/skills/do/SKILL.md +100 -10
  28. package/skills/doc/README.md +155 -0
  29. package/skills/doc/SKILL.md +43 -13
  30. package/skills/doc/authoring-notes.md +72 -0
  31. package/skills/doc/scripts/resolve_last_update.py +149 -0
  32. package/skills/doc-sync/SKILL.md +1 -1
  33. package/skills/dooo/SKILL.md +1 -1
  34. package/skills/error/SKILL.md +1 -1
  35. package/skills/evaluate/SKILL.md +1 -1
  36. package/skills/examplify/SKILL.md +1 -1
  37. package/skills/help/SKILL.md +1 -1
  38. package/skills/idea/SKILL.md +1 -1
  39. package/skills/improve/SKILL.md +1 -1
  40. package/skills/init/SKILL.md +1 -1
  41. package/skills/init/assets/scope-thresholds_template.json +3 -3
  42. package/skills/j-init/SKILL.md +168 -0
  43. package/skills/j-init/assets/.gitignore_template +15 -0
  44. package/skills/j-init/assets/PROJECT_SUMMARY_template.md +13 -0
  45. package/skills/j-init/assets/directory_structure.txt +14 -0
  46. package/skills/j-init/assets/scope-thresholds_template.json +7 -0
  47. package/skills/j-init/assets/strategy_stub_template.md +38 -0
  48. package/skills/j-init/assets/test-config_template.json +4 -0
  49. package/skills/j-init/assets/workflow_template.json +30 -0
  50. package/skills/j-init/scripts/apply-project-visibility.sh +176 -0
  51. package/skills/j-init/scripts/detect-existing-codebase.sh +166 -0
  52. package/skills/j-init/scripts/init.sh +116 -0
  53. package/skills/jbp/SKILL.md +1 -1
  54. package/skills/jenga/SKILL.md +1 -1
  55. package/skills/jenga/scripts/render-confirmation.sh +55 -18
  56. package/skills/jenga-permission-level/SKILL.md +1 -1
  57. package/skills/lgtm/SKILL.md +1 -1
  58. package/skills/pi-plan/SKILL.md +1 -1
  59. package/skills/proceed/SKILL.md +1 -1
  60. package/skills/publish/SKILL.md +1 -1
  61. package/skills/publish/adapters/npm-ci.md +26 -4
  62. package/skills/publish/scripts/npm_ci_pipeline.sh +21 -1
  63. package/skills/reconcile/SKILL.md +1 -1
  64. package/skills/reconcile-origin/SKILL.md +1 -1
  65. package/skills/redo/SKILL.md +1 -1
  66. package/skills/skillify/SKILL.md +1 -1
  67. package/skills/spinoff/SKILL.md +1 -1
  68. package/skills/status/SKILL.md +1 -1
  69. package/skills/todo/SKILL.md +40 -3
  70. package/skills/todo/scripts/add_trivial_task.sh +216 -0
  71. package/skills/todo/scripts/update_story_tasks.py +87 -0
  72. package/skills/uncharted/SKILL.md +1 -1
  73. package/skills/wtf/SKILL.md +1 -1
  74. package/templates/SCRUM_BOARD_SCHEMA.md +33 -2
  75. package/templates/agent-context.md.tpl +32 -9
  76. package/templates/copilot-instructions.md.tpl +25 -8
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ ASSETS_DIR="$SCRIPT_DIR/../assets"
6
+ VISIBILITY_SCRIPT="$SCRIPT_DIR/apply-project-visibility.sh"
7
+
8
+ # ─── Resolve the package root that owns templates/ and lib/ ──────────────────
9
+ # postinstall.js mirrors only skills/ and agents/ into .claude/ and .agents/ —
10
+ # templates/ and lib/ are never copied there, so a script running from a
11
+ # mirrored copy (.claude/skills/init/scripts/ or .agents/skills/init/scripts/)
12
+ # cannot reach its siblings via a fixed ../../../ climb the way it can in this
13
+ # monorepo checkout, where init.sh actually lives at skills/init/scripts/ with
14
+ # templates/ and lib/ three levels up. Consumers instead have them inside the
15
+ # installed npm package.
16
+ if [[ -d "$SCRIPT_DIR/../../../templates" ]]; then
17
+ PKG_ROOT="$SCRIPT_DIR/../../.."
18
+ elif [[ -d "$PWD/node_modules/@jenga-ai/agent/templates" ]]; then
19
+ PKG_ROOT="$PWD/node_modules/@jenga-ai/agent"
20
+ else
21
+ echo "Error: could not locate the jenga-agent package root (templates/ not found via monorepo checkout or node_modules/@jenga-ai/agent)." >&2
22
+ exit 1
23
+ fi
24
+
25
+ # ─── 0. Resolve project_files_visibility ─────────────────────────────────────
26
+ # Defaults to `visible` — the only value that touches nothing on disk — so an
27
+ # unattended run can never silently relocate directories or edit .gitignore.
28
+ VISIBILITY="${JENGA_PROJECT_FILES_VISIBILITY:-visible}"
29
+
30
+ while [[ $# -gt 0 ]]; do
31
+ case "$1" in
32
+ --visibility) VISIBILITY="${2:-}"; shift 2 ;;
33
+ --visibility=*) VISIBILITY="${1#*=}"; shift ;;
34
+ *) echo "Unknown argument: $1" >&2
35
+ echo "Usage: $(basename "$0") [--visibility <visible|ignored>]" >&2
36
+ exit 1 ;;
37
+ esac
38
+ done
39
+
40
+ # Validate before scaffolding so a typo cannot leave a half-initialised project.
41
+ bash "$VISIBILITY_SCRIPT" --check-only "$VISIBILITY"
42
+
43
+ # ─── 1. Initialize git repository ────────────────────────────────────────────
44
+ echo "→ Initializing git repository..."
45
+ git init
46
+
47
+ # ─── 2. Create .gitignore ─────────────────────────────────────────────────────
48
+ echo "→ Copying .gitignore from template..."
49
+ cp "$ASSETS_DIR/.gitignore_template" .gitignore
50
+
51
+ # ─── 3. Scaffold directory structure ──────────────────────────────────────────
52
+ echo "→ Scaffolding directory structure..."
53
+ while IFS= read -r dir || [[ -n "$dir" ]]; do
54
+ [[ -z "$dir" || "$dir" == \#* ]] && continue
55
+ mkdir -p "$dir"
56
+ done < "$ASSETS_DIR/directory_structure.txt"
57
+
58
+ # ─── 4. Create project/PROJECT_SUMMARY.md ────────────────────────────────────
59
+ echo "→ Copying PROJECT_SUMMARY.md from template..."
60
+ cp "$ASSETS_DIR/PROJECT_SUMMARY_template.md" project/PROJECT_SUMMARY.md
61
+
62
+ # ─── 5. Create project/configs/workflow.json ─────────────────────────────────
63
+ echo "→ Copying workflow.json from template..."
64
+ cp "$ASSETS_DIR/workflow_template.json" project/configs/workflow.json
65
+
66
+ # ─── 6. Create project/configs/test-config.json stub ─────────────────────────
67
+ echo "→ Copying test-config.json from template..."
68
+ cp "$ASSETS_DIR/test-config_template.json" project/configs/test-config.json
69
+
70
+ # ─── 6.5. Create project/configs/scope-thresholds.json ───────────────────────
71
+ # Consumed by skills/jenga (Phase 0) and skills/do (Step 0); both halt if it's
72
+ # missing, so it must exist immediately after scaffold.
73
+ echo "→ Copying scope-thresholds.json from template..."
74
+ cp "$ASSETS_DIR/scope-thresholds_template.json" project/configs/scope-thresholds.json
75
+
76
+ # ─── 7. Create project/data/baselines.json ───────────────────────────────────
77
+ echo "→ Creating baselines.json..."
78
+ echo '{}' > project/data/baselines.json
79
+
80
+ # ─── 8. Create project/logs/events.json ──────────────────────────────────────
81
+ echo "→ Creating events.json..."
82
+ echo '[]' > project/logs/events.json
83
+
84
+ # ─── 9. Create docs/STRATEGY.md ──────────────────────────────────────────────
85
+ echo "→ Creating docs/STRATEGY.md (strategic brief for investors, partners, and the product team)..."
86
+ mkdir -p docs
87
+ cp "$ASSETS_DIR/strategy_stub_template.md" docs/STRATEGY.md
88
+
89
+ # ─── 10. Create CHANGELOG.md ──────────────────────────────────────────────────
90
+ echo "→ Creating CHANGELOG.md from template..."
91
+ cp "$PKG_ROOT/templates/CHANGELOG_TEMPLATE.md" CHANGELOG.md
92
+
93
+ # ─── 11. Apply project_files_visibility ──────────────────────────────────────
94
+ # Runs before the commit so the .gitignore entry (ignored) is captured in the
95
+ # initial commit.
96
+ echo "→ Applying project files visibility ($VISIBILITY)..."
97
+ bash "$VISIBILITY_SCRIPT" "$VISIBILITY" "$PWD"
98
+
99
+ # ─── 12. Generate CLAUDE.md / AGENTS.md ──────────────────────────────────────
100
+ # Unconditional — never gated on agentTarget (E41_S04). Applies the J-
101
+ # collision rule and idempotent managed-block updates; see
102
+ # lib/generate-agent-context.js (shared with the published `jenga init` CLI).
103
+ echo "→ Generating CLAUDE.md / AGENTS.md..."
104
+ if command -v node >/dev/null 2>&1; then
105
+ node "$PKG_ROOT/lib/generate-agent-context.js" "$PWD"
106
+ else
107
+ echo " Warning: node not found — skipped CLAUDE.md/AGENTS.md generation." >&2
108
+ fi
109
+
110
+ # ─── 13. Initial commit ──────────────────────────────────────────────────────
111
+ echo "→ Staging and committing scaffolded files..."
112
+ git add -A
113
+ git commit -m "init: scaffold project structure and workflow config"
114
+
115
+ echo ""
116
+ echo "✓ Project scaffold complete."
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: jbp
2
+ name: j:jbp
3
3
  description: Scaffold the project using the JengaBasePlate boilerplate repo template from https://github.com/samwelmunga/JengaBasePlate.git
4
4
  keywords:
5
5
  - jbp
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: jenga
2
+ name: j:jenga
3
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
@@ -97,12 +97,18 @@
97
97
  # ENTIRE turn is rejected as an error turn (state left untouched) — there
98
98
  # is no partial application of the valid numbers in a mixed-validity reply.
99
99
  #
100
- # Toggling is NOT cascading: unchecking a parent epic/story does not
101
- # automatically uncheck its children, and vice versa. Each displayed
102
- # number is an independent checkbox. This is a deliberate simplicity
103
- # choice — the task only requires "uncheck or re-check individual
104
- # presented items", not cascading selection logic (that expansion/cascade
105
- # concern already belongs to cascade-resolve.sh, per its own header).
100
+ # Toggling CASCADES downward (E45_S02_T03): checking or unchecking a
101
+ # story applies the same resulting state to all of its tasks; checking or
102
+ # unchecking an epic applies the same resulting state to all of its
103
+ # stories and their tasks. This is a deliberate, explicit reversal of the
104
+ # original non-cascading design (see this story's 2026-08-27 close-out) —
105
+ # the user hit a real case where unchecking a parent epic left its child
106
+ # story/tasks checked, requiring a manual follow-up uncheck command.
107
+ # Cascade is STRICTLY DOWNWARD (parent -> descendants) only: checking a
108
+ # leaf task does NOT imply its ancestors should also be checked, so a
109
+ # checked child under an unchecked parent is a valid (if visually
110
+ # inconsistent) state. Toggling a leaf task (no children) behaves exactly
111
+ # as it always has — no descendants to cascade into.
106
112
  #
107
113
  # ---------------------------------------------------------------------------
108
114
  # OUTPUT CONTRACT (deliberately NOT uniform JSON — see rationale below)
@@ -165,8 +171,15 @@
165
171
  # STATE FILE
166
172
  # ---------------------------------------------------------------------------
167
173
  # Created under `mktemp -t jenga-confirm-XXXXXX.json`. Stores:
168
- # - `numbering`: displayed number -> {item, level, checked} — the ONLY
169
- # field that mutates across turns is `checked`.
174
+ # - `numbering`: displayed number -> {item, level, checked, children} —
175
+ # `children` is a fixed list of the item's direct descendant numbers
176
+ # (a story's task numbers; an epic's story numbers), computed once at
177
+ # build time so continue-mode can cascade a toggle without
178
+ # re-deriving parent/child relationships from `item_id`/`epic_id`/
179
+ # `story_id` at toggle time. `children` is always `[]` for a leaf
180
+ # task. The only fields that mutate across turns are `checked` values
181
+ # (potentially many at once, via cascade — see TOGGLE COMMAND GRAMMAR
182
+ # above).
170
183
  # - `layout`: the fixed print order (item lines + header markers),
171
184
  # computed once at start. Continue mode never recomputes tree shape —
172
185
  # it only re-renders from `layout` + the live `checked` flags in
@@ -305,15 +318,17 @@ def pluralize_task(n):
305
318
  return f"{n} task{'' if n == 1 else 's'}"
306
319
 
307
320
 
308
- def add_item(item, level, indent):
321
+ def add_item(item, level, indent, parent_number=None):
309
322
  global counter
310
323
  n = str(counter)
311
324
  counter += 1
312
325
  suffix = ""
313
326
  if item.get("id") in undecomposed_ids:
314
327
  suffix = " [needs decomposition -- no children on the board yet]"
315
- numbering[n] = {"item": item, "level": level, "checked": True}
328
+ numbering[n] = {"item": item, "level": level, "checked": True, "children": []}
316
329
  layout.append({"kind": "item", "number": n, "level": level, "indent": indent, "suffix": suffix})
330
+ if parent_number is not None:
331
+ numbering[parent_number]["children"].append(n)
317
332
  return n
318
333
 
319
334
 
@@ -328,7 +343,7 @@ def append_suffix(extra):
328
343
 
329
344
 
330
345
  for e in epics:
331
- add_item(e, "epic", INDENT["epic"])
346
+ e_num = add_item(e, "epic", INDENT["epic"])
332
347
  child_stories = stories_by_epic.get(e["id"], [])
333
348
  story_count = len(child_stories)
334
349
  task_count = sum(len(tasks_by_story.get(s["id"], [])) for s in child_stories)
@@ -340,23 +355,23 @@ for e in epics:
340
355
  append_suffix(", ".join(parts))
341
356
 
342
357
  for s in child_stories:
343
- add_item(s, "story", INDENT["story"])
358
+ s_num = add_item(s, "story", INDENT["story"], parent_number=e_num)
344
359
  child_tasks = tasks_by_story.get(s["id"], [])
345
360
  if child_tasks:
346
361
  append_suffix(pluralize_task(len(child_tasks)))
347
362
  for t in child_tasks:
348
- add_item(t, "task", INDENT["task"])
363
+ add_item(t, "task", INDENT["task"], parent_number=s_num)
349
364
 
350
365
  if orphan_stories:
351
366
  layout.append({"kind": "header", "text": ""})
352
367
  layout.append({"kind": "header", "text": "-- Directly Selected Stories (no epic in this selection) --"})
353
368
  for s in orphan_stories:
354
- add_item(s, "story", INDENT["story"])
369
+ s_num = add_item(s, "story", INDENT["story"])
355
370
  child_tasks = tasks_by_story.get(s["id"], [])
356
371
  if child_tasks:
357
372
  append_suffix(pluralize_task(len(child_tasks)))
358
373
  for t in child_tasks:
359
- add_item(t, "task", INDENT["task"])
374
+ add_item(t, "task", INDENT["task"], parent_number=s_num)
360
375
 
361
376
  if orphan_tasks:
362
377
  layout.append({"kind": "header", "text": ""})
@@ -644,18 +659,40 @@ if invalid:
644
659
  print(f"STATE_FILE: {state_file_path}", file=sys.stderr)
645
660
  sys.exit(1)
646
661
 
662
+ def apply_cascade(num, value):
663
+ """Set `num`'s checked state to `value`, then recurse into every
664
+ number in its `children` list (a story's tasks; an epic's stories,
665
+ which recurse further into their own tasks). Strictly downward —
666
+ never touches a parent. A leaf task has an empty `children` list, so
667
+ this degenerates to exactly the old single-flag assignment for the
668
+ non-cascading base case."""
669
+ numbering[num]["checked"] = value
670
+ for child in numbering[num].get("children", []):
671
+ apply_cascade(child, value)
672
+
673
+
647
674
  # All-or-nothing application, de-duplicated (first-seen wins on dupes).
675
+ # Resulting values are computed from PRE-mutation state in a first pass,
676
+ # then applied (with cascade) in a second pass -- this avoids a
677
+ # parent-then-child (or child-then-parent) double-toggle artifact when a
678
+ # single reply lists both a parent and one of its own descendants, e.g.
679
+ # bare-number toggle "5,6" where 6 is a child of 5.
648
680
  seen = set()
681
+ pending = []
649
682
  for tok in valid_tokens:
650
683
  if tok in seen:
651
684
  continue
652
685
  seen.add(tok)
653
686
  if action == "check":
654
- numbering[tok]["checked"] = True
687
+ value = True
655
688
  elif action == "uncheck":
656
- numbering[tok]["checked"] = False
689
+ value = False
657
690
  else:
658
- numbering[tok]["checked"] = not numbering[tok]["checked"]
691
+ value = not numbering[tok]["checked"]
692
+ pending.append((tok, value))
693
+
694
+ for tok, value in pending:
695
+ apply_cascade(tok, value)
659
696
 
660
697
  state["numbering"] = numbering
661
698
  with open(state_file_path, "w", encoding="utf-8") as f:
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: jenga-permission-level
2
+ name: j:jenga-permission-level
3
3
  description: Report or switch the current session's 5-tier permission level (Locked/Guarded/Standard/Elevated/Unrestricted) without hand-editing settings.json.
4
4
  keywords:
5
5
  - "permission level"
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: lgtm
2
+ name: j:lgtm
3
3
  description: Approve and commit the current work, then continue to the next task. Shortcut that chains /commit followed by /continue.
4
4
  keywords:
5
5
  - lgtm
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: pi-plan
2
+ name: j:pi-plan
3
3
  description: Define or expand project Epics in PROJECT_SUMMARY.md. Use this at the start of a project to establish its foundation, AND whenever the user wants to add major new features, plan a significant new area of work, or make epic-level changes to an existing project. Trigger whenever you hear things like "new feature area", "big change", "new epic", "expand the project", "add a major capability", or "plan a new phase" — even mid-project.
4
4
  keywords:
5
5
  - epic
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: proceed
2
+ name: j:proceed
3
3
  description: Review project progress by checking epics and stories, optionally consulting PROJECT_SUMMARY.md and WARP.md, then continue executing the project plan.
4
4
  keywords:
5
5
  - proceed
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: publish
2
+ name: j:publish
3
3
  description: Configure, validate, and orchestrate scaffolded release workflows through a single `/publish` entry point with bounded sub-commands.
4
4
  keywords:
5
5
  - publish
@@ -99,11 +99,33 @@ Run the adapter phases in this exact order:
99
99
  ```yaml
100
100
  permissions:
101
101
  id-token: write
102
- contents: read
102
+ contents: write
103
103
  ```
104
- and runs `npm publish --provenance` to attach a build provenance attestation
105
- to the published package. In `--dry-run` mode, print the rendered YAML to
106
- stdout and exit 0 without writing any file.
104
+ (`contents: write` — bumped from `read` — is required so the `publish` and
105
+ `stage` jobs can push the tags described below; this is the CI's own token
106
+ gaining write access to tag *its own* repository, nothing else, and no new
107
+ secret or credential is introduced) and runs `npm publish --provenance` to
108
+ attach a build provenance attestation to the published package. In
109
+ `--dry-run` mode, print the rendered YAML to stdout and exit 0 without
110
+ writing any file.
111
+
112
+ Each job also gains a final step, gated on `if: success()` so a failed
113
+ publish/stage never creates or moves a tag:
114
+ - **`publish` job — "Tag prod release and remove stage tag":** reads the
115
+ version from `package.json`, tags the checked-out commit `v<version>`
116
+ (no force — this tag is immutable; a genuine collision fails loudly
117
+ rather than silently moving a prod tag), pushes it, then best-effort
118
+ deletes the corresponding `v<version>-stage` tag both locally and on the
119
+ remote (tolerating its absence, e.g. a prod publish that skipped
120
+ staging).
121
+ - **`stage` job — "Tag stage release":** reads the version the same way
122
+ and tags the checked-out commit `v<version>-stage` — a **mutable**
123
+ pointer, force-created (`git tag -f`) and force-pushed, so re-staging the
124
+ same version moves the tag rather than failing.
125
+
126
+ Both new steps configure a `github-actions[bot]` git identity
127
+ (`user.name`/`user.email`) before tagging, since no prior step in the
128
+ workflow sets one.
107
129
 
108
130
  3. **`commit-workflow`** — write the generated YAML to `<workflow_path>`
109
131
  (creating the `.github/workflows/` directory if needed) and commit it with:
@@ -172,7 +172,7 @@ on:
172
172
 
173
173
  permissions:
174
174
  id-token: write
175
- contents: read
175
+ contents: write
176
176
 
177
177
  jobs:
178
178
  publish:
@@ -194,6 +194,17 @@ jobs:
194
194
  - name: Publish to npm
195
195
  run: npm publish --provenance --access ${NPM_ACCESS} --tag ${DIST_TAG}
196
196
 
197
+ - name: Tag prod release and remove stage tag
198
+ if: success()
199
+ run: |
200
+ git config user.name "github-actions[bot]"
201
+ git config user.email "github-actions[bot]@users.noreply.github.com"
202
+ VERSION="\$(node -p "require('./package.json').version")"
203
+ git tag "v\${VERSION}"
204
+ git push origin "v\${VERSION}"
205
+ git tag -d "v\${VERSION}-stage" 2>/dev/null || true
206
+ git push origin ":refs/tags/v\${VERSION}-stage" 2>/dev/null || true
207
+
197
208
  stage:
198
209
  if: \${{ github.event.inputs.mode == 'stage' }}
199
210
  runs-on: ubuntu-latest
@@ -212,6 +223,15 @@ jobs:
212
223
 
213
224
  - name: Stage to npm
214
225
  run: npm stage publish --provenance --access ${NPM_ACCESS} --tag ${DIST_TAG}
226
+
227
+ - name: Tag stage release
228
+ if: success()
229
+ run: |
230
+ git config user.name "github-actions[bot]"
231
+ git config user.email "github-actions[bot]@users.noreply.github.com"
232
+ VERSION="\$(node -p "require('./package.json').version")"
233
+ git tag -f "v\${VERSION}-stage"
234
+ git push origin "v\${VERSION}-stage" --force
215
235
  EOF
216
236
  )"
217
237
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: reconcile
2
+ name: j:reconcile
3
3
  description: Reconcile the scrum board with actual implementation state. Cross-checks every task's board status against git history and worktrees, merges orphaned worktree branches, demotes unimplemented "Done" items, promotes secretly-implemented items, flags code with no board provenance and offers /uncharted segment for it, and cleans stale entries from todo.md. Use when the board feels out of sync, after a big merge session, when tasks were completed outside the normal workflow, or when todo.md has grown stale. Trigger on phrases like "sync the board", "clean up the board", "reconcile", "board is out of date", "todo is stale", or "check what's really done".
4
4
  metadata:
5
5
  prefered_agent: scrum-master
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: reconcile-origin
2
+ name: j:reconcile-origin
3
3
  description: Sync the current (or specified) branch with origin by rebasing local commits on top of the latest upstream state.
4
4
  keywords:
5
5
  - "sync branch"
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: redo
2
+ name: j:redo
3
3
  description: Redo parts or entire previous implementations identified by a commit SHA or an Epic/Story number (e.g. E01, E02_S03). Expects an identifier and a description of what to redo and why. Use when the user wants to revisit, rework, or rewrite previously completed work, including updating all affected documentation.
4
4
  keywords:
5
5
  - redo
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: skillify
2
+ name: j:skillify
3
3
  description: Refactor one or more existing skills into a cleaner, more maintainable structure — extracting hardcoded content into asset files, offloading deterministic steps into scripts, and reorganizing the skill body to reflect the leaner result. Use this whenever the user wants to clean up, improve, or restructure an existing skill, mentions that a skill has hardcoded content that could be templated, or asks to "skillify", "refactor", or "tidy up" a skill. Trigger even if the user just pastes a skill and says something like "can we make this better?".
4
4
  ---
5
5
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: spinoff
2
+ name: j:spinoff
3
3
  description: Capture a diverging topic mid-conversation. Collects context and a mandatory origin, optionally runs /brainstorm for prerequisites, saves an /idea entry, and returns focus to the primary thread.
4
4
  keywords:
5
5
  - spinoff
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: status
2
+ name: j:status
3
3
  description: Print a human-readable summary of the entire scrum board — all epics, stories, and tasks with their statuses — plus any open rapports and unprocessed queue triggers. Use when you want a quick overview of project state without reading raw files.
4
4
  keywords:
5
5
  - status
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: todo
2
+ name: j:todo
3
3
  description: Add missions to the project todo list (project/todo.md), optionally linking them to epics and stories. Loops until the user is done, then optionally executes the list.
4
4
  keywords:
5
5
  - todo
@@ -16,6 +16,16 @@ metadata:
16
16
 
17
17
  # Todo — Add Missions to the Todo List
18
18
 
19
+ ## `--trivial` Flag
20
+
21
+ **Syntax:** `/todo --trivial <description>` — optionally combined with the same `: <Epic no.>_<Story no.>` linkage syntax normal `/todo` entries use, e.g. `/todo --trivial Fix typo in error message: E12_S03`.
22
+
23
+ When `--trivial` is present, the mission is written as a **fully-formed task board file immediately** (not just a raw `todo.md` line deferred to `/do`'s own breakdown pass) with `execution_scope: inline` forced unconditionally — no threshold computation is consulted for the scope value itself. See step 4.5 below for the mechanics.
24
+
25
+ **Human-only override.** `--trivial` is invoked by a human typing `/todo --trivial ...` — it is never applied by the scrum-master to itself during autonomous story/epic breakdown elsewhere (e.g. `/jenga`'s Phase 0.5, or `/do`'s own scrum-master decomposition step in `skills/do/SKILL.md` step 3). Those paths keep using the normal heuristic-only `execution_scope` assignment documented in `agents/scrum-master.md`'s Execution Scope Assignment section, unmodified by this flag.
26
+
27
+ **Fallback on failure is out of scope here.** If a `--trivial`-forced inline run fails the smoke-harness or shows scope creep at dispatch time, `/do`'s own `--trivial` handling (a separate task, E32_S14_T02) is responsible for falling back to the full `task` pipeline — this skill only ever writes the initial forced-inline task.
28
+
19
29
  ## Instructions
20
30
 
21
31
  1. **Ensure `project/todo.md` exists** — If it doesn't exist, it will be auto-created by `todo_manager.sh` — no manual action needed.
@@ -24,6 +34,7 @@ metadata:
24
34
  - Where do you want to do this?
25
35
  - What would you like to do?
26
36
  - What is the goal?
37
+ - (If `--trivial` was passed, these answers still apply — `--trivial` changes how the mission is written to the board in step 4.5, not what's asked here.)
27
38
 
28
39
  3. **Classify the mission** — Check if it fits into:
29
40
  - An existing story
@@ -31,18 +42,44 @@ metadata:
31
42
  - A new story inside a new Epic
32
43
  - None of the above
33
44
 
45
+ **`--trivial` requires an existing (or, in this same step, newly-created) story to attach to.** It forces the scope of a single task, not a container — if the mission has no story yet, create it now via step 4 below exactly as normal, then continue to step 4.5. `--trivial` cannot be used for "None of the above."
46
+
34
47
  4. **Update project documentation** — Add the mission to the appropriate files under `project/board/epics/` and `project/board/stories/` if applicable.
35
48
  - If the mission involves implementing or modifying a skill, apply the **Skill Implementation Principle — Scripts Over Inline Logic** (see `CLAUDE.md` / `AGENTS.md`): note in the story/task's acceptance criteria that deterministic, repeatable steps must be offloaded to scripts under `skills/<name>/scripts/` (or `scripts/`) rather than encoded as inline agent instructions in `SKILL.md`.
36
49
  - If the user indicates the mission is high-risk, or explicitly asks to flag it, set an elevated caution tier directly on the story or task frontmatter: `crucial_level` (one of `advisory`, `gated`, `locked` — see `templates/SCRUM_BOARD_SCHEMA.md` for valid values and their meaning), `crucial_set_by: user`, and `crucial_note` capturing the user's stated reason. This user-initiated flag is written immediately — it does not require the confirm-before-write gate, which applies only to scrum-master-*proposed* caution tiers (a separate, heuristic-driven path).
37
50
 
38
- 5. **Add to `project/todo.md`** by running:
51
+ 4.5. **If `--trivial` was passed, create the task now** (skip step 5 — this step writes the todo.md entry itself):
52
+
53
+ a. **Estimate the change**, using the same judgment `agents/scrum-master.md`'s Execution Scope Assignment heuristic applies: how many files will this mission likely touch, and roughly how many lines. This is a reasoning step, not a script step — do not guess wildly, but a rough, honest estimate is sufficient.
54
+
55
+ b. **Determine `computed_tier`** — what `execution_scope` the normal heuristic would have assigned to this estimate, purely for the audit trail (it is never written as the actual `execution_scope`, which is always forced to `inline`):
56
+ - Read `inline_max_files`, `inline_max_lines`, and `story_max_files` from `project/configs/scope-thresholds.json` at run time — never hardcode these numbers here.
57
+ - Apply `agents/scrum-master.md`'s `inline` / `story` / `task` heuristics (file count vs. `inline_max_files`, line estimate vs. `inline_max_lines`, contention and cross-cutting checks for `story`) to the estimate from (a). The result is `computed_tier` — one of `inline`, `task`, or `story` (never `epic` — the heuristic never autonomously computes `epic`).
58
+
59
+ c. **Run the helper script**, which handles everything mechanical — next task-ID assignment, writing the task board file with `execution_scope: inline` forced, registering the new task ID into the parent story's `tasks:` frontmatter list, and adding the `project/todo.md` entry using the full task ID (so `/do` routes straight into its Inline Execution Path with no redundant breakdown pass):
60
+ ```
61
+ bash skills/todo/scripts/add_trivial_task.sh \
62
+ --story <E##_S##> \
63
+ --title "<mission title>" \
64
+ --description "<mission description>" \
65
+ --criteria "<criterion 1>|<criterion 2>|..." \
66
+ --computed-tier <inline|task|story> \
67
+ --est-files <N> \
68
+ --est-lines <M> \
69
+ [--prerequisites "<text>"]
70
+ ```
71
+ The script writes `scope_rationale` in the form `"forced inline via --trivial; computed scope would have been '<computed_tier>' — estimated <N> files, ~<M> lines"` and sets `jenga_assigned: false` with a matching `override_justification`, so `/do` step 4.1's existing override-validation logs the override on dispatch — no separate acknowledgement step needed here.
72
+ On success the script prints the new task ID to stdout; on failure (e.g. the story doesn't exist yet, or `--computed-tier` is invalid) it exits non-zero with an explanatory message on stderr — surface that to the user rather than retrying blindly.
73
+ d. Continue to step 6 (skip step 5 — the script already added the `todo.md` entry).
74
+
75
+ 5. **Add to `project/todo.md`** by running (skip this step if step 4.5 already ran):
39
76
  ```
40
77
  bash scripts/todo_manager.sh add '<mission title>: <Epic no.>_<Story no.>'
41
78
  ```
42
79
  The epic and story reference is only required if the mission is assigned to one.
43
80
 
44
81
  6. **Ask the user**: "Add another todo" or "Done"?
45
- - If **add another** — go back to step 2.
82
+ - If **add another** — go back to step 2. (`--trivial` applies only to the mission it was passed with — it does not carry over to the next mission unless the user says `--trivial` again.)
46
83
  - If **done** — ask if they want to execute the todo list.
47
84
  - If **yes** — invoke the `/do` skill.
48
85
  - If **no** — exit.