syntropic 0.8.1 → 0.9.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,127 +1,112 @@
1
1
  # syntropic
2
2
 
3
- A development methodology for AI-assisted coding. Works with **Claude Code**, **Cursor**, **Windsurf**, **GitHub Copilot**, and **OpenAI Codex**.
3
+ **Ship better software. Prove it on your own code first.**
4
4
 
5
- One command gives your AI coding tools a disciplined development pipeline so they research before they plan, plan before they build, and review before they ship.
5
+ A development methodology for AI-assisted coding. Works with **Claude Code**, **Cursor**, **Windsurf**, **GitHub Copilot**, and **OpenAI Codex**.
6
6
 
7
- ## Quick Start
7
+ ## Try Before You Install
8
8
 
9
9
  ```bash
10
- npx syntropic init my-project
10
+ npx syntropic audit
11
11
  ```
12
12
 
13
- Or add to an existing project:
13
+ Analyses your last 20 git commits for process issues — localhost references, env files in git, commit discipline, fix ratios, governance docs. No install needed. Nothing sent anywhere. See what the methodology catches on **your** code.
14
+
15
+ ## Install
14
16
 
15
17
  ```bash
16
- cd my-project
17
18
  npx syntropic init
18
19
  ```
19
20
 
20
- You'll be asked which AI tools you use. The CLI generates a minimal instruction file for each:
21
-
22
- | Tool | File Generated |
23
- |------|---------------|
24
- | Claude Code | `CLAUDE.md` |
25
- | Cursor | `.cursorrules` |
26
- | Windsurf | `.windsurfrules` |
27
- | GitHub Copilot | `.github/copilot-instructions.md` |
28
- | OpenAI Codex | `AGENTS.md` |
29
-
30
- ## How It Works
31
-
32
- **Server-served, client-computed.** Your instruction file contains a single bootstrap rule (EG13) that tells your AI tool to fetch the full methodology from the Syntropic server at the start of every development cycle. All rules, agents, and learning data are served fresh — always up to date, zero local files to maintain.
33
-
34
- Your LLM does all the compute. Syntropic serves the methodology but runs zero inference. Your data stays on your machine.
21
+ You get: a disciplined development pipeline, governance doc templates, and a connection to the PRISM methodology network — so your rules stay current as the methodology evolves.
35
22
 
36
23
  ## What You Get
37
24
 
38
- **Evergreen Rules (EG1-EG13)** — fetched at runtime from the PRISM network:
25
+ **Evergreen Rules** — battle-tested development rules fetched fresh at every cycle:
39
26
 
40
- - **EG1: Pre-Flight Loop** build must pass, no localhost refs, verify after deploy
41
- - **EG2: Ship and Iterate** — bias to action, only pause for destructive/expensive/irreversible
42
- - **EG3: Hypothesis-Driven Debugging** state hypothesis, test without code changes, only code if confirmed
43
- - **EG7: Implementation Pipeline** scale process to task size (Full / Lightweight / Minimum cycle)
44
- - **EG8: Live Site Testing** test page first, promote to production with approval
45
- - **EG9: Session Continuity** re-read rules on reset, verify state before proceeding
46
- - **EG13: PRISM Sync** fetch methodology at cycle start, report at cycle end
27
+ | Rule | What it prevents | Real-world save |
28
+ |------|-----------------|-----------------|
29
+ | **EG1: Pre-flight** | Localhost refs, broken builds reaching production | Caught 3 localhost references pre-deploy |
30
+ | **EG7: Pipeline** | AI jumping to code without research or planning | Structured 123 features across Full/Lightweight/Minimum cycles |
31
+ | **EG8: Test first** | Untested changes reaching production users | Every fix caught on test page 12 verified promotions |
32
+ | **EG10: Env hygiene** | Env var corruption (trailing newlines, wrong formats) | Prevented silent API failures across 6 providers |
33
+ | **EG11: Prod sync** | Access control divergence between test and production | Caught lockout bug before 8+ users were affected |
34
+ | **EG14: Doc discipline** | Lost decisions, repeated mistakes, no project memory | Backlog, issues, and ADRs updated every cycle |
47
35
 
48
- **Generic Agents** (Claude Code, Codex) dev, qa, research, plan, devops, security served from the PRISM network, never cached to disk
36
+ **Governance Docs** — project management templates your AI assistant reads before every cycle:
49
37
 
50
- **Health Check** — daily GitHub Action with auto-remediation (npm audit fix PRs)
38
+ ```
39
+ .claude/docs/NORTH_STAR.md Your vision, goals, and design principles
40
+ .claude/docs/BACKLOG.md Prioritised work with status tracking
41
+ .claude/docs/ISSUES.md Bug log and iteration tracker
42
+ .claude/docs/adr/ Architectural Decision Records
43
+ ```
51
44
 
52
- **PRISM Network** — anonymous networked learning. Your AI tool fetches the latest methodology intelligence at cycle start, and optionally reports anonymous structural metadata at cycle end. Every user's cycles improve the methodology for everyone. Zero inference cost — your LLM does all compute.
45
+ **Pipeline Agents** — research, dev, plan, qa, devops, security fetched from the PRISM network so they're always up to date.
53
46
 
54
- ## Commands
47
+ **Health Check** — daily GitHub Action with auto-remediation (npm audit fix PRs).
55
48
 
56
- ```bash
57
- # Scaffold a new project
58
- npx syntropic init my-project
49
+ ## Track Record
59
50
 
60
- # Select specific tools
61
- npx syntropic init my-project --tools claude,cursor
51
+ Built in production on a real product (27 AI agents, 8-lens analyser, CLI, 7 free tools) over 10 weeks:
62
52
 
63
- # Customise project URLs (optional sensible defaults applied)
64
- npx syntropic init my-project --name "My App" --domain myapp.com --test-url /staging --prod-url /
53
+ - **123 features shipped**, each through a structured pipeline
54
+ - **12 test→production promotions** every feature verified on test page first
55
+ - **3 bug classes prevented** by specific EG rules before reaching users
56
+ - **0 undetected production incidents** after methodology adoption
65
57
 
66
- # Add a tool to an existing project
67
- npx syntropic add cursor
68
- npx syntropic add windsurf copilot
58
+ ## Trust & Privacy
69
59
 
70
- # Run a local health check (EG1 pre-flight)
71
- npx syntropic health
60
+ **Everything is local.** Your `.claude/` directory — rules, agents, governance docs — lives in your repo. It's yours.
72
61
 
73
- # Manage anonymous telemetry (opt-out, default on)
74
- npx syntropic telemetry status
75
- npx syntropic telemetry disable
76
- npx syntropic telemetry enable
62
+ **Telemetry is optional.** PRISM collects anonymous structural metadata (cycle weight, file count, framework — never code, names, or content). Double-hashed before transmission. Default: on. Opt out anytime:
77
63
 
78
- # Submit a PRISM cycle report (CLI handles hashing + signing)
79
- npx syntropic report --weight lightweight --phases research,plan,dev,qa,test --success true --iterations 1
64
+ ```bash
65
+ syntropic telemetry disable
80
66
  ```
81
67
 
82
- ## Existing Projects
83
-
84
- Running `syntropic init` in a project that already has a `CLAUDE.md` or `.cursorrules` will **append** the methodology to your existing file — it never overwrites. A `<!-- syntropic -->` marker prevents duplicate rules on re-runs.
68
+ **What's collected:** cycle weight, phases, success/failure, tool, OS, project shape.
69
+ **Never collected:** file contents, names, code, diffs, commits, identity, API keys.
85
70
 
86
- ## The Methodology
71
+ **Clean exit.** Remove everything syntropic added (preserves your governance docs):
87
72
 
88
- The core idea: AI coding tools are powerful but undisciplined. Without rules, they jump straight to code, skip investigation, retry failed approaches, and introduce regressions.
89
-
90
- Syntropic gives them a process:
73
+ ```bash
74
+ syntropic remove
75
+ ```
91
76
 
92
- 1. **Research** understand the problem before proposing solutions
93
- 2. **Plan** — break work into sequenced steps, identify risks
94
- 3. **Build** — implement with minimal changes, match existing patterns
95
- 4. **Review** — check security, quality, and correctness
96
- 5. **Verify** — test on a live URL, not just locally
77
+ **Inspect the output.** Run `npm pack` on the package everything that ships is plain text templates. The methodology is served from a public API endpoint you can curl yourself.
97
78
 
98
- Scale the process to the task. A typo fix doesn't need research. A new feature does.
79
+ ## Commands
99
80
 
100
- ## Privacy
81
+ ```bash
82
+ syntropic audit # Analyse git history (no install needed)
83
+ syntropic init [project-name] # Install methodology + docs
84
+ syntropic add cursor windsurf # Add tools to existing project
85
+ syntropic remove # Clean uninstall (preserves docs)
86
+ syntropic health # Run pre-flight checks
87
+ syntropic report # Submit anonymous cycle report
88
+ syntropic telemetry status # Check telemetry setting
89
+ syntropic analyse # Deep-dive analysis (8 philosophy lenses)
90
+ ```
101
91
 
102
- Syntropic collects pseudonymised usage patterns to improve the methodology for everyone. **Default: on (opt-out).**
92
+ ## How It Works
103
93
 
104
- **What is collected:** cycle weight, phases run, success/failure, iteration count, tool, OS, Node.js major version, project shape (has TypeScript/CI/tests, framework, file change bucket).
94
+ Your instruction file contains a bootstrap rule (EG13) that fetches the full methodology from the PRISM network at cycle start. Rules, agents, and patterns are served fresh — always current, zero maintenance. Your LLM does all compute. Syntropic serves the methodology but runs zero inference.
105
95
 
106
- **What is NEVER collected:** file contents, file names, project names, code, diffs, commit messages, user identity, email, API keys.
96
+ The governance docs give your AI assistant project memory it checks priorities before coding and logs issues after. Over time, your docs become a structured record of every decision, bug, and iteration.
107
97
 
108
- **Pseudonymisation:** A random device ID is generated locally at install time. Before transmission, it is hashed client-side with a daily-rotating salt (`SHA-256(device_id + date)`), then hashed again server-side with a separate salt (`SHA-256(client_hash + server_salt)`). Neither the client hash nor the original device ID is stored server-side — only the double-hashed value, which cannot be reversed to identify a device or user. Inspired by [TelemetryDeck's MIT-licensed approach](https://telemetrydeck.com/docs/articles/anonymization-how-it-works/). GDPR-compliant by design.
98
+ ## Existing Projects
109
99
 
110
- Opt out anytime: `npx syntropic telemetry disable`
100
+ Running `syntropic init` in a project that already has a `CLAUDE.md` or `.cursorrules` **appends** the methodology — never overwrites. A `<!-- syntropic -->` marker prevents duplicates.
111
101
 
112
- ## Philosophy
102
+ ## Research
113
103
 
114
- - **Ship and iterate** momentum over perfection
115
- - **Hypothesis-driven** — test before you code
116
- - **Outcome-aligned** — if the user succeeds, do we succeed?
117
- - **No workarounds** — no bypasses, no "fix later", no shortcuts without approval
104
+ The methodology is grounded in published research: [zenodo.org/records/17894441](https://zenodo.org/records/17894441)
118
105
 
119
106
  ## Links
120
107
 
121
108
  - [Website](https://www.syntropicworks.com)
122
- - [GitHub](https://github.com/petercholford-ship-it/syntropic-cli)
123
- - [Research Paper](https://zenodo.org/records/17894441) — the underlying research behind the methodology
124
- - [Intelligent Analyser](https://www.syntropicworks.com/analyser) — deep-dive analysis through 8 philosophy lenses
109
+ - [Intelligent Analyser](https://www.syntropicworks.com/analyser) — deep-dive product analysis through 8 philosophy lenses
125
110
 
126
111
  ## License
127
112
 
package/bin/syntropic.js CHANGED
@@ -14,8 +14,10 @@ const args = process.argv.slice(2);
14
14
  const command = args[0];
15
15
 
16
16
  const COMMANDS = {
17
+ audit: () => require('../commands/audit'),
17
18
  init: () => require('../commands/init'),
18
19
  add: () => require('../commands/add'),
20
+ remove: () => require('../commands/remove'),
19
21
  health: () => require('../commands/health'),
20
22
  telemetry: () => require('../commands/telemetry'),
21
23
  report: () => require('../commands/report'),
@@ -39,8 +41,10 @@ if (!command || args.includes('--help') || args.includes('-h')) {
39
41
  syntropic — Philosophy-as-code development pipeline
40
42
 
41
43
  Usage:
44
+ syntropic audit Analyse your git history for process issues (no install needed)
42
45
  syntropic init [project-name] Scaffold a new project with the Syntropic pipeline
43
46
  syntropic add <tool> [tool...] Add support for another AI tool
47
+ syntropic remove Remove syntropic from this project (preserves your docs)
44
48
  syntropic analyse Analyse your product using 8 philosophy lenses
45
49
  syntropic login Sign in to Syntropic (required for analyse)
46
50
  syntropic logout Sign out
@@ -0,0 +1,293 @@
1
+ /**
2
+ * syntropic audit [--commits <n>]
3
+ *
4
+ * Analyse your git history for development process issues.
5
+ * Proves value on your own code before installing anything.
6
+ * Pure local analysis — sends nothing, requires nothing.
7
+ */
8
+
9
+ const { execSync } = require('child_process');
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ const DEFAULTS = { commits: 20 };
14
+
15
+ function parseFlags(args) {
16
+ const flags = {};
17
+ for (let i = 0; i < args.length; i++) {
18
+ if (args[i] === '--help' || args[i] === '-h') { flags.help = true; continue; }
19
+ if (args[i].startsWith('--')) {
20
+ const key = args[i].replace('--', '');
21
+ flags[key] = args[i + 1] && !args[i + 1].startsWith('--') ? args[++i] : true;
22
+ }
23
+ }
24
+ return flags;
25
+ }
26
+
27
+ function git(cmd) {
28
+ try {
29
+ return execSync(`git ${cmd}`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
30
+ } catch {
31
+ return '';
32
+ }
33
+ }
34
+
35
+ function colour(text, code) {
36
+ if (!process.stdout.isTTY) return text;
37
+ return `\x1b[${code}m${text}\x1b[0m`;
38
+ }
39
+
40
+ const green = (t) => colour(t, '32');
41
+ const yellow = (t) => colour(t, '33');
42
+ const red = (t) => colour(t, '31');
43
+ const dim = (t) => colour(t, '2');
44
+ const bold = (t) => colour(t, '1');
45
+
46
+ function checkLocalhost(n) {
47
+ // Find commits that introduced localhost/127.0.0.1 references
48
+ const log = git(`log --oneline -${n} --format=%H`);
49
+ if (!log) return { issues: 0, detail: '' };
50
+
51
+ const hashes = log.split('\n').filter(Boolean);
52
+ let hits = 0;
53
+ const examples = [];
54
+
55
+ for (const hash of hashes) {
56
+ const diff = git(`diff ${hash}~1 ${hash} -- . ":(exclude)*.lock" ":(exclude)node_modules" 2>/dev/null`);
57
+ if (!diff) continue;
58
+
59
+ const addedLines = diff.split('\n').filter(l => l.startsWith('+') && !l.startsWith('+++'));
60
+ for (const line of addedLines) {
61
+ if (/localhost|127\.0\.0\.1/.test(line) && !/\/\/.*localhost/.test(line.replace(/https?:\/\/localhost/, 'MATCH'))) {
62
+ hits++;
63
+ if (examples.length < 2) {
64
+ const shortHash = hash.slice(0, 7);
65
+ const subject = git(`log --format=%s -1 ${hash}`);
66
+ examples.push(`${shortHash} ${subject}`);
67
+ }
68
+ break; // Count once per commit
69
+ }
70
+ }
71
+ }
72
+
73
+ return {
74
+ issues: hits,
75
+ detail: examples.length ? examples.map(e => ` ${dim(e)}`).join('\n') : '',
76
+ };
77
+ }
78
+
79
+ function checkEnvFiles(n) {
80
+ // Check if .env files are tracked in git
81
+ const tracked = git('ls-files').split('\n');
82
+ const envFiles = tracked.filter(f => {
83
+ const base = path.basename(f);
84
+ // .env.example, .env.sample, .env.template are fine
85
+ return /^\.env($|\.)/.test(base) && !/\.(example|sample|template)$/.test(base);
86
+ });
87
+ return {
88
+ issues: envFiles.length,
89
+ detail: envFiles.length ? envFiles.map(f => ` ${dim(f)}`).join('\n') : '',
90
+ };
91
+ }
92
+
93
+ function checkCommitConventions(n) {
94
+ const log = git(`log --oneline -${n} --no-merges --format=%s`);
95
+ if (!log) return { conventional: 0, total: 0, pct: 0 };
96
+
97
+ const subjects = log.split('\n').filter(Boolean);
98
+ const conventional = subjects.filter(s => /^(feat|fix|refactor|chore|docs|style|perf|test|ci|build|revert|sync|content|debug|security|spec)(\(.+\))?:/.test(s));
99
+
100
+ return {
101
+ conventional: conventional.length,
102
+ total: subjects.length,
103
+ pct: subjects.length > 0 ? Math.round(conventional.length / subjects.length * 100) : 0,
104
+ };
105
+ }
106
+
107
+ function checkFixRatio(n) {
108
+ const log = git(`log --oneline -${n} --no-merges --format=%s`);
109
+ if (!log) return { feats: 0, fixes: 0, ratio: 0, total: 0 };
110
+
111
+ const subjects = log.split('\n').filter(Boolean);
112
+ const feats = subjects.filter(s => /^feat(\(.+\))?:/.test(s)).length;
113
+ const fixes = subjects.filter(s => /^fix(\(.+\))?:/.test(s)).length;
114
+ const total = subjects.length;
115
+
116
+ return { feats, fixes, ratio: total > 0 ? Math.round(fixes / total * 100) : 0, total };
117
+ }
118
+
119
+ function checkFilesPerCommit(n) {
120
+ const log = git(`log --oneline -${n} --no-merges --format=%H`);
121
+ if (!log) return { avg: 0, max: 0 };
122
+
123
+ const hashes = log.split('\n').filter(Boolean);
124
+ const counts = hashes.map(h => {
125
+ const files = git(`diff --name-only ${h}~1 ${h} 2>/dev/null`);
126
+ return files ? files.split('\n').filter(Boolean).length : 0;
127
+ }).filter(c => c > 0);
128
+
129
+ if (counts.length === 0) return { avg: 0, max: 0 };
130
+
131
+ return {
132
+ avg: Math.round(counts.reduce((a, b) => a + b, 0) / counts.length * 10) / 10,
133
+ max: Math.max(...counts),
134
+ };
135
+ }
136
+
137
+ function checkGovernanceDocs() {
138
+ const cwd = process.cwd();
139
+ const docs = {
140
+ north_star: fs.existsSync(path.join(cwd, '.claude', 'docs', 'NORTH_STAR.md')) || fs.existsSync(path.join(cwd, '.claude', 'NORTH_STAR.md')),
141
+ backlog: fs.existsSync(path.join(cwd, '.claude', 'docs', 'BACKLOG.md')),
142
+ issues: fs.existsSync(path.join(cwd, '.claude', 'docs', 'ISSUES.md')),
143
+ adr: fs.existsSync(path.join(cwd, '.claude', 'docs', 'adr')),
144
+ };
145
+ const count = Object.values(docs).filter(Boolean).length;
146
+ return { count, total: 4, docs };
147
+ }
148
+
149
+ function computeScore(results) {
150
+ let score = 5; // Start at 5/10
151
+
152
+ // Localhost issues: -1 per issue, max -2
153
+ score -= Math.min(results.localhost.issues, 2);
154
+
155
+ // Env files tracked: -2 if any
156
+ if (results.envFiles.issues > 0) score -= 2;
157
+
158
+ // Conventional commits: +1 if >70%, +0.5 if >40%
159
+ if (results.conventions.pct >= 70) score += 1;
160
+ else if (results.conventions.pct >= 40) score += 0.5;
161
+
162
+ // Fix ratio: neutral if 30-50%, -0.5 if >60%
163
+ if (results.fixRatio.ratio > 60) score -= 0.5;
164
+
165
+ // Governance docs: +0.5 per doc present
166
+ score += results.governance.count * 0.5;
167
+
168
+ // Avg files per commit: -0.5 if >15 (giant commits)
169
+ if (results.filesPerCommit.avg > 15) score -= 0.5;
170
+
171
+ return Math.max(0, Math.min(10, Math.round(score * 2) / 2));
172
+ }
173
+
174
+ function run(args) {
175
+ const flags = parseFlags(args);
176
+
177
+ if (flags.help) {
178
+ console.log(`
179
+ syntropic audit — Analyse your git history for process issues
180
+
181
+ Usage:
182
+ syntropic audit [options]
183
+ npx syntropic audit (no install needed)
184
+
185
+ Options:
186
+ --commits <n> Number of recent commits to analyse (default: 20)
187
+
188
+ What it checks:
189
+ - Localhost/127.0.0.1 references committed to repo
190
+ - .env files tracked in git
191
+ - Commit message conventions
192
+ - Fix:feature ratio (iteration indicator)
193
+ - Average files per commit (scope discipline)
194
+ - Governance docs (North Star, Backlog, Issues, ADRs)
195
+
196
+ This is a local-only analysis. Nothing is sent anywhere.
197
+ `);
198
+ return;
199
+ }
200
+
201
+ // Check we're in a git repo
202
+ const gitRoot = git('rev-parse --show-toplevel');
203
+ if (!gitRoot) {
204
+ console.error('\n Not a git repository. Run this from a project with git history.\n');
205
+ process.exit(1);
206
+ }
207
+
208
+ const n = parseInt(flags.commits, 10) || DEFAULTS.commits;
209
+ const commitCount = git('rev-list --count HEAD');
210
+ const actualN = Math.min(n, parseInt(commitCount, 10) || n);
211
+
212
+ console.log(`\n ${bold('syntropic audit')} — last ${actualN} commits\n`);
213
+
214
+ // Run all checks
215
+ const results = {
216
+ localhost: checkLocalhost(actualN),
217
+ envFiles: checkEnvFiles(actualN),
218
+ conventions: checkCommitConventions(actualN),
219
+ fixRatio: checkFixRatio(actualN),
220
+ filesPerCommit: checkFilesPerCommit(actualN),
221
+ governance: checkGovernanceDocs(),
222
+ };
223
+
224
+ const score = computeScore(results);
225
+
226
+ // Display results
227
+ const PAD = 24;
228
+
229
+ // EG1: Localhost
230
+ if (results.localhost.issues > 0) {
231
+ console.log(` ${yellow('⚠')} ${'EG1 Pre-flight'.padEnd(PAD)} ${yellow(`${results.localhost.issues} commit${results.localhost.issues > 1 ? 's' : ''} contain localhost references`)}`);
232
+ if (results.localhost.detail) console.log(results.localhost.detail);
233
+ } else {
234
+ console.log(` ${green('✓')} ${'EG1 Pre-flight'.padEnd(PAD)} ${green('No localhost references found')}`);
235
+ }
236
+
237
+ // EG10: Env files
238
+ if (results.envFiles.issues > 0) {
239
+ console.log(` ${red('✗')} ${'EG10 Env hygiene'.padEnd(PAD)} ${red(`${results.envFiles.issues} .env file${results.envFiles.issues > 1 ? 's' : ''} tracked in git`)}`);
240
+ if (results.envFiles.detail) console.log(results.envFiles.detail);
241
+ } else {
242
+ console.log(` ${green('✓')} ${'EG10 Env hygiene'.padEnd(PAD)} ${green('No .env files tracked')}`);
243
+ }
244
+
245
+ // Commit conventions
246
+ const convPct = results.conventions.pct;
247
+ const convIcon = convPct >= 70 ? green('✓') : convPct >= 40 ? yellow('⚠') : red('✗');
248
+ const convColour = convPct >= 70 ? green : convPct >= 40 ? yellow : red;
249
+ console.log(` ${convIcon} ${'Commit discipline'.padEnd(PAD)} ${convColour(`${convPct}% conventional commits`)} ${dim(`(${results.conventions.conventional}/${results.conventions.total})`)}`);
250
+
251
+ // Fix ratio
252
+ const fixPct = results.fixRatio.ratio;
253
+ const fixIcon = fixPct <= 50 ? green('✓') : yellow('⚠');
254
+ const fixColour = fixPct <= 50 ? green : yellow;
255
+ console.log(` ${fixIcon} ${'Fix ratio'.padEnd(PAD)} ${fixColour(`${fixPct}% of commits are fixes`)} ${dim(`(${results.fixRatio.fixes} fixes, ${results.fixRatio.feats} features)`)}`);
256
+
257
+ // Files per commit
258
+ const avgFiles = results.filesPerCommit.avg;
259
+ const filesIcon = avgFiles <= 10 ? green('✓') : avgFiles <= 15 ? yellow('⚠') : red('✗');
260
+ const filesColour = avgFiles <= 10 ? green : avgFiles <= 15 ? yellow : red;
261
+ console.log(` ${filesIcon} ${'Scope discipline'.padEnd(PAD)} ${filesColour(`${avgFiles} avg files/commit`)} ${dim(`(max: ${results.filesPerCommit.max})`)}`);
262
+
263
+ // Governance docs
264
+ const govCount = results.governance.count;
265
+ const govIcon = govCount >= 3 ? green('✓') : govCount >= 1 ? yellow('⚠') : dim('○');
266
+ const govColour = govCount >= 3 ? green : govCount >= 1 ? yellow : dim;
267
+ const govNames = [];
268
+ if (results.governance.docs.north_star) govNames.push('North Star');
269
+ if (results.governance.docs.backlog) govNames.push('Backlog');
270
+ if (results.governance.docs.issues) govNames.push('Issues');
271
+ if (results.governance.docs.adr) govNames.push('ADRs');
272
+ console.log(` ${govIcon} ${'Governance docs'.padEnd(PAD)} ${govColour(`${govCount}/4 present`)} ${dim(govNames.length ? `(${govNames.join(', ')})` : '(none)')}`);
273
+
274
+ // Score
275
+ console.log('');
276
+ const scoreColour = score >= 7 ? green : score >= 4 ? yellow : red;
277
+ console.log(` ${bold('Score:')} ${scoreColour(`${score}/10`)}`);
278
+
279
+ // Recommendation
280
+ console.log('');
281
+ if (score >= 8) {
282
+ console.log(` ${green('Strong development discipline.')} Syntropic can keep it that way.`);
283
+ } else if (score >= 5) {
284
+ console.log(` ${yellow('Room for improvement.')} Common issues that a structured pipeline prevents.`);
285
+ } else {
286
+ console.log(` ${red('Significant process gaps.')} A development methodology would catch these early.`);
287
+ }
288
+
289
+ console.log(`\n ${dim('Run `syntropic init` to install the methodology and prevent these automatically.')}`);
290
+ console.log(` ${dim('Learn more: https://www.syntropicworks.com')}\n`);
291
+ }
292
+
293
+ module.exports = run;
package/commands/init.js CHANGED
@@ -186,6 +186,51 @@ function detectTools(targetDir) {
186
186
  return detected;
187
187
  }
188
188
 
189
+ function scaffoldDocs(targetDir, projectName) {
190
+ const docsDir = path.join(targetDir, '.claude', 'docs');
191
+ const adrDir = path.join(docsDir, 'adr');
192
+ const docsTemplateDir = path.join(TEMPLATES_DIR, 'docs');
193
+
194
+ // Skip if docs dir already exists with content
195
+ if (fs.existsSync(docsDir)) {
196
+ const existing = fs.readdirSync(docsDir).filter(f => !f.startsWith('.'));
197
+ if (existing.length > 0) {
198
+ console.log(` skip .claude/docs/ (already exists with ${existing.length} items)`);
199
+ return;
200
+ }
201
+ }
202
+
203
+ if (!fs.existsSync(docsTemplateDir)) return;
204
+
205
+ fs.mkdirSync(adrDir, { recursive: true });
206
+
207
+ const today = new Date().toISOString().slice(0, 10);
208
+ const replacements = {
209
+ '\\{\\{PROJECT_NAME\\}\\}': projectName,
210
+ '\\{\\{CREATED_DATE\\}\\}': today,
211
+ };
212
+
213
+ // Copy doc templates, renaming .template to .md
214
+ const docFiles = [
215
+ { src: 'NORTH_STAR.template', dest: path.join(docsDir, 'NORTH_STAR.md') },
216
+ { src: 'BACKLOG.template', dest: path.join(docsDir, 'BACKLOG.md') },
217
+ { src: 'ISSUES.template', dest: path.join(docsDir, 'ISSUES.md') },
218
+ { src: path.join('adr', '000-TEMPLATE.template'), dest: path.join(adrDir, '000-TEMPLATE.md') },
219
+ ];
220
+
221
+ for (const { src, dest } of docFiles) {
222
+ const srcPath = path.join(docsTemplateDir, src);
223
+ if (!fs.existsSync(srcPath)) continue;
224
+
225
+ let content = fs.readFileSync(srcPath, 'utf8');
226
+ for (const [key, value] of Object.entries(replacements)) {
227
+ content = content.replace(new RegExp(key, 'g'), () => value);
228
+ }
229
+ fs.writeFileSync(dest, content, 'utf8');
230
+ console.log(` create ${path.relative(process.cwd(), dest)}`);
231
+ }
232
+ }
233
+
189
234
  async function run(args) {
190
235
  console.log('\n syntropic init — Philosophy-as-code development pipeline\n');
191
236
 
@@ -261,6 +306,9 @@ async function run(args) {
261
306
  actions[tool] = writeOrAppend(fullTpl, appendTpl, destPath, replacements);
262
307
  }
263
308
 
309
+ // Scaffold governance docs (.claude/docs/)
310
+ scaffoldDocs(targetDir, projectName);
311
+
264
312
  // Make health check executable
265
313
  const healthScript = path.join(targetDir, 'scripts', 'health-check.js');
266
314
  if (fs.existsSync(healthScript)) {
@@ -288,6 +336,7 @@ async function run(args) {
288
336
 
289
337
  What was created:
290
338
  ${toolFiles}
339
+ .claude/docs/ Project governance docs (North Star, Backlog, Issues, ADRs)
291
340
  .github/workflows/ Daily health check with auto-remediation
292
341
  scripts/health-check.js Local health check script${hookLine}
293
342
 
@@ -299,23 +348,26 @@ ${toolFiles}
299
348
  agents, and learning data are always up to date — zero local files to
300
349
  maintain. All compute runs on your machine.
301
350
 
302
- Next steps:
303
- 1. Review your instruction file and add project-specific context
304
- 2. Start building! Your AI will follow the EG7 pipeline automatically
351
+ Your governance docs:
352
+ .claude/docs/NORTH_STAR.md Define your vision, goals, and principles
353
+ .claude/docs/BACKLOG.md Prioritise and track your work
354
+ .claude/docs/ISSUES.md Log bugs and track iterations
355
+ .claude/docs/adr/ Record architectural decisions
305
356
 
306
- Telemetry:
307
- Syntropic collects pseudonymised usage patterns to improve the methodology
308
- for everyone. All identifiers are double-hashed before transmission — no
309
- device ID, code, file names, or personal data is ever stored server-side.
310
- Run \`syntropic telemetry disable\` to opt out at any time.
357
+ These are YOUR docs — they stay even if you remove syntropic.
358
+ Your AI reads them before every cycle and updates them after.
311
359
 
312
- The methodology is your superpower. Ship and iterate.
360
+ Next steps:
361
+ 1. Fill in your North Star — vision, mission, and goals
362
+ 2. Review your instruction file and add project-specific context
363
+ 3. Start building! Your AI follows the EG7 pipeline automatically
313
364
 
314
- Coming soon: \`syntropic analyse\` — assess market opportunity,
315
- validate assumptions, and get a strategic way forward, all from
316
- your CLI. Your LLM, your compute, powered by 8 philosophy lenses.
365
+ Trust & privacy:
366
+ Everything in .claude/ is local and yours. PRISM telemetry is
367
+ pseudonymised (double-hashed) and opt-out: \`syntropic telemetry disable\`.
368
+ Remove everything: \`syntropic remove\` (preserves your docs).
317
369
 
318
- Try the web version now: syntropicworks.com/analyser
370
+ Run \`syntropic audit\` to see what this methodology catches on your existing code.
319
371
 
320
372
  Learn more: https://www.syntropicworks.com
321
373
  `);
@@ -0,0 +1,220 @@
1
+ /**
2
+ * syntropic remove [--force]
3
+ *
4
+ * Cleanly remove syntropic from a project.
5
+ * Preserves user's governance docs (.claude/docs/).
6
+ * Trust builder — users can always back out.
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const readline = require('readline');
12
+
13
+ function ask(question) {
14
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
15
+ return new Promise((resolve) => {
16
+ rl.question(question, (answer) => {
17
+ rl.close();
18
+ resolve(answer.trim().toLowerCase());
19
+ });
20
+ });
21
+ }
22
+
23
+ function detectSyntropicContent(projectDir) {
24
+ const found = [];
25
+
26
+ // Check CLAUDE.md for syntropic markers
27
+ const claudeMd = path.join(projectDir, 'CLAUDE.md');
28
+ if (fs.existsSync(claudeMd)) {
29
+ const content = fs.readFileSync(claudeMd, 'utf8');
30
+ if (content.includes('<!-- syntropic -->')) {
31
+ found.push({ type: 'marker', path: 'CLAUDE.md', desc: 'Syntropic pipeline rules' });
32
+ }
33
+ }
34
+
35
+ // Check other tool instruction files
36
+ const toolFiles = ['.cursorrules', '.windsurfrules', '.github/copilot-instructions.md', 'AGENTS.md'];
37
+ for (const file of toolFiles) {
38
+ const fullPath = path.join(projectDir, file);
39
+ if (fs.existsSync(fullPath)) {
40
+ const content = fs.readFileSync(fullPath, 'utf8');
41
+ if (content.includes('<!-- syntropic -->')) {
42
+ found.push({ type: 'marker', path: file, desc: 'Syntropic pipeline rules' });
43
+ }
44
+ }
45
+ }
46
+
47
+ // Check .claude/agents/
48
+ const agentsDir = path.join(projectDir, '.claude', 'agents');
49
+ if (fs.existsSync(agentsDir)) {
50
+ const agents = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
51
+ if (agents.length > 0) {
52
+ found.push({ type: 'dir', path: '.claude/agents/', desc: `${agents.length} pipeline agent${agents.length > 1 ? 's' : ''}` });
53
+ }
54
+ }
55
+
56
+ // Check post-commit hook
57
+ const hookPath = path.join(projectDir, '.git', 'hooks', 'post-commit');
58
+ if (fs.existsSync(hookPath)) {
59
+ const content = fs.readFileSync(hookPath, 'utf8');
60
+ if (content.includes('syntropic report')) {
61
+ found.push({ type: 'hook', path: '.git/hooks/post-commit', desc: 'PRISM cycle reporting' });
62
+ }
63
+ }
64
+
65
+ // Check health check workflow
66
+ const workflowDir = path.join(projectDir, '.github', 'workflows');
67
+ if (fs.existsSync(workflowDir)) {
68
+ for (const file of fs.readdirSync(workflowDir)) {
69
+ const content = fs.readFileSync(path.join(workflowDir, file), 'utf8');
70
+ if (content.includes('syntropic') || content.includes('health-check')) {
71
+ found.push({ type: 'file', path: `.github/workflows/${file}`, desc: 'Health check workflow' });
72
+ }
73
+ }
74
+ }
75
+
76
+ // Check health check script
77
+ const healthScript = path.join(projectDir, 'scripts', 'health-check.js');
78
+ if (fs.existsSync(healthScript)) {
79
+ found.push({ type: 'file', path: 'scripts/health-check.js', desc: 'Health check script' });
80
+ }
81
+
82
+ // Check cache files
83
+ const cacheFiles = ['.claude/.prism-cache.json', '.claude/.syntropic-config.json'];
84
+ for (const file of cacheFiles) {
85
+ if (fs.existsSync(path.join(projectDir, file))) {
86
+ found.push({ type: 'file', path: file, desc: 'Cache file' });
87
+ }
88
+ }
89
+
90
+ // Check governance docs (report but don't remove)
91
+ const docsDir = path.join(projectDir, '.claude', 'docs');
92
+ if (fs.existsSync(docsDir)) {
93
+ found.push({ type: 'preserved', path: '.claude/docs/', desc: 'Your project docs (PRESERVED)' });
94
+ }
95
+
96
+ return found;
97
+ }
98
+
99
+ function removeSyntropicMarkers(filePath) {
100
+ const content = fs.readFileSync(filePath, 'utf8');
101
+ // Remove everything between <!-- syntropic --> and <!-- /syntropic -->
102
+ const cleaned = content.replace(/\n*<!-- syntropic -->[\s\S]*?<!-- \/syntropic -->\n*/g, '');
103
+
104
+ if (cleaned.trim() === '') {
105
+ // File was entirely syntropic content — delete it
106
+ fs.unlinkSync(filePath);
107
+ return 'deleted';
108
+ } else {
109
+ fs.writeFileSync(filePath, cleaned, 'utf8');
110
+ return 'cleaned';
111
+ }
112
+ }
113
+
114
+ function removeSyntropicFromHook(hookPath) {
115
+ const content = fs.readFileSync(hookPath, 'utf8');
116
+ const lines = content.split('\n');
117
+ const cleaned = lines.filter(l =>
118
+ !l.includes('syntropic report') &&
119
+ !l.includes('# Syntropic PRISM') &&
120
+ !l.includes('Disable: syntropic telemetry')
121
+ ).join('\n');
122
+
123
+ if (cleaned.trim() === '#!/bin/sh' || cleaned.trim() === '') {
124
+ fs.unlinkSync(hookPath);
125
+ return 'deleted';
126
+ } else {
127
+ fs.writeFileSync(hookPath, cleaned, 'utf8');
128
+ return 'cleaned';
129
+ }
130
+ }
131
+
132
+ function removeDir(dirPath) {
133
+ if (!fs.existsSync(dirPath)) return;
134
+ fs.rmSync(dirPath, { recursive: true, force: true });
135
+ }
136
+
137
+ async function run(args) {
138
+ const force = args.includes('--force');
139
+ const projectDir = process.cwd();
140
+
141
+ console.log('\n syntropic remove — Clean uninstall\n');
142
+
143
+ const found = detectSyntropicContent(projectDir);
144
+
145
+ if (found.filter(f => f.type !== 'preserved').length === 0) {
146
+ console.log(' No syntropic content found in this project.\n');
147
+ return;
148
+ }
149
+
150
+ // Show what will be affected
151
+ console.log(' Found:\n');
152
+ for (const item of found) {
153
+ if (item.type === 'preserved') {
154
+ console.log(` ✓ ${item.path.padEnd(40)} ${item.desc}`);
155
+ } else {
156
+ console.log(` ✗ ${item.path.padEnd(40)} ${item.desc}`);
157
+ }
158
+ }
159
+ console.log('');
160
+
161
+ if (!force) {
162
+ const answer = await ask(' Remove syntropic content? Your docs will be preserved. (y/N) ');
163
+ if (answer !== 'y' && answer !== 'yes') {
164
+ console.log(' Cancelled.\n');
165
+ return;
166
+ }
167
+ console.log('');
168
+ }
169
+
170
+ // Remove each item
171
+ let removed = 0;
172
+ for (const item of found) {
173
+ if (item.type === 'preserved') continue;
174
+
175
+ const fullPath = path.join(projectDir, item.path);
176
+
177
+ try {
178
+ if (item.type === 'marker') {
179
+ const result = removeSyntropicMarkers(fullPath);
180
+ console.log(` ${result === 'deleted' ? 'delete' : 'clean '} ${item.path}`);
181
+ removed++;
182
+ } else if (item.type === 'hook') {
183
+ const result = removeSyntropicFromHook(fullPath);
184
+ console.log(` ${result === 'deleted' ? 'delete' : 'clean '} ${item.path}`);
185
+ removed++;
186
+ } else if (item.type === 'dir') {
187
+ removeDir(fullPath);
188
+ console.log(` delete ${item.path}`);
189
+ removed++;
190
+ } else if (item.type === 'file') {
191
+ if (fs.existsSync(fullPath)) {
192
+ fs.unlinkSync(fullPath);
193
+ console.log(` delete ${item.path}`);
194
+ removed++;
195
+ }
196
+ }
197
+ } catch (err) {
198
+ console.log(` skip ${item.path} (${err.message})`);
199
+ }
200
+ }
201
+
202
+ console.log(`\n Removed ${removed} item${removed !== 1 ? 's' : ''}.`);
203
+
204
+ // Check if .claude dir is now empty (except docs)
205
+ const claudeDir = path.join(projectDir, '.claude');
206
+ if (fs.existsSync(claudeDir)) {
207
+ const remaining = fs.readdirSync(claudeDir);
208
+ const onlyDocs = remaining.length === 1 && remaining[0] === 'docs';
209
+ if (remaining.length === 0) {
210
+ fs.rmdirSync(claudeDir);
211
+ console.log(' Cleaned up empty .claude/ directory.');
212
+ } else if (onlyDocs) {
213
+ console.log(' Your project docs in .claude/docs/ have been preserved.');
214
+ }
215
+ }
216
+
217
+ console.log('');
218
+ }
219
+
220
+ module.exports = run;
@@ -98,6 +98,42 @@ function autoDetectPhases(weight) {
98
98
  }
99
99
  }
100
100
 
101
+ function detectGovernanceDocs() {
102
+ const fs = require('fs');
103
+ const path = require('path');
104
+ const cwd = process.cwd();
105
+ const docsDir = path.join(cwd, '.claude', 'docs');
106
+
107
+ return {
108
+ has_north_star: fs.existsSync(path.join(docsDir, 'NORTH_STAR.md')),
109
+ has_backlog: fs.existsSync(path.join(docsDir, 'BACKLOG.md')),
110
+ has_issues: fs.existsSync(path.join(docsDir, 'ISSUES.md')),
111
+ adr_count: (() => {
112
+ const adrDir = path.join(docsDir, 'adr');
113
+ if (!fs.existsSync(adrDir)) return 0;
114
+ return fs.readdirSync(adrDir).filter(f => f.endsWith('.md') && f !== '000-TEMPLATE.md').length;
115
+ })(),
116
+ };
117
+ }
118
+
119
+ function detectGovernanceChanges() {
120
+ try {
121
+ const { execSync } = require('child_process');
122
+ const diff = execSync('git diff --name-only HEAD~1 HEAD 2>/dev/null || echo ""', { encoding: 'utf8' });
123
+ const changedFiles = diff.trim().split('\n').filter(Boolean);
124
+ const docChanges = changedFiles.filter(f => f.startsWith('.claude/docs/'));
125
+
126
+ return {
127
+ issues_modified: docChanges.some(f => f.includes('ISSUES')),
128
+ backlog_updated: docChanges.some(f => f.includes('BACKLOG')),
129
+ adr_created: docChanges.some(f => f.includes('/adr/')),
130
+ north_star_updated: docChanges.some(f => f.includes('NORTH_STAR')),
131
+ };
132
+ } catch {
133
+ return { issues_modified: false, backlog_updated: false, adr_created: false, north_star_updated: false };
134
+ }
135
+ }
136
+
101
137
  function autoDetectSuccess() {
102
138
  try {
103
139
  const { execSync } = require('child_process');
@@ -156,6 +192,12 @@ async function run(args) {
156
192
  const iterations = parseInt(flags.iterations, 10) || 1;
157
193
  if (flags.tool) env.tool = flags.tool;
158
194
 
195
+ // Detect governance docs
196
+ const governance = {
197
+ ...detectGovernanceDocs(),
198
+ ...detectGovernanceChanges(),
199
+ };
200
+
159
201
  // Build the report payload
160
202
  const idempotencyKey = crypto.randomUUID();
161
203
 
@@ -176,6 +218,7 @@ async function run(args) {
176
218
  },
177
219
  environment: env,
178
220
  project_shape: shapePayload,
221
+ governance,
179
222
  };
180
223
 
181
224
  // HMAC sign the payload (exclude the hmac field itself)
@@ -202,7 +245,15 @@ async function run(args) {
202
245
  await new Promise((resolve) => {
203
246
  const req = https.request(options, (res) => {
204
247
  if (res.statusCode === 200 || res.statusCode === 201) {
205
- console.log(` PRISM report submitted (${weight} cycle, ${phases.length} phases, ${success ? 'success' : 'failed'}).`);
248
+ // Honest, useful output
249
+ const parts = [`Syntropic: ${weight} cycle`, `${shape.changed_count || '?'} files`];
250
+ if (success) parts.push('build passing');
251
+ const docUpdates = [];
252
+ if (governance.issues_modified) docUpdates.push('ISSUES');
253
+ if (governance.backlog_updated) docUpdates.push('BACKLOG');
254
+ if (governance.adr_created) docUpdates.push('ADR');
255
+ if (docUpdates.length > 0) parts.push(`docs: ${docUpdates.join(', ')}`);
256
+ console.log(` ${parts.join(' | ')}`);
206
257
  } else {
207
258
  console.log(` PRISM report: server returned ${res.statusCode} (non-blocking).`);
208
259
  }
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "syntropic",
3
- "version": "0.8.1",
4
- "description": "Philosophy-as-code development pipeline with market analysis for Claude Code, Cursor, Windsurf, GitHub Copilot, and OpenAI Codex.",
3
+ "version": "0.9.0",
4
+ "description": "Ship better software with a proven development methodology. Audit your git history, install disciplined rules, and track iterations — for Claude Code, Cursor, Windsurf, GitHub Copilot, and OpenAI Codex.",
5
5
  "bin": {
6
6
  "syntropic": "./bin/syntropic.js"
7
7
  },
8
8
  "keywords": [
9
9
  "cli",
10
10
  "development-pipeline",
11
+ "audit",
12
+ "governance",
13
+ "project-docs",
11
14
  "philosophy-as-code",
12
15
  "outcome-thinking",
13
16
  "claude-code",
@@ -5,6 +5,28 @@
5
5
 
6
6
  ---
7
7
 
8
+ ## EG7: Implementation Pipeline (MANDATORY)
9
+
10
+ Before starting ANY task, state the cycle weight:
11
+ - **Full Cycle** (>3 files or new patterns): /research → /design → /arch → /plan → /dev → /qa → /test
12
+ - **Lightweight Cycle** (1-3 files, known patterns): /research → /plan → /dev → /qa → /test
13
+ - **Minimum Cycle** (trivial/obvious): /dev → /test
14
+
15
+ **Before coding:** Check `.claude/docs/BACKLOG.md` for current priorities and `.claude/docs/ISSUES.md` for known problems.
16
+
17
+ ---
18
+
19
+ ## EG14: Post-Cycle Documentation (MANDATORY)
20
+
21
+ After completing work, update:
22
+ - `.claude/docs/ISSUES.md` — log any new issues found during the cycle
23
+ - `.claude/docs/BACKLOG.md` — update status of items worked on
24
+ - `.claude/docs/adr/` — record any architectural decisions made
25
+
26
+ These updates happen as part of the cycle, not as a separate task.
27
+
28
+ ---
29
+
8
30
  ## EG13: PRISM Sync (MANDATORY)
9
31
 
10
32
  At the START of every development cycle, before any work:
@@ -19,6 +41,7 @@ At the START of every development cycle, before any work:
19
41
  - `cycle_recommendations`: adjust cycle weight if triggers match
20
42
  - `phase_guidance`: follow the instruction for each phase you run
21
43
  - `patterns`: prefer efficient patterns, avoid wasteful ones
44
+ - `config_version` + `last_updated`: if >7 days old, methodology may be stale
22
45
 
23
46
  3. At cycle END (after test phase passes or cycle completes):
24
47
  Run: `syntropic report`
@@ -60,3 +83,4 @@ Never ask permission for:
60
83
 
61
84
  <!-- Generated by syntropic — development methodology for AI coding tools (https://npmjs.com/package/syntropic) -->
62
85
  <!-- Research: https://zenodo.org/records/17894441 -->
86
+ <!-- /syntropic -->
@@ -5,6 +5,18 @@
5
5
 
6
6
  ---
7
7
 
8
+ ## Development Pipeline (MANDATORY)
9
+
10
+ Before starting ANY task, state the cycle weight:
11
+ - Full Cycle (>3 files): research → design → arch → plan → dev → qa → test
12
+ - Lightweight (1-3 files): research → plan → dev → qa → test
13
+ - Minimum (trivial): dev → test
14
+
15
+ Before coding: check `.claude/docs/BACKLOG.md` and `.claude/docs/ISSUES.md`.
16
+ After completing: update ISSUES.md, BACKLOG.md, and ADRs as needed.
17
+
18
+ ---
19
+
8
20
  ## PRISM Sync (MANDATORY)
9
21
 
10
22
  At the START of every development cycle, fetch the methodology by reading this URL:
@@ -41,3 +53,4 @@ If the fetch fails, use these fallback rules:
41
53
 
42
54
  <!-- Generated by syntropic — development methodology for AI coding tools (https://npmjs.com/package/syntropic) -->
43
55
  <!-- Research: https://zenodo.org/records/17894441 -->
56
+ <\!-- /syntropic -->
@@ -4,6 +4,16 @@
4
4
  <!-- syntropic -->
5
5
  ---
6
6
 
7
+ ## Development Pipeline (MANDATORY)
8
+
9
+ Before starting ANY task, state the cycle weight:
10
+ - Full Cycle (>3 files): research → design → arch → plan → dev → qa → test
11
+ - Lightweight (1-3 files): research → plan → dev → qa → test
12
+ - Minimum (trivial): dev → test
13
+
14
+ Before coding: check `.claude/docs/BACKLOG.md` and `.claude/docs/ISSUES.md`.
15
+ After completing: update ISSUES.md, BACKLOG.md, and ADRs as needed.
16
+
7
17
  ## EG13: PRISM Sync (MANDATORY)
8
18
 
9
19
  At the START of every development cycle, fetch the methodology:
@@ -3,6 +3,16 @@
3
3
 
4
4
  These instructions are loaded automatically by GitHub Copilot. Follow them for all work in this project.
5
5
 
6
+ ## Development Pipeline (MANDATORY)
7
+
8
+ Before starting ANY task, state the cycle weight:
9
+ - Full Cycle (>3 files): research → design → arch → plan → dev → qa → test
10
+ - Lightweight (1-3 files): research → plan → dev → qa → test
11
+ - Minimum (trivial): dev → test
12
+
13
+ Before coding: check `.claude/docs/BACKLOG.md` and `.claude/docs/ISSUES.md`.
14
+ After completing: update ISSUES.md, BACKLOG.md, and ADRs as needed.
15
+
6
16
  ## PRISM Sync (MANDATORY)
7
17
 
8
18
  At the START of every development cycle, fetch the methodology by reading this URL:
@@ -34,3 +44,4 @@ If the fetch fails, use these fallback rules:
34
44
 
35
45
  <!-- Generated by syntropic — development methodology for AI coding tools (https://npmjs.com/package/syntropic) -->
36
46
  <!-- Research: https://zenodo.org/records/17894441 -->
47
+ <\!-- /syntropic -->
@@ -5,6 +5,18 @@
5
5
 
6
6
  ---
7
7
 
8
+ ## Development Pipeline (MANDATORY)
9
+
10
+ Before starting ANY task, state the cycle weight:
11
+ - Full Cycle (>3 files): research → design → arch → plan → dev → qa → test
12
+ - Lightweight (1-3 files): research → plan → dev → qa → test
13
+ - Minimum (trivial): dev → test
14
+
15
+ Before coding: check `.claude/docs/BACKLOG.md` and `.claude/docs/ISSUES.md`.
16
+ After completing: update ISSUES.md, BACKLOG.md, and ADRs as needed.
17
+
18
+ ---
19
+
8
20
  ## PRISM Sync (MANDATORY)
9
21
 
10
22
  At the START of every development cycle, fetch the methodology by reading this URL:
@@ -40,3 +52,4 @@ If the fetch fails, use these fallback rules:
40
52
 
41
53
  <!-- Generated by syntropic — development methodology for AI coding tools (https://npmjs.com/package/syntropic) -->
42
54
  <!-- Research: https://zenodo.org/records/17894441 -->
55
+ <\!-- /syntropic -->
@@ -0,0 +1,40 @@
1
+ # {{PROJECT_NAME}} — Backlog
2
+
3
+ **Last Updated:** {{CREATED_DATE}}
4
+ **Source of truth for prioritised work.**
5
+
6
+ ---
7
+
8
+ ## In Progress
9
+
10
+ ### [ITEM-1]: [Title]
11
+ **Priority:** P0 | **Effort:** Small | **Status:** Building
12
+ - [What's being built]
13
+ - [Key decisions or constraints]
14
+
15
+ ---
16
+
17
+ ## Next Up
18
+
19
+ ### [ITEM-2]: [Title]
20
+ **Priority:** P1 | **Effort:** Medium | **Depends on:** ITEM-1
21
+ - [What needs to happen]
22
+
23
+ ---
24
+
25
+ ## Backlog
26
+
27
+ ### [ITEM-3]: [Title]
28
+ **Priority:** P2 | **Effort:** [Small/Medium/Large]
29
+ - [Description]
30
+
31
+ ---
32
+
33
+ ## Done (Recent)
34
+
35
+ - [x] [Completed item with date]
36
+
37
+ ---
38
+
39
+ _Update after every cycle. Move items between sections as status changes._
40
+ _Your AI assistant checks this before starting work (EG7) and updates it after (EG14)._
@@ -0,0 +1,51 @@
1
+ # {{PROJECT_NAME}} — Issue Log
2
+
3
+ **Last Updated:** {{CREATED_DATE}}
4
+
5
+ ---
6
+
7
+ ## Active Issues
8
+
9
+ _No issues yet. When something breaks or needs investigation, log it here._
10
+
11
+ <!--
12
+ ### ISSUE-001: [Title]
13
+ **Status:** Open | In Progress | Resolved
14
+ **Priority:** P0 (Critical) | P1 (High) | P2 (Medium) | P3 (Low)
15
+ **Created:** YYYY-MM-DD
16
+
17
+ **Description:**
18
+ [What is the issue?]
19
+
20
+ **Resolution:**
21
+ [How was/will it be fixed?]
22
+ -->
23
+
24
+ ---
25
+
26
+ ## Resolved Issues
27
+
28
+ _Resolved issues stay here as a record. They help track iteration patterns._
29
+
30
+ ---
31
+
32
+ ## Issue Template
33
+
34
+ ```markdown
35
+ ### ISSUE-XXX: [Title]
36
+ **Status:** Open | In Progress | Resolved | Won't Fix
37
+ **Priority:** P0 (Critical) | P1 (High) | P2 (Medium) | P3 (Low)
38
+ **Created:** YYYY-MM-DD
39
+ **Resolved:** YYYY-MM-DD (if resolved)
40
+
41
+ **Description:**
42
+ [What is the issue?]
43
+
44
+ **Resolution:**
45
+ [How was/will it be fixed?]
46
+ ```
47
+
48
+ ---
49
+
50
+ _Log issues as you find them. Your AI assistant checks this before starting work (EG7)._
51
+ _Each fix commit that references an issue here is a measurable iteration._
@@ -0,0 +1,73 @@
1
+ # {{PROJECT_NAME}} — North Star
2
+
3
+ **Created:** {{CREATED_DATE}}
4
+ **Status:** Active
5
+
6
+ ---
7
+
8
+ ## Vision
9
+
10
+ _What does this project exist to achieve? One sentence._
11
+
12
+ > [Your vision statement here]
13
+
14
+ ---
15
+
16
+ ## Mission
17
+
18
+ _How will you get there? The approach._
19
+
20
+ > [Your mission statement here]
21
+
22
+ ---
23
+
24
+ ## Goals (Prioritised)
25
+
26
+ ### G1: [Primary Goal]
27
+ **Priority:** Primary
28
+
29
+ [What does success look like? How will you measure it?]
30
+
31
+ ### G2: [Secondary Goal]
32
+ **Priority:** Secondary
33
+
34
+ [What does success look like? How will you measure it?]
35
+
36
+ ### G3: [Learning Goal]
37
+ **Priority:** Always
38
+
39
+ [What are you learning by building this?]
40
+
41
+ ---
42
+
43
+ ## Design Principles
44
+
45
+ ### DP1: [Principle Name]
46
+ [One sentence explaining the principle and why it matters.]
47
+
48
+ ### DP2: [Principle Name]
49
+ [One sentence explaining the principle and why it matters.]
50
+
51
+ ### DP3: [Principle Name]
52
+ [One sentence explaining the principle and why it matters.]
53
+
54
+ ---
55
+
56
+ ## Anti-Patterns
57
+
58
+ - **AP1**: [What to avoid and why]
59
+ - **AP2**: [What to avoid and why]
60
+ - **AP3**: [What to avoid and why]
61
+
62
+ ---
63
+
64
+ ## Current State
65
+
66
+ | Area | Status | Next Step |
67
+ |------|--------|-----------|
68
+ | [Area 1] | [Status] | [Next action] |
69
+ | [Area 2] | [Status] | [Next action] |
70
+
71
+ ---
72
+
73
+ _Update this document when priorities shift. Your AI assistant reads this at the start of every cycle._
@@ -0,0 +1,39 @@
1
+ # ADR-XXX: [Title]
2
+
3
+ **Status:** Proposed | Accepted | Deprecated | Superseded
4
+ **Date:** YYYY-MM-DD
5
+ **Author:** [Name]
6
+ **Supersedes:** ADR-XXX (if applicable)
7
+
8
+ ## Context
9
+
10
+ What is the issue that we're seeing that is motivating this decision or change?
11
+
12
+ ## Decision
13
+
14
+ What is the change that we're proposing and/or doing?
15
+
16
+ ## Consequences
17
+
18
+ What becomes easier or more difficult to do because of this change?
19
+
20
+ ### Positive
21
+ -
22
+
23
+ ### Negative
24
+ -
25
+
26
+ ### Risks
27
+ -
28
+
29
+ ## Alternatives Considered
30
+
31
+ What other options were considered and why were they rejected?
32
+
33
+ | Option | Pros | Cons | Why Rejected |
34
+ |--------|------|------|--------------|
35
+ | | | | |
36
+
37
+ ## References
38
+
39
+ - [Link to relevant documentation]
@@ -4,6 +4,16 @@
4
4
  <!-- syntropic -->
5
5
  ---
6
6
 
7
+ ## Development Pipeline (MANDATORY)
8
+
9
+ Before starting ANY task, state the cycle weight:
10
+ - Full Cycle (>3 files): research → design → arch → plan → dev → qa → test
11
+ - Lightweight (1-3 files): research → plan → dev → qa → test
12
+ - Minimum (trivial): dev → test
13
+
14
+ Before coding: check `.claude/docs/BACKLOG.md` and `.claude/docs/ISSUES.md`.
15
+ After completing: update ISSUES.md, BACKLOG.md, and ADRs as needed.
16
+
7
17
  ## PRISM Sync (MANDATORY)
8
18
 
9
19
  At the START of every development cycle, fetch the methodology by reading this URL:
@@ -5,6 +5,18 @@
5
5
 
6
6
  ---
7
7
 
8
+ ## Development Pipeline (MANDATORY)
9
+
10
+ Before starting ANY task, state the cycle weight:
11
+ - Full Cycle (>3 files): research → design → arch → plan → dev → qa → test
12
+ - Lightweight (1-3 files): research → plan → dev → qa → test
13
+ - Minimum (trivial): dev → test
14
+
15
+ Before coding: check `.claude/docs/BACKLOG.md` and `.claude/docs/ISSUES.md`.
16
+ After completing: update ISSUES.md, BACKLOG.md, and ADRs as needed.
17
+
18
+ ---
19
+
8
20
  ## PRISM Sync (MANDATORY)
9
21
 
10
22
  At the START of every development cycle, fetch the methodology by reading this URL:
@@ -40,3 +52,4 @@ If the fetch fails, use these fallback rules:
40
52
 
41
53
  <!-- Generated by syntropic — development methodology for AI coding tools (https://npmjs.com/package/syntropic) -->
42
54
  <!-- Research: https://zenodo.org/records/17894441 -->
55
+ <\!-- /syntropic -->