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 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));
@@ -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,6 @@
1
+ # Project Skills
2
+
3
+ Invocation-only — ask by name.
4
+
5
+ - `reference-from-tags` — refresh `reference/` from a tag-to-tag diff.
6
+ - `reference-baseline` — first baseline pass under `reference/`.
@@ -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.