etymd 0.1.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 +48 -0
- package/LICENSE +21 -0
- package/README.md +166 -0
- package/dist/approve-WM6OJHQG.js +37 -0
- package/dist/audit-OHOSWOWA.js +8 -0
- package/dist/brief-2MPNTITQ.js +94 -0
- package/dist/chunk-5D7WNJ6N.js +1148 -0
- package/dist/chunk-FXL4554F.js +176 -0
- package/dist/chunk-I566LDX7.js +120 -0
- package/dist/chunk-N64ZTBCW.js +105 -0
- package/dist/chunk-SMM2TW35.js +67 -0
- package/dist/chunk-TCWKIMCU.js +502 -0
- package/dist/chunk-U33XLT5I.js +9 -0
- package/dist/chunk-WVYKYPKS.js +332 -0
- package/dist/cli.js +104 -0
- package/dist/context-TT5H76LA.js +18 -0
- package/dist/doctor-NNRJTNIY.js +15 -0
- package/dist/gates-KPDEUC36.js +71 -0
- package/dist/index.d.ts +444 -0
- package/dist/index.js +2095 -0
- package/dist/init-V627UXKU.js +116 -0
- package/dist/ledger-YFTYCOIC.js +39 -0
- package/dist/scan-YL7JHLUA.js +22 -0
- package/package.json +83 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# etymd
|
|
2
|
+
|
|
3
|
+
## 0.1.0 — 2026-07-31
|
|
4
|
+
|
|
5
|
+
First public release.
|
|
6
|
+
|
|
7
|
+
The truth guard for agent instruction files — **keep your agent instructions true**. (Formerly
|
|
8
|
+
prototyped as "clothaid", a broader workflow installer; the pivot and its state-of-the-field
|
|
9
|
+
rationale are recorded in `docs/design/003-truth-guard-pivot.md`.)
|
|
10
|
+
|
|
11
|
+
- `etymd audit` — verify every instruction claim against the actual repo, through three lenses:
|
|
12
|
+
- **instruction-truth**: command claims vs `package.json` scripts, path claims vs the tree,
|
|
13
|
+
package-manager consistency, cross-reference integrity, and drift vs the committed baseline —
|
|
14
|
+
over AGENTS.md, CLAUDE.md, GEMINI.md, Copilot instructions, Cursor rules, and skills.
|
|
15
|
+
- **gate-integrity**: the CI ↔ local gate inventory (GitLab incl. `!reference`/includes/
|
|
16
|
+
script-less jobs, GitHub, husky modern + v3, lint-staged) with honesty rules — advisory jobs
|
|
17
|
+
are never gates, unseen templates are disclosed, server-side thresholds named as such.
|
|
18
|
+
- **context-economy**: the always-loaded footprint in words/tokens; extraction candidates.
|
|
19
|
+
- Ranked findings (risk → gap → polish) with evidence · a **committed ledger** (resolved /
|
|
20
|
+
regressed / dismissed-never-resurfaces) · lens-coverage reporting · `--fail-on <tier>` for CI.
|
|
21
|
+
- **Excluding a file never resolves its tracked findings.** A finding missing from a scoped run is
|
|
22
|
+
absent because nobody looked, not because it was fixed. The ledger holds those entries open
|
|
23
|
+
(`lastSeen` untouched) and the diff reports them as held rather than folding them into
|
|
24
|
+
"N resolved".
|
|
25
|
+
- **`init` baselines the repo it leaves behind.** It used to approve the scan taken *before* its
|
|
26
|
+
own scaffold, so the first baseline recorded AGENTS.md and the hooks as absent — and deleting
|
|
27
|
+
them later never registered as drift, which is the baseline's whole job. It now re-scans after
|
|
28
|
+
writing.
|
|
29
|
+
- **The committed baseline carries no machine path.** `baseline.json` used to record the scan's
|
|
30
|
+
absolute root — the approver's username and directory layout — in the one file etymd tells people
|
|
31
|
+
to commit and therefore publish. The root is now elided on write (`"."`; it is redundant inside
|
|
32
|
+
the repo it describes). A baseline written by an older etymd is detected and disclosed with the
|
|
33
|
+
fix: `etymd approve`.
|
|
34
|
+
- **`.etymd/config.json`** (optional, committed) — `instructions.include` / `instructions.exclude`
|
|
35
|
+
globs scope which instruction files are audited (a fork keeps its own layer honest without
|
|
36
|
+
auditing inherited upstream skills), and `context.perFileWords` / `context.totalWords` make the
|
|
37
|
+
economy budgets per-repo. Excluded files are counted and named in the disclosures, and malformed
|
|
38
|
+
config is disclosed — narrowing an audit can never quietly buy a clean report.
|
|
39
|
+
- `etymd init` — onboarding: approve the committed baseline, gitignore the cache, scaffold a
|
|
40
|
+
minimal AGENTS.md only where none exists. Never overwrites.
|
|
41
|
+
- `etymd doctor` — alias for `audit --truth`.
|
|
42
|
+
- `etymd context` — the per-file always-loaded footprint view.
|
|
43
|
+
- `etymd gates` — local git-hook gates built from the repo's own check commands (writers can
|
|
44
|
+
never enter the gate); pairs with the gate-integrity findings.
|
|
45
|
+
- `etymd scan` — the deterministic reckoning (corpus-validated detectors incl. husky v3 and
|
|
46
|
+
meta-script-proof command classification). `etymd brief` — the agent briefing for the
|
|
47
|
+
semantic layer.
|
|
48
|
+
- Zero-trace guarantee: read-only probes of foreign repos write nothing.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alkis Yuv
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# etymd
|
|
2
|
+
|
|
3
|
+
**Keep your agent instructions true.**
|
|
4
|
+
|
|
5
|
+
Your `AGENTS.md` is the interface between your team and every coding agent — and it rots silently.
|
|
6
|
+
Scripts get renamed, directories move, rules go stale, and the file keeps instructing agents with
|
|
7
|
+
confidence. etymd continuously **verifies the agent context layer against the actual repo**:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
$ etymd audit
|
|
11
|
+
|
|
12
|
+
RISK AGENTS.md tells agents to run `pnpm dev` — no such script exists
|
|
13
|
+
evidence AGENTS.md: `pnpm dev` · package.json scripts
|
|
14
|
+
action Update the instruction to the current script name.
|
|
15
|
+
|
|
16
|
+
GAP AGENTS.md references `src/legacy/` — it does not exist in the repo
|
|
17
|
+
GAP Type checking is enforced only in CI — no local hook runs it
|
|
18
|
+
GAP AGENTS.md loads 13,809 words (~18k tokens) into every session
|
|
19
|
+
|
|
20
|
+
since last audit: 1 new · 3 still open · 1 resolved · 1 REGRESSED
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
_From Greek **étymon** — a word's true, original sense (→ etymology) — clipped to **etym.** + the
|
|
24
|
+
**.md** family it guards._
|
|
25
|
+
|
|
26
|
+
## Why this exists
|
|
27
|
+
|
|
28
|
+
- Instruction files are now load-bearing: 20+ agents (Claude Code, Codex, Cursor, Copilot,
|
|
29
|
+
Gemini, …) read `AGENTS.md` natively. A stale claim doesn't error — it silently misleads every
|
|
30
|
+
session.
|
|
31
|
+
- Linters exist for these files, but they check **a point in time**. Truth is a property **over
|
|
32
|
+
time**: etymd measures drift against a **committed baseline**, remembers findings in a
|
|
33
|
+
**ledger** (fixed things stay fixed; a returning problem is named a _regression_, and a finding
|
|
34
|
+
you dismissed with a reason never resurfaces), and gates CI on it.
|
|
35
|
+
- **Honesty is structural.** Every report declares what it could NOT see — CI jobs inherited from
|
|
36
|
+
unreadable org templates, server-side quality-gate thresholds, skipped heuristics. No guess is
|
|
37
|
+
ever dressed as a fact.
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
cd your-project
|
|
43
|
+
npx etymd init # approve the baseline (+ scaffold AGENTS.md only if you have none)
|
|
44
|
+
npx etymd audit # verify every instruction claim against the repo
|
|
45
|
+
npx etymd audit --fail-on risk # the CI gate
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Requires Node ≥ 18.17. **Status: pre-publish** — run from a checkout (`npm run build &&
|
|
49
|
+
node dist/cli.js …`) until the first npm release.
|
|
50
|
+
|
|
51
|
+
## What it checks
|
|
52
|
+
|
|
53
|
+
**`instruction-truth`** — over `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, Copilot instructions,
|
|
54
|
+
`.cursor/rules/*`, `.clinerules`, `.claude/skills/*/SKILL.md`:
|
|
55
|
+
|
|
56
|
+
- **Command claims** — every `pnpm X` / `npm run X` the files tell agents to run must exist in
|
|
57
|
+
`package.json` scripts.
|
|
58
|
+
- **Path claims** — every repo path the files point at must exist (conservative heuristics; what's
|
|
59
|
+
skipped is disclosed). A path the surrounding prose tells the agent to _create_, and an obvious
|
|
60
|
+
naming stand-in like `my-custom-skill`, are forward-looking instructions, not stale references.
|
|
61
|
+
- **Package-manager consistency** — instructions must not command `yarn` in a `pnpm` repo.
|
|
62
|
+
- **Cross-references** — pointer chains (`CLAUDE.md` → `AGENTS.md` → state docs) must resolve.
|
|
63
|
+
- **Drift vs baseline** — documented commands/artifacts/layout that existed at approval and are
|
|
64
|
+
now gone.
|
|
65
|
+
|
|
66
|
+
**`gate-integrity`** — a CI config is a claim too: checks enforced only in CI (failures surface a
|
|
67
|
+
slow pipeline after the agent finished — `etymd gates` generates the local mirror), checks only in
|
|
68
|
+
skippable local hooks, latent gaps (coverage collected but nothing gates on it; commitlint
|
|
69
|
+
installed but unwired). `allow_failure` jobs count as advisory, never as gates.
|
|
70
|
+
|
|
71
|
+
**`context-economy`** — the always-loaded footprint in words/tokens (only genuinely
|
|
72
|
+
`alwaysApply` Cursor rules count), flagging files worth extracting into on-demand skills. Context
|
|
73
|
+
is the dominant cost of the loop; a lean contract is a correctness feature.
|
|
74
|
+
|
|
75
|
+
## Commands
|
|
76
|
+
|
|
77
|
+
| Command | What it does |
|
|
78
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
79
|
+
| `etymd audit` | Verify every claim; ranked findings (risk → gap → polish) + ledger diff. `--lens`, `--truth`, `--json`, `--no-ledger`, `--fail-on <tier>`. |
|
|
80
|
+
| `etymd init` | Onboard: approve the committed baseline; scaffold a minimal AGENTS.md **only if missing**. Never overwrites. |
|
|
81
|
+
| `etymd doctor` | Alias for `audit --truth`. |
|
|
82
|
+
| `etymd context` | The economy view: per-file always-loaded footprint + extraction candidates. |
|
|
83
|
+
| `etymd gates` | Install local git-hook gates (pre-commit / pre-push) built from your own check scripts. |
|
|
84
|
+
| `etymd scan` | The deterministic reckoning behind everything. `--json`. |
|
|
85
|
+
| `etymd brief` | A grounded briefing your in-repo agent completes to author the semantic layer. |
|
|
86
|
+
|
|
87
|
+
`--cwd <dir>` targets another directory. Read-only probing of any repo leaves **zero trace**
|
|
88
|
+
(`audit --no-ledger` writes nothing).
|
|
89
|
+
|
|
90
|
+
## The files etymd keeps
|
|
91
|
+
|
|
92
|
+
| Path | Lifecycle | Role |
|
|
93
|
+
| ---------------------- | ------------- | ------------------------------------------------ |
|
|
94
|
+
| `.etymd/baseline.json` | **committed** | the approved reckoning drift is measured against |
|
|
95
|
+
| `.etymd/ledger.json` | **committed** | the findings memory: statuses, diffs, dismissals |
|
|
96
|
+
| `.etymd/config.json` | **committed** | optional: audit scope + context budgets |
|
|
97
|
+
| `.etymd/cache/` | gitignored | transient scan cache |
|
|
98
|
+
|
|
99
|
+
The committed files are written to be publishable: the baseline records `"."` as its scan root, never
|
|
100
|
+
your absolute machine path. Only the gitignored cache keeps the real one.
|
|
101
|
+
|
|
102
|
+
### `.etymd/config.json` (optional)
|
|
103
|
+
|
|
104
|
+
Every key is optional; omit the file entirely and the defaults below apply.
|
|
105
|
+
|
|
106
|
+
```jsonc
|
|
107
|
+
{
|
|
108
|
+
"instructions": {
|
|
109
|
+
// Audit these too — files detection would not find on its own.
|
|
110
|
+
"include": ["design/**/*.md"],
|
|
111
|
+
// Leave these out. The classic case: a fork that inherits upstream's skills
|
|
112
|
+
// and will never fix them, but must keep its OWN instruction layer honest.
|
|
113
|
+
"exclude": [".claude/skills/**"],
|
|
114
|
+
},
|
|
115
|
+
"context": {
|
|
116
|
+
"perFileWords": 4000, // extraction candidate above this
|
|
117
|
+
"totalWords": 8000, // always-loaded footprint budget
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Globs are repo-relative: `*` within a path segment, `**` across segments, `?` one character. A
|
|
123
|
+
pattern with no wildcard is a **path prefix**, so `.claude/skills` covers everything beneath it.
|
|
124
|
+
|
|
125
|
+
Narrowing an audit can hide findings, so etymd never lets it happen quietly: **every excluded file
|
|
126
|
+
is counted and named in the lens disclosures**, and a config that fails to parse is reported as a
|
|
127
|
+
disclosure rather than silently falling back to defaults.
|
|
128
|
+
|
|
129
|
+
## Programmatic use
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { runAudit } from "etymd"
|
|
133
|
+
|
|
134
|
+
const audit = await runAudit(process.cwd(), { persistLedger: false })
|
|
135
|
+
console.log(audit.findings) // one schema: claim · evidence · why · action · effort · confidence
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## The corpus (how this is validated)
|
|
139
|
+
|
|
140
|
+
etymd is developed against a corpus of real sibling repos rather than fixtures alone —
|
|
141
|
+
[`sources.json`](sources.json) lists them by shape. Every heuristic here exists because a real
|
|
142
|
+
repo proved the previous one wrong, and each skip class in the truth lens is a false positive that
|
|
143
|
+
a corpus run caught.
|
|
144
|
+
|
|
145
|
+
Some corpus entries are private and are named by shape (`nx-monorepo`, `spa-bff`, `cra-legacy`)
|
|
146
|
+
rather than by directory. To run those smokes locally, add an untracked `sources.local.json`
|
|
147
|
+
mapping each name to its sibling directory:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{ "dirs": { "nx-monorepo": "my-monorepo-checkout" } }
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Each value is resolved as a sibling of the etymd checkout.
|
|
154
|
+
|
|
155
|
+
Without it — on a fresh clone or in CI — those suites skip cleanly and the rest still run.
|
|
156
|
+
|
|
157
|
+
## Design record & roadmap
|
|
158
|
+
|
|
159
|
+
[`docs/design/`](docs/design/) — 001 founding · 002 foundation re-lock · **003 the truth-guard
|
|
160
|
+
pivot** (the current identity; includes the state-of-the-field investigation it rests on).
|
|
161
|
+
[`ROADMAP.md`](ROADMAP.md) — what's now / next / later, the pre-publish checklist, and the
|
|
162
|
+
accepted heuristic trade-offs.
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { scanProject, PACK_VERSION } from './chunk-TCWKIMCU.js';
|
|
3
|
+
import { VERSION } from './chunk-U33XLT5I.js';
|
|
4
|
+
import { readBaseline, summarizeBaselineDrift, isDriftEmpty, writeBaseline, deriveProfile } from './chunk-SMM2TW35.js';
|
|
5
|
+
import { section, theme, print, renderBaselineDrift, glyph } from './chunk-WVYKYPKS.js';
|
|
6
|
+
|
|
7
|
+
// src/commands/approve.ts
|
|
8
|
+
async function run(opts) {
|
|
9
|
+
const prior = await readBaseline(opts.cwd);
|
|
10
|
+
if (!prior) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
"no committed baseline to re-approve \u2014 run `etymd init` to create the first one"
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
const facts = await scanProject(opts.cwd);
|
|
16
|
+
const drift = summarizeBaselineDrift(prior.facts, facts);
|
|
17
|
+
section(`Re-approving baseline ${theme.dim(`\xB7 ${facts.name} \xB7 ${prior.profile} profile`)}`);
|
|
18
|
+
if (isDriftEmpty(drift)) {
|
|
19
|
+
print(` ${theme.dim("no structural change on the measured axes \u2014 refreshing the stamp only")}`);
|
|
20
|
+
} else {
|
|
21
|
+
renderBaselineDrift(drift);
|
|
22
|
+
}
|
|
23
|
+
await writeBaseline(opts.cwd, {
|
|
24
|
+
packVersion: PACK_VERSION,
|
|
25
|
+
etymdVersion: VERSION,
|
|
26
|
+
approvedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27
|
+
// A refresh re-blesses the current tree; the profile is a human decision from init — keep it.
|
|
28
|
+
profile: prior.profile ?? deriveProfile(facts),
|
|
29
|
+
facts
|
|
30
|
+
});
|
|
31
|
+
print();
|
|
32
|
+
print(
|
|
33
|
+
` ${glyph.ok} ${theme.dim("baseline re-approved \u2192")} ${theme.info(".etymd/baseline.json")} ${theme.dim("(commit it \u2014 drift is now measured against this state)")}`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { run };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { scanProject } from './chunk-TCWKIMCU.js';
|
|
3
|
+
import './chunk-U33XLT5I.js';
|
|
4
|
+
import { ETYMD_DIR } from './chunk-SMM2TW35.js';
|
|
5
|
+
import { print, theme } from './chunk-WVYKYPKS.js';
|
|
6
|
+
import { promises } from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
|
|
9
|
+
async function run(opts) {
|
|
10
|
+
const facts = await scanProject(opts.cwd);
|
|
11
|
+
const contents = opts.human ? humanBrief(facts) : agentBrief(facts);
|
|
12
|
+
const rel = path.join(ETYMD_DIR, opts.human ? "onboarding.md" : "brief.md");
|
|
13
|
+
const target = path.join(opts.cwd, rel);
|
|
14
|
+
await promises.mkdir(path.dirname(target), { recursive: true });
|
|
15
|
+
await promises.writeFile(target, contents, "utf8");
|
|
16
|
+
print();
|
|
17
|
+
print(` ${theme.dim("wrote")} ${theme.info(rel)}`);
|
|
18
|
+
if (opts.human) {
|
|
19
|
+
print(` ${theme.dim("A human-readable onboarding brief drawn from the reckoning.")}`);
|
|
20
|
+
} else {
|
|
21
|
+
print(
|
|
22
|
+
` ${theme.dim("Hand this to the agent already in your repo (Claude Code / Cursor / Copilot):")}`
|
|
23
|
+
);
|
|
24
|
+
print(
|
|
25
|
+
` ${theme.dim(' "Read')} ${theme.info(rel)}${theme.dim(' and complete it against the codebase."')}`
|
|
26
|
+
);
|
|
27
|
+
print(
|
|
28
|
+
` ${theme.dim("Its answers become the semantic half of AGENTS.md \u2014 you approve before it lands.")}`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function factsSummary(facts) {
|
|
33
|
+
const dirs = facts.tree.dirs.slice(0, 14).map((d) => `- \`${d.name}/\` (${d.files} files)`).join("\n");
|
|
34
|
+
return `- Name: ${facts.name}
|
|
35
|
+
- Shape: ${facts.workspace.kind === "none" ? "single package" : `${facts.workspace.kind} workspace`}, ${facts.packageManager}
|
|
36
|
+
- Frameworks: ${facts.frameworks.join(", ") || "unknown"}
|
|
37
|
+
- CI: ${facts.ci.system}
|
|
38
|
+
- Top-level layout:
|
|
39
|
+
${dirs || "- (single package)"}`;
|
|
40
|
+
}
|
|
41
|
+
function agentBrief(facts) {
|
|
42
|
+
return `# Reckoning brief \u2014 ${facts.name}
|
|
43
|
+
|
|
44
|
+
You are completing the **semantic half** of this project's operating contract. etymd has already
|
|
45
|
+
gathered the deterministic facts below. Your job is to fill in what only reading the code reveals.
|
|
46
|
+
Ground every answer in real files; cite paths. Do not invent structure. When unsure, say so.
|
|
47
|
+
|
|
48
|
+
## Facts already known (do not re-derive)
|
|
49
|
+
|
|
50
|
+
${factsSummary(facts)}
|
|
51
|
+
|
|
52
|
+
## Produce these sections
|
|
53
|
+
|
|
54
|
+
1. **What this project is** \u2014 one paragraph: what it does, who uses it, the core domain.
|
|
55
|
+
2. **Composition points** \u2014 the 4\u20138 architectural seams a change usually flows through (entry
|
|
56
|
+
points, routers, the data-access layer, the shared contract surface). For each: file path +
|
|
57
|
+
one line on the invariant that must not break when editing it.
|
|
58
|
+
3. **Reuse inventory** \u2014 the existing components/hooks/utils/types a new task most often should
|
|
59
|
+
reuse instead of writing fresh. Point at where they live.
|
|
60
|
+
4. **Ownership boundaries** \u2014 which directories own which concerns; what must not leak across them.
|
|
61
|
+
5. **Gotchas** \u2014 non-obvious rules, environment traps, or footguns worth a failure-modes entry.
|
|
62
|
+
|
|
63
|
+
## Output
|
|
64
|
+
|
|
65
|
+
Write your answer to \`AGENTS.md\` under the matching headings (replace the \`<!-- ... -->\`
|
|
66
|
+
placeholders), or return it for review. The human approves before it becomes the contract.
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
function humanBrief(facts) {
|
|
70
|
+
return `# Onboarding \u2014 ${facts.name}
|
|
71
|
+
|
|
72
|
+
A quick orientation generated from the project reckoning.
|
|
73
|
+
|
|
74
|
+
## At a glance
|
|
75
|
+
|
|
76
|
+
${factsSummary(facts)}
|
|
77
|
+
|
|
78
|
+
## Getting started
|
|
79
|
+
|
|
80
|
+
\`\`\`bash
|
|
81
|
+
${facts.commands.dev ? `${facts.packageManager} ${facts.commands.dev} # run locally` : "# add the dev command"}
|
|
82
|
+
${facts.commands.test ? `${facts.packageManager} ${facts.commands.test} # run tests` : ""}
|
|
83
|
+
\`\`\`
|
|
84
|
+
|
|
85
|
+
## Where to look next
|
|
86
|
+
|
|
87
|
+
- \`AGENTS.md\` \u2014 the operating contract (stack, rules, repo map, definition of done).
|
|
88
|
+
- \`PROJECT_CONTEXT.md\` \u2014 current state and decisions.
|
|
89
|
+
|
|
90
|
+
_This is a starting point. Refine it with the domain knowledge only the team has._
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export { run };
|