reference-docs 1.0.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/LICENSE +21 -0
- package/README.md +24 -0
- package/bin/reference-docs.js +61 -0
- package/lib/installer.js +553 -0
- package/package.json +30 -0
- package/template/.agents/skills/README.md +6 -0
- package/template/.agents/skills/reference-baseline/SKILL.md +27 -0
- package/template/.agents/skills/reference-from-tags/SKILL.md +28 -0
- package/template/AGENTS.md +16 -0
- package/template/reference/README.md +62 -0
- package/template/reference/_authoring/README.md +46 -0
- package/template/reference/_authoring/areas/README.md +16 -0
- package/template/reference/_authoring/areas/_template.md +65 -0
- package/template/reference/_authoring/terminology.md +40 -0
- package/template/reference/_authoring/workflow.md +43 -0
- package/template/reference/_templates/area/README.md +58 -0
- package/template/reference/_templates/area/features/feature-template.md +71 -0
- package/template/reference/releases/index.md +20 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ricardo Mendez Rodriguez
|
|
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,24 @@
|
|
|
1
|
+
# reference-docs
|
|
2
|
+
|
|
3
|
+
Invocation-only skills and scaffold for release-anchored reference documentation.
|
|
4
|
+
|
|
5
|
+
Install into a project:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx reference-docs init --project-name "My App"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Adds `reference/` and skills `reference-from-tags` and `reference-baseline`.
|
|
12
|
+
|
|
13
|
+
Works independently of any planning workflow — the tag diff is the source of truth.
|
|
14
|
+
|
|
15
|
+
## Use
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
Create a baseline reference for this repo.
|
|
19
|
+
Refresh reference from <previous-tag> to <new-tag>.
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Skills are invocation-only — they do not run automatically.
|
|
23
|
+
|
|
24
|
+
Options: `--target`, `--dry-run`, `--force`, `status`.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
import { runCli, reportError } from '../lib/installer.js';
|
|
8
|
+
|
|
9
|
+
const cliName = 'reference-docs';
|
|
10
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
11
|
+
const packageJson = JSON.parse(await readFile(path.join(packageRoot, 'package.json'), 'utf8'));
|
|
12
|
+
|
|
13
|
+
const agentsStart = '<!-- reference-docs:start -->';
|
|
14
|
+
const agentsEnd = '<!-- reference-docs:end -->';
|
|
15
|
+
|
|
16
|
+
const skills = [
|
|
17
|
+
{
|
|
18
|
+
name: 'reference-from-tags',
|
|
19
|
+
readmeEntry:
|
|
20
|
+
'- `reference-from-tags` - invoke explicitly to refresh `reference/` from the diff between two release tags.'
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'reference-baseline',
|
|
24
|
+
readmeEntry:
|
|
25
|
+
'- `reference-baseline` - invoke explicitly for a first baseline pass under `reference/`.'
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
function renderAgentSection(projectName) {
|
|
30
|
+
return `${agentsStart}
|
|
31
|
+
## Reference Docs
|
|
32
|
+
|
|
33
|
+
Release-anchored reference under [\`reference/\`](reference/). Describes accepted behavior as of a release tag or baseline — not edited as a side effect of feature work.
|
|
34
|
+
|
|
35
|
+
Authoring workflow: [\`reference/_authoring/\`](reference/_authoring/README.md).
|
|
36
|
+
|
|
37
|
+
Invocation-only skills — ask by name:
|
|
38
|
+
|
|
39
|
+
- [\`.agents/skills/reference-from-tags/SKILL.md\`](.agents/skills/reference-from-tags/SKILL.md) — refresh from a tag-to-tag diff.
|
|
40
|
+
- [\`.agents/skills/reference-baseline/SKILL.md\`](.agents/skills/reference-baseline/SKILL.md) — document current accepted behavior.
|
|
41
|
+
${agentsEnd}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const config = {
|
|
45
|
+
cliName,
|
|
46
|
+
packageRoot,
|
|
47
|
+
packageJson,
|
|
48
|
+
summaryLabel: 'Reference Docs',
|
|
49
|
+
metadataPath: '.reference-docs/install.json',
|
|
50
|
+
skills,
|
|
51
|
+
agents: {
|
|
52
|
+
start: agentsStart,
|
|
53
|
+
end: agentsEnd,
|
|
54
|
+
render: renderAgentSection
|
|
55
|
+
},
|
|
56
|
+
nextSteps: [
|
|
57
|
+
'Then: invoke .agents/skills/reference-baseline/SKILL.md for a first baseline, or reference-from-tags at release time.'
|
|
58
|
+
]
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
runCli(config, process.argv.slice(2)).catch((error) => reportError(error, cliName));
|
package/lib/installer.js
ADDED
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
import { execPath } from 'node:process';
|
|
2
|
+
import { constants as fsConstants } from 'node:fs';
|
|
3
|
+
import { access, mkdir, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
const agentsSkillsRelative = '.agents/skills';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generic installer shared by durable-context and reference-docs packages.
|
|
10
|
+
*
|
|
11
|
+
* Each package supplies a `config` describing its payload:
|
|
12
|
+
* - cliName: bin name, used in help and error text
|
|
13
|
+
* - packageRoot: absolute path to the package directory
|
|
14
|
+
* - packageJson: parsed package.json of the package
|
|
15
|
+
* - skills: [{ name, readmeEntry }] copied into .agents/skills
|
|
16
|
+
* - agents: { start, end, render(projectName) } AGENTS.md section
|
|
17
|
+
* - metadataPath: relative path of the install metadata file in the target
|
|
18
|
+
* - nextSteps: strings printed after a successful install
|
|
19
|
+
* - summaryLabel: short label used in the final summary line
|
|
20
|
+
*/
|
|
21
|
+
export async function runCli(config, argv) {
|
|
22
|
+
const args = parseArgs(argv, config);
|
|
23
|
+
|
|
24
|
+
if (args.help) {
|
|
25
|
+
printHelp(config);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (args.version) {
|
|
30
|
+
console.log(config.packageJson.version);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (args.command === 'status') {
|
|
35
|
+
await printStatus(config, args.target);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (args.command !== 'init') {
|
|
40
|
+
throw new Error(`Unknown command "${args.command}". Run "${config.cliName} --help".`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const targetRoot = path.resolve(args.target);
|
|
44
|
+
const projectName = args.projectName ?? (await inferProjectName(targetRoot));
|
|
45
|
+
const installer = new Installer({
|
|
46
|
+
config,
|
|
47
|
+
targetRoot,
|
|
48
|
+
projectName,
|
|
49
|
+
force: args.force,
|
|
50
|
+
dryRun: args.dryRun
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
await installer.init();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function parseArgs(argv, config) {
|
|
57
|
+
const options = {
|
|
58
|
+
command: 'help',
|
|
59
|
+
target: process.cwd(),
|
|
60
|
+
projectName: undefined,
|
|
61
|
+
force: false,
|
|
62
|
+
dryRun: false,
|
|
63
|
+
help: false,
|
|
64
|
+
version: false
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const positionals = [];
|
|
68
|
+
|
|
69
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
70
|
+
const arg = argv[index];
|
|
71
|
+
|
|
72
|
+
if (arg === '--help' || arg === '-h') {
|
|
73
|
+
options.help = true;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (arg === '--version' || arg === '-v') {
|
|
78
|
+
options.version = true;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (arg === '--force') {
|
|
83
|
+
options.force = true;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (arg === '--dry-run') {
|
|
88
|
+
options.dryRun = true;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (arg.startsWith('--target=')) {
|
|
93
|
+
options.target = arg.slice('--target='.length);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (arg === '--target') {
|
|
98
|
+
options.target = readOptionValue(argv, index, '--target');
|
|
99
|
+
index += 1;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (arg.startsWith('--project-name=')) {
|
|
104
|
+
options.projectName = arg.slice('--project-name='.length);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (arg === '--project-name') {
|
|
109
|
+
options.projectName = readOptionValue(argv, index, '--project-name');
|
|
110
|
+
index += 1;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (arg.startsWith('-')) {
|
|
115
|
+
throw new Error(`Unknown option "${arg}". Run "${config.cliName} --help".`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
positionals.push(arg);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (positionals.length > 1) {
|
|
122
|
+
throw new Error(`Unexpected arguments: ${positionals.slice(1).join(' ')}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
options.command = positionals[0] ?? (options.help || options.version ? 'meta' : 'help');
|
|
126
|
+
options.help = options.help || options.command === 'help';
|
|
127
|
+
|
|
128
|
+
return options;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function readOptionValue(argv, index, optionName) {
|
|
132
|
+
const value = argv[index + 1];
|
|
133
|
+
|
|
134
|
+
if (!value || value.startsWith('-')) {
|
|
135
|
+
throw new Error(`${optionName} requires a value.`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function printHelp(config) {
|
|
142
|
+
console.log(`${config.cliName}
|
|
143
|
+
|
|
144
|
+
Usage:
|
|
145
|
+
${config.cliName} init [options]
|
|
146
|
+
${config.cliName} status [options]
|
|
147
|
+
|
|
148
|
+
Options:
|
|
149
|
+
--target <path> Project root to install into. Defaults to cwd.
|
|
150
|
+
--project-name <name> Name used to replace PROJECT_NAME placeholders.
|
|
151
|
+
--force Replace existing generated directories.
|
|
152
|
+
--dry-run Show planned changes without writing files.
|
|
153
|
+
-h, --help Show help.
|
|
154
|
+
-v, --version Show package version.
|
|
155
|
+
|
|
156
|
+
Examples:
|
|
157
|
+
npx ${config.packageJson.name} init --project-name "My App"
|
|
158
|
+
npx ${config.packageJson.name}@${config.packageJson.version} init --project-name "My App"
|
|
159
|
+
npx ${config.packageJson.name} status --target ../existing-project
|
|
160
|
+
|
|
161
|
+
The status command reads ${config.metadataPath} from an initialized project.
|
|
162
|
+
`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function inferProjectName(targetRoot) {
|
|
166
|
+
try {
|
|
167
|
+
const packageJson = JSON.parse(await readFile(path.join(targetRoot, 'package.json'), 'utf8'));
|
|
168
|
+
|
|
169
|
+
if (typeof packageJson.name === 'string' && packageJson.name.trim()) {
|
|
170
|
+
return packageJson.name.replace(/^@[^/]+\//, '');
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
// Fall through to the directory name.
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return path.basename(targetRoot);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
class Installer {
|
|
180
|
+
constructor({ config, targetRoot, projectName, force, dryRun }) {
|
|
181
|
+
this.config = config;
|
|
182
|
+
this.templateDir = path.join(config.packageRoot, 'template');
|
|
183
|
+
this.targetRoot = targetRoot;
|
|
184
|
+
this.projectName = projectName;
|
|
185
|
+
this.force = force;
|
|
186
|
+
this.dryRun = dryRun;
|
|
187
|
+
this.actions = [];
|
|
188
|
+
this.agentsFilePath = path.join(targetRoot, 'AGENTS.md');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async init() {
|
|
192
|
+
await this.ensureDirectory(this.targetRoot);
|
|
193
|
+
|
|
194
|
+
await this.installAgentsFile();
|
|
195
|
+
await this.installSkills();
|
|
196
|
+
await this.installPayloadRoots();
|
|
197
|
+
await this.writeMetadata();
|
|
198
|
+
|
|
199
|
+
this.printSummary();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async installPayloadRoots() {
|
|
203
|
+
const entries = await readdir(this.templateDir, { withFileTypes: true });
|
|
204
|
+
|
|
205
|
+
for (const entry of entries) {
|
|
206
|
+
if (entry.name === 'AGENTS.md' || entry.name === '.agents' || entry.name === '.DS_Store') {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
await this.copyTemplatePath(entry.name, entry.name);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async installAgentsFile() {
|
|
215
|
+
const targetFile = await this.findAgentsFile();
|
|
216
|
+
const targetDisplay = path.basename(targetFile);
|
|
217
|
+
this.agentsFilePath = targetFile;
|
|
218
|
+
|
|
219
|
+
const section = this.config.agents.render(this.projectName);
|
|
220
|
+
const { start, end } = this.config.agents;
|
|
221
|
+
|
|
222
|
+
if (!(await exists(targetFile))) {
|
|
223
|
+
const templateAgents = path.join(this.templateDir, 'AGENTS.md');
|
|
224
|
+
|
|
225
|
+
if (await exists(templateAgents)) {
|
|
226
|
+
const text = (await readFile(templateAgents, 'utf8')).replaceAll('PROJECT_NAME', this.projectName);
|
|
227
|
+
await this.writeFile(path.join(this.targetRoot, 'AGENTS.md'), text, 'create AGENTS.md');
|
|
228
|
+
this.agentsFilePath = path.join(this.targetRoot, 'AGENTS.md');
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
await this.writeFile(path.join(this.targetRoot, 'AGENTS.md'), `${section}\n`, 'create AGENTS.md');
|
|
233
|
+
this.agentsFilePath = path.join(this.targetRoot, 'AGENTS.md');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const current = await readFile(targetFile, 'utf8');
|
|
238
|
+
|
|
239
|
+
if (current.includes(start) && current.includes(end)) {
|
|
240
|
+
const updated = current.replace(
|
|
241
|
+
new RegExp(`${escapeRegExp(start)}[\\s\\S]*?${escapeRegExp(end)}`),
|
|
242
|
+
section
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
if (updated === current) {
|
|
246
|
+
this.note(`${targetDisplay} already has the ${this.config.summaryLabel} guidance`);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
await this.writeFile(targetFile, updated, `update ${targetDisplay} ${this.config.summaryLabel} section`);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const separator = current.endsWith('\n') ? '\n' : '\n\n';
|
|
255
|
+
await this.writeFile(
|
|
256
|
+
targetFile,
|
|
257
|
+
`${current}${separator}${section}\n`,
|
|
258
|
+
`append ${this.config.summaryLabel} guidance to ${targetDisplay}`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async findAgentsFile() {
|
|
263
|
+
const canonicalPath = path.join(this.targetRoot, 'AGENTS.md');
|
|
264
|
+
|
|
265
|
+
let entries;
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
entries = await readdir(this.targetRoot, { withFileTypes: true });
|
|
269
|
+
} catch {
|
|
270
|
+
return canonicalPath;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (entries.some((entry) => entry.isFile() && entry.name === 'AGENTS.md')) {
|
|
274
|
+
return canonicalPath;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const match = entries
|
|
278
|
+
.filter((entry) => entry.isFile() && entry.name.toLowerCase() === 'agents.md')
|
|
279
|
+
.map((entry) => entry.name)
|
|
280
|
+
.sort((left, right) => left.localeCompare(right))[0];
|
|
281
|
+
|
|
282
|
+
return match ? path.join(this.targetRoot, match) : canonicalPath;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async installSkills() {
|
|
286
|
+
for (const skill of this.config.skills) {
|
|
287
|
+
await this.copyTemplatePath(
|
|
288
|
+
`${agentsSkillsRelative}/${skill.name}`,
|
|
289
|
+
`${agentsSkillsRelative}/${skill.name}`
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const readmeTarget = await this.findExistingTargetPath(`${agentsSkillsRelative}/README.md`);
|
|
294
|
+
const readmePath = readmeTarget.exists
|
|
295
|
+
? readmeTarget.path
|
|
296
|
+
: path.join(this.targetRoot, `${agentsSkillsRelative}/README.md`);
|
|
297
|
+
const readmeDisplay = readmeTarget.exists ? readmeTarget.display : `${agentsSkillsRelative}/README.md`;
|
|
298
|
+
|
|
299
|
+
if (!(await exists(readmePath))) {
|
|
300
|
+
await this.copyTemplatePath(`${agentsSkillsRelative}/README.md`, `${agentsSkillsRelative}/README.md`);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const current = await readFile(readmePath, 'utf8');
|
|
305
|
+
const missingSkills = this.config.skills.filter((skill) => !current.includes(skill.name));
|
|
306
|
+
|
|
307
|
+
if (missingSkills.length === 0) {
|
|
308
|
+
this.note(`${readmeDisplay} already lists the ${this.config.summaryLabel} skills`);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const entry = [
|
|
313
|
+
'',
|
|
314
|
+
`## ${this.config.summaryLabel} Skills`,
|
|
315
|
+
'',
|
|
316
|
+
...missingSkills.map((skill) => skill.readmeEntry),
|
|
317
|
+
''
|
|
318
|
+
].join('\n');
|
|
319
|
+
|
|
320
|
+
await this.writeFile(
|
|
321
|
+
readmePath,
|
|
322
|
+
`${current.trimEnd()}\n${entry}`,
|
|
323
|
+
`append ${this.config.summaryLabel} skills to ${readmeDisplay}`
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async copyTemplatePath(sourceRelative, targetRelative) {
|
|
328
|
+
const sourcePath = path.join(this.templateDir, sourceRelative);
|
|
329
|
+
const targetInfo = await this.findExistingTargetPath(targetRelative);
|
|
330
|
+
|
|
331
|
+
if (!(await exists(sourcePath))) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const targetPath = path.join(this.targetRoot, targetRelative);
|
|
336
|
+
|
|
337
|
+
if (targetInfo.exists) {
|
|
338
|
+
const variantNote = targetInfo.caseVariant ? ` at ${targetInfo.display}` : '';
|
|
339
|
+
|
|
340
|
+
if (!this.force) {
|
|
341
|
+
this.note(`skip ${targetRelative} (already exists${variantNote}; use --force to replace)`);
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
await this.removePath(targetInfo.path, `replace ${targetInfo.display}`);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
await this.copyRecursive(sourcePath, targetPath, targetRelative);
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async findExistingTargetPath(targetRelative) {
|
|
353
|
+
const parts = targetRelative.split('/').filter(Boolean);
|
|
354
|
+
let currentPath = this.targetRoot;
|
|
355
|
+
const displayParts = [];
|
|
356
|
+
|
|
357
|
+
for (const part of parts) {
|
|
358
|
+
let entries;
|
|
359
|
+
|
|
360
|
+
try {
|
|
361
|
+
entries = await readdir(currentPath, { withFileTypes: true });
|
|
362
|
+
} catch {
|
|
363
|
+
return this.missingTargetPath(targetRelative);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const exactMatch = entries.find((entry) => entry.name === part);
|
|
367
|
+
const caseMatch = exactMatch ?? entries.find((entry) => entry.name.toLowerCase() === part.toLowerCase());
|
|
368
|
+
|
|
369
|
+
if (!caseMatch) {
|
|
370
|
+
return this.missingTargetPath(targetRelative);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
currentPath = path.join(currentPath, caseMatch.name);
|
|
374
|
+
displayParts.push(caseMatch.name);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const display = displayParts.join('/');
|
|
378
|
+
|
|
379
|
+
return {
|
|
380
|
+
caseVariant: display !== targetRelative,
|
|
381
|
+
display,
|
|
382
|
+
exists: true,
|
|
383
|
+
path: currentPath
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
missingTargetPath(targetRelative) {
|
|
388
|
+
return {
|
|
389
|
+
caseVariant: false,
|
|
390
|
+
display: targetRelative,
|
|
391
|
+
exists: false,
|
|
392
|
+
path: path.join(this.targetRoot, targetRelative)
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
async copyRecursive(sourcePath, targetPath, displayPath) {
|
|
397
|
+
const sourceStats = await stat(sourcePath);
|
|
398
|
+
|
|
399
|
+
if (sourceStats.isDirectory()) {
|
|
400
|
+
await this.ensureDirectory(targetPath, `create ${displayPath}/`);
|
|
401
|
+
const entries = await readdir(sourcePath, { withFileTypes: true });
|
|
402
|
+
|
|
403
|
+
for (const entry of entries) {
|
|
404
|
+
if (entry.name === '.DS_Store') {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
await this.copyRecursive(
|
|
409
|
+
path.join(sourcePath, entry.name),
|
|
410
|
+
path.join(targetPath, entry.name),
|
|
411
|
+
path.posix.join(displayPath, entry.name)
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const contents = await readFile(sourcePath);
|
|
419
|
+
const transformed = this.transformText(contents);
|
|
420
|
+
await this.writeFile(targetPath, transformed, `create ${displayPath}`);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
transformText(contents) {
|
|
424
|
+
return contents.toString('utf8').replaceAll('PROJECT_NAME', this.projectName);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async writeMetadata() {
|
|
428
|
+
const metadataPath = path.join(this.targetRoot, this.config.metadataPath);
|
|
429
|
+
const previous = await readOptionalJson(metadataPath);
|
|
430
|
+
const now = new Date().toISOString();
|
|
431
|
+
const metadata = {
|
|
432
|
+
schemaVersion: 1,
|
|
433
|
+
packageName: this.config.packageJson.name,
|
|
434
|
+
installedVersion: this.config.packageJson.version,
|
|
435
|
+
firstInstalledVersion:
|
|
436
|
+
previous?.firstInstalledVersion ?? previous?.installedVersion ?? this.config.packageJson.version,
|
|
437
|
+
firstInstalledAt: previous?.firstInstalledAt ?? previous?.installedAt ?? now,
|
|
438
|
+
lastUpdatedAt: now,
|
|
439
|
+
projectName: this.projectName,
|
|
440
|
+
installedSkills: this.config.skills.map((skill) => skill.name)
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
await this.writeFile(
|
|
444
|
+
metadataPath,
|
|
445
|
+
`${JSON.stringify(metadata, null, 2)}\n`,
|
|
446
|
+
`${previous ? 'update' : 'create'} ${this.config.metadataPath}`
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
async ensureDirectory(directory, message) {
|
|
451
|
+
if (message) {
|
|
452
|
+
this.note(message);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (!this.dryRun) {
|
|
456
|
+
await mkdir(directory, { recursive: true });
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
async removePath(filePath, message) {
|
|
461
|
+
this.note(message);
|
|
462
|
+
|
|
463
|
+
if (!this.dryRun) {
|
|
464
|
+
await rm(filePath, { recursive: true, force: true });
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async writeFile(filePath, contents, message) {
|
|
469
|
+
this.note(message);
|
|
470
|
+
|
|
471
|
+
if (!this.dryRun) {
|
|
472
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
473
|
+
await writeFile(filePath, contents);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
note(message) {
|
|
478
|
+
this.actions.push(message);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
printSummary() {
|
|
482
|
+
const prefix = this.dryRun ? '[dry-run] ' : '';
|
|
483
|
+
|
|
484
|
+
for (const action of this.actions) {
|
|
485
|
+
console.log(`${prefix}${action}`);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
console.log(`${prefix}${this.config.summaryLabel} ready for ${this.projectName}.`);
|
|
489
|
+
|
|
490
|
+
if (!this.dryRun) {
|
|
491
|
+
console.log(`Next: ask your agent to read ${this.agentsFilePath}.`);
|
|
492
|
+
|
|
493
|
+
for (const step of this.config.nextSteps ?? []) {
|
|
494
|
+
console.log(step);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
async function printStatus(config, target) {
|
|
501
|
+
const targetRoot = path.resolve(target);
|
|
502
|
+
const metadataPath = path.join(targetRoot, config.metadataPath);
|
|
503
|
+
const metadata = await readOptionalJson(metadataPath);
|
|
504
|
+
|
|
505
|
+
console.log(`${config.summaryLabel} status for ${targetRoot}`);
|
|
506
|
+
console.log(`Running CLI version: ${config.packageJson.version}`);
|
|
507
|
+
|
|
508
|
+
if (!metadata) {
|
|
509
|
+
console.log('Installed metadata: not found');
|
|
510
|
+
console.log(`Metadata path: ${config.metadataPath}`);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
console.log(`Installed version: ${metadata.installedVersion ?? 'Unknown'}`);
|
|
515
|
+
console.log(`Project: ${metadata.projectName ?? 'Unknown'}`);
|
|
516
|
+
console.log(`Installed skills: ${formatList(metadata.installedSkills)}`);
|
|
517
|
+
console.log(`Metadata path: ${config.metadataPath}`);
|
|
518
|
+
|
|
519
|
+
if (metadata.installedVersion && metadata.installedVersion !== config.packageJson.version) {
|
|
520
|
+
console.log('Note: running CLI version differs from installed metadata.');
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function formatList(value) {
|
|
525
|
+
return Array.isArray(value) && value.length > 0 ? value.join(', ') : 'Unknown';
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
async function readOptionalJson(filePath) {
|
|
529
|
+
try {
|
|
530
|
+
return JSON.parse(await readFile(filePath, 'utf8'));
|
|
531
|
+
} catch {
|
|
532
|
+
return undefined;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
async function exists(filePath) {
|
|
537
|
+
try {
|
|
538
|
+
await access(filePath, fsConstants.F_OK);
|
|
539
|
+
return true;
|
|
540
|
+
} catch {
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function escapeRegExp(value) {
|
|
546
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
export function reportError(error, cliName) {
|
|
550
|
+
console.error(error.message);
|
|
551
|
+
console.error(`Run "${path.basename(execPath)} ${cliName} --help" for usage.`);
|
|
552
|
+
process.exitCode = 1;
|
|
553
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "reference-docs",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Invocation-only skills and scaffold for release-anchored reference documentation refreshed from tag diffs.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"reference-docs": "bin/reference-docs.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin/",
|
|
12
|
+
"lib/",
|
|
13
|
+
"template/",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "node --test"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"agents",
|
|
25
|
+
"ai",
|
|
26
|
+
"documentation",
|
|
27
|
+
"reference",
|
|
28
|
+
"release-notes"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reference-baseline
|
|
3
|
+
description: Document current accepted behavior under reference/ as a first baseline. Use ONLY when the human explicitly asks for baseline/initial reference or domain terminology. Do not trigger automatically.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Reference Baseline
|
|
7
|
+
|
|
8
|
+
Documentation only — no executable changes.
|
|
9
|
+
|
|
10
|
+
## Invariants
|
|
11
|
+
|
|
12
|
+
- Read `AGENTS.md`, `reference/README.md`, `reference/_authoring/README.md`, and `reference/_authoring/workflow.md` first.
|
|
13
|
+
- Accepted current behavior → `reference/`. Uncertain/disputed → `reference/_authoring/baseline-clarifications.md`.
|
|
14
|
+
- Source-backed facts only; extend existing docs rather than replacing wholesale.
|
|
15
|
+
- Optional: read `context/project-profile.md` when durable-context is installed.
|
|
16
|
+
|
|
17
|
+
## Workflow
|
|
18
|
+
|
|
19
|
+
1. **Scope** — whole repo, one area, or as named by human. Record reference point in `reference/releases/index.md`.
|
|
20
|
+
2. **Inspect** — manifests, source roots, tests, CI/CD, IaC, observability, existing docs (use `rg` and repo tooling).
|
|
21
|
+
3. **Area guides** — create/update `reference/_authoring/areas/<slug>.md` from `_template.md`.
|
|
22
|
+
4. **Terminology** — update `reference/_authoring/terminology.md`; ambiguities → `baseline-clarifications.md`.
|
|
23
|
+
5. **Pages** — create/update `reference/<Area>/README.md` and `features/*.md` using `_templates/area/`.
|
|
24
|
+
6. **Record** — row in `reference/releases/index.md` (tag or `baseline/<label>`).
|
|
25
|
+
7. **Validate** — documentation-only diff; summarize areas, pages, open clarifications.
|
|
26
|
+
|
|
27
|
+
Procedural detail: `reference/_authoring/workflow.md` (baseline mode, audience, layout).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reference-from-tags
|
|
3
|
+
description: Refresh reference/ from the diff between two release tags. Use ONLY when the human explicitly asks to refresh reference for a release, update from tags, update a page, or fix a demonstrable error. Do not trigger during feature work or refactors.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Reference From Tags
|
|
7
|
+
|
|
8
|
+
Documentation only — no executable changes.
|
|
9
|
+
|
|
10
|
+
## Invariants
|
|
11
|
+
|
|
12
|
+
- Read `reference/README.md`, `reference/_authoring/workflow.md`, and relevant area guides first.
|
|
13
|
+
- Tag diff is source of truth; planning artifacts optional.
|
|
14
|
+
- Extend and correct pages; do not wipe existing reference.
|
|
15
|
+
|
|
16
|
+
## Workflow
|
|
17
|
+
|
|
18
|
+
1. **Tags** — resolve base and target from human input and `reference/releases/index.md`. Ask if ambiguous.
|
|
19
|
+
2. **Per area** — read `reference/_authoring/areas/<area>.md`; scope diff to area paths:
|
|
20
|
+
`git diff --name-status <base>..<target> -- <paths>`
|
|
21
|
+
3. **Optional hints** — read `context/initiatives/*/release-doc-notes.md` when present; verify against diff.
|
|
22
|
+
4. **Update** — area `README.md` and `features/*.md` for material behavior changes. Skip refactors, test-only, lint, dep bumps with no behavior change.
|
|
23
|
+
5. **Record** — append row to `reference/releases/index.md`.
|
|
24
|
+
6. **Validate** — `git diff --check`; confirm documentation-only diff; summarize.
|
|
25
|
+
|
|
26
|
+
**Single-page/fix requests:** minimal edit to that page; verify against source.
|
|
27
|
+
|
|
28
|
+
See `reference/_authoring/workflow.md` for audience, writing style, and diagrams.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Agent Guidance - PROJECT_NAME
|
|
2
|
+
|
|
3
|
+
Area-specific `AGENTS.md` files layer on top of this one.
|
|
4
|
+
|
|
5
|
+
<!-- reference-docs:start -->
|
|
6
|
+
## Reference Docs
|
|
7
|
+
|
|
8
|
+
Release-anchored reference under [`reference/`](reference/). Accepted behavior as of a release tag or baseline — not edited as a side effect of feature work.
|
|
9
|
+
|
|
10
|
+
Authoring: [`reference/_authoring/`](reference/_authoring/README.md).
|
|
11
|
+
|
|
12
|
+
Invocation-only skills — ask by name:
|
|
13
|
+
|
|
14
|
+
- [`reference-from-tags`](.agents/skills/reference-from-tags/SKILL.md) — refresh from a tag-to-tag diff.
|
|
15
|
+
- [`reference-baseline`](.agents/skills/reference-baseline/SKILL.md) — document current accepted behavior.
|
|
16
|
+
<!-- reference-docs:end -->
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Reference
|
|
2
|
+
|
|
3
|
+
This folder holds release-anchored reference material for PROJECT_NAME.
|
|
4
|
+
|
|
5
|
+
Reference describes accepted system behavior for a known release, tag, or
|
|
6
|
+
explicit baseline. It is not the place for in-progress planning,
|
|
7
|
+
implementation notes, or draft architecture decisions. Put that work in
|
|
8
|
+
`context/`.
|
|
9
|
+
|
|
10
|
+
## Start Here
|
|
11
|
+
|
|
12
|
+
- `releases/index.md` records release or baseline reference refreshes.
|
|
13
|
+
- `_authoring/README.md` explains how humans and agents should author
|
|
14
|
+
reference material.
|
|
15
|
+
- `_authoring/workflow.md` defines when reference material is refreshed and what
|
|
16
|
+
belongs here.
|
|
17
|
+
- `_authoring/areas/` contains per-area authoring guidance.
|
|
18
|
+
|
|
19
|
+
## Standard Layout
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
reference/
|
|
23
|
+
README.md
|
|
24
|
+
releases/
|
|
25
|
+
index.md
|
|
26
|
+
_authoring/
|
|
27
|
+
README.md
|
|
28
|
+
workflow.md
|
|
29
|
+
terminology.md
|
|
30
|
+
areas/
|
|
31
|
+
<area>.md
|
|
32
|
+
_templates/
|
|
33
|
+
area/
|
|
34
|
+
README.md
|
|
35
|
+
features/
|
|
36
|
+
feature-template.md
|
|
37
|
+
<Area>/
|
|
38
|
+
README.md
|
|
39
|
+
features/
|
|
40
|
+
<feature>.md
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Every documented area should have:
|
|
44
|
+
|
|
45
|
+
- a high-level `README.md` that explains the area's purpose and architecture
|
|
46
|
+
- one page per feature under `features/`
|
|
47
|
+
- an authoring guide under `reference/_authoring/areas/`
|
|
48
|
+
|
|
49
|
+
## Contributing
|
|
50
|
+
|
|
51
|
+
- Refresh reference material only when explicitly asked.
|
|
52
|
+
- For existing projects with little or no reference material, create
|
|
53
|
+
baseline reference only when explicitly asked; otherwise document touched
|
|
54
|
+
behavior during future release refreshes.
|
|
55
|
+
- Write for non-developer technical readers unless the project states
|
|
56
|
+
otherwise.
|
|
57
|
+
- Write from behavior outward: product-readable first, technically anchored
|
|
58
|
+
where details affect shipped behavior, operations, or support.
|
|
59
|
+
- Describe behavior, inputs, outputs, permissions, errors, business rules, and
|
|
60
|
+
operational expectations in domain language.
|
|
61
|
+
- Prefer Mermaid diagrams for flows, architecture, and relationships.
|
|
62
|
+
- Add release refreshes to `reference/releases/index.md`.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Reference Authoring Guide
|
|
2
|
+
|
|
3
|
+
This subtree owns all guidance for authoring and refreshing the reference
|
|
4
|
+
under `reference/`. Humans and agents both read from here to know how
|
|
5
|
+
reference is structured, when it is refreshed, what belongs in each area,
|
|
6
|
+
and which domain terminology to use.
|
|
7
|
+
|
|
8
|
+
## Start Here
|
|
9
|
+
|
|
10
|
+
- [`workflow.md`](workflow.md) explains how reference is versioned,
|
|
11
|
+
refreshed, and structured.
|
|
12
|
+
- [`terminology.md`](terminology.md) holds project-specific domain language.
|
|
13
|
+
- [`areas/`](areas/) contains one file per documented area, covering feature
|
|
14
|
+
inventory, code orientation, conventions, and what matters at release time.
|
|
15
|
+
|
|
16
|
+
## Area Guide Pattern
|
|
17
|
+
|
|
18
|
+
Create one authoring guide per documented area:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
reference/_authoring/areas/<area-slug>.md
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Each area guide should identify:
|
|
25
|
+
|
|
26
|
+
- the source locations that own the behavior, such as product code,
|
|
27
|
+
interfaces, tests, CI/CD, generated artifacts, infrastructure, or config
|
|
28
|
+
- the reference root under `reference/`
|
|
29
|
+
- feature pages that should exist
|
|
30
|
+
- behavior that matters at release time
|
|
31
|
+
- changes to ignore, such as pure refactors or test-only edits
|
|
32
|
+
- domain terms and cross-links specific to that area
|
|
33
|
+
|
|
34
|
+
Use [`areas/_template.md`](areas/_template.md) when adding a new area guide.
|
|
35
|
+
|
|
36
|
+
## Relationship To `AGENTS.md`
|
|
37
|
+
|
|
38
|
+
Area `AGENTS.md` files may point here, but they should not copy the detailed
|
|
39
|
+
reference workflow. Keep authoring rules in this subtree so the guidance
|
|
40
|
+
has one source of truth.
|
|
41
|
+
|
|
42
|
+
## Contributing
|
|
43
|
+
|
|
44
|
+
Edits to this subtree usually belong with documentation workflow changes or
|
|
45
|
+
release refresh work. If a project's documented area changes shape, update the
|
|
46
|
+
matching authoring guide.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Area Authoring Guides
|
|
2
|
+
|
|
3
|
+
This folder contains one authoring guide per documented area.
|
|
4
|
+
|
|
5
|
+
Create a guide from `_template.md` when adding a documentation area:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
reference/_authoring/areas/<area-slug>.md
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Each guide should help a human or agent refresh reference from a release diff
|
|
12
|
+
without rediscovering the area's structure from scratch.
|
|
13
|
+
|
|
14
|
+
## Current Area Guides
|
|
15
|
+
|
|
16
|
+
- None yet.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Area Name
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
- Source orientation: `path/to/runtime-or-product-code`, `path/to/contracts`,
|
|
6
|
+
`path/to/tests`, `path/to/ci-or-delivery`, `path/to/infra-or-config`
|
|
7
|
+
- Reference root: `reference/<Area>/`
|
|
8
|
+
- Owner or reviewer: TBD
|
|
9
|
+
|
|
10
|
+
Describe what this area owns and what it intentionally does not own.
|
|
11
|
+
|
|
12
|
+
## Audience And Depth
|
|
13
|
+
|
|
14
|
+
State any area-specific audience or depth rules. By default, write for
|
|
15
|
+
Product Owners, QA, support, operators, customer engineers, and technical
|
|
16
|
+
readers who need behavior, rules, data effects, permissions, errors, and
|
|
17
|
+
operational expectations without private implementation detail.
|
|
18
|
+
|
|
19
|
+
## Feature Inventory
|
|
20
|
+
|
|
21
|
+
| Feature | Reference page | Notes |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| TBD | `reference/<Area>/features/<feature>.md` | TBD |
|
|
24
|
+
|
|
25
|
+
## What Matters At Release Time
|
|
26
|
+
|
|
27
|
+
Document behavior changes that affect:
|
|
28
|
+
|
|
29
|
+
- user, operator, or API-visible behavior
|
|
30
|
+
- permissions, validation, or error handling
|
|
31
|
+
- data creation, mutation, retention, or migration
|
|
32
|
+
- integrations or external contracts
|
|
33
|
+
- observability, support, or operational procedures
|
|
34
|
+
- configuration, environment shape, or deployment behavior
|
|
35
|
+
|
|
36
|
+
## What To Ignore
|
|
37
|
+
|
|
38
|
+
Ignore changes that do not alter released behavior:
|
|
39
|
+
|
|
40
|
+
- pure refactors
|
|
41
|
+
- internal renames
|
|
42
|
+
- formatting or lint-only changes
|
|
43
|
+
- test-only changes
|
|
44
|
+
- dependency bumps with no behavior impact
|
|
45
|
+
- temporary migration scaffolding that will not ship as behavior
|
|
46
|
+
|
|
47
|
+
## Code Orientation
|
|
48
|
+
|
|
49
|
+
List the files, folders, entry points, or search terms that help an agent map a
|
|
50
|
+
release diff to documentation pages.
|
|
51
|
+
|
|
52
|
+
## Baseline Discovery Notes
|
|
53
|
+
|
|
54
|
+
Use this section when creating first-pass documentation for an existing
|
|
55
|
+
project. List stable workflows, important entry points, source references,
|
|
56
|
+
known gaps, and questions that should not yet appear in product-facing docs.
|
|
57
|
+
|
|
58
|
+
## Terminology
|
|
59
|
+
|
|
60
|
+
List area-specific terms or link to `reference/_authoring/terminology.md`.
|
|
61
|
+
|
|
62
|
+
## Cross-Links
|
|
63
|
+
|
|
64
|
+
List related areas and when reference should cross-link instead of duplicating
|
|
65
|
+
behavior.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Project Terminology
|
|
2
|
+
|
|
3
|
+
Use this file to define the domain language that documentation should use.
|
|
4
|
+
|
|
5
|
+
Reference should translate code-level names into reader-facing domain
|
|
6
|
+
terms when those differ. The goal is consistency for QA, product, support,
|
|
7
|
+
operators, and future agents.
|
|
8
|
+
|
|
9
|
+
## Core Terms
|
|
10
|
+
|
|
11
|
+
| Term | Meaning | Code-level names to translate |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| TBD | TBD | TBD |
|
|
14
|
+
|
|
15
|
+
## Relationships
|
|
16
|
+
|
|
17
|
+
Use this section for named relationships between important domain concepts.
|
|
18
|
+
|
|
19
|
+
| Relationship | Between | Meaning |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| TBD | TBD | TBD |
|
|
22
|
+
|
|
23
|
+
## Guardrails
|
|
24
|
+
|
|
25
|
+
Capture wording rules that prevent misleading documentation.
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
|
|
29
|
+
- Prefer one canonical term over an overloaded code name.
|
|
30
|
+
- Avoid implying that a relationship is permanent when it can change.
|
|
31
|
+
- Call out standards-driven terms that must remain as-is.
|
|
32
|
+
|
|
33
|
+
## Diagram
|
|
34
|
+
|
|
35
|
+
Add a Mermaid diagram when relationships are easier to understand visually.
|
|
36
|
+
|
|
37
|
+
```mermaid
|
|
38
|
+
flowchart LR
|
|
39
|
+
ConceptA["Concept A"] -->|"relationship"| ConceptB["Concept B"]
|
|
40
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Reference Workflow
|
|
2
|
+
|
|
3
|
+
How `reference/` is structured, written, and refreshed. Area-specific paths live in [`areas/`](areas/).
|
|
4
|
+
|
|
5
|
+
## When To Edit
|
|
6
|
+
|
|
7
|
+
Only when a human explicitly asks: release refresh, baseline, a specific page update, or a demonstrable fix. Never as a side effect of feature work — flag staleness in `release-doc-notes.md` instead.
|
|
8
|
+
|
|
9
|
+
## Modes
|
|
10
|
+
|
|
11
|
+
**Baseline** — document current accepted behavior. Use `.agents/skills/reference-baseline/SKILL.md`. Record reference point in `reference/releases/index.md`.
|
|
12
|
+
|
|
13
|
+
**Release-forward** — sparse start; refresh at tag time from diff. Use `.agents/skills/reference-from-tags/SKILL.md`. Optional hints from `context/initiatives/*/release-doc-notes.md`.
|
|
14
|
+
|
|
15
|
+
## Cadence
|
|
16
|
+
|
|
17
|
+
Refreshed once per accepted release, anchored to tag (default `release/vMAJOR_MINOR_PATCH`). Document custom tag conventions here before first refresh.
|
|
18
|
+
|
|
19
|
+
## Audience
|
|
20
|
+
|
|
21
|
+
Non-developer technical readers (QA, product, support, operators) unless the project defines otherwise. Behavior and rules in domain language; link to source for depth.
|
|
22
|
+
|
|
23
|
+
## Layout
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
reference/<Area>/
|
|
27
|
+
README.md
|
|
28
|
+
features/<feature>.md
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Write from observable behavior outward. Mermaid for architecture/flow when clearer than prose; keep diagrams small.
|
|
32
|
+
|
|
33
|
+
## Release Refresh (summary)
|
|
34
|
+
|
|
35
|
+
1. Diff `<previous-tag>..<target>`, one area at a time per area guide.
|
|
36
|
+
2. Update affected pages; ignore refactors and test-only changes.
|
|
37
|
+
3. Append `reference/releases/index.md` row.
|
|
38
|
+
|
|
39
|
+
Full steps: `.agents/skills/reference-from-tags/SKILL.md`.
|
|
40
|
+
|
|
41
|
+
## Do Not Document
|
|
42
|
+
|
|
43
|
+
Internal helpers, generated API docs (link instead), transient scaffolding, or open plans (those live in `context/`).
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Area Name
|
|
2
|
+
|
|
3
|
+
Briefly describe what this area does, who uses it, and why it exists.
|
|
4
|
+
|
|
5
|
+
## Reader Summary
|
|
6
|
+
|
|
7
|
+
Explain the area in product or domain language. A Product Owner should be able
|
|
8
|
+
to understand the purpose, scope, and user or business value from this section.
|
|
9
|
+
|
|
10
|
+
## Primary Workflows
|
|
11
|
+
|
|
12
|
+
- TBD
|
|
13
|
+
|
|
14
|
+
## Architecture At A Glance
|
|
15
|
+
|
|
16
|
+
```mermaid
|
|
17
|
+
flowchart LR
|
|
18
|
+
User["User or operator"] -->|"uses"| Area["Area"]
|
|
19
|
+
Area -->|"reads or writes"| Data["Data store"]
|
|
20
|
+
Area -->|"calls"| External["External system"]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Responsibilities
|
|
24
|
+
|
|
25
|
+
- TBD
|
|
26
|
+
|
|
27
|
+
## Data And State
|
|
28
|
+
|
|
29
|
+
Describe the important records, files, queues, external state, or generated
|
|
30
|
+
artifacts this area creates, reads, or changes.
|
|
31
|
+
|
|
32
|
+
- TBD
|
|
33
|
+
|
|
34
|
+
## Configuration And Dependencies
|
|
35
|
+
|
|
36
|
+
List configuration, environment assumptions, external systems, scheduled jobs,
|
|
37
|
+
or infrastructure this area depends on.
|
|
38
|
+
|
|
39
|
+
- TBD
|
|
40
|
+
|
|
41
|
+
## Operational Expectations
|
|
42
|
+
|
|
43
|
+
Describe support, observability, recovery, audit, or routine operational
|
|
44
|
+
expectations that matter to readers.
|
|
45
|
+
|
|
46
|
+
- TBD
|
|
47
|
+
|
|
48
|
+
## Source References
|
|
49
|
+
|
|
50
|
+
Optional links to source files, generated references, dashboards, runbooks, or
|
|
51
|
+
release context that help technical readers verify behavior. Keep explanation
|
|
52
|
+
in this page instead of replacing it with links.
|
|
53
|
+
|
|
54
|
+
- TBD
|
|
55
|
+
|
|
56
|
+
## Feature Pages
|
|
57
|
+
|
|
58
|
+
- [Feature Name](features/feature-template.md)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Feature Name
|
|
2
|
+
|
|
3
|
+
Describe the shipped behavior in product or domain language. Start with what a
|
|
4
|
+
Product Owner, QA reader, support person, operator, or API consumer can
|
|
5
|
+
observe.
|
|
6
|
+
|
|
7
|
+
## Reader Summary
|
|
8
|
+
|
|
9
|
+
Explain what the feature does, why it matters, and the outcome it provides.
|
|
10
|
+
|
|
11
|
+
## Who Uses It
|
|
12
|
+
|
|
13
|
+
- TBD
|
|
14
|
+
|
|
15
|
+
## Entry Points
|
|
16
|
+
|
|
17
|
+
Describe where the feature is triggered: UI, API, CLI, scheduled job,
|
|
18
|
+
integration, import/export, or operator workflow.
|
|
19
|
+
|
|
20
|
+
- TBD
|
|
21
|
+
|
|
22
|
+
## Behavior
|
|
23
|
+
|
|
24
|
+
- TBD
|
|
25
|
+
|
|
26
|
+
## Business Rules
|
|
27
|
+
|
|
28
|
+
Describe rules, limits, lifecycle states, timing, or decision logic in
|
|
29
|
+
reader-facing language.
|
|
30
|
+
|
|
31
|
+
- TBD
|
|
32
|
+
|
|
33
|
+
## Inputs And Outputs
|
|
34
|
+
|
|
35
|
+
| Input or output | Description |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| TBD | TBD |
|
|
38
|
+
|
|
39
|
+
## Data And State Changes
|
|
40
|
+
|
|
41
|
+
Describe important records, files, generated artifacts, messages, or external
|
|
42
|
+
state this feature creates, reads, updates, deletes, or retains.
|
|
43
|
+
|
|
44
|
+
- TBD
|
|
45
|
+
|
|
46
|
+
## Permissions And Validation
|
|
47
|
+
|
|
48
|
+
- TBD
|
|
49
|
+
|
|
50
|
+
## Configuration And Dependencies
|
|
51
|
+
|
|
52
|
+
List flags, settings, environment requirements, external systems, or
|
|
53
|
+
infrastructure dependencies that affect this feature.
|
|
54
|
+
|
|
55
|
+
- TBD
|
|
56
|
+
|
|
57
|
+
## Errors And Edge Cases
|
|
58
|
+
|
|
59
|
+
- TBD
|
|
60
|
+
|
|
61
|
+
## Operational Notes
|
|
62
|
+
|
|
63
|
+
- TBD
|
|
64
|
+
|
|
65
|
+
## Source References
|
|
66
|
+
|
|
67
|
+
Optional links to source files, generated references, runbooks, dashboards, or
|
|
68
|
+
release context that help technical readers verify behavior. Do not use this
|
|
69
|
+
section for private implementation detail that has no reader-visible impact.
|
|
70
|
+
|
|
71
|
+
- TBD
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Reference Release Index
|
|
2
|
+
|
|
3
|
+
One row per tagged release. Tag names default to `release/vMAJOR_MINOR_PATCH`
|
|
4
|
+
unless the project documents a different convention.
|
|
5
|
+
|
|
6
|
+
Reference at a given tag describes the behavior of that release.
|
|
7
|
+
|
|
8
|
+
| Tag | Date | Areas refreshed | Owner | Summary |
|
|
9
|
+
| --- | --- | --- | --- | --- |
|
|
10
|
+
| TBD | TBD | TBD | TBD | First documentation refresh. |
|
|
11
|
+
|
|
12
|
+
## Notes For Future Release Rows
|
|
13
|
+
|
|
14
|
+
- For an explicit baseline documentation pass, the tag may be a commit,
|
|
15
|
+
branch, date, or human-named baseline label when no release tag exists yet.
|
|
16
|
+
- The first row may be a bootstrap refresh. Subsequent rows should describe
|
|
17
|
+
incremental refreshes from `<previous-tag>..HEAD`.
|
|
18
|
+
- "Areas refreshed" lists only areas with material behavior changes.
|
|
19
|
+
- Keep the summary to one sentence. Link to an area or feature doc when a
|
|
20
|
+
change deserves more space.
|