tldr-experts 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -0
- package/README.md +2 -1
- package/dist/hooks/budget-gate.js +1 -1
- package/dist/hooks/{chunk-pf9d8ag8.js → chunk-6ytv36jd.js} +1 -1
- package/dist/hooks/{chunk-md1c7z7q.js → chunk-c4p5x1b4.js} +33 -16
- package/dist/hooks/session-start.js +12 -4
- package/dist/hooks/statusline.js +2 -2
- package/dist/tldrx.js +2438 -1359
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/templates/experts/stack/dotnet.md +95 -0
- package/templates/experts/stack/javascript.md +86 -0
- package/templates/experts/stack/overlays/aspnet-controllers.md +47 -0
- package/templates/experts/stack/overlays/aspnet-minimal-apis.md +51 -0
- package/templates/experts/stack/overlays/efcore-npgsql.md +57 -0
- package/templates/experts/stack/overlays/expo-router.md +50 -0
- package/templates/experts/stack/overlays/fastapi.md +55 -0
- package/templates/experts/stack/overlays/mediatr-cqrs.md +47 -0
- package/templates/experts/stack/overlays/next-app-router.md +61 -0
- package/templates/experts/stack/overlays/node-express.md +55 -0
- package/templates/experts/stack/overlays/postgres-testcontainers.md +55 -0
- package/templates/experts/stack/overlays/prisma.md +52 -0
- package/templates/experts/stack/overlays/react.md +62 -0
- package/templates/experts/stack/overlays/sqlalchemy-alembic.md +51 -0
- package/templates/experts/stack/overlays/vite-react-spa.md +49 -0
- package/templates/experts/stack/python.md +90 -0
- package/templates/experts/stack/typescript.md +89 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## 0.9.0 — 2026-09-06
|
|
5
|
+
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- **`AGENTS.md` is the canonical agent context, and `CLAUDE.md` imports it.** Four days of
|
|
9
|
+
live-maintenance tribal knowledge written down where every agent — Claude Code sessions in
|
|
10
|
+
fresh windows, Codex, anything reading `AGENTS.md` — starts with it: the golden evidence
|
|
11
|
+
rules (including "never quote a CLI flag from memory"), worktree+merge-wave discipline, the
|
|
12
|
+
five gates, the `gh run list --commit` lie and the non-empty-checks assertion, CHANGELOG
|
|
13
|
+
union and release ritual, the pinned house invariants, hermetic test rules, public-surface
|
|
14
|
+
guard rules, provider facts, and the known live traps. One file; the other imports it,
|
|
15
|
+
because two rule files drifting apart is the failure mode this repo exists to kill.
|
|
16
|
+
- **Stack packs — `tldrx expert packs <enable|disable|status>`.** A `<lang>-stack` expert was a
|
|
17
|
+
name-only stub: the language name was the only stack-specific token in its body, so the
|
|
18
|
+
developer built from the model's habits and the reviewer had no stack checklist to hold a
|
|
19
|
+
story against (the repo's own audit scored the experts' knowledge 6/10). Off by default,
|
|
20
|
+
behind one per-project switch: `enable` materialises four language packs (TypeScript,
|
|
21
|
+
JavaScript, Python, .NET) and thirteen manifest-detected framework overlays (`react`,
|
|
22
|
+
`next-app-router`, `vite-react-spa`, `expo-router`, `node-express`, `prisma`,
|
|
23
|
+
`aspnet-minimal-apis`, `aspnet-controllers`, `mediatr-cqrs`, `efcore-npgsql`, `fastapi`,
|
|
24
|
+
`sqlalchemy-alembic`, `postgres-testcontainers`) into `.tldrx/experts/<lang>-stack/`, kept apart
|
|
25
|
+
from `knowledge/`, which no packs command ever touches. A pack is interrogative by owner
|
|
26
|
+
decision, never prescriptive over a repo's own conventions: **Defaults** apply only where the
|
|
27
|
+
project is silent and each one names the signal that overrides it, and **Checks** are questions
|
|
28
|
+
the Build reviewer now asks under every diff, each carrying a `verify:` hint and yielding to
|
|
29
|
+
the project's own convention when it has one. `enable` replaces a body only when it is an
|
|
30
|
+
untouched stub — an edited body is `kept:` and the command says so — and a body one shipment
|
|
31
|
+
behind is `upgraded:` rather than silently frozen at the version it was first materialised
|
|
32
|
+
with, told apart by two additive front-matter keys the materialised body carries: `pack:
|
|
33
|
+
<lang>@<hash>` names the shipment and `pack_body:` names the body's own bytes, so "somebody
|
|
34
|
+
edited this" (bytes differ) and "this is one shipment behind" (bytes match, shipment differs)
|
|
35
|
+
are never the same answer. `disable` removes `overlays/` and nothing else. Overlays are
|
|
36
|
+
detected from manifests (`package.json`'s two dependency groups kept apart, `*.csproj` /
|
|
37
|
+
`Directory.Packages.props`, `pyproject.toml` and `requirements*.txt`) and never inferred from
|
|
38
|
+
the language, because two workspaces of the same language can run opposite architectures — one
|
|
39
|
+
prescriptive ".NET pack" would be wrong for whichever one it disagreed with. No new prompt
|
|
40
|
+
mechanism: every renderer already prints an expert's body, so `body + overlays` composes once
|
|
41
|
+
in `loadExpertBundles` and reaches every stage prompt and the Build developer unchanged; the
|
|
42
|
+
reviewer, which carried no expert content at all, is handed the active packs' Checks explicitly
|
|
43
|
+
under a new `## Stack checks (the repo's own conventions win)` section, rendered only when BOTH
|
|
44
|
+
the workspace switch and the story's own stage-level `stack_experts` are on — so a developer
|
|
45
|
+
turn that was never shown a stack expert is never graded against Checks it was never briefed
|
|
46
|
+
on. `workspace.yml` gains `stack_packs` and `repos[].overlays` (each with its evidence string)
|
|
47
|
+
— additive, `version: 1` unchanged, and read back on every re-init so a regenerate never
|
|
48
|
+
silently turns the switch off. For a workspace that never threw the switch, this is today's
|
|
49
|
+
bytes, byte for byte. Once `enable` has run, `disable` stops the overlays and the reviewer's
|
|
50
|
+
Checks, but a pack body already materialised into `expert.md` stays there until you delete
|
|
51
|
+
it — `disable` removes only `overlays/`, by design (fix round 2, ruled) — and `enable` re-seeds
|
|
52
|
+
a body it finds missing or still an untouched stub.
|
|
53
|
+
- **Project skills are named to the developer, independent of the packs switch.** A repo's own
|
|
54
|
+
`.claude/skills/*/SKILL.md` files are detected into `repos[].skills` and rendered under
|
|
55
|
+
`## Project skills` in every stage prompt and the Build developer's — name, description, and
|
|
56
|
+
the path to read — because skills are for doing and packs are for checking: the harness runs a
|
|
57
|
+
skill, the framework only says it exists. The Build developer's allowed tools gain `Skill` only
|
|
58
|
+
when that story's repo has one (whether an agent CLI's print mode actually denies an unlisted
|
|
59
|
+
`Skill` call is unverified — the framework's job is the list, not the enforcement). A skill git
|
|
60
|
+
does not track is flagged in the prompt and warned at Build start, by name and by repo, because
|
|
61
|
+
a story worktree carries tracked files only and the path the prompt names would not exist
|
|
62
|
+
there.
|
|
63
|
+
- **The context ledger separates `expert.md` bytes from overlay bytes.** `pending.json` gains
|
|
64
|
+
`overlays`/`overlay_bytes` on a stack expert's row — additive and absent (not `0` or `[]`) when
|
|
65
|
+
nothing was inlined, so a bundle the switch never touched stays byte-identical to one written
|
|
66
|
+
before packs existed — and a new `project_skills_bytes` beside the other context groups, a
|
|
67
|
+
required count like its siblings, `0` when the workspace detected no project skills rather than
|
|
68
|
+
absent. `expert_md_bytes` keeps the meaning it has always had, `expert.md`'s own bytes and never
|
|
69
|
+
the composed total, and the operator line prints the two counts separately for the same reason.
|
|
70
|
+
- Two out-of-scope findings from building this: stack-expert naming has two independent
|
|
71
|
+
derivations that agree today only because a mismatch fails silently (#152), and a project's own
|
|
72
|
+
`AGENTS.md`/`CLAUDE.md`/`CONTRIBUTING.md` are detected by presence only — their content never
|
|
73
|
+
reaches a stage prompt (#153).
|
|
74
|
+
|
|
3
75
|
## 0.8.0 — 2026-09-04
|
|
4
76
|
|
|
5
77
|
### Added
|
package/README.md
CHANGED
|
@@ -288,7 +288,7 @@ draws before installing anything.
|
|
|
288
288
|
The reference guide, in `docs/guide/`: [1 Quick start](docs/guide/01-quick-start.md) ·
|
|
289
289
|
[2 The loop](docs/guide/02-the-loop.md) (the four steps, what a stage file controls, the two execution modes) ·
|
|
290
290
|
[3 Runs and gates](docs/guide/03-runs-and-gates.md) (`run new`→`retro`, gate policy, `run auto`, unlock/cancel, dashboard, tickets) ·
|
|
291
|
-
[4 Experts](docs/guide/04-experts.md) (loading rules, role experts, training, levels) ·
|
|
291
|
+
[4 Experts](docs/guide/04-experts.md) (loading rules, role experts, stack packs, training, levels) ·
|
|
292
292
|
[5 Seeds and triage](docs/guide/05-seeds-and-triage.md) (`--seed`, `--from`, splitting a big seed) ·
|
|
293
293
|
[6 Budgets and cost](docs/guide/06-budgets-and-cost.md) · [7 Claude Code](docs/guide/07-claude-code.md) (plugin, hooks, `/tldrx`) ·
|
|
294
294
|
[8 CLI reference](docs/guide/08-cli-reference.md) (every command, flag and exit code) ·
|
|
@@ -314,6 +314,7 @@ back on the registry is 0.3.0.
|
|
|
314
314
|
|
|
315
315
|
| Version | Date | Status | Contains |
|
|
316
316
|
|---|---|---|---|
|
|
317
|
+
| 0.9.0 | 2026-09-06 | `beta` | opt-in stack packs: four language pack bodies and thirteen framework overlays detected from manifests, interrogative by default (Defaults yield to any repo signal, Checks are questions with `verify:` hints), behind one per-project switch (`tldrx expert packs enable`) that materialises into `.tldrx/experts/<lang>-stack/` without touching trained knowledge; the Build reviewer gets `## Stack checks (the repo's own conventions win)`; every stage names the project's `.claude/skills` and the developer may invoke them; workspace.yml records overlays with evidence and skills with a tracked flag, `version: 1` unchanged |
|
|
317
318
|
| 0.8.0 | 2026-09-04 | `beta` | the unattended mandate learns to keep going: a `## Do not stop` section that defines the one thing allowed to end a run early (a strict blocker, named against the work it does not block), product questions parked as **guided** ones with lettered options and a pre-declared fallback, and a budget stop that asks instead of halting — written against 26 `budget.raised` and 26 `question.answered` events on a real ten-run workspace where the owner had to re-authorise "unattended" mid-run. Plus `tldrx drive --tldr`: a reporting contract for runs nobody will audit — the `run status` block plus three bullets of delta, no operator notes, minimal gate evidence, handoffs trimmed of prose but never of the citations `claim-sources` gates on. The ask channel stays the console and the framework names no chat vendor |
|
|
318
319
|
| 0.7.0 | 2026-09-03 | `beta` | Codex as a second honest automated runner: recorded JSONL contract, structured envelopes, role-based sandboxes, token/session provenance, and explicitly unmetered USD accounting; Claude remains the default and the pilot harness. Also absorbs the citation-honesty work previously staged as 0.6.2: a `file` src resolves against the branches the run RECORDED and NAMES the unmerged ref instead of passing in silence or breaking with the temp dir (#140), watcher cards name it the same way (#143), and every run close reports the questions nobody answered (#141) |
|
|
319
320
|
| 0.6.1 | 2026-09-03 | `beta` | dogfooding fixes from the first fully-unattended runs: blocked stories never lose uncommitted work (rescue commits + `story.work_rescued`), a fix is only Resolved with a reachable sha, re-entered stages reconstruct their handoff from the ledger instead of degrading it, the Cost header reports the phase and names its lower bound (shared `spendBasis`), feature presets resolve their per-repo maps, Plan sees the command allowlist its gate enforces, the landing sells the unattended flow |
|
|
@@ -752,33 +752,50 @@ function pathsIntersect(a, b) {
|
|
|
752
752
|
// src/core/experts/expertKnowledge.ts
|
|
753
753
|
var DEFAULT_KNOWLEDGE_MAX_BYTES = 48 * 1024;
|
|
754
754
|
|
|
755
|
-
// src/core/
|
|
756
|
-
var DISPATCH_NOTES_MAX_BYTES = 8 * 1024;
|
|
757
|
-
|
|
758
|
-
// src/core/experts/stackExperts.ts
|
|
755
|
+
// src/core/experts/workspaceRepos.ts
|
|
759
756
|
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
760
757
|
import { join as join5 } from "node:path";
|
|
761
|
-
function
|
|
758
|
+
function readWorkspaceDocument(root) {
|
|
762
759
|
const path = join5(root, PROJECT_FRAMEWORK_DIR, "workspace.yml");
|
|
763
760
|
if (!existsSync4(path))
|
|
764
|
-
return
|
|
765
|
-
let doc;
|
|
761
|
+
return null;
|
|
766
762
|
try {
|
|
767
|
-
|
|
763
|
+
return parseYaml(readFileSync4(path, "utf8"));
|
|
768
764
|
} catch {
|
|
769
|
-
return
|
|
765
|
+
return null;
|
|
770
766
|
}
|
|
771
|
-
|
|
767
|
+
}
|
|
768
|
+
function workspaceRepoRows(doc) {
|
|
769
|
+
if (typeof doc !== "object" || doc === null)
|
|
770
|
+
return [];
|
|
771
|
+
const list = doc.repos;
|
|
772
772
|
if (!Array.isArray(list))
|
|
773
773
|
return [];
|
|
774
|
-
const
|
|
774
|
+
const rows = [];
|
|
775
775
|
for (const row of list) {
|
|
776
|
-
if (typeof row
|
|
776
|
+
if (typeof row !== "object" || row === null)
|
|
777
777
|
continue;
|
|
778
|
-
const
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
778
|
+
const record = row;
|
|
779
|
+
if (typeof record.name !== "string")
|
|
780
|
+
continue;
|
|
781
|
+
rows.push(record);
|
|
782
|
+
}
|
|
783
|
+
return rows;
|
|
784
|
+
}
|
|
785
|
+
function strings(value) {
|
|
786
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// src/core/facilitator/dispatchNotes.ts
|
|
790
|
+
var DISPATCH_NOTES_MAX_BYTES = 8 * 1024;
|
|
791
|
+
|
|
792
|
+
// src/core/experts/stackExperts.ts
|
|
793
|
+
function stackExpertNames(root, repos) {
|
|
794
|
+
const names = [];
|
|
795
|
+
for (const row of workspaceRepoRows(readWorkspaceDocument(root))) {
|
|
796
|
+
if (!repos.includes(row.name))
|
|
797
|
+
continue;
|
|
798
|
+
for (const language of strings(row.stack).filter((item) => item !== "")) {
|
|
782
799
|
const expert = `${language}-stack`;
|
|
783
800
|
if (!names.includes(expert))
|
|
784
801
|
names.push(expert);
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
openQuestions,
|
|
16
16
|
runSnapshot,
|
|
17
17
|
whatIsWaiting
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-6ytv36jd.js";
|
|
19
19
|
import {
|
|
20
20
|
evidencePath,
|
|
21
21
|
expertsDir,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
pathsIntersect,
|
|
26
26
|
readExpertDomain,
|
|
27
27
|
stackExpertNames
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-c4p5x1b4.js";
|
|
29
29
|
import {
|
|
30
30
|
parseEvidence
|
|
31
31
|
} from "./chunk-b9rjx4qc.js";
|
|
@@ -925,11 +925,19 @@ function evidenceCount(expert) {
|
|
|
925
925
|
// src/core/experts/roleExperts.ts
|
|
926
926
|
import { join as join5 } from "node:path";
|
|
927
927
|
var ROLE_TEMPLATES_DIR = join5(TEMPLATES_DIR, "experts");
|
|
928
|
+
// src/core/experts/packSections.ts
|
|
929
|
+
var PACK_MAX_BYTES = 24 * 1024;
|
|
928
930
|
// src/core/experts/domainRank.ts
|
|
929
931
|
var MAX_GRAPH_BYTES = 64 * 1024 * 1024;
|
|
932
|
+
// src/core/experts/packTemplates.ts
|
|
933
|
+
import { join as join6 } from "node:path";
|
|
934
|
+
var PACK_TEMPLATES_DIR = join6(TEMPLATES_DIR, "experts", "stack");
|
|
935
|
+
var OVERLAY_TEMPLATES_DIR = join6(PACK_TEMPLATES_DIR, "overlays");
|
|
936
|
+
var PACK_BODY_MAX_BYTES = 8 * 1024;
|
|
937
|
+
var OVERLAY_MAX_BYTES = 6 * 1024;
|
|
930
938
|
// src/core/training/mineRuns.ts
|
|
931
939
|
import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
|
|
932
|
-
import { join as
|
|
940
|
+
import { join as join7, relative as relative2 } from "node:path";
|
|
933
941
|
var MAX_RUN_BYTES = 64 * 1024;
|
|
934
942
|
var MINED_NAMES = ["handoff.md", "retro.md"];
|
|
935
943
|
var MAX_DEPTH = 4;
|
|
@@ -953,7 +961,7 @@ function findMined(dir, depth) {
|
|
|
953
961
|
for (const entry of [...entries].sort()) {
|
|
954
962
|
if (entry.startsWith("."))
|
|
955
963
|
continue;
|
|
956
|
-
const abs =
|
|
964
|
+
const abs = join7(dir, entry);
|
|
957
965
|
let isDir = false;
|
|
958
966
|
try {
|
|
959
967
|
isDir = statSync4(abs).isDirectory();
|
package/dist/hooks/statusline.js
CHANGED