create-cadmo 0.0.1 → 0.2.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/README.md CHANGED
@@ -1,11 +1,19 @@
1
- # create-cadmo
2
-
3
- Scaffold the **Cadmo** method into your project — a right-sized method for building software with AI as your pair.
4
-
5
- ```bash
6
- npm create cadmo
7
- ```
8
-
9
- The method, docs and templates: **https://github.com/tiagotorres91/cadmo** · **https://cadmo.dev**
10
-
11
- > This is an early placeholder reserving the name. The scaffolder (`cadmo init` drops `AGENTS.md`, the value gate, spec/plan templates into your project) is on the roadmap.
1
+ # create-cadmo
2
+
3
+ Scaffold the **Cadmo** method into your project — a right-sized method for building software with AI as your pair.
4
+
5
+ ```bash
6
+ npm create cadmo
7
+ ```
8
+
9
+ Drops into the current directory, never overwriting anything:
10
+
11
+ - `AGENTS.md` the local map your AI pair reads first (it will offer to fill it in for you)
12
+ - `cadmo/value-gate.md` — 5 lines before any spec: is it worth building?
13
+ - `cadmo/spec.md` — the rules, in the client's language, criteria first
14
+ - `cadmo/plan.md` — the internal route: tasks, constraints, how to validate
15
+ - `cadmo/decision.md` — architecture decisions with a "when to reconsider" trigger
16
+ - `cadmo/spec-drift.mjs` + a ready CI workflow — **specs must change with the code they watch** (the drift guard)
17
+ - `.claude/commands/cadmo-*.md` — `/cadmo-gate`, `/cadmo-spec`, `/cadmo-done` slash commands (when Claude Code is detected, or `--claude`)
18
+
19
+ The method, docs and protocols: **https://github.com/tiagotorres91/cadmo**
package/index.js ADDED
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * create-cadmo — scaffold the Cadmo method into the current project.
4
+ * No dependencies. Never overwrites an existing file.
5
+ * https://github.com/tiagotorres91/cadmo
6
+ */
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const args = process.argv.slice(2);
11
+ const DRY = args.includes('--dry-run');
12
+ const FORCE_CLAUDE = args.includes('--claude');
13
+ const NO_CLAUDE = args.includes('--no-claude');
14
+
15
+ if (args.includes('--help') || args.includes('-h')) {
16
+ console.log(`
17
+ create-cadmo — drop the Cadmo method into the current project.
18
+
19
+ Usage: npm create cadmo [-- --dry-run] [-- --claude | --no-claude]
20
+
21
+ --dry-run show what would be created, create nothing
22
+ --claude also install Claude Code slash commands (/cadmo-gate, /cadmo-spec, /cadmo-done)
23
+ --no-claude skip the Claude Code commands even if CLAUDE.md/.claude is detected
24
+
25
+ Creates (never overwrites):
26
+ AGENTS.md the local map your AI pair reads first
27
+ cadmo/value-gate.md 5 lines before any spec: is it worth building?
28
+ cadmo/spec.md the rules, client language, criteria first
29
+ cadmo/plan.md the internal route: tasks, constraints, validation
30
+ cadmo/decision.md ADR with a "when to reconsider" trigger
31
+ cadmo/spec-drift.mjs the drift guard: specs must change with the code they watch
32
+ cadmo/spec-drift-workflow.yml ready CI workflow (move into .github/workflows/)
33
+ .claude/commands/cadmo-*.md (when Claude Code is detected, or --claude)
34
+
35
+ The method in one page: https://github.com/tiagotorres91/cadmo
36
+ `);
37
+ process.exit(0);
38
+ }
39
+
40
+ const here = (...p) => path.join(__dirname, 'templates', ...p);
41
+ const cwd = process.cwd();
42
+
43
+ const FILES = [
44
+ ['AGENTS.md', 'AGENTS.md'],
45
+ ['value-gate.md', path.join('cadmo', 'value-gate.md')],
46
+ ['spec.md', path.join('cadmo', 'spec.md')],
47
+ ['plan.md', path.join('cadmo', 'plan.md')],
48
+ ['decision.md', path.join('cadmo', 'decision.md')],
49
+ ['spec-drift.mjs', path.join('cadmo', 'spec-drift.mjs')],
50
+ ['spec-drift-workflow.yml', path.join('cadmo', 'spec-drift-workflow.yml')],
51
+ ];
52
+
53
+ const hasClaude = FORCE_CLAUDE || (!NO_CLAUDE &&
54
+ (fs.existsSync(path.join(cwd, 'CLAUDE.md')) || fs.existsSync(path.join(cwd, '.claude'))));
55
+
56
+ const CLAUDE_FILES = [
57
+ [path.join('claude-commands', 'cadmo-gate.md'), path.join('.claude', 'commands', 'cadmo-gate.md')],
58
+ [path.join('claude-commands', 'cadmo-spec.md'), path.join('.claude', 'commands', 'cadmo-spec.md')],
59
+ [path.join('claude-commands', 'cadmo-done.md'), path.join('.claude', 'commands', 'cadmo-done.md')],
60
+ ];
61
+
62
+ const plan = hasClaude ? FILES.concat(CLAUDE_FILES) : FILES;
63
+
64
+ console.log(`\n Cadmo — write it down before you build it.${DRY ? ' (dry run)' : ''}\n`);
65
+
66
+ let placed = 0, skipped = 0;
67
+ for (const [src, dest] of plan) {
68
+ const target = path.join(cwd, dest);
69
+ if (fs.existsSync(target)) {
70
+ console.log(` = kept ${dest} (already exists — not touched)`);
71
+ skipped++;
72
+ continue;
73
+ }
74
+ if (DRY) {
75
+ console.log(` ~ would create ${dest}`);
76
+ } else {
77
+ fs.mkdirSync(path.dirname(target), { recursive: true });
78
+ fs.copyFileSync(here(src), target);
79
+ console.log(` + created ${dest}`);
80
+ }
81
+ placed++;
82
+ }
83
+
84
+ console.log(`\n ${placed} file(s) ${DRY ? 'would be created' : 'created'}, ${skipped} kept.\n`);
85
+ if (!hasClaude && !NO_CLAUDE) {
86
+ console.log(' (No CLAUDE.md/.claude detected — run with --claude to also install /cadmo-* slash commands.)');
87
+ }
88
+ console.log(' Next steps:');
89
+ console.log(' 1. Fill in AGENTS.md — the local map your AI pair reads first');
90
+ console.log(' (using CLAUDE.md? link or rename it — same idea).');
91
+ console.log(' 2. For your next relevant feature: cadmo/value-gate.md (5 lines, before any spec).');
92
+ console.log(' 3. For any 3+ step task: copy cadmo/plan.md — acceptance criteria before code.');
93
+ console.log(' 4. Turn on the drift guard: move cadmo/spec-drift-workflow.yml to .github/workflows/');
94
+ console.log(' and add a `watches:` front matter to your first spec.');
95
+ console.log('\n The method in one page: https://github.com/tiagotorres91/cadmo\n');
package/package.json CHANGED
@@ -1,26 +1,37 @@
1
- {
2
- "name": "create-cadmo",
3
- "version": "0.0.1",
4
- "description": "Scaffold the Cadmo method into your project a right-sized method for building software with AI as your pair.",
5
- "keywords": [
6
- "cadmo",
7
- "create-cadmo",
8
- "spec-driven-development",
9
- "ai",
10
- "methodology",
11
- "framework",
12
- "agents",
13
- "claude",
14
- "scaffold"
15
- ],
16
- "homepage": "https://cadmo.dev",
17
- "repository": {
18
- "type": "git",
19
- "url": "git+https://github.com/tiagotorres91/cadmo.git"
20
- },
21
- "author": "Tiago Torres (B2B Soluções em TI)",
22
- "license": "MIT",
23
- "files": [
24
- "README.md"
25
- ]
26
- }
1
+ {
2
+ "name": "create-cadmo",
3
+ "version": "0.2.0",
4
+ "description": "Scaffold the Cadmo method into your project \u2014 a right-sized method for building software with AI as your pair.",
5
+ "keywords": [
6
+ "cadmo",
7
+ "create-cadmo",
8
+ "spec-driven-development",
9
+ "ai",
10
+ "methodology",
11
+ "framework",
12
+ "agents",
13
+ "claude",
14
+ "scaffold"
15
+ ],
16
+ "homepage": "https://github.com/tiagotorres91/cadmo",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/tiagotorres91/cadmo.git"
20
+ },
21
+ "author": "Tiago Torres",
22
+ "license": "MIT",
23
+ "files": [
24
+ "index.js",
25
+ "templates/",
26
+ "README.md"
27
+ ],
28
+ "bin": {
29
+ "create-cadmo": "index.js"
30
+ },
31
+ "engines": {
32
+ "node": ">=16"
33
+ },
34
+ "scripts": {
35
+ "test": "node --test"
36
+ }
37
+ }
@@ -0,0 +1,31 @@
1
+ # AGENTS.md — <project name>
2
+
3
+ > Drop this at the root of your project so any AI pair works the Cadmo way from the first message.
4
+ > This is the *local map*: what this project is, where things live, and how to verify. The method
5
+ > itself is in AGENTS.md at the Cadmo repo; this file is the project-specific instance.
6
+ >
7
+ > **AI pair reading this while it still has `<placeholders>`:** your first job is to fill it —
8
+ > scan the repository (structure, package files, scripts, CI) and propose the map to your human:
9
+ > what the project is, where specs/plans should live, and the actual verify commands. Then remove
10
+ > this paragraph.
11
+
12
+ ## What this project is
13
+ <one paragraph: the product, the client/owner, the stack>
14
+
15
+ ## Where things live
16
+ - Specs / decisions: <path>
17
+ - Plans: <path>
18
+ - Demands / task board: <where>
19
+
20
+ ## How to verify (the harness — run before saying "done")
21
+ - Build/type-check: `<command>`
22
+ - Tests: `<command>`
23
+ - End-to-end / smoke: `<command>`
24
+ - Staging URL: <url> · Production: <url>
25
+
26
+ ## Gates
27
+ - Plan approved before building; production ships only with explicit human approval.
28
+ - <any project-specific rule or gotcha>
29
+
30
+ ## The method
31
+ Opening choreography, definition of done, the layers — see the Cadmo method (link).
@@ -0,0 +1,17 @@
1
+ # /cadmo-done — the definition of done, checked honestly
2
+
3
+ Run the definition of done for: **$ARGUMENTS** (or the work we just finished).
4
+
5
+ Check each item **against evidence, not memory** — run the commands, don't assume:
6
+
7
+ - [ ] Build/tests pass — run them now and show me the output
8
+ - [ ] **Tested functionally** — the real flow (browser, curl, CLI run), not just linters
9
+ - [ ] Validated in staging before production (when there is one)
10
+ - [ ] Acceptance criteria from the spec/plan — checked one by one, quoted
11
+ - [ ] Spec updated if a rule changed (same commit) — run `node cadmo/spec-drift.mjs --base origin/main` if present
12
+ - [ ] Anything untested? Say it explicitly: "I didn't test X"
13
+ - [ ] Touched auth/input/data/secrets? → flag that an adversarial security pass is due before shipping
14
+
15
+ Then the **process check** (the choreography, not the code): was there a plan before execution? criteria before code? If any answer is no, say so plainly — this checklist exists to be failed honestly, not passed cosmetically.
16
+
17
+ Finish with a verdict: **ready to ship** / **ready except <items>** / **not ready because <items>**.
@@ -0,0 +1,13 @@
1
+ # /cadmo-gate — open a value gate
2
+
3
+ Open a value gate for: **$ARGUMENTS**
4
+
5
+ Work with me (the human) to fill the five lines — copy `cadmo/value-gate.md` next to the demand, then:
6
+
7
+ 1. **Problem (measurable):** ask me what hurts today; push for a number (time lost, error rate, money).
8
+ 2. **Why this solution:** make me compare against at least one cheaper alternative (a rule? a process change? doing nothing?).
9
+ 3. **Success metric (business):** a number that will prove value after delivery — reject "it works" as a metric.
10
+ 4. **Data readiness:** check the actual sources (tables, exports, APIs) — 🟢/🟡/🔴 with the caveat named.
11
+ 5. **Verdict:** recommend GO / NO-GO / defer, with one sentence of reasoning — but the verdict is mine to make.
12
+
13
+ Keep it to ~5 lines of content. If the work is trivial (a fix, a tweak), tell me it doesn't need a gate and stop.
@@ -0,0 +1,13 @@
1
+ # /cadmo-spec — write the spec, criteria first
2
+
3
+ Write the spec for: **$ARGUMENTS**
4
+
5
+ Use `cadmo/spec.md` as the skeleton. Rules:
6
+
7
+ 1. **Goal in the client's language** — 2-5 lines a non-developer validates. No jargon.
8
+ 2. **Acceptance criteria before anything else** — each one observable and specific. For critical ones (money, data, integrations, security) use EARS: *"WHEN <trigger>, THE SYSTEM SHALL <behavior>"* — they become tests almost word for word.
9
+ 3. **Out of scope** — name what this does NOT cover.
10
+ 4. **Impact on stable specs** — which existing documented rules will absorb this on delivery. If this spec should be *watched* against code, add the `watches:` front matter (see `cadmo/spec-drift.mjs`).
11
+ 5. Then pair it with a plan (`cadmo/plan.md`) — technical route, tasks, how to validate. Don't repeat the criteria there.
12
+
13
+ Stop after the spec and ask me to validate it **before** writing any code. If it changes money, data or an external integration, remind me the client (or their proxy) validates it first.
@@ -0,0 +1,20 @@
1
+ # ADR — <short title of the decision>
2
+
3
+ **Status:** accepted · **Date:** <YYYY-MM-DD> · **Deciders:** <who>
4
+
5
+ ## Context
6
+ The forces at play: the problem, the constraints, what makes this decision necessary now (3–6 lines).
7
+
8
+ ## Decision
9
+ What was decided, stated as a full sentence ("We will…").
10
+
11
+ ## Alternatives considered
12
+ - **<Alternative A>** — why not: …
13
+ - **<Alternative B>** — why not: …
14
+ (Real alternatives you weighed — this section is what saves the re-investigation in six months.)
15
+
16
+ ## Consequences
17
+ What becomes easier, what becomes harder, what debt is knowingly taken on.
18
+
19
+ ## When to reconsider
20
+ The trigger that should reopen this decision (a scale threshold, a price change, a vendor event) — a decision without a reconsider-trigger quietly becomes dogma.
@@ -0,0 +1,21 @@
1
+ # <Demand name> — plan (internal)
2
+
3
+ Pairs with `spec.md` (acceptance criteria live there — don't repeat them).
4
+
5
+ ## Objective
6
+ What changes in the world when this is done (1–3 lines).
7
+
8
+ ## Investigation (optional)
9
+ What was tried/considered before and why it was discarded (3–6 lines) — avoids re-investigating dead ends.
10
+
11
+ ## Context & constraints
12
+ Current state, decisions already made, what NOT to change.
13
+
14
+ ## Technical plan
15
+ Files/tables/endpoints touched; approach; alternatives discarded.
16
+
17
+ ## Tasks
18
+ - [ ] Small, verifiable (status kept here — any session resumes without getting lost)
19
+
20
+ ## How to validate
21
+ Commands/flows that prove the acceptance criteria (build, tests, e2e, real manual flow).
@@ -0,0 +1,19 @@
1
+ # Example workflow — copy to .github/workflows/spec-drift.yml in your project.
2
+ # Fails a PR when a file watched by a spec changes and the spec doesn't change with it.
3
+ # Escape hatch (audited, never silent): write "spec-drift: skip — <reason>" in the PR body.
4
+ name: spec-drift
5
+ on:
6
+ pull_request:
7
+ jobs:
8
+ drift:
9
+ if: "${{ !contains(github.event.pull_request.body, 'spec-drift: skip') }}"
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ with:
14
+ fetch-depth: 0
15
+ - uses: actions/setup-node@v4
16
+ with:
17
+ node-version: "20"
18
+ - name: specs must change with the code they govern
19
+ run: node cadmo/spec-drift.mjs --base origin/${{ github.base_ref }}
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * spec-drift — the rule that keeps documentation honest:
4
+ * a spec declares which files implement it; if those files change and the spec
5
+ * doesn't change in the same diff, the check fails.
6
+ *
7
+ * No dependencies. How it works:
8
+ * 1. Scans the repo for .md files with a `watches:` list in their front matter.
9
+ * 2. Diffs the current branch against --base (default: origin/main).
10
+ * 3. For each spec: if a watched file changed and the spec didn't → DRIFT.
11
+ *
12
+ * Usage:
13
+ * node spec-drift.mjs [--base origin/main] [--dir .]
14
+ *
15
+ * Spec front matter example:
16
+ * ---
17
+ * watches:
18
+ * - src/billing/**
19
+ * - api/invoices.py
20
+ * ---
21
+ *
22
+ * Escape hatch (audited, not silent): if a change genuinely doesn't alter any
23
+ * documented rule, say so where reviewers can see it — e.g. run the CI step
24
+ * only when the PR body does NOT contain "spec-drift: skip — <reason>".
25
+ */
26
+ import { execFileSync } from 'node:child_process';
27
+ import fs from 'node:fs';
28
+ import path from 'node:path';
29
+
30
+ const args = process.argv.slice(2);
31
+ function opt(name, fallback) {
32
+ const i = args.indexOf(name);
33
+ return i >= 0 && args[i + 1] ? args[i + 1] : fallback;
34
+ }
35
+ const BASE = opt('--base', 'origin/main');
36
+ const ROOT = path.resolve(opt('--dir', '.'));
37
+
38
+ // --- collect specs that declare `watches:` in front matter ---
39
+ function* mdFiles(dir) {
40
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
41
+ if (e.name.startsWith('.') || e.name === 'node_modules') continue;
42
+ const p = path.join(dir, e.name);
43
+ if (e.isDirectory()) yield* mdFiles(p);
44
+ else if (e.name.endsWith('.md')) yield p;
45
+ }
46
+ }
47
+
48
+ function parseWatches(file) {
49
+ const text = fs.readFileSync(file, 'utf8');
50
+ if (!text.startsWith('---')) return null;
51
+ const end = text.indexOf('\n---', 3);
52
+ if (end < 0) return null;
53
+ const fm = text.slice(3, end);
54
+ const lines = fm.split('\n');
55
+ const watches = [];
56
+ let inWatches = false;
57
+ for (const line of lines) {
58
+ if (/^watches:\s*$/.test(line)) { inWatches = true; continue; }
59
+ if (inWatches) {
60
+ const m = line.match(/^\s+-\s+(.+?)\s*$/);
61
+ if (m) watches.push(m[1].replace(/^["']|["']$/g, ''));
62
+ else if (!/^\s/.test(line)) inWatches = false;
63
+ }
64
+ }
65
+ return watches.length ? watches : null;
66
+ }
67
+
68
+ // --- minimal glob → regex (supports ** and *) ---
69
+ function globToRegex(glob) {
70
+ // zero-backslash implementation: escape specials via char classes, never via backslash
71
+ const BS = String.fromCharCode(92);
72
+ let esc = '';
73
+ for (const ch of glob) {
74
+ if (ch === '*' || ch === '/') esc += ch;
75
+ else if ('.+^$(){}|[]?'.includes(ch) || ch === BS) esc += BS + ch;
76
+ else esc += ch;
77
+ }
78
+ esc = esc.split('**').join('__DSTAR__');
79
+ esc = esc.split('*').join('[^/]*');
80
+ esc = esc.split('__DSTAR__').join('.*');
81
+ return new RegExp('^' + esc + '$');
82
+ }
83
+
84
+ // --- changed files vs base ---
85
+ let changed;
86
+ try {
87
+ changed = execFileSync('git', ['diff', '--name-only', `${BASE}...HEAD`], { cwd: ROOT, encoding: 'utf8' })
88
+ .split('\n').filter(Boolean);
89
+ } catch (e) {
90
+ console.error(`spec-drift: cannot diff against ${BASE} — ${e.message}`);
91
+ process.exit(2);
92
+ }
93
+
94
+ const specs = [];
95
+ for (const f of mdFiles(ROOT)) {
96
+ const watches = parseWatches(f);
97
+ if (watches) specs.push({ spec: path.relative(ROOT, f).split(String.fromCharCode(92)).join('/'), watches });
98
+ }
99
+
100
+ if (!specs.length) {
101
+ console.log('spec-drift: no specs with a `watches:` front matter found — nothing to check.');
102
+ process.exit(0);
103
+ }
104
+
105
+ const changedSet = new Set(changed);
106
+ let drift = 0;
107
+ for (const { spec, watches } of specs) {
108
+ const regexes = watches.map(globToRegex);
109
+ const hits = changed.filter(c => regexes.some(r => r.test(c)));
110
+ if (hits.length && !changedSet.has(spec)) {
111
+ drift++;
112
+ console.error(`DRIFT: ${hits.join(', ')} changed, but ${spec} (which watches ${watches.join(', ')}) did not change in this diff.`);
113
+ }
114
+ }
115
+
116
+ if (drift) {
117
+ console.error(`\nspec-drift: ${drift} spec(s) out of sync. Update the spec in the same change — or state why no documented rule changed (visibly, where reviewers can see it).`);
118
+ process.exit(1);
119
+ }
120
+ console.log(`spec-drift: ${specs.length} spec(s) checked against ${changed.length} changed file(s) — in sync ✓`);
@@ -0,0 +1,24 @@
1
+ # Spec — <name>
2
+
3
+ **Status:** draft — awaiting validation (<who>) · **Demand:** <link/id>
4
+
5
+ ## Goal & context
6
+ The business problem and what changes in the world (2–5 lines, in the client's language).
7
+ (Relevant work already passed the value gate — its success metric becomes an acceptance criterion here.)
8
+
9
+ ## Acceptance criteria
10
+ - [ ] Simple ones in free form
11
+ - [ ] Critical ones (money / data / integration / security) in EARS:
12
+ WHEN <trigger>, THE SYSTEM SHALL <behavior>
13
+
14
+ ## Data (AI features only)
15
+ Source, owner, access, quality/bias, corpus refresh plan.
16
+
17
+ ## Risks (critical or AI demands only)
18
+ Risk → response. For AI: corpus drift, provider API change, cost, regulation.
19
+
20
+ ## Out of scope
21
+ What this delivery does NOT cover (controlled expectations).
22
+
23
+ ## Impact on stable specs
24
+ Which sections of the system/domain specs will be updated on delivery (the absorption).
@@ -0,0 +1,12 @@
1
+ # Value gate — <demand name>
2
+
3
+ Fill this in *before* writing a spec, for anything relevant (a new feature, module, project).
4
+ Trivial work and routine fixes skip this.
5
+
6
+ **Problem (measurable):** what hurts today, in numbers when possible.
7
+ **Why this solution:** AI vs a rule vs a process vs doing nothing — why this path.
8
+ **Success metric (business):** the number that will prove value — not "it works", but "reduced X", "freed Y hours", "raised Z".
9
+ **Data readiness:** 🟢 data exists, accessible, reliable · 🟡 exists with caveats (which?) · 🔴 doesn't exist → resolve *before* specifying.
10
+ **Verdict:** GO / NO-GO / defer (why).
11
+
12
+ <!-- At close, come back and record: did the metric materialize? -->