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 +63 -78
- package/bin/syntropic.js +4 -0
- package/commands/audit.js +293 -0
- package/commands/init.js +65 -13
- package/commands/remove.js +220 -0
- package/commands/report.js +52 -1
- package/package.json +5 -2
- package/templates/CLAUDE.md +24 -0
- package/templates/agents-md.template +13 -0
- package/templates/claude-append.template +10 -0
- package/templates/copilot-instructions.template +11 -0
- package/templates/cursorrules.template +13 -0
- package/templates/docs/BACKLOG.template +40 -0
- package/templates/docs/ISSUES.template +51 -0
- package/templates/docs/NORTH_STAR.template +73 -0
- package/templates/docs/adr/000-TEMPLATE.template +39 -0
- package/templates/tool-append.template +10 -0
- package/templates/windsurfrules.template +13 -0
package/README.md
CHANGED
|
@@ -1,127 +1,112 @@
|
|
|
1
1
|
# syntropic
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Ship better software. Prove it on your own code first.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A development methodology for AI-assisted coding. Works with **Claude Code**, **Cursor**, **Windsurf**, **GitHub Copilot**, and **OpenAI Codex**.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Try Before You Install
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx syntropic
|
|
10
|
+
npx syntropic audit
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
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
|
|
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
|
|
25
|
+
**Evergreen Rules** — battle-tested development rules fetched fresh at every cycle:
|
|
39
26
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
**
|
|
36
|
+
**Governance Docs** — project management templates your AI assistant reads before every cycle:
|
|
49
37
|
|
|
50
|
-
|
|
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
|
-
**
|
|
45
|
+
**Pipeline Agents** — research, dev, plan, qa, devops, security — fetched from the PRISM network so they're always up to date.
|
|
53
46
|
|
|
54
|
-
|
|
47
|
+
**Health Check** — daily GitHub Action with auto-remediation (npm audit fix PRs).
|
|
55
48
|
|
|
56
|
-
|
|
57
|
-
# Scaffold a new project
|
|
58
|
-
npx syntropic init my-project
|
|
49
|
+
## Track Record
|
|
59
50
|
|
|
60
|
-
|
|
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
|
-
|
|
64
|
-
|
|
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
|
-
|
|
67
|
-
npx syntropic add cursor
|
|
68
|
-
npx syntropic add windsurf copilot
|
|
58
|
+
## Trust & Privacy
|
|
69
59
|
|
|
70
|
-
|
|
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
|
-
|
|
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
|
-
|
|
79
|
-
|
|
64
|
+
```bash
|
|
65
|
+
syntropic telemetry disable
|
|
80
66
|
```
|
|
81
67
|
|
|
82
|
-
|
|
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
|
-
|
|
71
|
+
**Clean exit.** Remove everything syntropic added (preserves your governance docs):
|
|
87
72
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
73
|
+
```bash
|
|
74
|
+
syntropic remove
|
|
75
|
+
```
|
|
91
76
|
|
|
92
|
-
|
|
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
|
-
|
|
79
|
+
## Commands
|
|
99
80
|
|
|
100
|
-
|
|
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
|
-
|
|
92
|
+
## How It Works
|
|
103
93
|
|
|
104
|
-
|
|
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
|
-
|
|
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
|
-
|
|
98
|
+
## Existing Projects
|
|
109
99
|
|
|
110
|
-
|
|
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
|
-
##
|
|
102
|
+
## Research
|
|
113
103
|
|
|
114
|
-
|
|
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
|
-
- [
|
|
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
|
-
|
|
303
|
-
|
|
304
|
-
|
|
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
|
-
|
|
307
|
-
|
|
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
|
-
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
-
|
|
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;
|
package/commands/report.js
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
4
|
-
"description": "
|
|
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",
|
package/templates/CLAUDE.md
CHANGED
|
@@ -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 -->
|