tldr-experts 0.3.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 (75) hide show
  1. package/CHANGELOG.md +913 -0
  2. package/LICENSE +21 -0
  3. package/README.md +174 -0
  4. package/dist/hooks/answer-capture.js +174 -0
  5. package/dist/hooks/budget-gate.js +173 -0
  6. package/dist/hooks/chunk-0bt6yb2q.js +88 -0
  7. package/dist/hooks/chunk-1zwcxd3f.js +66 -0
  8. package/dist/hooks/chunk-9gb21660.js +66 -0
  9. package/dist/hooks/chunk-a8p2rc94.js +20 -0
  10. package/dist/hooks/chunk-ae6bkfs5.js +0 -0
  11. package/dist/hooks/chunk-azctppjh.js +198 -0
  12. package/dist/hooks/chunk-g395gk7e.js +503 -0
  13. package/dist/hooks/chunk-j234zf0t.js +339 -0
  14. package/dist/hooks/chunk-kw4tffzf.js +139 -0
  15. package/dist/hooks/chunk-p274ckxv.js +7435 -0
  16. package/dist/hooks/chunk-sdjnnmzz.js +497 -0
  17. package/dist/hooks/chunk-t56k6146.js +14 -0
  18. package/dist/hooks/chunk-t8tdv11p.js +35 -0
  19. package/dist/hooks/chunk-x98qs959.js +302 -0
  20. package/dist/hooks/chunk-y0jdr3et.js +627 -0
  21. package/dist/hooks/claim-sources.js +72 -0
  22. package/dist/hooks/dod-gate.js +198 -0
  23. package/dist/hooks/no-reask.js +67 -0
  24. package/dist/hooks/session-start.js +1348 -0
  25. package/dist/hooks/statusline.js +116 -0
  26. package/dist/tldrx.js +34219 -0
  27. package/env.yml +79 -0
  28. package/package.json +60 -0
  29. package/plugin/.claude-plugin/plugin.json +9 -0
  30. package/plugin/README.md +113 -0
  31. package/plugin/agents/README.md +22 -0
  32. package/plugin/hooks/hooks.json +107 -0
  33. package/plugin/skills/tldrx/SKILL.md +170 -0
  34. package/stages/build/stage.md +70 -0
  35. package/stages/build/stage.yml +54 -0
  36. package/stages/how/stage.md +89 -0
  37. package/stages/how/stage.yml +53 -0
  38. package/stages/plan/stage.md +89 -0
  39. package/stages/plan/stage.yml +48 -0
  40. package/stages/watch/stage.md +85 -0
  41. package/stages/watch/stage.yml +61 -0
  42. package/stages/what/stage.md +89 -0
  43. package/stages/what/stage.yml +61 -0
  44. package/templates/budget.yml +17 -0
  45. package/templates/competencies.yml +14 -0
  46. package/templates/env.yml +19 -0
  47. package/templates/epic.md +38 -0
  48. package/templates/expert.md +51 -0
  49. package/templates/experts/architect.md +77 -0
  50. package/templates/experts/delivery.md +76 -0
  51. package/templates/experts/developer.md +78 -0
  52. package/templates/experts/operations.md +74 -0
  53. package/templates/experts/product.md +78 -0
  54. package/templates/facts.yml +18 -0
  55. package/templates/handoff.md +63 -0
  56. package/templates/process.yml +33 -0
  57. package/templates/questions.md +63 -0
  58. package/templates/run.yml +24 -0
  59. package/templates/story.md +55 -0
  60. package/templates/watcher.md +68 -0
  61. package/templates/waves.yml +17 -0
  62. package/templates/workspace.yml +30 -0
  63. package/workflows/bugfix.yml +26 -0
  64. package/workflows/docs.yml +23 -0
  65. package/workflows/feature.yml +22 -0
  66. package/workflows/hotfix.yml +24 -0
  67. package/workflows/integration.yml +24 -0
  68. package/workflows/migration.yml +24 -0
  69. package/workflows/performance.yml +23 -0
  70. package/workflows/prototype.yml +24 -0
  71. package/workflows/refactor.yml +24 -0
  72. package/workflows/retro.yml +20 -0
  73. package/workflows/security-patch.yml +23 -0
  74. package/workflows/spike.yml +23 -0
  75. package/workflows/upgrade.yml +23 -0
package/env.yml ADDED
@@ -0,0 +1,79 @@
1
+ # schema: draft
2
+ #
3
+ # The local dev environment manifest. `tldrx doctor` reads this file, runs each
4
+ # `check` command, and prints what it found.
5
+ #
6
+ # The framework NEVER installs anything. `install` holds a copy-paste hint per OS
7
+ # and nothing more. Keys: macos | linux | windows | all.
8
+ #
9
+ # `check` must exit 0 when the tool is usable and print something version-shaped
10
+ # (the first dotted numeric run in stdout+stderr is taken as the version).
11
+
12
+ version: 1
13
+
14
+ tools:
15
+ - id: bun
16
+ required: true
17
+ min_version: "1.3.0"
18
+ check: "bun --version"
19
+ purpose: "Runs the tldrx CLI, the hooks and the test suite. Bun 1.3+ is required for native Bun.YAML."
20
+ install:
21
+ macos: "curl -fsSL https://bun.sh/install | bash"
22
+ linux: "curl -fsSL https://bun.sh/install | bash"
23
+ windows: "powershell -c \"irm bun.sh/install.ps1 | iex\" (or: npm install -g bun)"
24
+
25
+ - id: node
26
+ required: true
27
+ min_version: "20.0.0"
28
+ check: "node --version"
29
+ purpose: "Runs the published build (package.json bin + engines). Also required by Claude Code itself."
30
+ install:
31
+ macos: "brew install node (or: https://nodejs.org)"
32
+ linux: "https://nodejs.org/en/download/package-manager"
33
+ windows: "winget install OpenJS.NodeJS (or: https://nodejs.org)"
34
+
35
+ - id: git
36
+ required: true
37
+ min_version: "2.30.0"
38
+ check: "git --version"
39
+ purpose: "Workspace detection, worktrees for parallel stories, churn data for map/hotspots.md."
40
+ install:
41
+ macos: "xcode-select --install (or: brew install git)"
42
+ linux: "sudo apt-get install git (or your distro's package manager)"
43
+ windows: "winget install Git.Git"
44
+
45
+ - id: claude
46
+ required: true
47
+ min_version: "2.0.0"
48
+ check: "claude --version"
49
+ purpose: "The pilot harness. Sub-agents run as `claude -p --output-format json`; hooks and the statusline are Claude Code primitives."
50
+ install:
51
+ all: "npm install -g @anthropic-ai/claude-code (see https://code.claude.com/docs/en/quickstart)"
52
+
53
+ - id: python3
54
+ required: false
55
+ min_version: "3.10.0"
56
+ check: "python3 --version"
57
+ purpose: "Runtime for graphify (the code-map tool). Only needed if you want `tldrx map`."
58
+ install:
59
+ macos: "brew install python@3.12 (or: https://www.python.org/downloads)"
60
+ linux: "sudo apt-get install python3 python3-pip"
61
+ windows: "winget install Python.Python.3.12"
62
+
63
+ - id: graphify
64
+ required: false
65
+ min_version: "0.8.0"
66
+ check: "graphify --version"
67
+ purpose: "Deterministic tree-sitter code map. Feeds map/*.md. Absent = `tldrx map` cannot run; nothing else is affected."
68
+ install:
69
+ all: "pip install graphify (requires python3 >= 3.10)"
70
+
71
+ - id: gh
72
+ required: false
73
+ min_version: "2.0.0"
74
+ check: "gh --version"
75
+ purpose: "Optional ticket adapter (GitHub issues) and PR operations."
76
+ install:
77
+ macos: "brew install gh"
78
+ linux: "https://github.com/cli/cli/blob/trunk/docs/install_linux.md"
79
+ windows: "winget install GitHub.cli"
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "tldr-experts",
3
+ "version": "0.3.0",
4
+ "description": "tldr-experts: a lightweight, file-based AI development workflow. Installs the `tldrx` (and `tldr-experts`) command. Alpha.",
5
+ "license": "MIT",
6
+ "author": "Alan Martinez",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/ederwii/tldr-experts.git"
10
+ },
11
+ "homepage": "https://github.com/ederwii/tldr-experts#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/ederwii/tldr-experts/issues"
14
+ },
15
+ "keywords": [
16
+ "ai",
17
+ "workflow",
18
+ "claude-code",
19
+ "agentic",
20
+ "developer-experience",
21
+ "tldr",
22
+ "experts",
23
+ "cli"
24
+ ],
25
+ "type": "module",
26
+ "bin": {
27
+ "tldrx": "dist/tldrx.js",
28
+ "tldr-experts": "dist/tldrx.js"
29
+ },
30
+ "engines": {
31
+ "node": ">=20",
32
+ "bun": ">=1.3.0"
33
+ },
34
+ "files": [
35
+ "CHANGELOG.md",
36
+ "LICENSE",
37
+ "README.md",
38
+ "dist",
39
+ "env.yml",
40
+ "plugin",
41
+ "stages",
42
+ "templates",
43
+ "workflows"
44
+ ],
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "scripts": {
49
+ "test": "bun test",
50
+ "build": "bun scripts/build.ts",
51
+ "typecheck": "tsc --noEmit",
52
+ "doctor": "bun bin/tldrx.ts doctor",
53
+ "prepublishOnly": "bun run build"
54
+ },
55
+ "devDependencies": {
56
+ "@types/bun": "^1.4.0",
57
+ "typescript": "^7.0.2",
58
+ "yaml": "^2.9.0"
59
+ }
60
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "$doc": "Shape verified from https://code.claude.com/docs/en/plugins.md (Quickstart > Create the plugin manifest). Fields used here: name, description, version, author.name. Only plugin.json goes inside .claude-plugin/; skills/, agents/ and hooks/ live at the plugin root.",
3
+ "name": "tldrx",
4
+ "description": "tldr-experts: a file-based AI development workflow. One loop, five phases, everything on disk. Alpha.",
5
+ "version": "0.3.0",
6
+ "author": {
7
+ "name": "Alan Martinez"
8
+ }
9
+ }
@@ -0,0 +1,113 @@
1
+ # tldrx — Claude Code plugin packaging
2
+
3
+ Load it for development straight from this directory:
4
+
5
+ ```bash
6
+ claude --plugin-dir ./plugin
7
+ ```
8
+
9
+ Then type `/tldrx:tldrx`. (Plugin skills are always namespaced `/<plugin>:<skill>`.)
10
+
11
+ ## Or install it, and skip the flag
12
+
13
+ `--plugin-dir` lasts one session and needs this checkout. For a project or a
14
+ machine that should just have it:
15
+
16
+ ```bash
17
+ tldrx install --claude # ./.claude/ (this project; needs a git repo)
18
+ tldrx install --claude --user # ~/.claude/ (this machine)
19
+ ```
20
+
21
+ That writes the same skill and the same six hooks into a real `.claude/`, plus the
22
+ status line this plugin cannot install (see below). It is idempotent, it never
23
+ touches `permissions`, and `--uninstall` takes exactly it back out. The README's
24
+ [Claude Code integration](../README.md#claude-code-integration) section has the
25
+ settings fragment it writes.
26
+
27
+ **The two wirings differ in one thing only: how a hook is named.** The plugin
28
+ spawns `bun ${CLAUDE_PLUGIN_ROOT}/../src/hooks/<name>.ts`, and it keeps doing that
29
+ on purpose — a plugin must work for someone who cloned the repo and installed
30
+ nothing, so it cannot depend on a global `tldrx`. The installed `settings.json`
31
+ uses `tldrx hook <name>` instead, because that file gets committed and cloned onto
32
+ a machine whose checkout is somewhere else, where an absolute path is simply wrong.
33
+ Same scripts, same matchers, same timeouts, same decisions.
34
+
35
+ ## What is wired
36
+
37
+ | Path | What it is |
38
+ |---|---|
39
+ | `.claude-plugin/plugin.json` | Manifest: `name`, `description`, `version`, `author`. |
40
+ | `skills/tldrx/SKILL.md` | The facilitator. `disable-model-invocation: true` — only you can invoke it, and its body costs nothing until you do. |
41
+ | `hooks/hooks.json` | Eight handlers over six hook scripts on four events. **All live** — see the table below. |
42
+ | `agents/` | Deliberately empty — experts are generated per project. |
43
+
44
+ ## The hooks
45
+
46
+ | Script | Event(s) | Matcher | What it does |
47
+ |---|---|---|---|
48
+ | `claim-sources.ts` | PreToolUse, PostToolUse | `Write\|Edit` | Computes the **would-be** content (Write: `content`; Edit: `old_string`→`new_string` applied to the file on disk) and, when it is a handoff under `tldrx-work/`, denies unless every `- ` bullet under Findings / Decisions / Unknowns / Evidence ledger ends with a resolvable `[src: …]` token (spec §2.8). On PostToolUse the same check can only report, so it emits `additionalContext`. |
49
+ | `no-reask.ts` | PreToolUse | `Write\|Edit` | On `questions.md`: for each question the file does not already carry, denies when a non-retired `facts.yml` row in the same `area` scores Jaccard ≥ 0.6 over ≥4-char tokens, and names the fact. |
50
+ | `answer-capture.ts` | PostToolUse, FileChanged | `Write\|Edit` / none | For every block that is `status: open` with a non-empty `[Answer]:`, writes the answer footer, appends a `facts.yml` row (`kind: answer`, `source.q`) plus `question.answered` and `fact.added` events, and echoes `tldrx: recorded Q4 → F020`. Never blocks. |
51
+ | `dod-gate.ts` | PreToolUse | `Write\|Edit` | On a `stories/*.md` write that sets `status: done`: re-runs every command in the story's fenced ```` ```dod ```` block from the repo named by `repo:` (resolved through `workspace.yml`), each within `timeout_s` (default 900). Denies unless all exit 0, or if the block is missing. |
52
+ | `budget-gate.ts` | PreToolUse | `Bash` | On a command matching `^(claude -p\|tldrx next)`: resolves the run (`--run`, the cwd, or the newest non-terminal `run.yml`), and denies when the cursor phase cannot afford the stage's `budget_usd` and `on_exceed: block`. Appends `budget.blocked`. |
53
+ | `session-start.ts` | SessionStart | none | Up to three lines of "where we are" via `additionalContext`. Silent when there is no non-terminal run. |
54
+
55
+ **Two rules the whole set obeys.** Only PreToolUse can block, and it blocks by
56
+ printing `{"hookSpecificOutput": {"hookEventName": "PreToolUse",
57
+ "permissionDecision": "deny", "permissionDecisionReason": "…"}}` and exiting `0` —
58
+ an exit code never denies here. And every hook except `dod-gate` fails **open**: an
59
+ internal error exits `0` and writes one line to stderr
60
+ (`tldrx hook <name>: internal error, allowing — …`). `dod-gate` fails **closed**
61
+ once it has identified the write as a story being marked done, because an unproven
62
+ story must stay not-done.
63
+
64
+ The `matcher` on the `FileChanged` entry is deliberately omitted: matcher support
65
+ for that event is not in the verified docs, so the script filters on the path
66
+ itself. The `budget-gate` matcher is `Bash`, not `Task` — the money is spent by a
67
+ shell command whose estimate is in `tool_input.command`, and nothing in the
68
+ verified docs says a subagent spawn arrives with a budget to check.
69
+
70
+ Shapes were copied from the official docs, with the source URL recorded next to
71
+ each one:
72
+
73
+ - https://code.claude.com/docs/en/plugins.md
74
+ - https://code.claude.com/docs/en/hooks.md
75
+ - https://code.claude.com/docs/en/skills.md
76
+ - https://code.claude.com/docs/en/statusline.md
77
+
78
+ ## The status line is not a hook
79
+
80
+ `statusLine` is a **settings key**, not a hook event, and a plugin's own
81
+ `settings.json` supports only `agent` and `subagentStatusLine` — so the plugin
82
+ cannot install it for you. `tldrx install --claude` can, because it writes the real
83
+ settings file; it puts in `{"type": "command", "command": "tldrx statusline"}`, and
84
+ leaves any status line that is not tldrx's alone. If you are loading the plugin
85
+ instead, add this to your `~/.claude/settings.json` or the project's
86
+ `.claude/settings.json` yourself:
87
+
88
+ ```json
89
+ {
90
+ "statusLine": {
91
+ "type": "command",
92
+ "command": "bun /absolute/path/to/tldr-experts/src/hooks/statusline.ts",
93
+ "padding": 2
94
+ }
95
+ }
96
+ ```
97
+
98
+ It renders `[tldrx] <model> ctx:<n>% $<cost>` from the fields Claude Code already
99
+ measures, and `[tldrx] no session data` when they are absent. The richer line from
100
+ the concept doc (run id, phase, progress bar, budget ceiling) needs `run.yml`,
101
+ which v0 does not write yet — so it is not rendered rather than faked.
102
+
103
+ ## Known `claude plugin validate` warnings
104
+
105
+ `claude plugin validate ./plugin` exits 0 with two warnings. Both are deliberate:
106
+
107
+ 1. **`$doc: Unknown field '$doc'`** — JSON has no comments, and this repo's rule is
108
+ that every Claude Code shape carries its source URL beside it. The validator
109
+ itself confirms the field is *ignored at load time*, so it costs nothing.
110
+ 2. **`agents/README.md: No frontmatter block found`** — the directory holds
111
+ documentation, not an agent. Adding frontmatter would register a fake agent
112
+ named `README`, which is worse than a warning. Experts are generated per project
113
+ by `tldrx init`; nothing belongs here.
@@ -0,0 +1,22 @@
1
+ # Agents
2
+
3
+ **Nothing ships here.**
4
+
5
+ Experts in tldr-experts are *generated per project* by `tldrx init` (concept §4.5):
6
+ one stack expertise per language/framework detected, one domain expert per detected
7
+ domain. They are written to the project's `.tldrx/experts/<name>/` as a pair of
8
+ files:
9
+
10
+ ```
11
+ .tldrx/experts/<name>/
12
+ expert.md role, domain, how to reason, what to cite
13
+ competencies.yml {area, level 0-5, evidence: [...], last_trained}
14
+ knowledge/*.md trained material, with file:line provenance (v1.1)
15
+ ```
16
+
17
+ A shipped `agents/*.md` here would be the opposite of that: a fixed cast of
18
+ personas that knows nothing about your code. If a stage needs a persona, it names
19
+ it in `stage.yml` and the facilitator loads the generated file.
20
+
21
+ See `templates/expert.md` and `templates/competencies.yml` for the shapes
22
+ `tldrx init` will write.
@@ -0,0 +1,107 @@
1
+ {
2
+ "description": "tldrx v0 hooks — LIVE. Shape verified from https://code.claude.com/docs/en/hooks.md: top-level `hooks` map keyed by event name, each entry { matcher?, hooks: [ { type, command, args?, timeout? } ] }. Exec form (`command` + `args`) and ${CLAUDE_PLUGIN_ROOT} are from that page. Only PreToolUse can deny, and it denies by printing {\"hookSpecificOutput\": {\"hookEventName\": \"PreToolUse\", \"permissionDecision\": \"deny\", \"permissionDecisionReason\": \"…\"}} and exiting 0 — never by an exit code. Every hook but DoD-gate fails OPEN. NOTE: the status line is NOT a hook event — it is the `statusLine` settings key, and a plugin settings.json only supports `agent` and `subagentStatusLine`. Wire it yourself; see plugin/README.md.",
3
+ "hooks": {
4
+ "PreToolUse": [
5
+ {
6
+ "_note": "claim-sources (spec §4) — the gate. Denies a handoff under tldrx-work/ whose Findings/Decisions/Unknowns/Evidence-ledger bullets do not each end with a resolvable [src: …] token.",
7
+ "matcher": "Write|Edit",
8
+ "hooks": [
9
+ {
10
+ "type": "command",
11
+ "command": "bun",
12
+ "args": ["${CLAUDE_PLUGIN_ROOT}/../src/hooks/claim-sources.ts"],
13
+ "timeout": 15
14
+ }
15
+ ]
16
+ },
17
+ {
18
+ "_note": "no-re-ask (spec §4, concept §1.2) — denies a NEW open question in tldrx-work/**/questions.md whose subject already has a non-retired facts.yml row (Jaccard >= 0.6 on >=4-char tokens, same area).",
19
+ "matcher": "Write|Edit",
20
+ "hooks": [
21
+ {
22
+ "type": "command",
23
+ "command": "bun",
24
+ "args": ["${CLAUDE_PLUGIN_ROOT}/../src/hooks/no-reask.ts"],
25
+ "timeout": 15
26
+ }
27
+ ]
28
+ },
29
+ {
30
+ "_note": "DoD-gate (spec §4, concept §8) — re-runs every command in a story's fenced ```dod block, in its repo, and denies unless each exits 0. This hook is not <50 ms by design, and it is the one hook that fails CLOSED.",
31
+ "matcher": "Write|Edit",
32
+ "hooks": [
33
+ {
34
+ "type": "command",
35
+ "command": "bun",
36
+ "args": ["${CLAUDE_PLUGIN_ROOT}/../src/hooks/dod-gate.ts"],
37
+ "timeout": 960
38
+ }
39
+ ]
40
+ },
41
+ {
42
+ "_note": "budget-gate (spec §4) — matcher is Bash, because the money is spent by `claude -p …` / `tldrx next`, which is a Bash command with the estimate in tool_input.command. The earlier `Task` matcher was a guess and is dropped: nothing in the verified docs says a subagent spawn arrives here with a budget to check.",
43
+ "matcher": "Bash",
44
+ "hooks": [
45
+ {
46
+ "type": "command",
47
+ "command": "bun",
48
+ "args": ["${CLAUDE_PLUGIN_ROOT}/../src/hooks/budget-gate.ts"],
49
+ "timeout": 15
50
+ }
51
+ ]
52
+ }
53
+ ],
54
+ "PostToolUse": [
55
+ {
56
+ "_note": "answer-capture (spec §2.7/§4) — writes the answer footer, the facts.yml row and the question.answered event for every block that is `status: open` with a non-empty [Answer]:. Never blocks; echoes one line of additionalContext.",
57
+ "matcher": "Write|Edit",
58
+ "hooks": [
59
+ {
60
+ "type": "command",
61
+ "command": "bun",
62
+ "args": ["${CLAUDE_PLUGIN_ROOT}/../src/hooks/answer-capture.ts"],
63
+ "timeout": 15
64
+ }
65
+ ]
66
+ },
67
+ {
68
+ "_note": "claim-sources twin (spec §4: 'a PostToolUse twin re-checks and feeds back only'). Same script, same checks; on PostToolUse it can only report, so it emits additionalContext instead of a denial.",
69
+ "matcher": "Write|Edit",
70
+ "hooks": [
71
+ {
72
+ "type": "command",
73
+ "command": "bun",
74
+ "args": ["${CLAUDE_PLUGIN_ROOT}/../src/hooks/claim-sources.ts"],
75
+ "timeout": 15
76
+ }
77
+ ]
78
+ }
79
+ ],
80
+ "FileChanged": [
81
+ {
82
+ "_note": "answer-capture again — a human editing questions.md in an editor never goes through Write/Edit. Matcher omitted: FileChanged's matcher support is not in the verified docs, so the script filters on the path itself.",
83
+ "hooks": [
84
+ {
85
+ "type": "command",
86
+ "command": "bun",
87
+ "args": ["${CLAUDE_PLUGIN_ROOT}/../src/hooks/answer-capture.ts"],
88
+ "timeout": 15
89
+ }
90
+ ]
91
+ }
92
+ ],
93
+ "SessionStart": [
94
+ {
95
+ "_note": "session-start (concept §3) — up to three lines of 'where we are' from the newest non-terminal run.yml, injected as additionalContext. Matcher omitted so it fires for every start reason (startup, resume, clear, compact, fork).",
96
+ "hooks": [
97
+ {
98
+ "type": "command",
99
+ "command": "bun",
100
+ "args": ["${CLAUDE_PLUGIN_ROOT}/../src/hooks/session-start.ts"],
101
+ "timeout": 15
102
+ }
103
+ ]
104
+ }
105
+ ]
106
+ }
107
+ }
@@ -0,0 +1,170 @@
1
+ ---
2
+ # Fields verified from https://code.claude.com/docs/en/skills.md (§ "Frontmatter
3
+ # reference"). `disable-model-invocation: true` means ONLY the user can invoke this
4
+ # skill: its body stays out of context until someone types /tldrx — concept §1.3's
5
+ # non-intrusive requirement, satisfied natively.
6
+ name: tldrx
7
+ description: The tldr-experts facilitator. Finds what is pending in this workspace and walks the human through it one item at a time, reading and writing files only. Invoke with /tldrx.
8
+ disable-model-invocation: true
9
+ argument-hint: "[optional: which item, or what you want to work on]"
10
+ ---
11
+
12
+ # tldrx — status, then guide
13
+
14
+ **Alpha.** Every command is implemented. `tldrx --help` is the authoritative
15
+ surface — read it before you promise anything, and never narrate progress a tool
16
+ did not make.
17
+
18
+ ## What you are
19
+
20
+ A facilitator, not an author. You read files, hand ONE sub-agent ONE task, write
21
+ the result back, and stop at the gate. You hold no state between steps — the files
22
+ are the state. You do not decide anything that is the human's to decide.
23
+
24
+ ## Step 1, always
25
+
26
+ ```
27
+ tldrx status --json
28
+ ```
29
+
30
+ It is free, deterministic, and exits 0 whatever it finds (exit 3 only means there
31
+ is no `.tldrx/` here — then the answer is `tldrx init`). It returns
32
+ `{root, pending, items[], advice[]}`, each item `{kind, summary, command, details}`,
33
+ already in the order the items block each other. `items` are the BLOCKERS and all
34
+ `pending` counts; `advice` blocks nothing — relay it once, briefly. **That list is
35
+ the agenda.** Do not ask "what would you like to do?" first.
36
+
37
+ Then take item 1. One item at a time, in order. Say in one plain sentence what it
38
+ is and why it matters — no jargon a first-time user would not have — then either
39
+ ask or act, per the rule below. **After each item, re-run `tldrx status`**: acting
40
+ on one item changes the list.
41
+
42
+ ## Ask, or act
43
+
44
+ **The human decides** — you present, quote the relevant file section, and ASK.
45
+ Never answer on their behalf, never pick a default, never "assume yes":
46
+
47
+ - `init-questions` — facts about their project nobody could detect. Run
48
+ `tldrx interview --init` and relay each question. Piped stdin is ONE LINE PER
49
+ QUESTION in file order; a single letter `A`–`E` picks that option, other text is
50
+ recorded verbatim, an empty line or `s` skips, `q` stops. **Never pass
51
+ `--yes-to-defaults`** — it answers every question with its first option.
52
+ - `seed-split` — a proposal that creates nothing until someone applies it. Show
53
+ `split.md`, the unanswered questions, and the seed documents still marked
54
+ `proposed`. Record decisions with `tldrx seed answer <split.yml> <Qid> "<text>"`;
55
+ edit `split.yml` if they want different runs.
56
+ - a gate, an answer, or any ADR/decision document — quote it and ask.
57
+ - a gate `tldrx status` reports as signed `by: auto` that they disagree with. It signs
58
+ only when its five conditions hold and cannot judge whether a decision was RIGHT: quote
59
+ the note — it carries all five measured values — and ask before revoking.
60
+
61
+ **You act** once they have said what they want — these are mechanical:
62
+
63
+ - `tldrx seed apply <split.yml> --dry-run`, then the real apply when they say so.
64
+ - `tldrx answer <Qid> "<what they said>" --run <id>` · `tldrx approve --run <id>`
65
+ after they said yes · `tldrx reject --run <id> --note "<their reason>"`, and
66
+ `tldrx reject --run <id> --stage <phase>/<stage> --note "…"` to take back an
67
+ approval already given (including one the harness signed `by: auto`).
68
+ - `tldrx questions lint --run <id>` when a stage wrote a `questions.md`: it exits 2
69
+ if any block is invisible to the parser, and `--fix` converts it without changing
70
+ a word. An unreadable file reads as "no questions" to everything downstream.
71
+ - one stage of a run, via the in-session recipe below.
72
+ - `tldrx expert train <name> --area <a> --mode <light|full> --print-prompt` — the
73
+ printed prompt costs nothing; running it is a spend, so see Money. The `expert`
74
+ entry arrives in `advice`, not `items`, and its `command` is always
75
+ `tldrx expert list`: it degrades a stage, it never blocks one. Its `details` name
76
+ the trainable experts and, separately, any role expert that has no past run to
77
+ mine — that one is not a task yet. Mention it once and carry on with `items`.
78
+
79
+ ## When nothing is pending
80
+
81
+ `pending: 0` means open work — and what the work IS is the human's decision, not a
82
+ lookup. Offer `tldrx run new <slug> --scope <s> [--seed <path>] [--budget <usd>]`,
83
+ where `<s>` is a file stem in `.tldrx/workflows/` or the shipped `workflows/`:
84
+ `feature` `bugfix` `hotfix` `refactor` `docs` `spike` `prototype` `migration`
85
+ `integration` `performance` `security-patch` `upgrade` `retro`. If `run new --seed`
86
+ prints `note: seed is N files / ~T tokens …` on stderr, relay it and offer
87
+ `tldrx seed triage <path>` (free, spawns nothing): one run carrying that much seed
88
+ pays for it at every stage.
89
+
90
+ ## Running one stage of a run
91
+
92
+ ```
93
+ 1 tldrx next --prepare [<run>] # writes the prompt bundle; exits 0 and stops
94
+ 2 dispatch ONE sub-agent # Agent tool, prompt = .agent/<stage>/prompt.md
95
+ 3 write .agent/<stage>/result.json # {outputs, questions_asked, notes}
96
+ 4 tldrx next --commit [<run>] --cost-usd <n> # validates outputs + checks, rolls up cost, gates
97
+ ```
98
+
99
+ Step 1 names the bundle, the writable files and the finishing command. Step 2:
100
+ pass `prompt.md` to the Agent tool **unedited** — it already inlines the stage
101
+ body, the experts and every declared input — and tell the sub-agent to write ONLY
102
+ the files `pending.json` lists, read nothing else, and end every bullet under
103
+ Findings / Decisions / Unknowns / Evidence ledger with a `[src: …]` token. Step 4
104
+ re-reads every output off disk and re-runs the checks whatever step 3 claimed.
105
+ Pass `--cost-usd <n>` on step 4 when you know what the sub-agent cost: an in-session
106
+ turn has no meter of its own, and without a declared number the task is recorded as
107
+ `cost_usd: null, metered: false` — honest, but it makes the run's `spent` a lower
108
+ bound rather than a total. Never guess one; omitting it is the correct move when you
109
+ do not know.
110
+
111
+ **One stage per `/tldrx` call.** When a run's remaining gates are mostly `auto`
112
+ (`run.yml` `gates_policy:`) and nobody needs to watch, say so and offer
113
+ `tldrx run auto <id>` — the headless loop. It spawns its own sessions, so suggest
114
+ it for a terminal, never run it from inside this one.
115
+
116
+ | exit | meaning | what you do |
117
+ |---|---|---|
118
+ | 0 | done, cursor advanced | `tldrx status` again |
119
+ | 2 | refused — budget, a held lock, an uncommitted `--prepare` bundle, or you left off the run id | report it; do not retry blindly. A lock whose pid is dead clears with `tldrx run unlock <id>`; a run they have given up on closes with `tldrx run cancel <id> --note "<their reason>"` — both need their say-so first |
120
+ | 3 | not found | `tldrx status` says what exists instead |
121
+ | 4 | a human is needed | `tldrx approve` (gate) or `tldrx answer <Qid> "…"` (question) |
122
+ | 5 | the stage failed | report the reason verbatim; the cost is spent, not refunded. If it names an unreadable `questions.md`, `tldrx questions lint --fix --run <id>` converts it without changing a word, then `--commit` again |
123
+
124
+ **Several runs open**: every run-targeting command refuses with exit 2 rather than
125
+ guessing, and lists the candidates. That means "you forgot the id", not "something
126
+ broke" — pass it. `tldrx status` and `tldrx run status` always show all of them.
127
+
128
+ ## Money
129
+
130
+ Before anything that spends: **state the ceiling and ask.** `tldrx next`,
131
+ `tldrx run auto`, `tldrx expert train` (without `--print-prompt`) and
132
+ `tldrx seed triage --propose` (`--max-usd 1.00` by default) all cost real money;
133
+ `seed triage` without `--propose` is free. Never raise `--max-usd` or run
134
+ `tldrx budget raise` for them — a stage that costs more than remains exits 2 and
135
+ names the exact command; report it and let them decide.
136
+
137
+ Three free read-only commands answer what it will cost and what it did: `tldrx run
138
+ estimate` (the only one that guesses, and says so), `tldrx cost [--all]` (per attempt —
139
+ retries are where the money is) and `tldrx budget show`. Quote them, never the arithmetic;
140
+ `cost` reports an in-session turn as UNMETERED unless step 4 declared `--cost-usd`.
141
+
142
+ ## Rules you do not get to bend
143
+
144
+ 1. **Never hand-edit `run.yml` or `events.jsonl`.** The tools own them; the log is
145
+ append-only. Want a state change? Run the command that owns it.
146
+ 2. **Never answer a question on the human's behalf.** An invented answer poisons
147
+ `facts.yml` permanently — every future run will cite it.
148
+ 3. **Every claim carries a source**: `[src: path:line]`, `[src: <url>]`,
149
+ `[src: Q<n>]`, `[src: F<n>]`. Unsourced goes in Unknowns and becomes a question.
150
+ 4. **Never ask what is already known.** Grep `.tldrx/memory/facts.yml` first.
151
+ 5. **Verify from the source, not from your own output.** After a write, re-read it
152
+ from disk. A sub-agent reporting "ok" is not evidence.
153
+ 6. **Say which you are in: measured, inferred, or assumed.** Never blur them.
154
+ 7. **Stop at gates.** You never close one — not even an `auto` gate, which the
155
+ framework closes itself and only when all five of its conditions hold.
156
+ 8. **A checked section holds at least one item.** Nothing to report is still an
157
+ item: `- none [src: absent:<what you looked at>]`. Prose is refused.
158
+ 9. **`.tldrx/` and `tldrx-work/` are committed** — the files ARE the state. `init`
159
+ gitignores only the machine-local scratch (`graphify-out/`, `cache/`,
160
+ `worktrees/`, `tldrx-work/*/.lock`, `tldrx-work/*/.agent/`).
161
+
162
+ ## The loop, for orientation
163
+
164
+ Every stage is the same four steps: **Investigate** (read code, docs and memory;
165
+ findings carry sources) → **Handoff** (one `.md`: found, decided, still unknown) →
166
+ **Interview** (only the unknowns become questions; answers land in `facts.yml`) →
167
+ **Gate** (a human approves; recorded in `run.yml` + `events.jsonl`). The five
168
+ phases — **what · how · plan · build · watch** — are that loop with different
169
+ inputs, outputs and experts: `.tldrx/stages/<slug>/stage.yml` declares which,
170
+ `.tldrx/workflows/<scope>.yml` declares the order.
@@ -0,0 +1,70 @@
1
+ <!-- schema: draft -->
2
+ <!-- Stage template: build (phase 4). -->
3
+ <!--
4
+ READ THIS FIRST: unlike every other stage, this file is NOT the prompt.
5
+
6
+ `04-build` is run by the wave executor (spec §5, "Build executor"), which builds
7
+ its own per-story developer prompt and per-story reviewer prompt from the Plan
8
+ artefacts, and writes `04-build/handoff.md` itself. Editing this file changes the
9
+ documentation of the phase, not what the sub-agents are told. The prompts live in
10
+ `src/core/build/prompts.ts`; the pipeline lives in
11
+ `src/core/facilitator/executors/build.ts`.
12
+ -->
13
+
14
+ # Build — what the phase does
15
+
16
+ ## Role
17
+
18
+ The facilitator is the contractor here, not an author. It hands each story to a
19
+ developer sub-agent, proves the result, and merges it — and it writes the handoff
20
+ from what it measured rather than asking anyone to summarise it.
21
+
22
+ ## Objective
23
+
24
+ Turn `03-plan/waves.yml` into merged code on epic branches, one story at a time,
25
+ in wave order. Done-when: every scheduled story is `done` (DoD green, reviewer
26
+ approved, evidence written into its front matter) or `blocked` with a reason a
27
+ human can act on, and every epic branch is left ready to merge **by hand**.
28
+
29
+ ## Inputs
30
+
31
+ `03-plan/waves.yml`, `03-plan/stories/<id>.md`, `03-plan/epics/<id>.md`, the
32
+ workspace conventions, and — per story — the content of every path its `touches`
33
+ list names, read from that story's own worktree.
34
+
35
+ ## Investigate
36
+
37
+ Per story, in `waves.yml` order:
38
+
39
+ 1. resolve the story's repo from `workspace.yml`, and refuse the whole phase if
40
+ that repo's tree is dirty;
41
+ 2. ensure `epic/<slug>` exists, cut from the repo's `default_branch`;
42
+ 3. open a worktree at `.tldrx/worktrees/<repo>/<story-id>` on `story/<id>`;
43
+ 4. spawn ONE developer sub-agent with cwd = that worktree.
44
+
45
+ ## Produce
46
+
47
+ - `04-build/log/<story-id>.md` — the review log, one per story touched
48
+ - `04-build/handoff.md` — Findings per story, Evidence ledger of dod commands
49
+ - `03-plan/stories/<id>.md` — `status:` and `evidence:` written back
50
+ - `epic/<slug>` branches, merged from `story/<id>`, **never pushed**
51
+
52
+ ## Rules
53
+
54
+ - Done means proven: the ```dod block is re-run by the facilitator, in the story's
55
+ worktree, and every command must exit 0. A sub-agent's own "it works" is not
56
+ evidence and is never recorded as any.
57
+ - A reviewer's `changes` requeues the story ONCE, with the review under
58
+ `## Previous attempt`. A second `changes` blocks it.
59
+ - A DoD failure or a merge conflict blocks that story only — the wave carries on.
60
+ - Nothing pushes. No epic is merged into a default branch.
61
+
62
+ ## Questions
63
+
64
+ None. The Interview happened in What and How; a story that still needs a human
65
+ answer is a Plan bug, and it surfaces here as `blocked`.
66
+
67
+ ## Stop
68
+
69
+ At the gate. `tldrx approve` after merging the epic branches, or
70
+ `tldrx reject --note "…"` to send the phase back.