agent-docs-bootstrap 0.2.0 → 0.4.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 +27 -0
- package/README.md +32 -14
- package/THIRD_PARTY.md +8 -6
- package/agents/docs-scout.md +0 -1
- package/install.mjs +89 -30
- package/package.json +3 -3
- package/skills/docs-bootstrap/SKILL.md +11 -7
- package/skills/docs-bootstrap/references/scout-briefs.md +2 -2
- package/skills/docs-bootstrap/references/signals.md +1 -1
- package/skills/docs-check/SKILL.md +3 -3
- package/skills/docs-check/scripts/reader-run.mjs +18 -7
- package/skills/third-party/grill-with-docs/SKILL.md +0 -7
- package/skills/third-party/grill-with-docs/agents/openai.yaml +0 -5
- package/skills/third-party/writing-for-agents/LICENSE +0 -21
- /package/skills/{third-party → docs-bootstrap/vendor}/diataxis-audit/LICENSE +0 -0
- /package/skills/{third-party/diataxis-audit/SKILL.md → docs-bootstrap/vendor/diataxis-audit/diataxis-audit.md} +0 -0
- /package/skills/{third-party → docs-bootstrap/vendor}/doc-coauthoring/LICENSE +0 -0
- /package/skills/{third-party/doc-coauthoring/SKILL.md → docs-bootstrap/vendor/doc-coauthoring/doc-coauthoring.md} +0 -0
- /package/skills/{third-party → docs-bootstrap/vendor}/domain-modeling/ADR-FORMAT.md +0 -0
- /package/skills/{third-party → docs-bootstrap/vendor}/domain-modeling/CONTEXT-FORMAT.md +0 -0
- /package/skills/{third-party → docs-bootstrap/vendor}/domain-modeling/LICENSE +0 -0
- /package/skills/{third-party → docs-bootstrap/vendor}/domain-modeling/agents/openai.yaml +0 -0
- /package/skills/{third-party/domain-modeling/SKILL.md → docs-bootstrap/vendor/domain-modeling/domain-modeling.md} +0 -0
- /package/skills/{third-party/grill-with-docs → docs-bootstrap/vendor/grilling}/LICENSE +0 -0
- /package/skills/{third-party → docs-bootstrap/vendor}/grilling/agents/openai.yaml +0 -0
- /package/skills/{third-party/grilling/SKILL.md → docs-bootstrap/vendor/grilling/grilling.md} +0 -0
- /package/skills/{third-party/grilling → docs-bootstrap/vendor/writing-for-agents}/LICENSE +0 -0
- /package/skills/{third-party → docs-bootstrap/vendor}/writing-for-agents/SKILL-MECHANICS.md +0 -0
- /package/skills/{third-party → docs-bootstrap/vendor}/writing-for-agents/agents/openai.yaml +0 -0
- /package/skills/{third-party/writing-for-agents/SKILL.md → docs-bootstrap/vendor/writing-for-agents/writing-for-agents.md} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,33 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versions follo
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.4.0] - 2026-10-27
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- `.agent-docs-bootstrap` lines are `<path> <content hash>`. A path is replaced or removed only if its content still matches what the kit wrote; lines without a hash, from 0.3.0 and earlier, are checked against the hashes of everything those versions installed.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- An update or `--uninstall` removed a listed path whatever was in it, so a skill the user had replaced with their own version under the same name, such as `grilling` after 0.2.0, was deleted. A changed path is now left in place as the user's, with a warning, and drops out of the marker. Subagent files a 0.3.0 or earlier install rendered with `--scout-model` or `--reader-model` do not match the known hashes and are left in place too: delete them and run the installer again.
|
|
14
|
+
|
|
15
|
+
## [0.3.0] - 2026-10-27
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- Third-party skills are bundled inside `docs-bootstrap` as guides in `vendor/<name>/`, read by path, instead of being installed as separate skills. Each `SKILL.md` is renamed to `<name>.md`, content unchanged: Codex and OpenCode find a nested `SKILL.md` and register it as a skill, and OpenCode silently keeps one of two skills with the same name. A user's own `grilling` or `domain-modeling` no longer clashes with the kit's copy. The install now has two skills, `docs-bootstrap` and `docs-check`.
|
|
19
|
+
- The installer removes paths an earlier version installed into the same targets and this version no longer ships, so an update from 0.2.0 drops the old third-party skill folders.
|
|
20
|
+
- README, package description and keywords: a set of agent skills for any agent that runs them; the installer sets up Claude Code, Codex and OpenCode. New "Other agents" section. `docs-check` falls back to `--snapshot-only` for any other harness.
|
|
21
|
+
- `docs-scout` for OpenCode no longer needs the `diataxis-audit` skill permission; the brief gives it the guide's path.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- `--uninstall` and updates removed every path listed in `.agent-docs-bootstrap`, which is committed, so a line added by a bad merge (`src`, `../x`) deleted project or outside folders. Only lines shaped like a path the kit installs, `<layout folder>/<kit name>`, are now trusted; others are ignored with a warning and dropped from the marker. `reader-run.mjs` applies the same rule, so a stray `docs` line no longer hides every document from the snapshot.
|
|
25
|
+
- `docs-check` snapshot: a nested `CLAUDE.md` came from the parent commit instead of the working tree. `README` stays from the parent commit on purpose, now stated in the skill.
|
|
26
|
+
- README no longer says the Codex reader has no access to the repository: its read-only sandbox blocks writes, not reading other folders.
|
|
27
|
+
- `docs-check`: global instructions wording no longer claims `claude -p --restricted` loads `~/.claude/CLAUDE.md`.
|
|
28
|
+
- `reader-run.mjs`: `--timeout-min` is documented; on Windows the timeout stops the CLI, not only its shell; snapshot folders of two repositories with the same name no longer collide.
|
|
29
|
+
- `install.mjs` accepts `--flag=value` as well as `--flag value`.
|
|
30
|
+
|
|
31
|
+
### Removed
|
|
32
|
+
- `grill-with-docs`: the kit did not use it, and it only calls the `grilling` and `domain-modeling` skills, which are no longer installed as skills.
|
|
33
|
+
|
|
7
34
|
## [0.2.0] - 2026-10-27
|
|
8
35
|
|
|
9
36
|
### Added
|
package/README.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
[](https://github.com/TraneDev/agent-docs-bootstrap/actions/workflows/check.yml)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
**agent-docs-bootstrap** is a set of skills and
|
|
7
|
+
**agent-docs-bootstrap** is a set of agent skills and instructions, not tied to one tool. It interviews your team and writes the glossary, decision records, architecture, how-tos and `AGENTS.md` that coding agents and new developers need. If you want to see how well they work, an **optional** check has a fresh agent plan a task from the docs alone: one you bring, or real past tasks from your git history compared with the commits that solved them.
|
|
8
|
+
|
|
9
|
+
The installer sets up **Claude Code**, **Codex** and **OpenCode**. Any other agent that runs skills can use the two skill folders as they are: see [Other agents](#other-agents).
|
|
8
10
|
|
|
9
11
|
[Quick start](#quick-start) · [How it works](#how-it-works) · [Optional: test the docs](#optional-test-the-docs-with-docs-check) · [Install options](#install-options) · [Harness differences](#harness-differences)
|
|
10
12
|
|
|
@@ -15,7 +17,7 @@ You need Node.js 18+ and a git repository.
|
|
|
15
17
|
1. From your project root, install the skills and subagents:
|
|
16
18
|
|
|
17
19
|
```bash
|
|
18
|
-
npx agent-docs-bootstrap@0.
|
|
20
|
+
npx agent-docs-bootstrap@0.4.0 --target claude
|
|
19
21
|
```
|
|
20
22
|
|
|
21
23
|
Replace `claude` with `codex`, `opencode`, a list such as `claude,codex`, or `all`.
|
|
@@ -79,7 +81,7 @@ flowchart LR
|
|
|
79
81
|
|
|
80
82
|
1. The agent picks three real past tasks from git history, preferring commits made after the docs were written, and drops any whose solution is already in the code or the docs.
|
|
81
83
|
2. For each task, the code is extracted **as it was before the task**, outside your repository, and your current documents from the working tree go on top.
|
|
82
|
-
3. A fresh reader plans the task. It runs as a **separate process** of your harness (`claude -p`, `codex exec`, `opencode run`), read-only, with no history
|
|
84
|
+
3. A fresh reader plans the task. It runs as a **separate process** of your harness (`claude -p`, `codex exec`, `opencode run`), read-only, with no history and no MCP tools, in a snapshot outside your repository: a subagent of the same session could find the solution in your current code. Claude Code and OpenCode keep the reader's file access inside the snapshot; Codex's read-only sandbox blocks writes but not reading elsewhere, so there only the reader's instructions keep it in the snapshot (see [Harness differences](#harness-differences)).
|
|
83
85
|
4. Its plan is compared with what the real commit changed. Missed files, missed verification commands, wrong terms, rejected approaches and guesses are **gaps**.
|
|
84
86
|
5. The gaps become one list of fixes, grouped by document. You strike out what came from a poor commit rather than the docs, and the rest is applied.
|
|
85
87
|
|
|
@@ -101,19 +103,19 @@ All options run the same installer from your project root. Pin the version: the
|
|
|
101
103
|
**From npm** (recommended):
|
|
102
104
|
|
|
103
105
|
```bash
|
|
104
|
-
npx agent-docs-bootstrap@0.
|
|
106
|
+
npx agent-docs-bootstrap@0.4.0 --target claude
|
|
105
107
|
```
|
|
106
108
|
|
|
107
109
|
**From a GitHub release tag**, when the npm registry is blocked or unavailable:
|
|
108
110
|
|
|
109
111
|
```bash
|
|
110
|
-
npx github:TraneDev/agent-docs-bootstrap#v0.
|
|
112
|
+
npx github:TraneDev/agent-docs-bootstrap#v0.4.0 --target claude
|
|
111
113
|
```
|
|
112
114
|
|
|
113
115
|
**From a clone**, to read or change the kit first:
|
|
114
116
|
|
|
115
117
|
```bash
|
|
116
|
-
git clone --branch v0.
|
|
118
|
+
git clone --branch v0.4.0 https://github.com/TraneDev/agent-docs-bootstrap.git ~/agent-docs-bootstrap
|
|
117
119
|
node ~/agent-docs-bootstrap/install.mjs --target claude
|
|
118
120
|
```
|
|
119
121
|
|
|
@@ -127,11 +129,26 @@ Files are copied into the project, not linked, so they get committed with it.
|
|
|
127
129
|
| `codex` | `.agents/skills/` | `.codex/agents/*.toml` |
|
|
128
130
|
| `opencode` | `.agents/skills/` | `.opencode/agents/*.md`, plus `/docs-bootstrap` and `/docs-check` commands |
|
|
129
131
|
|
|
130
|
-
|
|
132
|
+
Two skills are installed, `docs-bootstrap` and `docs-check`. The guides by other authors that `docs-bootstrap` relies on travel inside it, in `docs-bootstrap/vendor/`, and are not registered as skills, so a skill of yours with the same name, such as `grilling`, never clashes with them.
|
|
133
|
+
|
|
134
|
+
`.agent-docs-bootstrap` lists every installed path with a hash of what was written. The installer replaces or removes a path only if it is listed there and its content still matches, so it never touches files it did not create or that you changed:
|
|
135
|
+
|
|
136
|
+
- a path that exists but is not listed is skipped with a warning;
|
|
137
|
+
- a listed path whose content you changed, for example a skill you replaced with your own version, is left in place as yours, with a warning, and drops out of the marker;
|
|
138
|
+
- a marker line not shaped like a path the kit installs (for example `src` or `../x`, added by a bad merge) is ignored with a warning.
|
|
139
|
+
|
|
140
|
+
### Other agents
|
|
141
|
+
|
|
142
|
+
The skills are plain `SKILL.md` folders with Markdown references and templates. For an agent the installer does not know, copy `skills/docs-bootstrap` and `skills/docs-check` from a clone (see above) into the folder where that agent looks for skills, and start it with "document this project". An agent without skill support can be pointed at `docs-bootstrap/SKILL.md` directly.
|
|
143
|
+
|
|
144
|
+
What changes without the installer's targets:
|
|
145
|
+
|
|
146
|
+
- **No subagents.** `docs-bootstrap` does the scout's briefs itself and keeps only summaries in the conversation.
|
|
147
|
+
- **`docs-check`** builds the snapshot with `reader-run.mjs --snapshot-only`; you start a fresh session of your agent in that folder and paste the task. Starting the reader automatically works only with `claude`, `codex` and `opencode`.
|
|
131
148
|
|
|
132
149
|
### Update or remove
|
|
133
150
|
|
|
134
|
-
- **Update:** run the installer again with the new version and commit the result.
|
|
151
|
+
- **Update:** run the installer again with the new version and commit the result. Paths the previous version installed and this one no longer ships are removed. Do not install an older version over a newer one: an older installer does not read the newer marker and treats the kit's files as yours. Run `--uninstall` with the newer version first.
|
|
135
152
|
- **Remove:** run it with `--uninstall`. Everything listed in `.agent-docs-bootstrap` is deleted, along with the marker itself.
|
|
136
153
|
|
|
137
154
|
<details>
|
|
@@ -155,19 +172,20 @@ The protocol is the same everywhere; how strictly each harness can enforce the l
|
|
|
155
172
|
|
|
156
173
|
| Guarantee | Claude Code | Codex | OpenCode |
|
|
157
174
|
|---|---|---|---|
|
|
158
|
-
| Reader cannot see the solution or history | Snapshot outside the repo, no history; `--restricted` keeps file tools inside it | Snapshot outside the repo, no history | Snapshot outside the repo, no history; `external_directory: deny` |
|
|
175
|
+
| Reader cannot see the solution or history | Snapshot outside the repo, no history; `--restricted` keeps file tools inside it | Snapshot outside the repo, no history; reading other folders is not blocked, only the prompt forbids it | Snapshot outside the repo, no history; `external_directory: deny` |
|
|
159
176
|
| Reader cannot edit or run commands | `--restricted --tools Read,Grep,Glob` | `-s read-only` sandbox | Permissions (`"*": deny`) |
|
|
160
177
|
| Scout writes only to the scratch folder | Instructions (edit tool removed) | Instructions only | Path permissions |
|
|
161
178
|
| External docs are never modified | Instructions | Instructions | Instructions |
|
|
179
|
+
| Scout reads the bundled guides | File tools | File tools | Read permission; a `--global` install is outside the project, so `external_directory` asks once |
|
|
162
180
|
|
|
163
181
|
Where a guarantee is "instructions only", tighten it with your harness's own permission settings if you need to. For example, deny the write tools of your wiki's MCP server.
|
|
164
182
|
|
|
165
183
|
## Repository layout
|
|
166
184
|
|
|
167
185
|
```text
|
|
168
|
-
skills/docs-bootstrap/ orchestrator: SKILL.md, references/ (formats, scout briefs), templates
|
|
186
|
+
skills/docs-bootstrap/ orchestrator: SKILL.md, references/ (formats, scout briefs), templates/,
|
|
187
|
+
vendor/ (guides by other authors, each with its LICENSE)
|
|
169
188
|
skills/docs-check/ optional reader test: SKILL.md, templates/, scripts/reader-run.mjs (snapshot and reader process)
|
|
170
|
-
skills/third-party/ skills by other authors, unmodified, each with its LICENSE
|
|
171
189
|
agents/ docs-scout, docs-reader: one prompt + per-harness frontmatter blocks
|
|
172
190
|
package.json npm package metadata and the version
|
|
173
191
|
install.mjs installer (the package's `bin`)
|
|
@@ -178,12 +196,12 @@ To work on the kit itself, start with [AGENTS.md](AGENTS.md) and run `node scrip
|
|
|
178
196
|
|
|
179
197
|
## Credits
|
|
180
198
|
|
|
181
|
-
The workflow builds on skills by other authors, bundled
|
|
199
|
+
The workflow builds on skills by other authors, bundled inside `docs-bootstrap` under their licenses, unmodified except that each `SKILL.md` is renamed so it does not register as a separate skill. Pinned commits and update steps are in [THIRD_PARTY.md](THIRD_PARTY.md).
|
|
182
200
|
|
|
183
|
-
- Matt Pocock, [mattpocock/skills](https://github.com/mattpocock/skills): `domain-modeling`, `grilling
|
|
201
|
+
- Matt Pocock, [mattpocock/skills](https://github.com/mattpocock/skills): `domain-modeling`, `grilling` and `writing-for-agents` (MIT).
|
|
184
202
|
- Georges Martin, [jrjsmrtn/diataxis-skills](https://github.com/jrjsmrtn/diataxis-skills): `diataxis-audit` (MIT).
|
|
185
203
|
- Anthropic, [anthropics/skills](https://github.com/anthropics/skills): `doc-coauthoring` (Apache 2.0).
|
|
186
204
|
|
|
187
205
|
## License
|
|
188
206
|
|
|
189
|
-
[MIT](LICENSE) for the kit's own files.
|
|
207
|
+
[MIT](LICENSE) for the kit's own files. Bundled third-party guides keep their own licenses.
|
package/THIRD_PARTY.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
# Third-party
|
|
1
|
+
# Third-party guides
|
|
2
2
|
|
|
3
|
-
Copies of skills by other authors, pinned to a commit and **not modified
|
|
3
|
+
Copies of skills by other authors, pinned to a commit and **not modified**, bundled inside `docs-bootstrap` as guides it reads by path. Each folder under `skills/docs-bootstrap/vendor/` carries the license of its source.
|
|
4
|
+
|
|
5
|
+
The only change is a rename: each `SKILL.md` becomes `<name>.md`. Codex and OpenCode look for `SKILL.md` recursively inside skill folders, and Claude Code does not document how deep it looks, so a bundled `SKILL.md` would register as a separate skill and clash with a user's own skill of the same name. Other files keep their names, so links between them still resolve.
|
|
4
6
|
|
|
5
7
|
| Skill | Source | Commit | Author | License |
|
|
6
8
|
|---|---|---|---|---|
|
|
7
9
|
| `domain-modeling` | [mattpocock/skills](https://github.com/mattpocock/skills), `skills/engineering/domain-modeling` | `3cca18b` | Matt Pocock | MIT |
|
|
8
10
|
| `grilling` | [mattpocock/skills](https://github.com/mattpocock/skills), `skills/productivity/grilling` | `3cca18b` | Matt Pocock | MIT |
|
|
9
|
-
| `grill-with-docs` | [mattpocock/skills](https://github.com/mattpocock/skills), `skills/engineering/grill-with-docs` | `3cca18b` | Matt Pocock | MIT |
|
|
10
11
|
| `writing-for-agents` | [mattpocock/skills](https://github.com/mattpocock/skills), `skills/productivity/writing-for-agents` | `3cca18b` | Matt Pocock | MIT |
|
|
11
12
|
| `diataxis-audit` | [jrjsmrtn/diataxis-skills](https://github.com/jrjsmrtn/diataxis-skills), `skills/diataxis-audit` | `4f36079` | Georges Martin | MIT |
|
|
12
13
|
| `doc-coauthoring` | [anthropics/skills](https://github.com/anthropics/skills), `skills/doc-coauthoring` | `34040c9` | Anthropic | Apache 2.0 |
|
|
@@ -17,17 +18,18 @@ Full commit hashes: `3cca18b368ae95cdbdebbff572ccafa662551015`, `4f36079fd36e498
|
|
|
17
18
|
|
|
18
19
|
## Updating
|
|
19
20
|
|
|
20
|
-
Fresh clone of the source at the new commit → diff against the copy → review for harmful or harness-specific instructions → replace the folder
|
|
21
|
+
Fresh clone of the source at the new commit → diff against the copy (compare the source's `SKILL.md` with `<name>.md`) → review for harmful or harness-specific instructions → replace the folder, rename `SKILL.md` to `<name>.md`, keep its `LICENSE` → update the table. `node scripts/check.mjs` verifies every folder has `<name>.md`, a `LICENSE`, a row here and no `SKILL.md`.
|
|
21
22
|
|
|
22
23
|
## Known quirks
|
|
23
24
|
|
|
24
|
-
- `grill-with-docs` sets `disable-model-invocation: true`: Claude Code and Codex (via `agents/openai.yaml`) only run it when the user asks; OpenCode ignores the field. The kit's own workflow does not depend on it.
|
|
25
25
|
- `doc-coauthoring`: its "Reader Testing" step suggests opening a new chat on claude.ai. In this kit that step is skipped (the optional `docs-check` skill covers it); only the Context Gathering and Refinement stages are used.
|
|
26
26
|
- `diataxis-audit` links to `diataxis-create`, `diataxis-convert` and `diataxis-plan`, which are not bundled; those links do not resolve, which is expected.
|
|
27
|
-
- `agents/
|
|
27
|
+
- `writing-for-agents/SKILL-MECHANICS.md` links back to `SKILL.md`, which is `writing-for-agents.md` here; that file is about writing skills and is not used for `AGENTS.md`.
|
|
28
|
+
- `agents/openai.yaml` inside Matt Pocock's skills is Codex UI metadata for a skill; as bundled guides they are inert.
|
|
28
29
|
|
|
29
30
|
## Considered and not bundled
|
|
30
31
|
|
|
31
32
|
- `setup-matt-pocock-skills` — writes its own config and creates issues via `gh`/`glab`; its role (wiring docs into the other skills) is played by `AGENTS.md` here.
|
|
32
33
|
- `improve-codebase-architecture`, `codebase-design` — not about documentation; they work well on top of a finished `CONTEXT.md` and ADRs.
|
|
33
34
|
- `diataxis-create`, `diataxis-convert`, `diataxis-plan` — not needed by the workflow.
|
|
35
|
+
- `grill-with-docs` — bundled up to 0.2.0; it only calls the `grilling` and `domain-modeling` skills, which are no longer installed as skills.
|
package/agents/docs-scout.md
CHANGED
|
@@ -45,7 +45,6 @@ opencode: |
|
|
|
45
45
|
"*": deny
|
|
46
46
|
"docs-bootstrap": allow
|
|
47
47
|
"docs-check": allow
|
|
48
|
-
"diataxis-audit": allow
|
|
49
48
|
---
|
|
50
49
|
|
|
51
50
|
You are a scout. Your job is to collect facts about the project and return them to the lead agent. You write to the repository only in the scratch folder `docs/agents/scratch/`, when the brief asks for a file.
|
package/install.mjs
CHANGED
|
@@ -10,13 +10,17 @@
|
|
|
10
10
|
// claude skills → .claude/skills/ agents → .claude/agents/*.md
|
|
11
11
|
// codex skills → .agents/skills/ agents → .codex/agents/*.toml
|
|
12
12
|
// opencode skills → .agents/skills/ agents → .opencode/agents/*.md commands → .opencode/commands/*.md
|
|
13
|
-
// Installed paths are listed in .agent-docs-bootstrap
|
|
13
|
+
// Installed paths are listed in .agent-docs-bootstrap with a hash of what was written. A path is replaced or removed
|
|
14
|
+
// only if it is listed, has the shape of a path the kit writes (<layout folder>/<kit name>), and its content still
|
|
15
|
+
// matches that hash; a changed path is left in place as the user's. On an update, listed paths this version no
|
|
16
|
+
// longer ships are removed under the same rule.
|
|
14
17
|
// No network access, no changes to harness settings, no admin rights.
|
|
15
18
|
|
|
16
19
|
import fs from 'node:fs';
|
|
17
20
|
import path from 'node:path';
|
|
18
21
|
import os from 'node:os';
|
|
19
22
|
import { fileURLToPath } from 'node:url';
|
|
23
|
+
import { createHash } from 'node:crypto';
|
|
20
24
|
|
|
21
25
|
const KIT = path.dirname(fileURLToPath(import.meta.url));
|
|
22
26
|
const TARGETS = ['claude', 'codex', 'opencode'];
|
|
@@ -36,7 +40,42 @@ const exists = (p) => { try { fs.lstatSync(p); return true; } catch { return fal
|
|
|
36
40
|
if (!GLOBAL && (BASE === KIT || BASE.startsWith(KIT + path.sep)))
|
|
37
41
|
die(`This is the kit's own directory (${BASE}). Run it from the project root: cd <project> && node ${path.join(KIT, 'install.mjs')} --target …`);
|
|
38
42
|
|
|
39
|
-
const
|
|
43
|
+
const codexHome = process.env.CODEX_HOME ? path.relative(BASE, process.env.CODEX_HOME) : '.codex';
|
|
44
|
+
const ocConfig = process.env.OPENCODE_CONFIG_DIR ? path.relative(BASE, process.env.OPENCODE_CONFIG_DIR) : path.join('.config', 'opencode');
|
|
45
|
+
const LAYOUT = {
|
|
46
|
+
claude: { skills: '.claude/skills', agents: '.claude/agents' },
|
|
47
|
+
codex: { skills: '.agents/skills', agents: GLOBAL ? path.join(codexHome, 'agents') : '.codex/agents' },
|
|
48
|
+
opencode: { skills: '.agents/skills', agents: GLOBAL ? path.join(ocConfig, 'agents') : '.opencode/agents',
|
|
49
|
+
commands: GLOBAL ? path.join(ocConfig, 'commands') : '.opencode/commands' },
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Every name any version of the kit installed. Add to it, never remove: an old install's marker may list them.
|
|
53
|
+
const SHIPPED = new Set(['docs-bootstrap', 'docs-check', 'docs-scout', 'docs-reader',
|
|
54
|
+
'grilling', 'domain-modeling', 'writing-for-agents', 'doc-coauthoring', 'diataxis-audit', 'grill-with-docs']);
|
|
55
|
+
const layoutDirs = new Set(Object.values(LAYOUT).flatMap(L => Object.values(L)).map(d => path.normalize(d)));
|
|
56
|
+
// The marker is committed, so a bad merge or PR can add any line to it. Only a line shaped like a path the kit
|
|
57
|
+
// writes, <layout folder>/<shipped name>[.md|.toml], is trusted; nothing else is ever replaced or removed.
|
|
58
|
+
const isOwnedPath = (r) => layoutDirs.has(path.normalize(path.dirname(r))) && SHIPPED.has(path.basename(r).replace(/\.(md|toml)$/, ''));
|
|
59
|
+
// Marker lines are `<path> <hash>`; versions up to 0.3.0 wrote the path alone, so their content is checked
|
|
60
|
+
// against everything those versions installed (LEGACY).
|
|
61
|
+
const old = new Map();
|
|
62
|
+
for (const l of read(MARKER).split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('version='))) {
|
|
63
|
+
const [r, h] = l.split(/\s+/);
|
|
64
|
+
if (isOwnedPath(r)) old.set(r, h);
|
|
65
|
+
else warn(`ignored '${r}' in .agent-docs-bootstrap: not a path this kit installs`);
|
|
66
|
+
}
|
|
67
|
+
// Hashes of every path versions 0.1.0–0.3.0 installed (all targets, no model flags). Fixed: never edit.
|
|
68
|
+
const LEGACY = new Set([
|
|
69
|
+
'00ca80d7077c0e4b', '122ae594f7eb38bd', '185ec7d02d9cf70b', '1f5a0fe496f38dd6', '3798ad63dd954bac',
|
|
70
|
+
'4c36074d70c5a88c', '562d1e8f3a090ffd', '698cadefe39cb46f', '6acf8481d4dd6a1a', '72bcff6d0e5476ba',
|
|
71
|
+
'790d7e6ae5034b3e', '79d9da94af685633', '7cd7eeac11324b51', '855778c0459cea17', '8c5adb3f63300a43',
|
|
72
|
+
'900cf27ab683e5d1', '96288a3e60126264', '9e0e5c30da22c059', 'b45162299d9aa78b', 'c5d47d8811aa61ee',
|
|
73
|
+
'c87450584ed42c8b', 'cf2f8a40c91f3c45', 'dac09810ceb351f7', 'dc418221c7363caa', 'f741ba5711364c55',
|
|
74
|
+
'fceff4c3b3159c80', 'fd975138dcda6b38', 'fe412d3c3c312f7a',
|
|
75
|
+
]);
|
|
76
|
+
// The path is the kit's and nobody changed it since it was installed.
|
|
77
|
+
const isUnchanged = (r) => { const h = contentHash(abs(r)); return old.get(r) ? h === old.get(r) : LEGACY.has(h); };
|
|
78
|
+
const changedNote = (r) => `${r} changed since it was installed, so it is left in place as yours`;
|
|
40
79
|
if (a.uninstall) { uninstall(); process.exit(0); }
|
|
41
80
|
|
|
42
81
|
if (!a.target) usage(1, 'Missing --target.');
|
|
@@ -49,25 +88,17 @@ if (!GLOBAL) {
|
|
|
49
88
|
die(`No .git here (${BASE}) — is this the project root? Run from the root or add --yes.`);
|
|
50
89
|
}
|
|
51
90
|
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const LAYOUT = {
|
|
55
|
-
claude: { skills: '.claude/skills', agents: '.claude/agents' },
|
|
56
|
-
codex: { skills: '.agents/skills', agents: GLOBAL ? path.join(codexHome, 'agents') : '.codex/agents' },
|
|
57
|
-
opencode: { skills: '.agents/skills', agents: GLOBAL ? path.join(ocConfig, 'agents') : '.opencode/agents',
|
|
58
|
-
commands: GLOBAL ? path.join(ocConfig, 'commands') : '.opencode/commands' },
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const installed = new Set();
|
|
62
|
-
const ours = (r) => oldList.includes(r);
|
|
91
|
+
const installed = new Map();
|
|
92
|
+
const released = new Set();
|
|
63
93
|
function writeOwned(r, fn) {
|
|
64
|
-
if (installed.has(r)) return false;
|
|
94
|
+
if (installed.has(r) || released.has(r)) return false;
|
|
65
95
|
const dst = abs(r);
|
|
66
|
-
if (exists(dst) && !
|
|
96
|
+
if (exists(dst) && !old.has(r)) { warn(`skipped ${r}: exists and was not installed by this kit`); return false; }
|
|
97
|
+
if (exists(dst) && !isUnchanged(r)) { warn(`skipped ${changedNote(r)}; delete it and run again to get this version`); released.add(r); return false; }
|
|
67
98
|
fs.rmSync(dst, { recursive: true, force: true });
|
|
68
99
|
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
|
69
100
|
fn(dst);
|
|
70
|
-
installed.
|
|
101
|
+
installed.set(r, contentHash(dst));
|
|
71
102
|
return true;
|
|
72
103
|
}
|
|
73
104
|
|
|
@@ -94,9 +125,17 @@ for (const t of targets) {
|
|
|
94
125
|
}
|
|
95
126
|
}
|
|
96
127
|
|
|
97
|
-
//
|
|
98
|
-
const
|
|
99
|
-
|
|
128
|
+
// Paths an earlier version installed into these targets' folders and this version no longer ships.
|
|
129
|
+
const ownDirs = new Set(targets.flatMap(t => Object.values(LAYOUT[t])));
|
|
130
|
+
for (const r of old.keys()) {
|
|
131
|
+
if (installed.has(r) || released.has(r) || !ownDirs.has(path.dirname(r)) || !exists(abs(r))) continue;
|
|
132
|
+
if (isUnchanged(r)) { fs.rmSync(abs(r), { recursive: true, force: true }); log(`removed ${r} (no longer shipped)`); }
|
|
133
|
+
else { warn(`not removed: ${changedNote(r)}`); released.add(r); }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Keep entries of earlier installs (e.g. another target) that are still on disk; a changed path is no longer listed.
|
|
137
|
+
const keep = [...old].filter(([r]) => !installed.has(r) && !released.has(r) && exists(abs(r)));
|
|
138
|
+
fs.writeFileSync(MARKER, [`version=${VERSION}`, ...[...keep, ...installed].map(([r, h]) => h ? `${r} ${h}` : r)].join('\n') + '\n');
|
|
100
139
|
|
|
101
140
|
console.log(`\nDone: agent-docs-bootstrap ${VERSION}, ${targets.join(', ')}${GLOBAL ? ' (global)' : ''}.`);
|
|
102
141
|
if (!GLOBAL) log(`commit the installed folders and .agent-docs-bootstrap so the whole team gets the same version`);
|
|
@@ -139,27 +178,33 @@ function parseAgent(file) {
|
|
|
139
178
|
// ---------- helpers
|
|
140
179
|
function skillDirs() {
|
|
141
180
|
const out = [];
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
181
|
+
const base = path.join(KIT, 'skills');
|
|
182
|
+
for (const e of fs.readdirSync(base, { withFileTypes: true })) {
|
|
183
|
+
const d = path.join(base, e.name);
|
|
184
|
+
if (!e.isDirectory() || !fs.existsSync(path.join(d, 'SKILL.md'))) continue;
|
|
185
|
+
const fm = (read(path.join(d, 'SKILL.md')).match(/^name:\s*["']?([^"'\n]+)["']?\s*$/m) || ['', ''])[1].trim();
|
|
186
|
+
if (!NAME_RE.test(e.name) || fm !== e.name) { warn(`skipped skill ${e.name}: frontmatter name '${fm}' must match the folder`); continue; }
|
|
187
|
+
out.push(d);
|
|
188
|
+
}
|
|
150
189
|
return out;
|
|
151
190
|
}
|
|
152
191
|
function uninstall() {
|
|
153
|
-
if (!
|
|
192
|
+
if (!old.size) die(`Nothing to remove: no ${MARKER}.`);
|
|
154
193
|
console.log(`Removing agent-docs-bootstrap from ${BASE}`);
|
|
155
|
-
for (const r of
|
|
194
|
+
for (const r of old.keys()) {
|
|
195
|
+
if (!exists(abs(r))) continue;
|
|
196
|
+
if (isUnchanged(r)) { fs.rmSync(abs(r), { recursive: true, force: true }); log(`removed ${r}`); }
|
|
197
|
+
else warn(`not removed: ${changedNote(r)}`);
|
|
198
|
+
}
|
|
156
199
|
fs.rmSync(MARKER, { force: true });
|
|
157
|
-
const dirs = new Set(
|
|
200
|
+
const dirs = new Set([...old.keys()].flatMap(r => [path.dirname(r), path.dirname(path.dirname(r))]));
|
|
158
201
|
for (const d of [...dirs].sort((x, y) => y.length - x.length)) try { fs.rmdirSync(abs(d)); } catch {}
|
|
159
202
|
}
|
|
160
203
|
function parseArgs(argv) {
|
|
161
204
|
const o = {}; const withVal = new Set(['target', 'project', 'scout-model', 'reader-model']);
|
|
162
205
|
for (let i = 0; i < argv.length; i++) {
|
|
206
|
+
const eq = argv[i].match(/^--([a-z-]+)=(.*)$/);
|
|
207
|
+
if (eq && withVal.has(eq[1])) { o[eq[1]] = eq[2]; continue; }
|
|
163
208
|
const k = argv[i].replace(/^--/, '');
|
|
164
209
|
if (argv[i] === '-h' || k === 'help') o.help = true;
|
|
165
210
|
else if (withVal.has(k)) { if (i + 1 >= argv.length) die(`--${k} needs a value`); o[k] = argv[++i]; }
|
|
@@ -174,6 +219,20 @@ function usage(code, msg) {
|
|
|
174
219
|
console.log(src.slice(0, src.findIndex(l => !l.startsWith('//'))).map(l => l.replace(/^\/\/ ?/, '')).join('\n'));
|
|
175
220
|
process.exit(code);
|
|
176
221
|
}
|
|
222
|
+
// Content hash of an installed file or folder: relative names and text with line endings normalised, so a
|
|
223
|
+
// checkout with CRLF line endings still matches.
|
|
224
|
+
function contentHash(p) {
|
|
225
|
+
const h = createHash('sha256');
|
|
226
|
+
const files = fs.lstatSync(p).isDirectory() ? listFiles(p).sort() : [''];
|
|
227
|
+
for (const f of files) h.update(`${f}\0${read(path.join(p, f)).replace(/\r\n/g, '\n')}\0`);
|
|
228
|
+
return h.digest('hex').slice(0, 16);
|
|
229
|
+
}
|
|
230
|
+
function listFiles(dir, base = dir) {
|
|
231
|
+
return fs.readdirSync(dir, { withFileTypes: true }).flatMap(e => {
|
|
232
|
+
const p = path.join(dir, e.name);
|
|
233
|
+
return e.isDirectory() ? listFiles(p, base) : [path.relative(base, p).split(path.sep).join('/')];
|
|
234
|
+
});
|
|
235
|
+
}
|
|
177
236
|
function read(p) { try { return fs.readFileSync(p, 'utf8'); } catch { return ''; } }
|
|
178
237
|
function log(s) { console.log(` ${s}`); }
|
|
179
238
|
function warn(s) { console.error(`WARNING: ${s}`); }
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-docs-bootstrap",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Agent skills that build reference documentation for a codebase (glossary, ADRs, architecture, how-tos, AGENTS.md) through interviews with the team, with an optional check by a fresh agent. Works with any agent that runs skills; the installer sets up Claude Code, Codex and OpenCode.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": { "type": "git", "url": "git+https://github.com/TraneDev/agent-docs-bootstrap.git" },
|
|
7
7
|
"homepage": "https://github.com/TraneDev/agent-docs-bootstrap#readme",
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
"bin": { "agent-docs-bootstrap": "install.mjs" },
|
|
10
10
|
"files": ["install.mjs", "agents/", "skills/", "THIRD_PARTY.md", "CHANGELOG.md"],
|
|
11
11
|
"engines": { "node": ">=18" },
|
|
12
|
-
"keywords": ["claude-code", "codex", "opencode", "agents-md", "documentation", "skills"]
|
|
12
|
+
"keywords": ["claude-code", "codex", "opencode", "agents-md", "documentation", "skills", "agent-skills", "ai-agents", "coding-agents"]
|
|
13
13
|
}
|
|
@@ -27,7 +27,7 @@ They hold at every stage.
|
|
|
27
27
|
- **Keep your own context for the conversation.** Do not read external docs or scan the whole repository yourself: delegate to `docs-scout` and read its results from `docs/agents/scratch/` in parts.
|
|
28
28
|
- **Secrets never reach the documents.** Passwords, tokens, keys and credentials, test environments included, are not written down: only where to get them (a vault, an environment variable, who to ask). If the human dictates a secret, record its source instead of the value and say why.
|
|
29
29
|
- **Do not judge documentation quality yourself.** The human confirms what is written. If they want a measured check, the optional `docs-check` skill compares a fresh agent's plan with real commits.
|
|
30
|
-
- **Formats are not duplicated.** Glossary and ADRs follow
|
|
30
|
+
- **Formats are not duplicated.** Glossary and ADRs follow `domain-modeling`: [CONTEXT-FORMAT.md](vendor/domain-modeling/CONTEXT-FORMAT.md), [ADR-FORMAT.md](vendor/domain-modeling/ADR-FORMAT.md). Diagrams — [references/c4-format.md](references/c4-format.md). `AGENTS.md` — [references/agents-md-format.md](references/agents-md-format.md). Reader test — the optional `docs-check` skill.
|
|
31
31
|
- **Language.** Documents are written in the language recorded in the state file; identifiers and code terms stay as they are, and a glossary term carries its code name: "**Order request** (`Request`)". Templates in this skill are in English: translate headings and text when the documents language differs, keep file names.
|
|
32
32
|
|
|
33
33
|
## Subagents
|
|
@@ -38,6 +38,10 @@ Independent calls run in parallel, such as the stage 1.5 batches. Start them tog
|
|
|
38
38
|
|
|
39
39
|
If the harness cannot start the `docs-scout` subagent, do the brief yourself but write the result to the scratch file and keep only a summary in the conversation.
|
|
40
40
|
|
|
41
|
+
## Bundled guides
|
|
42
|
+
|
|
43
|
+
`vendor/` holds guides by other authors (`grilling`, `domain-modeling`, `writing-for-agents`, `doc-coauthoring`, `diataxis-audit`), unmodified except that each `SKILL.md` is renamed to `<name>.md`. They are not separate skills: read the file at the stage that names it and follow it, even if a skill with the same name is installed in the session — this kit is tested with these copies. When a brief names a file under `vendor/`, give the scout its full path: the scout does not know where this skill is installed. This skill's folder is `.claude/skills/docs-bootstrap` or `.agents/skills/docs-bootstrap` in the project, or the same under the home directory for a global install; if unsure, search for `vendor/diataxis-audit/diataxis-audit.md`.
|
|
44
|
+
|
|
41
45
|
## Stage 0. Session start
|
|
42
46
|
|
|
43
47
|
1. Read `docs/agents/bootstrap-state.md`. No file → ask the questions below, create `docs/agents/` and copy the templates from [templates/](templates/) into it: `bootstrap-state.md`, `sources.md`. Create `docs/agents/scratch/` and add the line `docs/agents/scratch/` to the project's `.gitignore`. Record the mode, the documents language and the kit version (first line of `.agent-docs-bootstrap` in the project root, if present) in the state file.
|
|
@@ -77,8 +81,8 @@ Skipped when `sources.md` lists no external sources, or the agent has no tools t
|
|
|
77
81
|
**Scout.** Brief "Stage 2": draft terms from code with evidence and synonyms; name conflicts; ADR candidates from traces of decisions with reasons marked `ASSUMPTION`; comparison with facts from external docs (matches / differs / not in code).
|
|
78
82
|
|
|
79
83
|
**You.**
|
|
80
|
-
1.
|
|
81
|
-
2. First decide single- or multi-context — the rule is in
|
|
84
|
+
1. Read [vendor/grilling/grilling.md](vendor/grilling/grilling.md) and [vendor/domain-modeling/domain-modeling.md](vendor/domain-modeling/domain-modeling.md) and follow them.
|
|
85
|
+
2. First decide single- or multi-context — the rule is in [CONTEXT-FORMAT.md](vendor/domain-modeling/CONTEXT-FORMAT.md).
|
|
82
86
|
3. Interview along the tree: term conflicts → definitions → each ADR candidate (reason, rejected alternatives, still valid?) → open questions accumulated at stages 1–1.5.
|
|
83
87
|
4. Write as you go: `CONTEXT.md` (or `CONTEXT-MAP.md` + one `CONTEXT.md` per context), `docs/adr/NNNN-slug.md`. No ADR without a confirmed reason.
|
|
84
88
|
|
|
@@ -104,14 +108,14 @@ A how-to is a step-by-step procedure for a recurring task: "add a migration", "a
|
|
|
104
108
|
|
|
105
109
|
**You.** Show the list; the human picks the 3–7 most frequent. For each:
|
|
106
110
|
- an up-to-date external page exists → transfer it to `docs/how-to/<slug>.md`, checking every step against the code;
|
|
107
|
-
- an outdated one exists →
|
|
111
|
+
- an outdated one exists → read [vendor/doc-coauthoring/doc-coauthoring.md](vendor/doc-coauthoring/doc-coauthoring.md) and rewrite it with the human (stages Context Gathering and Refinement; its Reader Testing step is skipped; the optional `docs-check` skill covers it);
|
|
108
112
|
- none → do not write it from memory. List it as deferred: real team tasks will supply the material. If `docs/agents/reader-tests.md` exists, do not write how-tos from its tasks: a document written from a test task holds its answer, and the check on that task stops meaning anything.
|
|
109
113
|
|
|
110
114
|
**Done when:** every step of every how-to points to an existing file or a command verified at stage 1; the deferred how-tos are listed in the state file.
|
|
111
115
|
|
|
112
116
|
## Stage 5. AGENTS.md
|
|
113
117
|
|
|
114
|
-
**You.**
|
|
118
|
+
**You.** Read [vendor/writing-for-agents/writing-for-agents.md](vendor/writing-for-agents/writing-for-agents.md) and follow it. Format — `agents-md-format.md`. Order:
|
|
115
119
|
1. Root `AGENTS.md`: up to 150 lines, only what is needed on every turn. Commands from stage 1, directory map from stage 3, pointers to `CONTEXT.md`, `docs/adr/`, `docs/how-to/`, `docs/architecture.md`.
|
|
116
120
|
2. Nested `AGENTS.md` in large areas (an app in a monorepo, a big module): only rules specific to that area.
|
|
117
121
|
3. Behaviour rules only from the human ("don't run e2e locally", "don't touch generated code").
|
|
@@ -131,7 +135,7 @@ There is no code, or very little, so there is nothing to reverse-engineer: all t
|
|
|
131
135
|
|
|
132
136
|
### N1. Interview the idea
|
|
133
137
|
|
|
134
|
-
|
|
138
|
+
Read `grilling` and `domain-modeling` from `vendor/` as in stage 2. Tree: what the system does and for whom → the main entities and their names → boundaries (single- or multi-context per `CONTEXT-FORMAT.md`) → decisions already made before the start (stack, state, storage, integrations) with reasons and rejected alternatives. Rounds as in stage 2.
|
|
135
139
|
|
|
136
140
|
**Write:** `CONTEXT.md` (or `CONTEXT-MAP.md`), `docs/adr/0001-…` onwards — only with a reason from a human. Also `docs/agents/sources.md` if the project already has external pages (spec, design).
|
|
137
141
|
|
|
@@ -145,7 +149,7 @@ From the design, not the code: C4 Context and Container per `c4-format.md`. A co
|
|
|
145
149
|
|
|
146
150
|
### N3. Starter AGENTS.md
|
|
147
151
|
|
|
148
|
-
|
|
152
|
+
Read `writing-for-agents` from `vendor/` as in stage 5. Use [templates/AGENTS.starter.md](templates/AGENTS.starter.md): commands already in the manifest (the scout verifies them by running, brief "Stage 1", sections 1–2), the planned directory map, rules from the human, pointers to `CONTEXT.md`, `docs/adr/`, `docs/architecture.md`. The how-to section stays empty with the note "will appear after the first features". Handle `CLAUDE.md` as in stage 5, step 4.
|
|
149
153
|
|
|
150
154
|
**Done when:** the file is within 80 lines; every command is verified; every rule is confirmed.
|
|
151
155
|
|
|
@@ -27,7 +27,7 @@ Use the tools the session has for the source listed in `docs/agents/sources.md`
|
|
|
27
27
|
|
|
28
28
|
**Batches 1..K — classification.** For each page in the range:
|
|
29
29
|
1. Get the structure, if the source can return it without the body: section headings, presence of code, tables, step lists.
|
|
30
|
-
2. Determine the Diátaxis type from title and structure (criteria —
|
|
30
|
+
2. Determine the Diátaxis type from title and structure (criteria — `vendor/diataxis-audit/diataxis-audit.md` in the `docs-bootstrap` skill folder; the lead gives its full path). Numbered steps → how-to; parameter and API tables → reference; "why" and history → explanation; learning from zero → tutorial; a mix → mixed.
|
|
31
31
|
3. Only if the type is unclear, read the start of the body: at most 2000 characters. Read no further.
|
|
32
32
|
4. Note whether the page refers to files or commands (code blocks, paths) — without checking; checks happen at stages 2 and 4.
|
|
33
33
|
|
|
@@ -43,7 +43,7 @@ Return these sections:
|
|
|
43
43
|
|
|
44
44
|
1. **Terms** — for each: term, name in code, a one-sentence draft definition without implementation details, evidence files (up to 3), synonyms seen in code, UI strings, API. Leave out framework concepts.
|
|
45
45
|
2. **Name conflicts** — one entity under different names (frontend/backend, DTO/UI, code/UI strings) and one name for different entities.
|
|
46
|
-
3. **ADR candidates** — what was decided (fact), evidence, a hypothesis for the reason marked `ASSUMPTION`. Run each through the three criteria in `ADR-FORMAT.md` of the `
|
|
46
|
+
3. **ADR candidates** — what was decided (fact), evidence, a hypothesis for the reason marked `ASSUMPTION`. Run each through the three criteria in `vendor/domain-modeling/ADR-FORMAT.md` of the `docs-bootstrap` skill folder (the lead gives its full path); for rejected ones name the failed criterion.
|
|
47
47
|
4. **Check against external docs** — for each term and decision mentioned in the 1.5 audit: matches the code / differs (how) / not found in code. Read pages selectively: find the relevant section first, then read only that part, in chunks of at most 4000 characters. No more than 5 pages per run; if more are needed, return the list and the lead will start another run.
|
|
48
48
|
|
|
49
49
|
## Stage 3. Architecture
|
|
@@ -15,7 +15,7 @@ The scout does not know in advance where things live in a given stack. It determ
|
|
|
15
15
|
|
|
16
16
|
- Framework concepts (component, service, store, guard, DTO as a pattern) are not domain terms.
|
|
17
17
|
- A code folder is not a container unless it deploys on its own.
|
|
18
|
-
- A dependency is not an ADR until it passes the three criteria in
|
|
18
|
+
- A dependency is not an ADR until it passes the three criteria in [ADR-FORMAT.md](../vendor/domain-modeling/ADR-FORMAT.md).
|
|
19
19
|
|
|
20
20
|
## Name conflict detector
|
|
21
21
|
|
|
@@ -53,16 +53,16 @@ The reader must not see the solution, the history, your session's instructions o
|
|
|
53
53
|
|
|
54
54
|
What the script does:
|
|
55
55
|
|
|
56
|
-
- the snapshot is the parent's code without the documents and the kit's installed files, with the current documents from the working tree on top, committed or not (git-ignored and deleted ones are skipped, `docs/agents/` never goes in). Do not keep unfinished hand edits in the documents during a run: the reader gets them as they are;
|
|
56
|
+
- the snapshot is the parent's code without the documents and the kit's installed files, with the current documents from the working tree on top, committed or not (git-ignored and deleted ones are skipped, `docs/agents/` never goes in). Do not keep unfinished hand edits in the documents during a run: the reader gets them as they are. `README` and other files stay as they were in the parent commit, like the code: today's `README` may already describe the solution;
|
|
57
57
|
- the snapshot gets an empty `git init`, which stops the harness from loading `AGENTS.md` or `CLAUDE.md` from parent directories. No installed dependencies: the reader builds a plan, it does not execute it;
|
|
58
58
|
- the reader: Claude Code `claude -p --restricted` with only `Read`, `Grep`, `Glob` and no MCP servers; Codex `codex exec -s read-only` with every MCP server, plugin and app turned off; OpenCode `opencode run --pure` with the `docs-reader` agent, whose permissions deny everything but reading, MCP tools included. The prompt is the installed `docs-reader`, the task goes through stdin;
|
|
59
59
|
- it writes `rt-<N>-plan.md` and `rt-<N>-log.md` to the run directory and prints a three-line summary.
|
|
60
60
|
|
|
61
61
|
Non-zero exit or "plan EMPTY" → show the human the summary and `rt-<N>-log.md`; do not guess. A plan that cites files outside the snapshot, the history, a tracker or external docs is invalid: note why in `reader-tests.md` and rerun.
|
|
62
62
|
|
|
63
|
-
The user's global instructions
|
|
63
|
+
The user's global instructions may still reach the reader: Codex loads `~/.codex/AGENTS.md`, OpenCode `~/.config/opencode/AGENTS.md`; whether `claude -p --restricted` loads `~/.claude/CLAUDE.md` is not documented. If they are about this project, ask the human to move them aside for the test.
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
Your harness is not `claude`, `codex` or `opencode`, its CLI is not in PATH, or there is no `node` → do not play the reader yourself: you have seen the docs and the history. Run the script with `--snapshot-only` (it prints the snapshot path) and ask the human to start a new agent session with its working directory set to that path, paste the `docs-reader` prompt and the task, and save the answer to `rt-<N>-plan.md`.
|
|
66
66
|
|
|
67
67
|
## Step 4. Gaps
|
|
68
68
|
|
|
@@ -2,20 +2,23 @@
|
|
|
2
2
|
// docs-check steps 2–3: a history-free snapshot outside the repository and a fresh reader started as a
|
|
3
3
|
// separate process of your harness. Works the same from bash, PowerShell and cmd; needs git and Node 18+.
|
|
4
4
|
//
|
|
5
|
-
// node <skills>/docs-check/scripts/reader-run.mjs <run dir> <N> --harness claude|codex|opencode [--reader <path>]
|
|
5
|
+
// node <skills>/docs-check/scripts/reader-run.mjs <run dir> <N> --harness claude|codex|opencode [--reader <path>] [--timeout-min <m>]
|
|
6
6
|
// node <skills>/docs-check/scripts/reader-run.mjs <run dir> <N> --snapshot-only
|
|
7
7
|
//
|
|
8
8
|
// <run dir> holds tasks.json: { "tasks": [ { "n": 1, "parent": "<hash>", "task": "<wording>" } ] }.
|
|
9
9
|
// Writes rt-<N>-plan.md (the reader's answer) and rt-<N>-log.md there; prints a short summary.
|
|
10
|
+
// --timeout-min stops the reader after that many minutes (default 12).
|
|
10
11
|
|
|
11
12
|
import fs from 'node:fs';
|
|
12
13
|
import path from 'node:path';
|
|
13
14
|
import os from 'node:os';
|
|
14
15
|
import { execFileSync, spawn } from 'node:child_process';
|
|
16
|
+
import { createHash } from 'node:crypto';
|
|
15
17
|
|
|
16
18
|
const a = parseArgs(process.argv.slice(2));
|
|
17
19
|
if (a.help || a._.length < 2) {
|
|
18
|
-
|
|
20
|
+
const src = fs.readFileSync(new URL(import.meta.url), 'utf8').split('\n').slice(1);
|
|
21
|
+
console.log(src.slice(0, src.findIndex(l => !l.startsWith('//'))).map(l => l.replace(/^\/\/ ?/, '')).join('\n'));
|
|
19
22
|
process.exit(a.help ? 0 : 1);
|
|
20
23
|
}
|
|
21
24
|
|
|
@@ -26,15 +29,21 @@ const spec = JSON.parse(read(path.join(RUN, 'tasks.json'), 'no tasks.json in the
|
|
|
26
29
|
const task = (spec.tasks || []).find(t => Number(t.n) === N) || die(`tasks.json has no task n=${N}`);
|
|
27
30
|
if (!task.parent || !task.task) die(`task ${N} has no parent or task`);
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
// The path hash keeps two repositories with the same folder name apart.
|
|
33
|
+
const SNAPS = path.join(os.tmpdir(), `agent-docs-check-${path.basename(ROOT)}-${createHash('sha1').update(ROOT).digest('hex').slice(0, 8)}`);
|
|
30
34
|
const SNAP = path.join(SNAPS, `rt-${N}`);
|
|
31
35
|
const TIMEOUT_MS = Number(a['timeout-min'] || 12) * 60 * 1000;
|
|
32
36
|
const win = process.platform === 'win32';
|
|
33
37
|
|
|
34
|
-
// Documents the kit builds; kit-installed paths and its run files never reach the reader.
|
|
35
|
-
|
|
38
|
+
// Documents the kit builds; kit-installed paths and its run files never reach the reader. The marker is committed
|
|
39
|
+
// and could hold any line, so only lines shaped like an installed path count (a line `docs` would hide every document).
|
|
40
|
+
const KIT_DIRS = ['.claude/skills', '.claude/agents', '.agents/skills', '.codex/agents', '.opencode/agents', '.opencode/commands'];
|
|
41
|
+
const kitPaths = read(path.join(ROOT, '.agent-docs-bootstrap'), '', true).split('\n').map(l => l.trim().split(/\s+/)[0])
|
|
42
|
+
.filter(l => KIT_DIRS.includes(path.posix.dirname(l)) && /^[a-z0-9-]+(\.md|\.toml)?$/.test(path.posix.basename(l)));
|
|
36
43
|
const isKit = (p) => p === '.agent-docs-bootstrap' || p.startsWith('docs/agents/') || kitPaths.some(k => p === k || p.startsWith(k + '/'));
|
|
37
|
-
|
|
44
|
+
// README and other files stay as they were in the parent commit, like the code: they are the project as it was,
|
|
45
|
+
// not the documents under test, and today's README may already describe the solution.
|
|
46
|
+
const isDoc = (p) => /(^|\/)(AGENTS\.md|CLAUDE\.md|CONTEXT[^/]*\.md)$/.test(p) || p.startsWith('docs/');
|
|
38
47
|
|
|
39
48
|
// ---------- snapshot: the parent's code without documents, today's documents from the working tree on top
|
|
40
49
|
fs.rmSync(SNAP, { recursive: true, force: true });
|
|
@@ -97,7 +106,9 @@ child.stdin.end(input);
|
|
|
97
106
|
let out = '', err = '';
|
|
98
107
|
child.stdout.on('data', d => { out += d; });
|
|
99
108
|
child.stderr.on('data', d => { err += d; });
|
|
100
|
-
|
|
109
|
+
// With shell: true on Windows, child.kill() stops only cmd.exe; taskkill /T takes the CLI with it.
|
|
110
|
+
const stop = () => win ? spawn('taskkill', ['/pid', String(child.pid), '/T', '/F'], { stdio: 'ignore' }) : child.kill();
|
|
111
|
+
const timer = setTimeout(() => { err += `\nstopped after ${TIMEOUT_MS / 60000} min`; stop(); }, TIMEOUT_MS);
|
|
101
112
|
child.on('error', e => die(`${cmd} did not start: ${e.message}`));
|
|
102
113
|
child.on('close', code => {
|
|
103
114
|
clearTimeout(timer);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Matt Pocock
|
|
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.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/skills/{third-party/grilling/SKILL.md → docs-bootstrap/vendor/grilling/grilling.md}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|