sinapse-ai 1.15.0 → 1.17.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/.claude/hooks/doc-first-gate.cjs +156 -0
- package/.claude/hooks/enforce-story-gate.cjs +6 -2
- package/.claude/rules/hook-governance.md +1 -0
- package/.sinapse-ai/constitution.md +1 -1
- package/.sinapse-ai/core/atlas/atlas-data.js +278 -0
- package/.sinapse-ai/core/atlas/flows-pt.js +253 -0
- package/.sinapse-ai/core/atlas/flows.js +266 -0
- package/.sinapse-ai/core/atlas/index.js +62 -0
- package/.sinapse-ai/core/atlas/render-html.js +216 -0
- package/.sinapse-ai/core/atlas/render-markdown.js +313 -0
- package/.sinapse-ai/core/atlas/render-research-card.js +164 -0
- package/.sinapse-ai/core/orchestration/build-command.js +136 -0
- package/.sinapse-ai/core/orchestration/doc-first-resolver.js +322 -0
- package/.sinapse-ai/core/orchestration/route-command.js +97 -0
- package/.sinapse-ai/data/entity-registry.yaml +113 -16
- package/.sinapse-ai/development/agents/snps-orqx.md +9 -0
- package/.sinapse-ai/development/tasks/create-doc.md +1 -1
- package/.sinapse-ai/development/tasks/create-next-story.md +2 -3
- package/.sinapse-ai/development/tasks/spec-analyze.md +460 -0
- package/.sinapse-ai/development/tasks/spec-clarify.md +374 -0
- package/.sinapse-ai/development/tasks/spec-gather-requirements.md +11 -0
- package/.sinapse-ai/development/templates/approval-table.md +106 -0
- package/.sinapse-ai/development/workflows/spec-pipeline.yaml +122 -7
- package/.sinapse-ai/install-manifest.yaml +70 -18
- package/.sinapse-ai/product/templates/prd-tmpl.yaml +6 -2
- package/.sinapse-ai/product/templates/spec-tmpl.md +18 -0
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +18 -3
- package/bin/sinapse.js +121 -0
- package/docs/framework/atlas/OPERATING-ATLAS.md +537 -0
- package/docs/framework/atlas/README.md +34 -0
- package/docs/framework/atlas/atlas-data.json +2810 -0
- package/docs/framework/atlas/atlas.html +392 -0
- package/package.json +1 -1
- package/packages/installer/src/wizard/ide-config-generator.js +6 -0
- package/scripts/install-chrome-brain.sh +2 -2
- package/scripts/validate-no-personal-leaks.js +24 -9
- package/squads/squad-copy/knowledge-base/consequence-headline-patterns.md +2 -2
- package/docs/guides/hooks-two-layers.md +0 -66
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atlas → HTML dashboard renderer (visual).
|
|
3
|
+
*
|
|
4
|
+
* Produces a single self-contained HTML file (data embedded) with the same
|
|
5
|
+
* atlas data as the markdown atlas: at-a-glance counts, the operating-model
|
|
6
|
+
* Mermaid diagram, and searchable/filterable tables for workflows, agents,
|
|
7
|
+
* squads, the constitution, and rules. SINAPSE B&W aesthetic. No build step,
|
|
8
|
+
* no server — open the file.
|
|
9
|
+
*
|
|
10
|
+
* @module core/atlas/render-html
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
function esc(s) {
|
|
16
|
+
return String(s == null ? '' : s)
|
|
17
|
+
.replace(/&/g, '&')
|
|
18
|
+
.replace(/</g, '<')
|
|
19
|
+
.replace(/>/g, '>')
|
|
20
|
+
.replace(/"/g, '"');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function renderAtlasHtml(d) {
|
|
24
|
+
const c = d.counts;
|
|
25
|
+
const stamp = d.generatedAt ? `Generated ${esc(d.generatedAt)}` : '';
|
|
26
|
+
const dataJson = JSON.stringify(d).replace(/</g, '\\u003c');
|
|
27
|
+
|
|
28
|
+
const stat = (n, label) => `<div class="stat"><b>${n}</b><span>${label}</span></div>`;
|
|
29
|
+
|
|
30
|
+
const flowsSection = (d.flows || [])
|
|
31
|
+
.map(
|
|
32
|
+
(f) => `<h3 style="margin:1.6rem 0 .3rem">${esc(f.title)}</h3>
|
|
33
|
+
<p class="lead">${esc(f.purpose)}</p>
|
|
34
|
+
<div class="mermaid">
|
|
35
|
+
${esc(f.mermaid)}
|
|
36
|
+
</div>`,
|
|
37
|
+
)
|
|
38
|
+
.join('\n');
|
|
39
|
+
|
|
40
|
+
return `<!doctype html>
|
|
41
|
+
<html lang="en">
|
|
42
|
+
<head>
|
|
43
|
+
<meta charset="utf-8" />
|
|
44
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
45
|
+
<title>SINAPSE · Framework Operating Atlas</title>
|
|
46
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
|
47
|
+
<style>
|
|
48
|
+
:root{
|
|
49
|
+
--bg:#0a0a0a; --fg:#f5f5f0; --mut:#8a8a85; --line:#222; --card:#121212; --accent:#f5f5f0;
|
|
50
|
+
--font:'Inter',system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
|
|
51
|
+
--mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
|
|
52
|
+
}
|
|
53
|
+
*{box-sizing:border-box}
|
|
54
|
+
body{margin:0;background:var(--bg);color:var(--fg);font-family:var(--font);line-height:1.5;
|
|
55
|
+
background-image:radial-gradient(rgba(255,255,255,.025) 1px,transparent 1px);background-size:3px 3px}
|
|
56
|
+
.wrap{max-width:min(1400px,94vw);margin:0 auto;padding:clamp(1.5rem,4vw,3rem) 0 5rem}
|
|
57
|
+
h1{font-size:clamp(1.6rem,4vw,2.6rem);font-weight:800;letter-spacing:-.02em;margin:0 0 .25rem}
|
|
58
|
+
.sub{color:var(--mut);font-family:var(--mono);font-size:.8rem;margin-bottom:2rem}
|
|
59
|
+
.stats{display:flex;flex-wrap:wrap;gap:.6rem;margin-bottom:2rem}
|
|
60
|
+
.stat{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:.7rem 1rem;min-width:96px}
|
|
61
|
+
.stat b{display:block;font-size:1.5rem;font-weight:800;font-family:var(--mono)}
|
|
62
|
+
.stat span{color:var(--mut);font-size:.72rem;text-transform:uppercase;letter-spacing:.06em}
|
|
63
|
+
nav{display:flex;flex-wrap:wrap;gap:.4rem;margin-bottom:1.5rem;position:sticky;top:0;
|
|
64
|
+
background:linear-gradient(var(--bg),var(--bg) 70%,transparent);padding:.6rem 0;z-index:5}
|
|
65
|
+
nav button{background:transparent;color:var(--mut);border:1px solid var(--line);border-radius:999px;
|
|
66
|
+
padding:.35rem .9rem;font-family:var(--mono);font-size:.78rem;cursor:pointer;transition:.15s}
|
|
67
|
+
nav button:hover{color:var(--fg);border-color:#444}
|
|
68
|
+
nav button.on{background:var(--fg);color:var(--bg);border-color:var(--fg)}
|
|
69
|
+
section{display:none;animation:fade .2s ease}
|
|
70
|
+
section.on{display:block}
|
|
71
|
+
@keyframes fade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
|
|
72
|
+
h2{font-size:1.2rem;font-weight:700;margin:0 0 1rem;letter-spacing:-.01em}
|
|
73
|
+
.mermaid{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:1.5rem;margin-bottom:1.5rem}
|
|
74
|
+
.ctrl{display:flex;gap:.6rem;flex-wrap:wrap;margin-bottom:1rem}
|
|
75
|
+
input,select{background:var(--card);color:var(--fg);border:1px solid var(--line);border-radius:8px;
|
|
76
|
+
padding:.5rem .8rem;font-family:var(--mono);font-size:.82rem}
|
|
77
|
+
input{flex:1;min-width:200px}
|
|
78
|
+
table{width:100%;border-collapse:collapse;font-size:.82rem}
|
|
79
|
+
th,td{text-align:left;padding:.55rem .7rem;border-bottom:1px solid var(--line);vertical-align:top}
|
|
80
|
+
th{color:var(--mut);font-family:var(--mono);font-size:.7rem;text-transform:uppercase;letter-spacing:.06em;
|
|
81
|
+
position:sticky;top:3.4rem;background:var(--bg);cursor:pointer}
|
|
82
|
+
td code{font-family:var(--mono);font-size:.78rem;color:var(--fg);background:#1c1c1c;padding:.1rem .35rem;border-radius:4px}
|
|
83
|
+
.tag{font-family:var(--mono);font-size:.68rem;padding:.1rem .45rem;border-radius:999px;border:1px solid var(--line);color:var(--mut)}
|
|
84
|
+
.nn{color:#fff;border-color:#555}
|
|
85
|
+
.count{color:var(--mut);font-family:var(--mono);font-size:.75rem;margin-bottom:.6rem}
|
|
86
|
+
p.lead{color:var(--mut);max-width:70ch;margin:0 0 1.2rem}
|
|
87
|
+
a{color:var(--fg)}
|
|
88
|
+
</style>
|
|
89
|
+
</head>
|
|
90
|
+
<body>
|
|
91
|
+
<div class="wrap">
|
|
92
|
+
<h1>SINAPSE · Framework Operating Atlas</h1>
|
|
93
|
+
<div class="sub">How the framework works — routing, models, constitution, workflows, agents, squads. ${stamp}</div>
|
|
94
|
+
<div class="stats">
|
|
95
|
+
${stat(c.squads, 'squads')}
|
|
96
|
+
${stat(c.agentsTotal, 'agents')}
|
|
97
|
+
${stat(c.orqx, 'orchestrators')}
|
|
98
|
+
${stat(c.workflowsTotal, 'workflows')}
|
|
99
|
+
${stat(c.articles, 'articles')}
|
|
100
|
+
${stat(c.rules, 'rules')}
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<nav id="nav"></nav>
|
|
104
|
+
|
|
105
|
+
<section id="s-model" class="on">
|
|
106
|
+
<h2>Operating model</h2>
|
|
107
|
+
<p class="lead">Every briefing flows through the same spine: the Imperator routes to a squad orchestrator or framework agent, the doc-first pipeline turns intent into PRD → Epic → Story → Spec, gates block code without docs, then implementation → QA → ship.</p>
|
|
108
|
+
<div class="mermaid">
|
|
109
|
+
flowchart TD
|
|
110
|
+
U[User briefing] --> I[Imperator · master orchestrator]
|
|
111
|
+
I -->|classify intent + project type| R{Route}
|
|
112
|
+
R -->|domain work| SQ[Squad orchestrator -orqx]
|
|
113
|
+
R -->|framework dev| FW[Framework agents]
|
|
114
|
+
SQ --> SP[Squad specialist]
|
|
115
|
+
FW --> DOC[Doc-first pipeline]
|
|
116
|
+
SP --> DOC
|
|
117
|
+
DOC -->|PRD - Epic - Story - Spec| GATE{{Gates}}
|
|
118
|
+
GATE -->|pass| EXEC[Implementation]
|
|
119
|
+
GATE -->|fail| BLOCK[Blocked: produce docs first]
|
|
120
|
+
EXEC --> QA[Quality gate] --> SHIP[Push / PR]
|
|
121
|
+
</div>
|
|
122
|
+
</section>
|
|
123
|
+
|
|
124
|
+
<section id="s-flows">
|
|
125
|
+
<h2>Framework flows</h2>
|
|
126
|
+
<p class="lead">How each mechanism of the framework runs — routing, models, doc-first enforcement, gates, project classification. The meta-workflows behind the machine.</p>
|
|
127
|
+
${flowsSection}
|
|
128
|
+
</section>
|
|
129
|
+
|
|
130
|
+
<section id="s-constitution"><h2>Constitution · ${c.articles} articles</h2><div id="t-constitution"></div></section>
|
|
131
|
+
<section id="s-workflows"><h2>Workflows · ${c.workflowsTotal}</h2>
|
|
132
|
+
<div class="ctrl"><input id="q-workflows" placeholder="search workflows…"><select id="f-workflows-src"><option value="">all sources</option><option value="framework">framework</option><option value="squad">squad</option></select></div>
|
|
133
|
+
<div class="count" id="c-workflows"></div><div id="t-workflows"></div></section>
|
|
134
|
+
<section id="s-agents"><h2>Agents · ${c.agentsTotal}</h2>
|
|
135
|
+
<div class="ctrl"><input id="q-agents" placeholder="search agents…"><select id="f-agents-squad"></select><label style="color:var(--mut);font-family:var(--mono);font-size:.78rem;display:flex;align-items:center;gap:.4rem"><input type="checkbox" id="f-agents-orqx" style="flex:none">orchestrators only</label></div>
|
|
136
|
+
<div class="count" id="c-agents"></div><div id="t-agents"></div></section>
|
|
137
|
+
<section id="s-squads"><h2>Squads · ${c.squads}</h2><div id="t-squads"></div></section>
|
|
138
|
+
<section id="s-rules"><h2>Rules · ${c.rules}</h2><div id="t-rules"></div></section>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<script id="atlas-data" type="application/json">${dataJson}</script>
|
|
142
|
+
<script>
|
|
143
|
+
const D = JSON.parse(document.getElementById('atlas-data').textContent);
|
|
144
|
+
// startOnLoad:false — Mermaid renders diagrams in display:none sections at zero
|
|
145
|
+
// width. We render each section's diagrams the first time its tab is shown.
|
|
146
|
+
try{ mermaid.initialize({startOnLoad:false,theme:'dark',themeVariables:{background:'#121212',primaryColor:'#1c1c1c',primaryTextColor:'#f5f5f0',lineColor:'#555'}}); }catch(e){}
|
|
147
|
+
function renderDiagrams(sectionId){
|
|
148
|
+
try{
|
|
149
|
+
const nodes=[...document.querySelectorAll('#'+sectionId+' .mermaid:not([data-processed])')];
|
|
150
|
+
if(nodes.length&&window.mermaid&&mermaid.run) mermaid.run({nodes});
|
|
151
|
+
}catch(e){}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const TABS=[['s-model','Operating model'],['s-flows','Flows'],['s-constitution','Constitution'],['s-workflows','Workflows'],['s-agents','Agents'],['s-squads','Squads'],['s-rules','Rules']];
|
|
155
|
+
const nav=document.getElementById('nav');
|
|
156
|
+
TABS.forEach(([id,label],i)=>{const b=document.createElement('button');b.textContent=label;if(i===0)b.className='on';
|
|
157
|
+
b.onclick=()=>{document.querySelectorAll('nav button').forEach(x=>x.classList.remove('on'));b.classList.add('on');
|
|
158
|
+
document.querySelectorAll('section').forEach(s=>s.classList.remove('on'));document.getElementById(id).classList.add('on');
|
|
159
|
+
renderDiagrams(id);};
|
|
160
|
+
nav.appendChild(b);});
|
|
161
|
+
renderDiagrams('s-model'); // initial visible tab
|
|
162
|
+
|
|
163
|
+
function tbl(cols,rows){return '<table><thead><tr>'+cols.map(c=>'<th>'+c+'</th>').join('')+'</tr></thead><tbody>'+
|
|
164
|
+
rows.map(r=>'<tr>'+r.map(c=>'<td>'+c+'</td>').join('')+'</tr>').join('')+'</tbody></table>';}
|
|
165
|
+
const code=s=>'<code>'+(s||'')+'</code>';
|
|
166
|
+
const sev=s=>'<span class="tag'+(/NON-NEGOTIABLE/.test(s)?' nn':'')+'">'+s+'</span>';
|
|
167
|
+
|
|
168
|
+
document.getElementById('t-constitution').innerHTML=tbl(['Art.','Principle','Severity'],
|
|
169
|
+
D.articles.map(a=>[a.number,a.title,sev(a.severity)]));
|
|
170
|
+
|
|
171
|
+
document.getElementById('t-squads').innerHTML=tbl(['Squad','Name','Agents','Workflows','Orchestrators'],
|
|
172
|
+
D.squads.map(s=>[code(s.id),s.name,s.agents,s.workflows,(s.orqx||[]).map(code).join(' ')||'—']));
|
|
173
|
+
|
|
174
|
+
document.getElementById('t-rules').innerHTML=tbl(['Rule','Governs'],
|
|
175
|
+
D.rules.map(r=>[code(r.id),r.title]));
|
|
176
|
+
|
|
177
|
+
// Workflows (search + source filter)
|
|
178
|
+
function renderWorkflows(){
|
|
179
|
+
const q=(document.getElementById('q-workflows').value||'').toLowerCase();
|
|
180
|
+
const src=document.getElementById('f-workflows-src').value;
|
|
181
|
+
const rows=D.workflows.filter(w=>{
|
|
182
|
+
const isFw=w.source==='framework';
|
|
183
|
+
if(src==='framework'&&!isFw)return false; if(src==='squad'&&isFw)return false;
|
|
184
|
+
return !q||(w.id+' '+w.name+' '+(w.description||'')+' '+(w.squad||'')).toLowerCase().includes(q);
|
|
185
|
+
});
|
|
186
|
+
document.getElementById('c-workflows').textContent=rows.length+' of '+D.workflows.length;
|
|
187
|
+
document.getElementById('t-workflows').innerHTML=tbl(['Workflow','Source','Type','Description'],
|
|
188
|
+
rows.map(w=>[code(w.id),w.squad?code(w.squad):'<span class="tag">framework</span>',w.type||'—',w.description||'—']));
|
|
189
|
+
}
|
|
190
|
+
['q-workflows','f-workflows-src'].forEach(id=>document.getElementById(id).addEventListener('input',renderWorkflows));
|
|
191
|
+
|
|
192
|
+
// Agents (search + squad filter + orqx toggle)
|
|
193
|
+
const squads=[...new Set(D.agents.map(a=>a.squad))].sort();
|
|
194
|
+
const sel=document.getElementById('f-agents-squad');
|
|
195
|
+
sel.innerHTML='<option value="">all squads</option>'+squads.map(s=>'<option>'+s+'</option>').join('');
|
|
196
|
+
function renderAgents(){
|
|
197
|
+
const q=(document.getElementById('q-agents').value||'').toLowerCase();
|
|
198
|
+
const sq=sel.value; const onlyOrqx=document.getElementById('f-agents-orqx').checked;
|
|
199
|
+
const rows=D.agents.filter(a=>{
|
|
200
|
+
if(sq&&a.squad!==sq)return false; if(onlyOrqx&&!a.isOrqx)return false;
|
|
201
|
+
return !q||(a.id+' '+(a.persona||'')+' '+(a.role||a.title||'')+' '+a.squad).toLowerCase().includes(q);
|
|
202
|
+
});
|
|
203
|
+
document.getElementById('c-agents').textContent=rows.length+' of '+D.agents.length;
|
|
204
|
+
document.getElementById('t-agents').innerHTML=tbl(['Agent','Persona','Squad','Role',''],
|
|
205
|
+
rows.map(a=>[code(a.id),a.persona||'—',code(a.squad),a.role||a.title||'—',a.isOrqx?'<span class="tag nn">orqx</span>':'']));
|
|
206
|
+
}
|
|
207
|
+
['q-agents','f-agents-orqx'].forEach(id=>document.getElementById(id).addEventListener('input',renderAgents));
|
|
208
|
+
sel.addEventListener('change',renderAgents);
|
|
209
|
+
|
|
210
|
+
renderWorkflows();renderAgents();
|
|
211
|
+
</script>
|
|
212
|
+
</body>
|
|
213
|
+
</html>`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = { renderAtlasHtml };
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atlas → Markdown renderer (LLM-readable).
|
|
3
|
+
*
|
|
4
|
+
* Produces a single, dense, navigable document describing how the SINAPSE
|
|
5
|
+
* framework operates — optimized to be read top-to-bottom by an LLM or a human.
|
|
6
|
+
* The narrative "operating model" sections are authored here; the catalogs
|
|
7
|
+
* (constitution, workflows, agents, squads, rules) are generated from the live
|
|
8
|
+
* atlas data so counts and lists never drift (Article VII).
|
|
9
|
+
*
|
|
10
|
+
* @module core/atlas/render-markdown
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
function h(s) {
|
|
16
|
+
return String(s == null ? '' : s).replace(/\|/g, '\\|').replace(/\r?\n/g, ' ').trim();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
20
|
+
// Operating-model narrative (authored — the connective tissue)
|
|
21
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
function operatingModel(d) {
|
|
24
|
+
const c = d.counts;
|
|
25
|
+
return `## 1. How SINAPSE works (operating model)
|
|
26
|
+
|
|
27
|
+
SINAPSE is a **meta-framework**: it does not run application code itself — it
|
|
28
|
+
orchestrates AI agents (inside Claude Code / Codex) through a governed pipeline.
|
|
29
|
+
Every user request flows through the same spine:
|
|
30
|
+
|
|
31
|
+
\`\`\`mermaid
|
|
32
|
+
flowchart TD
|
|
33
|
+
U[User briefing] --> I[Imperator · master orchestrator]
|
|
34
|
+
I -->|classify intent + project type| R{Route}
|
|
35
|
+
R -->|domain work| SQ[Squad orchestrator -orqx]
|
|
36
|
+
R -->|framework dev| FW[Framework agents pm/architect/dev/qa/...]
|
|
37
|
+
SQ --> SP[Squad specialist agent]
|
|
38
|
+
FW --> DOC[Doc-first pipeline]
|
|
39
|
+
SP --> DOC
|
|
40
|
+
DOC -->|PRD -> Epic -> Story -> Spec| GATE{{Gates}}
|
|
41
|
+
GATE -->|pass| EXEC[Implementation]
|
|
42
|
+
GATE -->|fail| BLOCK[Blocked — produce docs first]
|
|
43
|
+
EXEC --> QA[Quality gate] --> SHIP[Push / PR · devops only]
|
|
44
|
+
\`\`\`
|
|
45
|
+
|
|
46
|
+
**Two routing decisions happen up front, both deterministic in spirit:**
|
|
47
|
+
|
|
48
|
+
1. **Agent routing** — the Imperator (master \`-orqx\`) absorbs the briefing,
|
|
49
|
+
diagnoses the domain, and **delegates** to the right squad orchestrator,
|
|
50
|
+
which in turn routes to a specialist. Orchestrators never execute domain work
|
|
51
|
+
themselves (Article VIII — Mandatory Delegation). There are **${c.orqx}
|
|
52
|
+
orchestrators** (${c.squads} squad + 1 master) fronting **${c.agentsTotal}
|
|
53
|
+
agents** across **${c.squads} squads**.
|
|
54
|
+
|
|
55
|
+
2. **Model routing** — each task picks the cheapest model that solves it
|
|
56
|
+
(haiku → sonnet → opus), escalating only when needed. Documentation/spec work
|
|
57
|
+
spends the tokens; execution then just reads the finished doc (see §4).
|
|
58
|
+
|
|
59
|
+
**Documentation-First is the law** (Article III). No project reaches code without
|
|
60
|
+
its planning documents. A briefing like "build a site" is forced through:
|
|
61
|
+
|
|
62
|
+
\`\`\`
|
|
63
|
+
brief → PRD → Epic → Story (validated, status ≥ Ready) → Spec → implementation
|
|
64
|
+
\`\`\`
|
|
65
|
+
|
|
66
|
+
The pipeline produces scannable approval tables in the terminal (requirements,
|
|
67
|
+
epics, stories) and is guarded so that a brand-new project cannot start coding
|
|
68
|
+
with no PRD / epic / story. Observability: \`sinapse route "<brief>"\` prints,
|
|
69
|
+
for any project, its type → workflow → which documents are missing → whether the
|
|
70
|
+
gate is satisfied — i.e. *exactly where it is breaking*.
|
|
71
|
+
|
|
72
|
+
This atlas is itself generated by \`sinapse atlas\`; its counts are read from disk,
|
|
73
|
+
so they are always exact.`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function modelRouting() {
|
|
77
|
+
return `## 4. Model routing (cheapest model that solves it)
|
|
78
|
+
|
|
79
|
+
The token economy is a consequence of the pipeline: heavy thinking goes into the
|
|
80
|
+
PRD/spec, so execution mostly *reads a finished document* instead of reasoning.
|
|
81
|
+
|
|
82
|
+
| Task | Model | Effort |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| Cross-system architecture, complex debug, multi-file refactor | **opus** | xhigh |
|
|
85
|
+
| Spec Pipeline COMPLEX (score ≥ 16) | **opus** | max |
|
|
86
|
+
| Feature from spec, code review, bug fix, tests, stories | **sonnet** | high |
|
|
87
|
+
| Single-file analysis, factual question | **sonnet** | medium |
|
|
88
|
+
| Lint, rename, YAML, lookup, bulk | **haiku** | low |
|
|
89
|
+
|
|
90
|
+
Rule of thumb: when in doubt, drop a tier and escalate only on failure. A
|
|
91
|
+
sub-agent is only spawned for real parallel fan-out (≥ 8 tool calls), otherwise
|
|
92
|
+
work runs inline. *(Source of truth: \`.claude/rules/token-economy.md\`.)*`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
96
|
+
// Generated catalogs
|
|
97
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
function constitutionTable(d) {
|
|
100
|
+
const rows = d.articles
|
|
101
|
+
.map((a) => `| ${a.number} | ${h(a.title)} | ${h(a.severity)} |`)
|
|
102
|
+
.join('\n');
|
|
103
|
+
return `## 3. Constitution — the ${d.counts.articles} articles
|
|
104
|
+
|
|
105
|
+
Gates automatically block violations of NON-NEGOTIABLE / MUST articles.
|
|
106
|
+
*(Source of truth: \`.sinapse-ai/constitution.md\`.)*
|
|
107
|
+
|
|
108
|
+
| Art. | Principle | Severity |
|
|
109
|
+
|---|---|---|
|
|
110
|
+
${rows}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function rulesTable(d) {
|
|
114
|
+
const rows = d.rules.map((r) => `| \`${h(r.id)}\` | ${h(r.title)} |`).join('\n');
|
|
115
|
+
return `## 5. Non-negotiable rules (${d.counts.rules})
|
|
116
|
+
|
|
117
|
+
Loaded automatically by the harness. *(Source: \`.claude/rules/\`.)*
|
|
118
|
+
|
|
119
|
+
| Rule | What it governs |
|
|
120
|
+
|---|---|
|
|
121
|
+
${rows}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function workflowCatalog(d) {
|
|
125
|
+
const fw = d.workflows.filter((w) => w.source === 'framework');
|
|
126
|
+
const sq = d.workflows.filter((w) => w.source !== 'framework');
|
|
127
|
+
|
|
128
|
+
const fwRows = fw
|
|
129
|
+
.map((w) => `| \`${h(w.id)}\` | ${h(w.type) || '—'} | ${h(w.description) || '—'} |`)
|
|
130
|
+
.join('\n');
|
|
131
|
+
|
|
132
|
+
// group squad workflows by squad
|
|
133
|
+
const bySquad = {};
|
|
134
|
+
for (const w of sq) (bySquad[w.squad] = bySquad[w.squad] || []).push(w);
|
|
135
|
+
const sqRows = Object.keys(bySquad)
|
|
136
|
+
.sort()
|
|
137
|
+
.map((s) => `| \`${h(s)}\` | ${bySquad[s].map((w) => `\`${h(w.id)}\``).join(', ')} |`)
|
|
138
|
+
.join('\n');
|
|
139
|
+
|
|
140
|
+
return `## 6. Workflow catalog (${d.counts.workflowsTotal} total)
|
|
141
|
+
|
|
142
|
+
**${d.counts.frameworkWorkflows} framework workflows** + **${d.counts.squadWorkflows}
|
|
143
|
+
squad workflows**. The 13 primary framework workflows have detailed docs in
|
|
144
|
+
\`docs/sinapse-workflows/\`.
|
|
145
|
+
|
|
146
|
+
### Framework workflows (${fw.length})
|
|
147
|
+
|
|
148
|
+
| Workflow | Type | Description |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
${fwRows}
|
|
151
|
+
|
|
152
|
+
### Squad workflows (${sq.length}, grouped by squad)
|
|
153
|
+
|
|
154
|
+
| Squad | Workflows |
|
|
155
|
+
|---|---|
|
|
156
|
+
${sqRows}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function agentsSquadsMap(d) {
|
|
160
|
+
const orqxRows = d.agents
|
|
161
|
+
.filter((a) => a.isOrqx)
|
|
162
|
+
.sort((a, b) => a.squad.localeCompare(b.squad))
|
|
163
|
+
.map((a) => `| \`${h(a.id)}\` | ${h(a.persona) || '—'} | ${h(a.squad)} | ${h(a.role || a.title) || '—'} |`)
|
|
164
|
+
.join('\n');
|
|
165
|
+
|
|
166
|
+
const squadRows = d.squads
|
|
167
|
+
.map((s) => `| \`${h(s.id)}\` | ${h(s.name)} | ${s.agents} | ${s.workflows} | ${s.orqx.map((o) => `\`${h(o)}\``).join(', ') || '—'} |`)
|
|
168
|
+
.join('\n');
|
|
169
|
+
|
|
170
|
+
return `## 7. Agents & squads map
|
|
171
|
+
|
|
172
|
+
**${d.counts.agentsTotal} agents** = ${d.counts.frameworkAgents} framework +
|
|
173
|
+
${d.counts.squadAgents} squad, fronted by **${d.counts.orqx} orchestrators**.
|
|
174
|
+
|
|
175
|
+
### Orchestrators (${d.counts.orqx}) — the routing layer
|
|
176
|
+
|
|
177
|
+
| Orchestrator | Persona | Squad | Role |
|
|
178
|
+
|---|---|---|---|
|
|
179
|
+
${orqxRows}
|
|
180
|
+
|
|
181
|
+
### Squads (${d.counts.squads})
|
|
182
|
+
|
|
183
|
+
| Squad | Name | Agents | Workflows | Orchestrator(s) |
|
|
184
|
+
|---|---|---|---|---|
|
|
185
|
+
${squadRows}
|
|
186
|
+
|
|
187
|
+
> The full ${d.counts.agentsTotal}-agent index is in the generated
|
|
188
|
+
> \`atlas-data.json\` (one object per agent, with file path and role).`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
192
|
+
// Routing detail (authored §2)
|
|
193
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
194
|
+
|
|
195
|
+
function routingDetail() {
|
|
196
|
+
return `## 2. Agent routing — briefing to specialist
|
|
197
|
+
|
|
198
|
+
\`\`\`mermaid
|
|
199
|
+
sequenceDiagram
|
|
200
|
+
participant U as User
|
|
201
|
+
participant I as Imperator (master -orqx)
|
|
202
|
+
participant S as Squad -orqx
|
|
203
|
+
participant A as Specialist agent
|
|
204
|
+
U->>I: briefing (natural language)
|
|
205
|
+
I->>I: classify intent + project type (deterministic)
|
|
206
|
+
alt domain work
|
|
207
|
+
I->>S: delegate (announce plan, await go)
|
|
208
|
+
S->>A: route to specialist
|
|
209
|
+
A-->>S: artifact / result
|
|
210
|
+
S-->>I: consolidated
|
|
211
|
+
else framework dev
|
|
212
|
+
I->>A: route to framework agent (pm/architect/dev/qa)
|
|
213
|
+
end
|
|
214
|
+
I-->>U: business-language result (no internal jargon)
|
|
215
|
+
\`\`\`
|
|
216
|
+
|
|
217
|
+
Rules that make this deterministic, not improvised:
|
|
218
|
+
- **Article VIII — Mandatory Delegation:** an orchestrator that does domain work
|
|
219
|
+
itself is a constitutional violation. Even "just do it yourself" → delegate.
|
|
220
|
+
- **Auto-routing:** the user never types an agent name; the system detects the
|
|
221
|
+
domain and routes. Acknowledgement is business language, never \`@agent-id\`.
|
|
222
|
+
- **Project-type gate:** site / lp / app / platform / saas / api / service with
|
|
223
|
+
no epic → the greenfield workflow is invoked *before* any code.`;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
227
|
+
// Framework flows (authored data → diagrams)
|
|
228
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
229
|
+
|
|
230
|
+
function frameworkFlows(d) {
|
|
231
|
+
const flows = d.flows || [];
|
|
232
|
+
if (!flows.length) return '';
|
|
233
|
+
const blocks = flows
|
|
234
|
+
.map(
|
|
235
|
+
(f) => `### ${f.title}
|
|
236
|
+
|
|
237
|
+
${f.purpose}
|
|
238
|
+
|
|
239
|
+
\`\`\`mermaid
|
|
240
|
+
${f.mermaid}
|
|
241
|
+
\`\`\``,
|
|
242
|
+
)
|
|
243
|
+
.join('\n\n');
|
|
244
|
+
return `## 2b. Framework flows — how each mechanism runs
|
|
245
|
+
|
|
246
|
+
The meta-workflows of the framework itself (not the development workflows in
|
|
247
|
+
\`docs/sinapse-workflows/\`). Each is a single diagram you can read at a glance.
|
|
248
|
+
|
|
249
|
+
${blocks}`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
253
|
+
// Public
|
|
254
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Render the full LLM-readable atlas markdown from atlas data.
|
|
258
|
+
* @param {object} d - Output of buildAtlasData.
|
|
259
|
+
* @returns {string} Markdown.
|
|
260
|
+
*/
|
|
261
|
+
function renderAtlasMarkdown(d) {
|
|
262
|
+
const stamp = d.generatedAt ? `\n> Generated: ${d.generatedAt}` : '';
|
|
263
|
+
return `# SINAPSE — Framework Operating Atlas
|
|
264
|
+
|
|
265
|
+
> Single, generated map of how the SINAPSE framework works: routing, models,
|
|
266
|
+
> constitution, workflows, agents, squads. Regenerate with \`sinapse atlas\`.
|
|
267
|
+
> Counts are read from disk (Article VII — always exact).${stamp}
|
|
268
|
+
|
|
269
|
+
**At a glance:** ${d.counts.squads} squads · ${d.counts.agentsTotal} agents
|
|
270
|
+
(${d.counts.frameworkAgents} framework + ${d.counts.squadAgents} squad) ·
|
|
271
|
+
${d.counts.orqx} orchestrators · ${d.counts.workflowsTotal} workflows
|
|
272
|
+
(${d.counts.frameworkWorkflows} framework + ${d.counts.squadWorkflows} squad) ·
|
|
273
|
+
${d.counts.articles} constitutional articles · ${d.counts.rules} rules.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
${operatingModel(d)}
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
${routingDetail()}
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
${frameworkFlows(d)}
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
${constitutionTable(d)}
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
${modelRouting()}
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
${rulesTable(d)}
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
${workflowCatalog(d)}
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
${agentsSquadsMap(d)}
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
*Generated by \`.sinapse-ai/core/atlas\` · data: \`docs/framework/atlas/atlas-data.json\`.*
|
|
310
|
+
`;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
module.exports = { renderAtlasMarkdown };
|