@jesdi/skills 0.0.20 → 0.0.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jesdi/skills",
3
- "version": "0.0.20",
3
+ "version": "0.0.21",
4
4
  "description": "jesdi's agent skills (content package consumed by @jesdi/skills-cli)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -71,8 +71,12 @@ TypeScript targets still need `node` and the project's own `typescript` package.
71
71
  Coverage commands still need the project's test dependencies; configure them
72
72
  with its normal runner (for example, `cd backend && pipenv run pytest ...`).
73
73
  The launcher preserves PATH and the caller's environment for these commands;
74
- its private Python is only for the gate engine. It does not install project
75
- dependencies or edit project environments.
74
+ its private Python is only for the gate engine. One exception: when no
75
+ virtualenv is active and the repo root has `.venv/bin`, that directory goes
76
+ first on PATH, so a bare `python -m coverage` reaches the project's
77
+ interpreter. It does not install project dependencies or edit project
78
+ environments. When a command writes no report, the error ends with the last
79
+ lines of its log.
76
80
 
77
81
  By default the engine runs each target's coverage command only when that
78
82
  target has changed files, so a backend-only change never runs the frontend
@@ -12,6 +12,7 @@ from __future__ import annotations
12
12
 
13
13
  import argparse
14
14
  import json
15
+ import os
15
16
  import subprocess
16
17
  import sys
17
18
  import tempfile
@@ -109,6 +110,18 @@ def _score_target(
109
110
 
110
111
  # ── coverage commands ───────────────────────────────────────────────────────
111
112
 
113
+ def _coverage_env(root: Path) -> dict[str, str]:
114
+ """The caller's environment, plus the repo's `.venv/bin` first on PATH when
115
+ no virtualenv is active, so a bare `python -m coverage` finds the project's
116
+ interpreter instead of one without its test dependencies."""
117
+ env = dict(os.environ)
118
+ venv = root / ".venv"
119
+ if not env.get("VIRTUAL_ENV") and (venv / "bin").is_dir():
120
+ env["VIRTUAL_ENV"] = str(venv)
121
+ env["PATH"] = f"{venv / 'bin'}{os.pathsep}{env.get('PATH', '')}"
122
+ return env
123
+
124
+
112
125
  def _maybe_run_coverage(target: Target, root: Path, run_mode: str, needed: bool) -> TargetRun:
113
126
  report = root / target.coverage_report
114
127
  should_run = run_mode == "run" or (run_mode == "auto" and needed)
@@ -126,13 +139,17 @@ def _maybe_run_coverage(target: Target, root: Path, run_mode: str, needed: bool)
126
139
  # config (same trust model as a Makefile or no-mistakes' commands.*), never
127
140
  # user input — it needs `cd … && …`, env assignments and pipes.
128
141
  with log.open("w") as fh:
129
- proc = subprocess.run(target.coverage_command, shell=True, cwd=root, stdout=fh, stderr=subprocess.STDOUT)
142
+ proc = subprocess.run(
143
+ target.coverage_command, shell=True, cwd=root, env=_coverage_env(root),
144
+ stdout=fh, stderr=subprocess.STDOUT,
145
+ )
130
146
  seconds = time.monotonic() - started
131
147
  fresh = report.exists() and (before is None or report.stat().st_mtime_ns > before)
132
148
  if not fresh:
133
149
  raise ToolError(
134
150
  f"{target.name}: coverage command exited {proc.returncode} and wrote no report "
135
- f"({target.coverage_report}); see {log.relative_to(root)}"
151
+ f"({target.coverage_report}); see {log.relative_to(root)}. Last lines:\n"
152
+ + "\n".join(log.read_text(errors="replace").splitlines()[-10:])
136
153
  )
137
154
  if proc.returncode != 0:
138
155
  print(
@@ -69,7 +69,8 @@ if [ ! -x "$uv" ]; then
69
69
  fi
70
70
 
71
71
  # Limit uv settings to this subprocess. Do not activate a venv or change PATH:
72
- # coverage commands must inherit the caller's project environment unchanged.
72
+ # coverage commands inherit the caller's project environment (the engine adds
73
+ # only the repo's own .venv/bin, when no virtualenv is active).
73
74
  managed_uv() (
74
75
  unset UV_NO_MANAGED_PYTHON UV_PYTHON UV_PYTHON_DOWNLOADS UV_PYTHON_BIN_DIR
75
76
  export UV_PYTHON_INSTALL_DIR="$cache/python"
@@ -150,3 +150,27 @@ def test_config_not_at_git_toplevel_is_a_tool_error(tmp_path, monkeypatch, capsy
150
150
  monkeypatch.chdir(sub)
151
151
  assert crap.main([]) == 2
152
152
  assert "git repository root" in capsys.readouterr().err
153
+
154
+
155
+ def test_coverage_command_prefers_the_repo_venv(repo, monkeypatch, capsys):
156
+ # A bare `python` in the command must reach the repo's .venv, not whatever
157
+ # interpreter the caller's PATH has (which may lack coverage).
158
+ monkeypatch.delenv("VIRTUAL_ENV", raising=False)
159
+ venv_bin = repo / ".venv" / "bin"
160
+ venv_bin.mkdir(parents=True)
161
+ (venv_bin / "venvpy").write_text('#!/bin/sh\nexec python3 "$@"\n')
162
+ (venv_bin / "venvpy").chmod(0o755)
163
+ cfg = json.loads((repo / ".crap-gate.json").read_text())
164
+ cfg["targets"][0]["coverage"]["command"] = "venvpy fake_cov.py"
165
+ (repo / ".crap-gate.json").write_text(json.dumps(cfg))
166
+ (repo / "pkg" / "m.py").write_text(BASE_SRC + "\n\ndef k():\n return 1\n")
167
+ assert crap.main([]) == 0
168
+
169
+
170
+ def test_coverage_command_without_report_shows_the_log_tail(repo, capsys):
171
+ cfg = json.loads((repo / ".crap-gate.json").read_text())
172
+ cfg["targets"][0]["coverage"]["command"] = "echo 'No module named coverage' && exit 1"
173
+ (repo / ".crap-gate.json").write_text(json.dumps(cfg))
174
+ (repo / "pkg" / "m.py").write_text(BASE_SRC + "\n\ndef k():\n return 1\n")
175
+ assert crap.main([]) == 2
176
+ assert "No module named coverage" in capsys.readouterr().err
@@ -11,7 +11,10 @@ Changes: a model tier per subagent; a context-isolated test-writer commits
11
11
  locked acceptance tests at the ticket's Seam, the implementer turns them green
12
12
  with /tdd and reports to a contract; per-ticket review before merge, fix loop
13
13
  capped at 4 rounds with escalation; a ruling ledger and four stop conditions;
14
- a per-ticket gate (check command + crap-gate) before DONE, re-run by the reviewer; check command after each merge; final /review-diff on the most capable model, one
14
+ a per-ticket gate (check command + crap-gate) before DONE, re-run by the reviewer;
15
+ already-green locked tests need a demonstrated mutation; a Codex correctness
16
+ pass per risky ticket; tickets touching the same functions run in sequence;
17
+ check command after each merge; final /review-diff on the most capable model, one
15
18
  fixer; closes tickets only if they are issues. Review loop and ledger adapt
16
19
  superpowers' subagent-driven-development (obra/superpowers, MIT).
17
20
  -->
@@ -26,6 +29,8 @@ Communication to and from subagents should be sparse. Communicate primarily thro
26
29
 
27
30
  Run ticket subagents in the background where possible for **maximum concurrency**.
28
31
 
32
+ **Every dispatch prompt says: never `git stash`, reset or check out other branches; worktrees share one stash and one ref store.**
33
+
29
34
  **Name the model on every dispatch.** Omitted, it inherits yours. Exploration, test-writer, reviewer: mid tier (reviewer higher for risky diffs). Implementer: mid tier; cheapest when the ticket carries the complete code; most capable for design judgment or broad codebase work. Merger: cheapest. Escalations: one tier above the agent that got stuck. Final reviewer: most capable.
30
35
 
31
36
  **Rule, don't stall.** Keep a **ledger** file in the notes directory: every decision as `Ruling: <what> — <why> — <cost if wrong>`, and each ticket's state, so you can resume after compaction. Don't check in between tickets. Stop and ask only for: an irreversible or destructive operation, a security-sensitive action, a side effect outside the worktrees (a push to a shared branch, a publish), or a spec so broken that every path forward is a guess.
@@ -38,15 +43,19 @@ Run ticket subagents in the background where possible for **maximum concurrency*
38
43
 
39
44
  3. Create a branch, and a draft PR. If the spec and tickets are issues, mark the PR as 'closing' them.
40
45
 
41
- 4. Each ticket gets its own worktree and branch. For a ticket with behavioral criteria, a **test-writer subagent** goes first. It sees ONLY the spec, the ticket, CONTEXT.md/ADRs and the public interface of the ticket's **Seam** line (pointers, not summaries), never the implementer's plan or code. It writes one black-box acceptance test per criterion through that interface (defining the interface if it doesn't exist yet), confirms each fails for the right reason (missing behavior, not an import or syntax error), commits them red, and reports the SHA and files. Those files are now **locked**. A ticket with no behavioral criteria (Seam: `none — refactor`) skips this: its existing tests are the contract, unmodified.
46
+ 4. Each ticket gets its own worktree and branch. For a ticket with behavioral criteria, a **test-writer subagent** goes first. It sees ONLY the spec, the ticket, CONTEXT.md/ADRs and the public interface of the ticket's **Seam** line (pointers, not summaries), never the implementer's plan or code. It writes one black-box acceptance test per criterion through that interface (defining the interface if it doesn't exist yet), confirms each fails for the right reason (missing behavior, not an import or syntax error), commits them red, and reports the SHA and files. A test that is already green before any implementation is vacuous until proven otherwise (an earlier guard or early return often satisfies it for an unrelated reason): the test-writer rewrites it to fail, or, when the criterion truly holds already, reports the production-code mutation that turns it red and the red output. Those files are now **locked**. A ticket with no behavioral criteria (Seam: `none — refactor`) skips this: its existing tests are the contract, unmodified.
42
47
 
43
48
  5. An **implementer subagent** starts from that commit and makes the locked tests green, using /tdd vertical slices for anything internal. It never edits locked files and never dispatches subagents. Before reporting DONE it runs the **gate** in its worktree: the repo's check command (lint, typecheck, full test suite: `make check`, or what AGENTS.md documents) and, when the repo has `.crap-gate.json`, crap-gate scoped to the ticket (`run.sh --base <PR branch>`, or the repo's `make crap-gate` wrapper). DONE means both are green; a gate it can't turn green is BLOCKED, with the output. It reports: status (DONE, DONE_WITH_CONCERNS, NEEDS_CONTEXT or BLOCKED), commits, red→green evidence for locked tests and its own slices, the gate's final lines, files touched, concerns. If a locked test contradicts the spec or ticket, it reports BLOCKED with evidence; you rule, and either send the test-writer a correction or overrule the implementer. Handle any BLOCKED by changing something: more context, a stronger model, a split ticket, or a ruling. Never retry unchanged.
44
49
 
45
- 6. On DONE, a **reviewer subagent** re-runs the gate first (a red gate is a Critical finding; don't trust the report), then checks the diff against the ticket and spec, then for quality. It also checks that `git diff <test-writer-sha>..HEAD -- <locked files>` is empty and that every criterion has a locked test. Critical or Important findings start a fix loop of at most 4 rounds, each a fix plus a re-review scoped to that fix: rounds 1-2 resume the implementer; rounds 3-4 go to a fresh implementer one tier up. After round 4, rule on each open finding in the ledger and move on. Minor findings go to the ledger for the final review.
50
+ 6. On DONE, a **reviewer subagent** re-runs the gate first (a red gate is a Critical finding; don't trust the report), then checks the diff against the ticket and spec, then for quality. It also checks that `git diff <test-writer-sha>..HEAD -- <locked files>` is empty and that every criterion has a locked test. For each locked test, it breaks the production line the test exists to protect (a temporary edit, reverted after) and confirms that test goes red; a test that stays green is Critical. It re-runs every mutation the test-writer reported. Name your specific suspicions in the reviewer prompt (a sibling caller, a key built from the old identity, a guard another ticket added): named suspicions find regressions a generic review misses.
51
+
52
+ A **risky** ticket touches shared state, persistence keys or identities, concurrency, money or auth. For those, run the correctness pass from /review-diff yourself, in parallel with the reviewer: `codex exec` with that skill's `correctness.md` on range `<PR branch>...<ticket branch>` (three dots: from the merge-base, so tickets merged meanwhile don't show up), in quick mode (the command is in the review-diff skill). Its findings join the reviewer's, with the same severities.
53
+
54
+ Critical or Important findings start a fix loop of at most 4 rounds, each a fix plus a re-review scoped to that fix: rounds 1-2 resume the implementer; rounds 3-4 go to a fresh implementer one tier up. After round 4, rule on each open finding in the ledger and move on. Minor findings go to the ledger for the final review.
46
55
 
47
56
  7. Once a ticket passes review, a **merger subagent** merges it to the PR branch and runs the repo's check command (lint, typecheck, full suite). If it fails, an implementer fixes the PR branch before the next merge.
48
57
 
49
- 8. If this changes the **frontier** of available tickets, start the next tickets. This allows for maximum concurrency.
58
+ 8. If this changes the **frontier** of available tickets, start the next tickets. This allows for maximum concurrency. Exception: two ready tickets that change the same function never run at once. Compare their **Touches** lines (or ask the exploration subagent where each will land); on overlap, start one and hold the other until the first merges, then branch it from the updated PR branch. Record the hold as a ruling.
50
59
 
51
60
  9. Once all tickets are complete, a reviewer on the most capable model runs /review-diff on the PR branch, given the ledger's minor findings and rulings. One **implementer subagent** fixes every finding, then re-review that fix once. Rule on anything left.
52
61
 
@@ -40,11 +40,30 @@ Given the tables/fields (from `design.md` or a sketch), produce:
40
40
  4. **Permissions** — who can see or mutate what; staff vs. customer vs. owner
41
41
  boundaries; what an authenticated-but-wrong-role request can still reach.
42
42
 
43
+ ## Identity inventory (when the change widens a key)
44
+
45
+ When the change widens an identity or key space (`issue` becomes
46
+ `target#issue`, `user` becomes `tenant+user`), the top 5 is not enough: one
47
+ missed identity is a cross-tenant bug. After the top 5, grep the code for every
48
+ identity built from the old key and list each one as **covered** (the design
49
+ rekeys it) or **out of scope** (with the reason). Look for:
50
+
51
+ - file and directory names (`task-{N}.json`, `messages/{issue}.jsonl`),
52
+ including legacy files a save or migration retires;
53
+ - hashes, fingerprints and dedupe keys;
54
+ - cache keys, lock names, markers, dict and set keys;
55
+ - command and URL arguments that take the bare key (`/attach N`);
56
+ - log and event fields other code reads back.
57
+
58
+ This list is exhaustive, not ranked. It is not a fix: say what is keyed by
59
+ the old identity, not how to rekey it.
60
+
43
61
  ## What NOT to do
44
62
 
45
63
  - Don't suggest schema changes, indexes, or constraints — that's the design
46
64
  session's job, after this list exists.
47
65
  - Don't hedge with "it depends" — pick the worst plausible interpretation and
48
66
  state its consequence.
49
- - Don't produce more than 5. Rank and cut; the top failure matters more than
50
- a complete list.
67
+ - Don't produce more than 5 failure scenarios. Rank and cut; the top failure
68
+ matters more than a complete list. (The identity inventory is the one
69
+ exhaustive list.)
@@ -43,12 +43,15 @@ the spec before the design is written. Don't write code.
43
43
  Run only when asked (for example "/to-openspec <slug> stage 2"), after the human has reviewed
44
44
  stage 1. Re-read `proposal.md` and `spec.md` first; the human may have edited them.
45
45
 
46
- 1. Run the `red-team-data-model` skill against the data model. Print the top 5; don't write them
47
- to a file.
46
+ 1. Run the `red-team-data-model` skill against the data model. Print the top 5, and its identity
47
+ inventory when the change widens a key; don't write them to a file.
48
48
  2. Write `specs/<slug>/design.md`:
49
49
  - **Decisions**: one line each with its tradeoff. Include the ones the red-team findings force.
50
50
  - **Data model**: every invariant a DB constraint can enforce (`CHECK`, `UNIQUE`, `NOT NULL`,
51
51
  FK, conditional `UPDATE ... WHERE`) goes in the table, not only in app code.
52
+ - **Identities**: when the change widens a key, every item of the red-team's identity
53
+ inventory, marked covered (task IDs filled in step 3) or out of scope (why). Otherwise "None." Add the
54
+ heading when the repo's template lacks it.
52
55
  - **Seams**: the endpoint, function, or command the tests drive through, marked existing or
53
56
  new. Prefer one high seam.
54
57
  3. Write `specs/<slug>/tasks.md`: vertical slices, each small enough for one commit and one green
@@ -58,6 +61,8 @@ stage 1. Re-read `proposal.md` and `spec.md` first; the human may have edited th
58
61
  makes the list a task graph `implement-spec` can run directly.
59
62
  - A slice adds only the tables and columns its own scenarios need, not the whole model up front.
60
63
  - No standalone "run the checks" task: every task already ends with the check command green.
64
+ - Then fill the task IDs into `design.md`'s **Identities**: every identity marked covered names
65
+ the task that rekeys it. A covered identity with no task is a missing task; add it.
61
66
 
62
67
  Print the task list, then **Open questions**: every red-team finding the design leaves
63
68
  unresolved, and every input the design assumes but the sources don't provide. Then stop. Don't
@@ -14,6 +14,14 @@ Tables/fields touched or added, and the invariants that go in DB constraints (no
14
14
  |---|---|---|---|
15
15
  | | | | |
16
16
 
17
+ ## Identities
18
+
19
+ When this change widens a key, each identity built from the old key (file names, hashes,
20
+ dedupe keys, command args, dict keys): covered by which task, or out of scope and why. Otherwise
21
+ "None."
22
+
23
+ - `<identity>` — covered by <task> | out of scope: <why>.
24
+
17
25
  ## Seams
18
26
 
19
27
  Where tests drive through: module, function, command, or endpoint. Mark each existing or new.
@@ -9,8 +9,9 @@ Modified copy of https://github.com/mattpocock/skills/tree/3cca18b368ae95cdbdebb
9
9
  Changes: tickets always go to `.agent/tickets/<NN>-<slug>.md` (no tracker path);
10
10
  numbering is contiguous from 01 in dependency order; acceptance criteria must state
11
11
  observable behavior; every ticket names its **Seam** (the public interface its
12
- acceptance tests hit); the approval quiz is skipped when unattended; model
13
- invocation is allowed.
12
+ acceptance tests hit) and what it **Touches** (files and functions, for
13
+ scheduling); the approval quiz is skipped when unattended; model invocation is
14
+ allowed.
14
15
  -->
15
16
 
16
17
  # To Tickets
@@ -53,6 +54,7 @@ When a human is in the loop, present the proposed breakdown as a numbered list.
53
54
  - **Title**: short descriptive name
54
55
  - **Blocked by**: which other tickets (if any) must complete first
55
56
  - **Seam**: the public interface its acceptance tests hit
57
+ - **Touches**: the files and functions it expects to change
56
58
  - **What it delivers**: the end-to-end behaviour this ticket makes work
57
59
 
58
60
  Ask the user:
@@ -85,6 +87,8 @@ Do NOT close or modify any parent issue.
85
87
 
86
88
  **Seam:** the public interface the acceptance tests hit (a function, an HTTP route, a CLI command, a config loader…), or `none — refactor`.
87
89
 
90
+ **Touches:** the files, and the functions within them, this ticket expects to change.
91
+
88
92
  - [ ] Acceptance criterion 1
89
93
  - [ ] Acceptance criterion 2
90
94
 
@@ -102,4 +106,10 @@ Every ticket carries a **Seam** line: the one public interface through which its
102
106
 
103
107
  </seam-rule>
104
108
 
105
- Avoid specific file paths or code snippets: they go stale fast. Exception: if a prototype produced a snippet that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), inline it and note briefly that it came from a prototype. Trim to the decision-rich parts, not a working demo, just the important bits.
109
+ <touches-rule>
110
+
111
+ The **Touches** line is a best guess, for scheduling: `implement-spec` never runs two tickets at once that change the same function, because parallel restructures of one function turn into rebase churn and broken locked tests. Name functions, not only files, when a file is shared (`dispatcher/main.py: _run_pass, _resume_woken`). Two tickets restructuring the same function is also a hint to add a blocking edge between them, or to merge them.
112
+
113
+ </touches-rule>
114
+
115
+ Outside the **Touches** line, avoid specific file paths or code snippets: they go stale fast. Exception: if a prototype produced a snippet that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), inline it and note briefly that it came from a prototype. Trim to the decision-rich parts, not a working demo, just the important bits.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-09-24T15:47:23.496Z",
3
+ "generatedAt": "2026-09-24T19:16:41.414Z",
4
4
  "skills": [
5
5
  {
6
6
  "name": "backlog",
@@ -22,8 +22,8 @@
22
22
  },
23
23
  {
24
24
  "name": "crap-gate",
25
- "version": "0.1.3",
26
- "hash": "sha256-39041927a985061599a39bb287232b83655ecbac61b7de52486f485991a99d30",
25
+ "version": "0.1.4",
26
+ "hash": "sha256-a3fe7bcb7ad6566aa25c44b0bc7823c625b536b4f3eb5cdfe73e6628ad04ee05",
27
27
  "description": "Score every function a branch changed with CRAP (cyclomatic complexity × untested fraction), fail on existing functions above 15 and new functions above 9, and drive a fixer + independent reviewer loop until the gate passes. Use when implementation is done and before pushing, when the user says \"run the crap gate\", \"check CRAP\", \"is this change tested enough\", or when a push gate reports CRAP violations."
28
28
  },
29
29
  {
@@ -46,8 +46,8 @@
46
46
  },
47
47
  {
48
48
  "name": "implement-spec",
49
- "version": "0.1.1",
50
- "hash": "sha256-678f3481bce18448d0d27ef33c096d4b64faf8dd7254dd8d0bc73f8c134a7f58",
49
+ "version": "0.1.2",
50
+ "hash": "sha256-ae8c88981b359c9b19ba285bacc38264ba11dca163be7b1fde4ff73ac278465b",
51
51
  "description": "Implement a specification in code."
52
52
  },
53
53
  {
@@ -64,8 +64,8 @@
64
64
  },
65
65
  {
66
66
  "name": "red-team-data-model",
67
- "version": "0.1.0",
68
- "hash": "sha256-3c7a00bbb05190a431ea101db79b6e27bbfc6c8b24b14b0fe560a82a201afdb9",
67
+ "version": "0.1.1",
68
+ "hash": "sha256-37737ab44c3c2f4812ceedbf2a14cdb259ceca0c8d8b9bb9ac9af92b23742808",
69
69
  "description": "Attack a proposed or existing data model for the ways it breaks under real conditions — concurrency, time windows, money, permissions — without proposing a redesign. Use right after sketching a data model, before writing the spec, so the top failure scenarios shape the spec's requirements and tests instead of getting discovered mid-build. Trigger on \"red-team my data model\", \"what breaks in this schema\", or \"/red-team\"."
70
70
  },
71
71
  {
@@ -76,8 +76,8 @@
76
76
  },
77
77
  {
78
78
  "name": "to-openspec",
79
- "version": "0.1.0",
80
- "hash": "sha256-c3c66a08fe27afa1f530989b77c7b4fd2d6a379cc844a9ca5f55072bede9b64a",
79
+ "version": "0.1.1",
80
+ "hash": "sha256-223f00ac309e5365e77708e8f3fc22c36a02e52f4c071af54ea25ea4d9461965",
81
81
  "description": "Turn settled discovery notes and a sketched data model into a spec folder in openspec shape (proposal, spec, design, tasks) under specs/<slug>/. Runs in two stages with a human review between them. No interview, just synthesis of decisions already made. Trigger on \"write the spec\", \"to-openspec\", or \"/to-openspec <slug> [stage 2]\"."
82
82
  },
83
83
  {
@@ -88,8 +88,8 @@
88
88
  },
89
89
  {
90
90
  "name": "to-tickets",
91
- "version": "0.1.1",
92
- "hash": "sha256-4c838fa240c742353f77b3a3c1246a0948140587e81c9bc587f84c648e552bba",
91
+ "version": "0.1.2",
92
+ "hash": "sha256-13e639c6412c6d875d285e452fd0f8c64597c4653cedbbe0e7aa0c19cd717ec1",
93
93
  "description": "Break a spec, plan, or the current conversation into numbered tracer-bullet ticket files under .agent/tickets/, each declaring its blocking edges and acceptance criteria phrased as observable behavior. Use after a spec is approved and before implementation starts."
94
94
  },
95
95
  {