eidosmd 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +133 -0
  2. package/NOTICE +15 -0
  3. package/README.md +146 -0
  4. package/browser/index.html +268 -0
  5. package/dist/src/cli.js +5 -0
  6. package/dist/src/commands/agents.js +47 -0
  7. package/dist/src/commands/browser.js +40 -0
  8. package/dist/src/commands/check.js +61 -0
  9. package/dist/src/commands/convert.js +30 -0
  10. package/dist/src/commands/framework.js +76 -0
  11. package/dist/src/commands/index.js +64 -0
  12. package/dist/src/commands/init.js +66 -0
  13. package/dist/src/commands/instructions.js +40 -0
  14. package/dist/src/commands/list.js +73 -0
  15. package/dist/src/commands/new.js +68 -0
  16. package/dist/src/commands/seeds.js +40 -0
  17. package/dist/src/commands/show.js +24 -0
  18. package/dist/src/commands/whoami.js +84 -0
  19. package/dist/src/context.js +35 -0
  20. package/dist/src/core/blueprint.js +129 -0
  21. package/dist/src/core/check.js +407 -0
  22. package/dist/src/core/convert.js +37 -0
  23. package/dist/src/core/framework-markdown.js +233 -0
  24. package/dist/src/core/framework-model.js +48 -0
  25. package/dist/src/core/framework-structured.js +334 -0
  26. package/dist/src/core/framework.js +56 -0
  27. package/dist/src/core/frontmatter.js +116 -0
  28. package/dist/src/core/index-leaf.js +83 -0
  29. package/dist/src/core/markdown.js +100 -0
  30. package/dist/src/core/me.js +89 -0
  31. package/dist/src/core/naming.js +46 -0
  32. package/dist/src/core/root.js +88 -0
  33. package/dist/src/core/scaffold.js +118 -0
  34. package/dist/src/core/seed.js +223 -0
  35. package/dist/src/core/server.js +275 -0
  36. package/dist/src/core/shape.js +26 -0
  37. package/dist/src/output.js +38 -0
  38. package/dist/src/paths.js +28 -0
  39. package/dist/src/program.js +242 -0
  40. package/instructions/authoring.md +50 -0
  41. package/instructions/configuring.md +65 -0
  42. package/instructions/init-required.md +32 -0
  43. package/instructions/overview.md +37 -0
  44. package/instructions/validating.md +33 -0
  45. package/package.json +53 -0
  46. package/standard/EIDOS.md +324 -0
  47. package/standard/seeds/README.md +25 -0
  48. package/standard/seeds/book/Framework.md +87 -0
  49. package/standard/seeds/book/README.md +22 -0
  50. package/standard/seeds/book/_gitignore +4 -0
  51. package/standard/seeds/book/me.md +18 -0
  52. package/standard/seeds/book/roles/README.md +12 -0
  53. package/standard/seeds/book/roles/collaborator.md +16 -0
  54. package/standard/seeds/book/roles/editor.md +16 -0
  55. package/standard/seeds/book/roles/framework-owner.md +16 -0
  56. package/standard/seeds/book/roles/reader.md +16 -0
  57. package/standard/seeds/book/shapes/chapter.full.md +45 -0
  58. package/standard/seeds/book/shapes/chapter.sketch.md +26 -0
  59. package/standard/seeds/book/shapes/frame.market.md +23 -0
  60. package/standard/seeds/book/shapes/frame.premise.md +24 -0
  61. package/standard/seeds/book/shapes/frame.reader.md +23 -0
  62. package/standard/seeds/book/shapes/frame.voice.md +24 -0
  63. package/standard/seeds/research/Framework.md +88 -0
  64. package/standard/seeds/research/README.md +23 -0
  65. package/standard/seeds/research/_gitignore +4 -0
  66. package/standard/seeds/research/me.md +18 -0
  67. package/standard/seeds/research/roles/README.md +12 -0
  68. package/standard/seeds/research/roles/framework-owner.md +16 -0
  69. package/standard/seeds/research/roles/researcher.md +16 -0
  70. package/standard/seeds/research/roles/reviewer.md +16 -0
  71. package/standard/seeds/research/roles/sponsor.md +16 -0
  72. package/standard/seeds/research/shapes/frame.ethics.md +23 -0
  73. package/standard/seeds/research/shapes/frame.method.md +24 -0
  74. package/standard/seeds/research/shapes/frame.prior-work.md +23 -0
  75. package/standard/seeds/research/shapes/frame.question.md +24 -0
  76. package/standard/seeds/research/shapes/investigation.full.md +49 -0
  77. package/standard/seeds/research/shapes/investigation.note.md +26 -0
  78. package/standard/seeds/software/Framework.md +88 -0
  79. package/standard/seeds/software/README.md +24 -0
  80. package/standard/seeds/software/_gitignore +4 -0
  81. package/standard/seeds/software/me.md +18 -0
  82. package/standard/seeds/software/roles/.gitkeep +0 -0
  83. package/standard/seeds/software/roles/README.md +13 -0
  84. package/standard/seeds/software/roles/designer.md +16 -0
  85. package/standard/seeds/software/roles/developer.md +16 -0
  86. package/standard/seeds/software/roles/framework-owner.md +16 -0
  87. package/standard/seeds/software/roles/project-manager.md +18 -0
  88. package/standard/seeds/software/roles/stakeholder.md +16 -0
  89. package/standard/seeds/software/shapes/.gitkeep +0 -0
  90. package/standard/seeds/software/shapes/frame.architecture.md +26 -0
  91. package/standard/seeds/software/shapes/frame.audience.md +26 -0
  92. package/standard/seeds/software/shapes/frame.criteria.md +27 -0
  93. package/standard/seeds/software/shapes/frame.market.md +31 -0
  94. package/standard/seeds/software/shapes/spec.full.md +67 -0
  95. package/standard/seeds/software/shapes/spec.micro.md +32 -0
@@ -0,0 +1,28 @@
1
+ // Where the package keeps the files it ships beside its code: the vendored
2
+ // standard (EIDOS.md and the seeds) and the agent instructions.
3
+ import { readFileSync } from 'node:fs';
4
+ import { fileURLToPath } from 'node:url';
5
+ import path from 'node:path';
6
+ // dist/src/paths.js sits two levels below the package root.
7
+ export const packageRoot = fileURLToPath(new URL('../../', import.meta.url));
8
+ export const standardDir = path.join(packageRoot, 'standard');
9
+ export const seedsDir = path.join(standardDir, 'seeds');
10
+ export const standardFile = path.join(standardDir, 'EIDOS.md');
11
+ export const instructionsDir = path.join(packageRoot, 'instructions');
12
+ export const browserDir = path.join(packageRoot, 'browser');
13
+ export function readStandard() {
14
+ return readFileSync(standardFile, 'utf8');
15
+ }
16
+ // The version of the standard this CLI carries, read off EIDOS.md's own header
17
+ // so the vendored copy is the single source of it.
18
+ export function standardVersion() {
19
+ const match = /^\*\*Version:\*\*\s*(\S+)/m.exec(readStandard());
20
+ if (!match || !match[1]) {
21
+ throw new Error(`no **Version:** header in ${standardFile}`);
22
+ }
23
+ return match[1];
24
+ }
25
+ export function packageVersion() {
26
+ const manifest = JSON.parse(readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
27
+ return manifest.version;
28
+ }
@@ -0,0 +1,242 @@
1
+ // The eidos command line, assembled: every command, its options, and its help.
2
+ // `cli.ts` is the executable entry; this module is what tests build.
3
+ import { Command } from 'commander';
4
+ import { loadRoot } from './context.js';
5
+ import { runAgents } from './commands/agents.js';
6
+ import { DEFAULT_PORT, runBrowser } from './commands/browser.js';
7
+ import { runCheck } from './commands/check.js';
8
+ import { runConvert } from './commands/convert.js';
9
+ import { runFramework } from './commands/framework.js';
10
+ import { runIndex } from './commands/index.js';
11
+ import { runInit } from './commands/init.js';
12
+ import { runInstructions, runStandard } from './commands/instructions.js';
13
+ import { runList } from './commands/list.js';
14
+ import { runNew } from './commands/new.js';
15
+ import { runSeeds } from './commands/seeds.js';
16
+ import { runShow } from './commands/show.js';
17
+ import { runRoles, runWhoami } from './commands/whoami.js';
18
+ import { CliError, EXIT_USAGE, printError, today } from './output.js';
19
+ import { packageVersion, standardVersion } from './paths.js';
20
+ const collect = (value, previous) => [...previous, value];
21
+ function run(action) {
22
+ try {
23
+ process.exitCode = action();
24
+ }
25
+ catch (cause) {
26
+ if (cause instanceof CliError) {
27
+ printError(`error: ${cause.message}`);
28
+ process.exitCode = cause.exitCode;
29
+ return;
30
+ }
31
+ const message = cause instanceof Error ? cause.message : String(cause);
32
+ printError(`error: ${message}`);
33
+ process.exitCode = EXIT_USAGE;
34
+ }
35
+ }
36
+ export function buildProgram() {
37
+ const program = new Command();
38
+ // --root is accepted before or after the command name.
39
+ const globals = (local = {}) => ({ root: local.root ?? program.opts().root });
40
+ const withRoot = (command) => command.option('--root <path>', 'the root to work in');
41
+ program
42
+ .name('eidos')
43
+ .description(`Eidos: one markdown file is the complete source of truth for one unit of a thing.\nScaffold, validate, and index a root of blueprints; hand an agent the workflow with \`eidos instructions\`.`)
44
+ .version(`eidosmd ${packageVersion()} (standard ${standardVersion()})`, '-v, --version', 'print the CLI version and the standard it carries')
45
+ .option('--root <path>', 'the root to work in (default: found from the working directory by its _eidos/ marker)')
46
+ .enablePositionalOptions()
47
+ .showHelpAfterError('(run with --help for usage)')
48
+ .addHelpText('after', `
49
+ Exit codes: 0 done · 1 the check found errors, or an index is stale · 2 the command could not run
50
+
51
+ Start with \`eidos instructions\` for the workflow, or \`eidos seeds\` and \`eidos init\` to create a root.`);
52
+ program
53
+ .command('init')
54
+ .argument('[root]', 'the root folder to create', 'Blueprints')
55
+ .description('create a root from a bundled seed: its framework as _eidos/Framework.yaml, a folder per collection, a blank blueprint per framing flavor')
56
+ .option('--seed <name>', 'the seed to install (see `eidos seeds`)', 'software')
57
+ .option('--naming <convention>', 'kebab-case | TitleCase | "Title Case"; governs every human-facing name, settled once', 'kebab-case')
58
+ .option('--group <name>', 'a starting group under the grouped collection (repeatable)', collect, [])
59
+ .option('--product <name>', "fills the README's {{Product}} placeholder")
60
+ .option('--date <YYYY-MM-DD>', 'the date written into the scaffolded frames', today())
61
+ .option('--dry-run', 'print every write and touch nothing', false)
62
+ .option('--json', 'machine-readable result', false)
63
+ .addHelpText('after', `
64
+ Writes no prose: the README one-liner, each group's description, and every frame's summary and body stay the owner's.
65
+
66
+ Examples:
67
+ eidos init
68
+ eidos init Blueprints --seed software --group Identity --group Billing --product "Care Connect"
69
+ eidos init docs/product --seed research --naming TitleCase --dry-run
70
+
71
+ Writes Framework.yaml, the form the CLI works in. A root that keeps Framework.md (the form for people) is converted with \`eidos convert\`.`)
72
+ .action((root, options) => {
73
+ run(() => runInit(root, options));
74
+ });
75
+ program
76
+ .command('seeds')
77
+ .description('list the bundled seeds: each one a complete starting framework, with its collections and flavors')
78
+ .option('--json', 'machine-readable result', false)
79
+ .action((options) => {
80
+ run(() => runSeeds(options));
81
+ });
82
+ withRoot(program.command('framework'))
83
+ .description("show the root's framework: version, naming, top-level docs, collections (flavors, canvas, groups), and the property Schema")
84
+ .option('--json', 'the framework as JSON: the document form plus root, file, and format', false)
85
+ .option('--as <format>', 'print the framework as the yaml document a scriptable root keeps in _eidos/')
86
+ .addHelpText('after', `
87
+ Read this before assuming any collection, flavor, section, or property name; the framework declares its own.
88
+ The document is _eidos/Framework.md (for people) or Framework.yaml (for scripts and agents): the same fields in each.
89
+
90
+ Output (--json): { root, file, format, eidos_version, naming, top_level[], collections[{ name, description, canvas, flavors[{ name, shape, description, default }], grouping{ label, property, groups[] } }], schema{ core[], custom[{ name, type, applies_to, meaning }] } }
91
+
92
+ This is the one command that also reads a Framework.md root, so a root can be inspected before \`eidos convert\` moves it.`)
93
+ .action((options) => {
94
+ run(() => runFramework(loadRoot(globals(options), process.cwd(), { allowMarkdown: true }), options));
95
+ });
96
+ withRoot(program.command('convert'))
97
+ .description('move a markdown root to Framework.yaml, the form the CLI works in: the same framework with the index inside it; Framework.md and each index.md removed')
98
+ .option('--dry-run', 'print the writes and touch nothing', false)
99
+ .option('--json', 'machine-readable result', false)
100
+ .addHelpText('after', `
101
+ Every command except this one and \`framework\` needs Framework.yaml, so on a markdown root this is the first thing to run. The markdown form's prose (section intros, comments) has no field to land in and is left behind; each collection's description travels. Blueprints are untouched.`)
102
+ .action((options) => {
103
+ run(() => runConvert(globals(options), options));
104
+ });
105
+ withRoot(program.command('list'))
106
+ .argument('[collection]', 'only this collection')
107
+ .description('list the blueprints in the root')
108
+ .option('--group <name>', 'only this group (sub-folder)')
109
+ .option('--flavor <name>', 'only blueprints on this flavor (resolved, so the default counts)')
110
+ .option('--where <key=value>', 'only blueprints whose property equals the value, case-insensitive (repeatable; a list matches any item)', collect, [])
111
+ .option('--json', 'one object per blueprint: id, title, summary, collection, group, flavor, path, properties', false)
112
+ .addHelpText('after', `
113
+ Examples:
114
+ eidos list
115
+ eidos list Specs --group Identity
116
+ eidos list --where status=Draft --json`)
117
+ .action((collection, options) => {
118
+ run(() => runList(loadRoot(globals(options)), collection, options));
119
+ });
120
+ withRoot(program.command('show'))
121
+ .argument('<blueprint>', 'an id, a filename, or a path')
122
+ .description('print one blueprint as written; with --json, its properties and sections parsed out')
123
+ .option('--json', '{ id, title, summary, collection, group, flavor, path, absolute_path, properties, sections[{ heading, body }], body }', false)
124
+ .action((ref, options) => {
125
+ run(() => runShow(loadRoot(globals(options)), ref, options));
126
+ });
127
+ withRoot(program.command('new'))
128
+ .argument('<collection>', 'the collection the blueprint belongs to')
129
+ .argument('<title...>', 'the human-readable title')
130
+ .description("scaffold a blueprint that is born conforming: frontmatter from the Schema, body from the flavor's shape, filename in the naming convention, a permanent kebab-case id")
131
+ .option('--flavor <name>', "one of the collection's declared flavors (default: the collection's default)")
132
+ .option('--group <name>', 'the sub-folder to place it in')
133
+ .option('--id <kebab-case>', 'the permanent id (default: the title in kebab-case)')
134
+ .option('--summary <line>', 'the one-line summary, so the index lists it at once')
135
+ .option('--set <key=value>', 'a property value at creation (repeatable; lists are comma-separated)', collect, [])
136
+ .option('--date <YYYY-MM-DD>', 'the date written into date properties the Schema declares', today())
137
+ .option('--dry-run', 'print the file instead of writing it', false)
138
+ .option('--json', '{ path, id, collection, group, flavor, notes[] }', false)
139
+ .addHelpText('after', `
140
+ The body keeps the shape's guidance prompts; fill them with the owner and delete them as you go. The CLI writes no prose.
141
+
142
+ Examples:
143
+ eidos new Specs "Session Management" --group Identity --summary "Keeps a signed-in user signed in across tabs and devices."
144
+ eidos new Specs "Passkeys" --flavor micro --set status=Intake --set tags=auth,security
145
+ eidos new Frames Market --dry-run`)
146
+ .action((collection, title, options) => {
147
+ run(() => runNew(loadRoot(globals(options)), collection, title, options));
148
+ });
149
+ withRoot(program.command('check'))
150
+ .argument('[blueprint...]', 'only these blueprints (paths); default: the whole root')
151
+ .description("validate the root against its own framework: the Framework.md and shapes, every blueprint's frontmatter and body, the layout, and the indexes")
152
+ .option('--strict', 'warnings fail too', false)
153
+ .option('--json', '{ ok, root, eidos_version, naming, blueprints, errors, warnings, findings[{ level, code, path, message }] }', false)
154
+ .addHelpText('after', `
155
+ Errors are wrong on any reading (unparseable frontmatter, a missing or duplicate id, an undeclared flavor, a broken link). Warnings are gaps the standard says to surface, never refuse (a missing property or section, a stale index, a version gap). Exit 1 on an error; with --strict, on a warning too.
156
+
157
+ Examples:
158
+ eidos check
159
+ eidos check Specs/Identity/login.md
160
+ eidos check --strict --json`)
161
+ .action((blueprints, options) => {
162
+ run(() => runCheck(loadRoot(globals(options)), blueprints, options));
163
+ });
164
+ withRoot(program.command('index'))
165
+ .description("regenerate each collection's index.md: every blueprint as a link with its summary, grouped by sub-folder")
166
+ .option('--collection <name>', 'only this collection (repeatable)', collect, [])
167
+ .option('--check', 'write nothing; exit 1 if any index is stale', false)
168
+ .option('--json', '{ ok, indexes[{ collection, path, status, blueprints }], missing_summary[] }', false)
169
+ .addHelpText('after', `
170
+ Under a markdown framework each collection gets its own index.md, regenerated wholesale: nothing hand-written in it survives. Under a YAML framework every collection's index is written into the framework document under \`index\`, and the rest of the document is left as written. A blueprint without a summary is listed with a TODO marker (or a null summary) and named on stderr.`)
171
+ .action((options) => {
172
+ run(() => runIndex(loadRoot(globals(options)), options));
173
+ });
174
+ withRoot(program.command('roles'))
175
+ .description('list the roles the framework installed under _eidos/roles/')
176
+ .option('--json', 'machine-readable result', false)
177
+ .action((options) => {
178
+ run(() => runRoles(loadRoot(globals(options)), options));
179
+ });
180
+ withRoot(program.command('whoami'))
181
+ .description('show the actor in the seat (_eidos/me.md: role and calibration), or set it')
182
+ .option('--role <name>', 'a role from `eidos roles`')
183
+ .option('--ownership <text>', 'what you own on this root, in your own words')
184
+ .option('--experience <text>', 'your experience with the scope: new, familiar, deep')
185
+ .option('--capacity <text>', 'your technical capacity: non-technical, some, fluent')
186
+ .option('--clear', 'blank the actor (full facilitation)', false)
187
+ .option('--json', 'machine-readable result', false)
188
+ .addHelpText('after', `
189
+ me.md is personal and gitignored: one per person, never shared. An agent reads it before acting and responds as the role file says.
190
+
191
+ Examples:
192
+ eidos whoami
193
+ eidos whoami --role developer --experience "new to this product" --capacity fluent`)
194
+ .action((options) => {
195
+ run(() => runWhoami(loadRoot(globals(options)), options));
196
+ });
197
+ withRoot(program.command('browser'))
198
+ .description('open the root in a local web page: browse and read blueprints, create one, edit one, run the check, rebuild the index')
199
+ .option('-p, --port <port>', 'the port to serve on; the next free one is used if it is busy', (value) => Number.parseInt(value, 10), DEFAULT_PORT)
200
+ .option('--no-open', 'print the URL without opening a browser')
201
+ .addHelpText('after', `
202
+ Serves on 127.0.0.1 only. Every change the page makes runs the same code as the command it mirrors (new, index, check), so an agent should use the commands and leave the page to people. Press Ctrl+C to stop.`)
203
+ .action(async (options) => {
204
+ try {
205
+ process.exitCode = await runBrowser(globals(options), options);
206
+ }
207
+ catch (cause) {
208
+ if (cause instanceof CliError) {
209
+ printError(`error: ${cause.message}`);
210
+ process.exitCode = cause.exitCode;
211
+ }
212
+ else {
213
+ printError(`error: ${cause instanceof Error ? cause.message : String(cause)}`);
214
+ process.exitCode = EXIT_USAGE;
215
+ }
216
+ }
217
+ });
218
+ program
219
+ .command('instructions')
220
+ .argument('[guide]', 'overview | authoring | validating | configuring | init-required')
221
+ .description('print the workflow an agent follows in a root; no argument lists the guides')
222
+ .action((guide) => {
223
+ run(() => runInstructions(guide));
224
+ });
225
+ program
226
+ .command('standard')
227
+ .description('print the text of the Eidos standard this CLI carries (EIDOS.md)')
228
+ .option('--version', 'print only its version', false)
229
+ .action((options) => {
230
+ run(() => runStandard(options));
231
+ });
232
+ program
233
+ .command('agents')
234
+ .description('print the short nudge that points agents at `eidos instructions`, or write it into an instruction file')
235
+ .option('--write', 'append the nudge to the file (or refresh the one already there)', false)
236
+ .option('--file <path>', 'the instruction file', 'AGENTS.md')
237
+ .addHelpText('after', '\nExamples:\n eidos agents\n eidos agents --write\n eidos agents --write --file CLAUDE.md')
238
+ .action((options) => {
239
+ run(() => runAgents(options));
240
+ });
241
+ return program;
242
+ }
@@ -0,0 +1,50 @@
1
+ ## Authoring a blueprint
2
+
3
+ A blueprint is one markdown file defining one unit completely: a frontmatter contract plus a body that follows a shape. You scaffold it with the CLI and fill it with the owner.
4
+
5
+ ### 1. Place it
6
+
7
+ Run `eidos framework`. Decide with the owner which collection the blueprint belongs to, which flavor (the collection's default unless they choose another), and which group if the collection groups its blueprints. If the idea is still rough, question it first: what it is, what it is not, and how it sits beside the blueprints already there (`eidos list`, `eidos show <id>`). Write nothing until that holds still.
8
+
9
+ ### 2. Scaffold it
10
+
11
+ ```bash
12
+ eidos new <collection> "<Title>" [--flavor <flavor>] [--group <group>] [--summary "<one line>"]
13
+ ```
14
+
15
+ `new` generates the frontmatter from the properties that apply to the collection, renders the body from the flavor's shape with its guidance kept, names the file in the framework's convention, and puts a permanent kebab-case `id` inside. Set a property at creation with `--set key=value`. Use `--dry-run` to see the file before writing it, and `--json` to get its path.
16
+
17
+ Write the `summary` at creation when you can: one plain line saying what the blueprint is, so the collection index lists it the moment it exists.
18
+
19
+ ### 3. Fill it, with the owner
20
+
21
+ Open the file. The shape's sections are in order, each with an italic prompt saying what belongs there. Work through them top to bottom:
22
+
23
+ - Lead with the opening sections, the ones saying why the unit exists and what it observably does.
24
+ - Press hardest on the section for what the blueprint deliberately will not do. That is where scope is held; a blueprint without it is rarely finished. Prompt for non-goals if the owner has not named them.
25
+ - Where the owner is vague, ask. Do not fill the gap with plausible prose.
26
+ - Keep the shape's section order and names. Leave a section out when it genuinely does not apply rather than leaving it empty. Beneath the sections, write it the way a person would read it: sub-headings, tables, lists.
27
+ - Follow whatever labeling the shape asks for (for example `**AC1:**` on acceptance criteria) and keep checkable statements short.
28
+ - Reference other blueprints with markdown links, never bare names, in prose and in properties alike: `[Session Management](../identity/session-management.md)`. If the target has no blueprint yet, name it plainly rather than fabricating a link.
29
+ - Delete each italic prompt as its section is filled.
30
+
31
+ Frontmatter stays what `new` generated. Fill values; do not add keys the Schema does not declare (`eidos instructions configuring` is how a property is added). Leave a property blank rather than guessing it.
32
+
33
+ ### 4. Check and index
34
+
35
+ ```bash
36
+ eidos check <path-to-blueprint>
37
+ eidos index
38
+ ```
39
+
40
+ `check` reports what is missing or malformed against this framework and the blueprint's flavor. Surface the findings; the owner decides what to act on. `index` rebuilds the collection's `index.md` so the new blueprint is listed.
41
+
42
+ ### Frames and top-level docs
43
+
44
+ A frame is a blueprint in the framing collection (the first one `eidos framework` lists): same procedure, kept as loose prose. Fill what is known and leave the rest; a declared frame left unwritten is a gap to surface, not a failure.
45
+
46
+ A top-level doc (a Roadmap, a Vision) is one-of-a-kind and free-form: no shape, no validation, edited in place. Draft it with the owner, then register it under `top_level` in `_eidos/Framework.yaml`.
47
+
48
+ ### Reshaping a draft the owner already wrote
49
+
50
+ When the thinking is already on the page and only needs shape, scaffold nothing. Read the flavor's shape (`_eidos/shapes/<kind>.<flavor>.md`), move the author's own words under the right sections in the shape's order, keep their wording, add nothing, and run `eidos check` on the result. What does not fit any section stays in the file, under a note, for the owner to place.
@@ -0,0 +1,65 @@
1
+ ## Configuring the framework
2
+
3
+ The framework is the structure a root is written in: the framework document (version, naming, the Top-Level index, the Collections, and the property Schema) plus `_eidos/shapes/` (one file per flavor) and `_eidos/roles/`. This CLI reads it; changing it is an edit to those files, made with the owner and verified with `eidos check`.
4
+
5
+ The document is `_eidos/Framework.yaml`: `top_level`, `collections[]` (each with `flavors`, `canvas`, `grouping`), and `schema.custom[]`, documented field by field in `eidos standard`. The procedures below show the markdown form the standard documents; the fields are the same. Never touch the `index` key: `eidos index` owns it.
6
+
7
+ Press the owner to decide. A collection, flavor, or property nobody thought through reads as meaningful while no one knows what it holds. If they offer only a name, ask for the rest.
8
+
9
+ Never touch `### Eidos Core`: those properties move with the standard's version. And never change the naming convention on a root with files in it without renaming every file and link.
10
+
11
+ ### Adding a collection
12
+
13
+ Decide its **name** (the folder, in the naming convention `eidos framework` shows), a one-line **description**, how it **groups** its blueprints (one level of sub-folders, or flat), at least one **flavor** with a **default**, and how it **draws** on a canvas (`file` for prose read whole; `card from ## <Section>` for blueprints scanned by a headline; ask, do not assume the section).
14
+
15
+ 1. Create the folder under the root.
16
+ 2. Create the default flavor's shape in `_eidos/shapes/<kind>.<flavor>.md`: body only, `# {{title}}` first, then the `##` sections in order, each with an italic guidance prompt. Pattern it on the shapes already there.
17
+ 3. Register it under `## Collections` in `Framework.md` with a `###` heading, the description, then bullets in this form (bullets, so the next flavor is a copied line):
18
+
19
+ ```markdown
20
+ ### Decisions
21
+
22
+ Architecture decision records, one per significant choice.
23
+
24
+ - **Leaf:** [Decisions/index.md](../Decisions/index.md)
25
+ - **Flavors:**
26
+ - [full](shapes/decision.full.md) — context, decision, consequences (default).
27
+ - **Canvas:** card from `## Decision`
28
+ - **Kinds:**
29
+ - **Runtime** — decisions about what runs where.
30
+ ```
31
+
32
+ The grouping bullet (`**Kinds:**` above) is optional; its label is the collection's own, and each nested bullet is one group. A property carrying the group is a Schema change, below.
33
+ 4. Run `eidos index` for the new leaf and `eidos check` to confirm the framework parses as intended.
34
+
35
+ ### Adding a flavor
36
+
37
+ Decide its **name** (lowercase), a one-line **description**, and its **shape**. A second flavor is a deliberate variant, a lighter one to grow out of or a genuine split in kind, never a fork per category label.
38
+
39
+ 1. Create `_eidos/shapes/<kind>.<flavor>.md`, starting from the collection's default flavor and trimming or extending it. Keep the order and names of whatever it shares with the default.
40
+ 2. Add it to the collection's **Flavors** bullets. Move `(default)` to it only if it should be the default; exactly one flavor carries the marker.
41
+ 3. Existing blueprints are untouched: an absent `flavor` still means the default. `eidos new --flavor <name>` scaffolds in it from here on.
42
+
43
+ ### Adding a property
44
+
45
+ Decide all four: **name** (lowercase, words joined by underscores), **type** (Text, List, Number, Checkbox, Date, or Date & time; anything richer belongs in the body), **applies to** (`all`, or a list of collections), and **meaning** (one line).
46
+
47
+ 1. Add a row to `### Custom Properties` in `## Schema`:
48
+
49
+ ```markdown
50
+ | team | Text | all | Owning team, for filtering. |
51
+ ```
52
+
53
+ 2. Backfill the blueprints it applies to with an empty or owner-supplied stub, so each is fillable; `eidos check` lists the ones still missing it as `property-missing`. New blueprints get it from `eidos new`.
54
+
55
+ ### Renaming or retiring a property
56
+
57
+ Renaming: change the `Name` cell, then the key in every blueprint's frontmatter, carrying values across unchanged. Retiring: first show the owner every value that would be lost and ask whether to fold them somewhere or drop them; only then remove the row and the keys. Never silently drop values.
58
+
59
+ ### Refreshing the Top-Level index
60
+
61
+ `## Top-Level` lists the root's one-of-a-kind documents, `README` first, one bullet each: `- [Title](../Title.md) — one-line description`. Frames are a collection, not top-level. Keep the owner's existing descriptions; a doc with none gets a `<!-- TODO: describe -->`, and you ask. `eidos check` reports an entry whose file does not exist.
62
+
63
+ ### After
64
+
65
+ Run `eidos check`. It will tell you whether the collection, its flavors, its shapes, and its groups are declared consistently, and which blueprints the change left with a gap.
@@ -0,0 +1,32 @@
1
+ ## Eidos root required
2
+
3
+ No root was found from this directory: nothing here holds a `_eidos/` folder with a `Framework.md` inside it. A root is found by that marker, never by its name.
4
+
5
+ If the root lives elsewhere in the repository, pass it explicitly:
6
+
7
+ ```bash
8
+ eidos --root path/to/Blueprints framework
9
+ ```
10
+
11
+ To create one, pick a seed (a complete starting framework) and install it:
12
+
13
+ ```bash
14
+ eidos seeds # what each seed is for, and its collections
15
+ eidos init # Blueprints/ from the software seed, kebab-case
16
+ eidos init Blueprints --seed book --naming "Title Case" --group "Part One" --product "My Book"
17
+ ```
18
+
19
+ `init` asks the owner nothing: choose the seed, the root folder name, the naming convention, the first groups, and the product name with them first, then run it. Everything a seed ships is reshapeable later, so a seed that is merely close is the right choice. `--dry-run` prints every write and touches nothing.
20
+
21
+ If there is a root but it keeps its framework as `_eidos/Framework.md`, the CLI's first job is to convert it:
22
+
23
+ ```bash
24
+ eidos convert --dry-run # the writes it would make
25
+ eidos convert # Framework.yaml with the index inside; Framework.md and each index.md removed
26
+ ```
27
+
28
+ After that, run:
29
+
30
+ ```bash
31
+ eidos instructions overview
32
+ ```
@@ -0,0 +1,37 @@
1
+ ## Eidos Overview (CLI)
2
+
3
+ This repository keeps a root of Eidos blueprints. One markdown file is the complete source of truth for one unit of the thing being made, true whether or not it has been built. A blueprint captures state and intent, not work: no sprint, estimate, or assignee, and no progress notes in the body.
4
+
5
+ ### The one rule: facilitate, do not author
6
+
7
+ Eidos is human-first. The owner holds the intent, the scope, and the decisions; you format, structure, ask, and press on scope. Do not generate a finished blueprint from a one-line prompt, invent a purpose or a behavior, resolve an open question on the owner's behalf, or set direction. A blueprint no one thought through is worse than none. When unsure, ask rather than write.
8
+
9
+ ### Start every request here
10
+
11
+ 1. `eidos framework` reads the root's own framework: its collections, their flavors and groups, and the property Schema. Never assume a collection, flavor, or section name; read what this framework declares. The document behind it is `_eidos/Framework.yaml`; if a root still keeps `Framework.md` (the form for people), every command says so and `eidos convert` moves it first.
12
+ 2. `eidos whoami` says who is in the seat. Open the role file it names under `_eidos/roles/` and respond as that contract says (vocabulary, depth, what to surface, who decides). A blank actor means full, framework-owner-style facilitation.
13
+ 3. `eidos list` and `eidos show <id>` read what already exists. Read before writing.
14
+ 4. `eidos instructions <guide>` before authoring, validating, or changing the framework. The overview says when to act; the guides say how.
15
+
16
+ Add `--json` to `framework`, `list`, `show`, and `check` when a script needs stable fields.
17
+
18
+ ### The CLI owns structure; the conversation owns the words
19
+
20
+ - `eidos new <collection> "<Title>"` scaffolds a blueprint that is born conforming: frontmatter from the Schema, body from the flavor's shape, filename in the naming convention, a permanent kebab-case `id` inside. Never hand-assemble frontmatter.
21
+ - `eidos check` validates the root against its own framework. Its findings are a review the owner acts on; surface them, do not block on them.
22
+ - `eidos index` regenerates the indexes, the `index` key inside `Framework.yaml`. Never edit it by hand.
23
+ - The prose inside a blueprint is written in the file, with the owner, by you. The CLI never writes a sentence of it.
24
+ - `eidos browser` opens the root in a local web page for a person. Everything the page can do runs the same code as a command (`new`, `check`, `index`), so it adds nothing you cannot do from the shell. Use the commands; leave the page to people.
25
+
26
+ ### Version
27
+
28
+ The framework records the standard it targets as `eidos_version` in `_eidos/Framework.yaml`; `eidos standard --version` prints the one this CLI carries. `eidos check` notes a gap once. A gap never blocks the work: the framework in front of you is the operative contract either way.
29
+
30
+ ### Guides
31
+
32
+ - `eidos instructions authoring`: read before creating or editing a blueprint
33
+ - `eidos instructions validating`: read before reviewing a blueprint or reporting on a root
34
+ - `eidos instructions configuring`: read before changing the framework (a collection, a flavor, a property, the Top-Level index)
35
+ - `eidos instructions init-required`: when there is no root here yet
36
+
37
+ `eidos <command> --help` explains any command's options and output.
@@ -0,0 +1,33 @@
1
+ ## Validating blueprints
2
+
3
+ Validation is framework-defined. `eidos check` reads the root's own `_eidos/Framework.yaml` and shapes and enforces those, never a contract of its own.
4
+
5
+ ```bash
6
+ eidos check # the whole root: framework, layout, every blueprint
7
+ eidos check <path> [<path>...] # only these blueprints
8
+ eidos check --json # stable fields for a script
9
+ eidos check --strict # warnings fail too (CI)
10
+ ```
11
+
12
+ Exit code 0 means no errors; 1 means at least one error (or, with `--strict`, any warning); 2 means the command could not run.
13
+
14
+ ### What the levels mean
15
+
16
+ - An **error** is wrong on any reading: frontmatter that does not parse, a missing `id` or `title`, an `id` that is not kebab-case or is used twice, a `flavor` the collection does not declare, a link to a file that does not exist, a shape file the framework points at but does not have.
17
+ - A **warning** is a gap the standard says to note and offer, never refuse: a missing or empty property the Schema applies to this collection, a property the Schema does not declare, a work-tracking field, a body section the flavor's shape declares but the blueprint lacks, a section the shape does not know, sections out of the shape's order, a grouping value that does not match its folder, a declared frame nobody has written, a stale `index.md`, a version gap.
18
+
19
+ ### Reporting a review
20
+
21
+ The output is a review the owner acts on. When you report:
22
+
23
+ - Lead with the errors, then the warnings, grouped by file, as `check` prints them.
24
+ - Flag an absent non-goals section first among the section gaps: it is the one the standard leans on hardest.
25
+ - Offer to add a missing core property with a note on why it exists; never refuse the file.
26
+ - Confirm no work-tracking fields crept in, and that any section describing approach reads as intent, not progress.
27
+ - A version gap is worth one line and an offer to migrate, once per session; then carry on with the framework as it stands.
28
+
29
+ Do not fix silently. Show the finding, propose the change, and let the owner decide, unless the change is purely mechanical and they have asked for it (regenerating an index, adding a blank property stub).
30
+
31
+ ### Things `check` cannot judge
32
+
33
+ Whether the prose is true, whether the scope is right, and whether an open question should be settled are the owner's. `check` tells you the file is well-formed against its framework; it says nothing about whether the thing described is the thing they mean. Read the blueprint with the frames in mind and raise what does not fit.
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "eidosmd",
3
+ "version": "0.1.0",
4
+ "description": "The Eidos CLI: scaffold, validate, index, and browse a root of Eidos blueprints, and hand any agent the workflow it needs to work in one.",
5
+ "keywords": [
6
+ "eidos",
7
+ "blueprints",
8
+ "specs",
9
+ "markdown",
10
+ "cli",
11
+ "product-management",
12
+ "documentation"
13
+ ],
14
+ "homepage": "https://eidosmd.com/docs/cli",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://gitlab.com/the-virtual-panda/eidosmd.git",
18
+ "directory": "cli"
19
+ },
20
+ "license": "PolyForm-Noncommercial-1.0.0",
21
+ "author": "The Virtual Panda",
22
+ "type": "module",
23
+ "bin": {
24
+ "eidos": "./dist/src/cli.js"
25
+ },
26
+ "files": [
27
+ "dist/src",
28
+ "browser",
29
+ "instructions",
30
+ "standard",
31
+ "NOTICE"
32
+ ],
33
+ "engines": {
34
+ "node": ">=20"
35
+ },
36
+ "dependencies": {
37
+ "commander": "^14.0.0",
38
+ "marked": "^18.0.13",
39
+ "yaml": "^2.8.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.0.0",
43
+ "typescript": "^5.9.0"
44
+ },
45
+ "bugs": "https://gitlab.com/the-virtual-panda/eidosmd/-/issues",
46
+ "scripts": {
47
+ "build": "tsc -p tsconfig.json",
48
+ "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
49
+ "test": "pnpm build && node --test \"dist/test/**/*.test.js\"",
50
+ "check": "tsc -p tsconfig.json --noEmit",
51
+ "sync-standard": "node scripts/sync-standard.mjs"
52
+ }
53
+ }