bossbuild 0.97.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/LICENSE +21 -0
- package/PRINCIPLES.md +70 -0
- package/README.md +213 -0
- package/VERSION +1 -0
- package/bin/boss +3 -0
- package/library/README.md +19 -0
- package/library/agents/.gitkeep +0 -0
- package/library/agents/mentor-venture.md +57 -0
- package/library/hooks/.gitkeep +0 -0
- package/library/hooks/auto-log.js +133 -0
- package/library/hooks/memory-cue.js +82 -0
- package/library/hooks/secrets-guard.js +87 -0
- package/library/memory-seed/README.md +29 -0
- package/library/memory-seed/durable-facts-example.md +16 -0
- package/library/practices/.gitkeep +0 -0
- package/library/practices/agent-security.md +111 -0
- package/library/practices/ai-adoption-culture.md +104 -0
- package/library/practices/ai-ux-patterns.md +246 -0
- package/library/practices/celebration-of-done.md +100 -0
- package/library/practices/conscience-voicing.md +121 -0
- package/library/practices/context-discipline.md +116 -0
- package/library/practices/design-system.md +152 -0
- package/library/practices/git-workflow.md +119 -0
- package/library/practices/harm-taxonomy.md +45 -0
- package/library/practices/quality-ratchet.md +48 -0
- package/library/practices/revalidation.md +57 -0
- package/library/practices/scalable-architecture.md +111 -0
- package/library/practices/ship-it-live.md +149 -0
- package/library/practices/skill-authoring.md +70 -0
- package/library/skills/.gitkeep +0 -0
- package/library/skills/boss-learn/SKILL.md +63 -0
- package/library/skills/boss-sync/SKILL.md +48 -0
- package/package.json +49 -0
- package/registry/CHANGELOG.md +2737 -0
- package/src/board.js +655 -0
- package/src/brain.js +288 -0
- package/src/cli.js +542 -0
- package/src/conscience.js +426 -0
- package/src/insights.js +147 -0
- package/src/learn.js +92 -0
- package/src/map.js +103 -0
- package/src/modes.js +82 -0
- package/src/paths.js +36 -0
- package/src/registry.js +34 -0
- package/src/scaffold.js +138 -0
- package/src/sync.js +292 -0
- package/src/team.js +103 -0
- package/stages/L0-quickstart/manifest.json +12 -0
- package/stages/L0-quickstart/template/.claude/agents/coder-generalist.md +31 -0
- package/stages/L0-quickstart/template/.claude/agents/mentor-venture.md +57 -0
- package/stages/L0-quickstart/template/.claude/agents/pm.md +28 -0
- package/stages/L0-quickstart/template/.claude/hooks/conscience.js +89 -0
- package/stages/L0-quickstart/template/.claude/hooks/lib/loop-runtime.js +507 -0
- package/stages/L0-quickstart/template/.claude/hooks/lib/yaml.js +163 -0
- package/stages/L0-quickstart/template/.claude/hooks/memory-cue.js +82 -0
- package/stages/L0-quickstart/template/.claude/hooks/secrets-guard.js +87 -0
- package/stages/L0-quickstart/template/.claude/rules/your-app-code.md +17 -0
- package/stages/L0-quickstart/template/.claude/settings.json +36 -0
- package/stages/L0-quickstart/template/.claude/skills/boss/SKILL.md +161 -0
- package/stages/L0-quickstart/template/.claude/skills/boss-learn/SKILL.md +63 -0
- package/stages/L0-quickstart/template/.claude/skills/boss-sync/SKILL.md +55 -0
- package/stages/L0-quickstart/template/.claude/skills/canvas/SKILL.md +112 -0
- package/stages/L0-quickstart/template/.claude/skills/comprehend/SKILL.md +72 -0
- package/stages/L0-quickstart/template/.claude/skills/decide/SKILL.md +122 -0
- package/stages/L0-quickstart/template/.claude/skills/feedback/SKILL.md +68 -0
- package/stages/L0-quickstart/template/.claude/skills/import/SKILL.md +73 -0
- package/stages/L0-quickstart/template/.claude/skills/persona/SKILL.md +92 -0
- package/stages/L0-quickstart/template/.claude/skills/prototype/SKILL.md +114 -0
- package/stages/L0-quickstart/template/.claude/skills/triage/SKILL.md +104 -0
- package/stages/L0-quickstart/template/.claude/skills/welcome/SKILL.md +262 -0
- package/stages/L0-quickstart/template/AGENTS.md +31 -0
- package/stages/L0-quickstart/template/CLAUDE.md +57 -0
- package/stages/L0-quickstart/template/docs/IDS.md +42 -0
- package/stages/L0-quickstart/template/docs/ideas/INDEX.md +24 -0
- package/stages/L0-quickstart/template/docs/loops/canvas-loop.md +90 -0
- package/stages/L0-quickstart/template/docs/loops/capture-loop.md +64 -0
- package/stages/L1-mvp/manifest.json +12 -0
- package/stages/L1-mvp/template/.claude/agents/mentor-architect.md +124 -0
- package/stages/L1-mvp/template/.claude/agents/mentor-cofounder.md +85 -0
- package/stages/L1-mvp/template/.claude/agents/mentor-gtm.md +49 -0
- package/stages/L1-mvp/template/.claude/agents/program-manager.md +46 -0
- package/stages/L1-mvp/template/.claude/agents/tester.md +42 -0
- package/stages/L1-mvp/template/.claude/hooks/auto-log.js +133 -0
- package/stages/L1-mvp/template/.claude/rules/feature-context.md +18 -0
- package/stages/L1-mvp/template/.claude/skills/ai-cost/SKILL.md +249 -0
- package/stages/L1-mvp/template/.claude/skills/ai-failure-states/SKILL.md +226 -0
- package/stages/L1-mvp/template/.claude/skills/ai-first-init/SKILL.md +227 -0
- package/stages/L1-mvp/template/.claude/skills/close/SKILL.md +170 -0
- package/stages/L1-mvp/template/.claude/skills/consult/SKILL.md +72 -0
- package/stages/L1-mvp/template/.claude/skills/cost-review/SKILL.md +204 -0
- package/stages/L1-mvp/template/.claude/skills/design-tokens-init/SKILL.md +192 -0
- package/stages/L1-mvp/template/.claude/skills/drift-deep/SKILL.md +170 -0
- package/stages/L1-mvp/template/.claude/skills/evals/SKILL.md +154 -0
- package/stages/L1-mvp/template/.claude/skills/extract/SKILL.md +209 -0
- package/stages/L1-mvp/template/.claude/skills/judge-traces/SKILL.md +68 -0
- package/stages/L1-mvp/template/.claude/skills/log/SKILL.md +64 -0
- package/stages/L1-mvp/template/.claude/skills/practice/SKILL.md +92 -0
- package/stages/L1-mvp/template/.claude/skills/pretotype/SKILL.md +95 -0
- package/stages/L1-mvp/template/.claude/skills/red-team/SKILL.md +137 -0
- package/stages/L1-mvp/template/.claude/skills/revalidate/SKILL.md +51 -0
- package/stages/L1-mvp/template/.claude/skills/ship/SKILL.md +105 -0
- package/stages/L1-mvp/template/.claude/skills/smoke/SKILL.md +43 -0
- package/stages/L1-mvp/template/.claude/skills/spec/SKILL.md +145 -0
- package/stages/L1-mvp/template/claude-append.md +122 -0
- package/stages/L1-mvp/template/docs/loops/ai-failure-state-loop.md +107 -0
- package/stages/L1-mvp/template/docs/loops/coordination-loop.md +116 -0
- package/stages/L1-mvp/template/docs/loops/cost-budget-loop.md +117 -0
- package/stages/L1-mvp/template/docs/loops/cost-review-loop.md +113 -0
- package/stages/L1-mvp/template/docs/loops/design-tokens-loop.md +98 -0
- package/stages/L1-mvp/template/docs/loops/drift-loop.md +149 -0
- package/stages/L1-mvp/template/docs/loops/extraction-loop.md +128 -0
- package/stages/L1-mvp/template/docs/loops/focus-loop.md +106 -0
- package/stages/L1-mvp/template/docs/loops/pretotype-loop.md +88 -0
- package/stages/L1-mvp/template/docs/loops/spec-loop.md +83 -0
- package/stages/L2-v1/manifest.json +12 -0
- package/stages/L2-v1/template/.claude/agents/db-architect.md +91 -0
- package/stages/L2-v1/template/.claude/agents/mentor-business.md +124 -0
- package/stages/L2-v1/template/.claude/agents/mentor-fundraising.md +72 -0
- package/stages/L2-v1/template/.claude/agents/mentor-pitch.md +84 -0
- package/stages/L2-v1/template/.claude/agents/mentor-talent.md +84 -0
- package/stages/L2-v1/template/.claude/agents/ui-designer.md +81 -0
- package/stages/L2-v1/template/.claude/agents/ux-designer.md +87 -0
- package/stages/L2-v1/template/.claude/skills/board/SKILL.md +98 -0
- package/stages/L2-v1/template/.claude/skills/design-review/SKILL.md +77 -0
- package/stages/L2-v1/template/.claude/skills/ux-check/SKILL.md +93 -0
- package/stages/L2-v1/template/claude-append.md +59 -0
- package/stages/L2-v1/template/docs/loops/design-drift-loop.md +108 -0
- package/stages/L3-scale/README.md +13 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// Minimal YAML parser for the BOSS loop-runtime — zero deps.
|
|
2
|
+
// Covers the subset used by loop specs and eval files:
|
|
3
|
+
// - top-level sequence (- item) or mapping
|
|
4
|
+
// - block mappings (key: value with indented children)
|
|
5
|
+
// - inline mappings ({k: v, k2: v2})
|
|
6
|
+
// - inline sequences ([a, b, c])
|
|
7
|
+
// - scalars: bare string, quoted string, int, true/false, null
|
|
8
|
+
// - comments (# ...) and blank lines
|
|
9
|
+
// NOT supported: anchors, aliases, multi-line scalars, flow-style mixing.
|
|
10
|
+
// Lifted from docs/architecture/conscience-evals/runner.js so the same parser
|
|
11
|
+
// is available to the project-side hook.
|
|
12
|
+
|
|
13
|
+
export function parseYaml(text) {
|
|
14
|
+
const tokens = tokenize(text);
|
|
15
|
+
if (tokens.length === 0) return null;
|
|
16
|
+
const baseIndent = tokens[0].indent;
|
|
17
|
+
const [result] = parseBlock(tokens, 0, baseIndent);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Extract YAML frontmatter from a markdown file (between leading `---` and `---`).
|
|
22
|
+
// Returns the parsed object, or null if no frontmatter is present.
|
|
23
|
+
export function parseFrontmatter(text) {
|
|
24
|
+
if (!text.startsWith('---\n')) return null;
|
|
25
|
+
const end = text.indexOf('\n---\n', 4);
|
|
26
|
+
if (end < 0) return null;
|
|
27
|
+
return parseYaml(text.slice(4, end));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function parseScalar(s) {
|
|
31
|
+
s = s.trim();
|
|
32
|
+
if (s === '' || s === '~' || s === 'null') return null;
|
|
33
|
+
if (s === 'true') return true;
|
|
34
|
+
if (s === 'false') return false;
|
|
35
|
+
if (/^-?\d+$/.test(s)) return parseInt(s, 10);
|
|
36
|
+
if (/^-?\d+\.\d+$/.test(s)) return parseFloat(s);
|
|
37
|
+
if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
|
|
38
|
+
return s.slice(1, -1);
|
|
39
|
+
}
|
|
40
|
+
if (s.startsWith('[') && s.endsWith(']')) {
|
|
41
|
+
const inner = s.slice(1, -1).trim();
|
|
42
|
+
if (!inner) return [];
|
|
43
|
+
return splitTopLevel(inner, ',').map((p) => parseScalar(p));
|
|
44
|
+
}
|
|
45
|
+
if (s.startsWith('{') && s.endsWith('}')) {
|
|
46
|
+
const inner = s.slice(1, -1).trim();
|
|
47
|
+
if (!inner) return {};
|
|
48
|
+
const obj = {};
|
|
49
|
+
for (const pair of splitTopLevel(inner, ',')) {
|
|
50
|
+
const colonIdx = findTopLevelChar(pair, ':');
|
|
51
|
+
if (colonIdx < 0) continue;
|
|
52
|
+
const k = pair.slice(0, colonIdx).trim();
|
|
53
|
+
const v = pair.slice(colonIdx + 1).trim();
|
|
54
|
+
obj[k] = parseScalar(v);
|
|
55
|
+
}
|
|
56
|
+
return obj;
|
|
57
|
+
}
|
|
58
|
+
return s;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function splitTopLevel(s, sep) {
|
|
62
|
+
const parts = [];
|
|
63
|
+
let depth = 0;
|
|
64
|
+
let inQuote = null;
|
|
65
|
+
let start = 0;
|
|
66
|
+
for (let i = 0; i < s.length; i++) {
|
|
67
|
+
const c = s[i];
|
|
68
|
+
if (inQuote) { if (c === inQuote) inQuote = null; continue; }
|
|
69
|
+
if (c === '"' || c === "'") { inQuote = c; continue; }
|
|
70
|
+
if (c === '[' || c === '{') depth++;
|
|
71
|
+
else if (c === ']' || c === '}') depth--;
|
|
72
|
+
else if (c === sep && depth === 0) {
|
|
73
|
+
parts.push(s.slice(start, i));
|
|
74
|
+
start = i + 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
parts.push(s.slice(start));
|
|
78
|
+
return parts.map((p) => p.trim()).filter((p) => p.length > 0);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function findTopLevelChar(s, ch) {
|
|
82
|
+
let depth = 0;
|
|
83
|
+
let inQuote = null;
|
|
84
|
+
for (let i = 0; i < s.length; i++) {
|
|
85
|
+
const c = s[i];
|
|
86
|
+
if (inQuote) { if (c === inQuote) inQuote = null; continue; }
|
|
87
|
+
if (c === '"' || c === "'") { inQuote = c; continue; }
|
|
88
|
+
if (c === '[' || c === '{') depth++;
|
|
89
|
+
else if (c === ']' || c === '}') depth--;
|
|
90
|
+
else if (c === ch && depth === 0) return i;
|
|
91
|
+
}
|
|
92
|
+
return -1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function indentOf(line) {
|
|
96
|
+
let i = 0;
|
|
97
|
+
while (i < line.length && line[i] === ' ') i++;
|
|
98
|
+
return i;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function tokenize(text) {
|
|
102
|
+
return text.split('\n')
|
|
103
|
+
.map((line, i) => ({ raw: line, lineNum: i + 1 }))
|
|
104
|
+
.filter((t) => t.raw.trim().length > 0 && !t.raw.trim().startsWith('#'))
|
|
105
|
+
.map((t) => ({ ...t, indent: indentOf(t.raw), body: t.raw.trim() }));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function parseBlock(tokens, startIdx, indent) {
|
|
109
|
+
if (startIdx >= tokens.length) return [null, startIdx];
|
|
110
|
+
const first = tokens[startIdx];
|
|
111
|
+
if (first.indent < indent) return [null, startIdx];
|
|
112
|
+
|
|
113
|
+
if (first.body.startsWith('- ')) {
|
|
114
|
+
const arr = [];
|
|
115
|
+
let i = startIdx;
|
|
116
|
+
while (i < tokens.length && tokens[i].indent === indent && tokens[i].body.startsWith('- ')) {
|
|
117
|
+
const itemBody = tokens[i].body.slice(2);
|
|
118
|
+
const colonIdx = findTopLevelChar(itemBody, ':');
|
|
119
|
+
if (colonIdx >= 0 && !itemBody.startsWith('{') && !itemBody.startsWith('[')) {
|
|
120
|
+
const syntheticTokens = [...tokens];
|
|
121
|
+
const key = itemBody.slice(0, colonIdx).trim();
|
|
122
|
+
const val = itemBody.slice(colonIdx + 1).trim();
|
|
123
|
+
syntheticTokens[i] = { ...tokens[i], indent: indent + 2, body: `${key}: ${val}` };
|
|
124
|
+
const [obj, nextIdx] = parseMapping(syntheticTokens, i, indent + 2);
|
|
125
|
+
arr.push(obj);
|
|
126
|
+
i = nextIdx;
|
|
127
|
+
} else {
|
|
128
|
+
arr.push(parseScalar(itemBody));
|
|
129
|
+
i++;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return [arr, i];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return parseMapping(tokens, startIdx, indent);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function parseMapping(tokens, startIdx, indent) {
|
|
139
|
+
const obj = {};
|
|
140
|
+
let i = startIdx;
|
|
141
|
+
while (i < tokens.length && tokens[i].indent === indent && !tokens[i].body.startsWith('- ')) {
|
|
142
|
+
const line = tokens[i].body;
|
|
143
|
+
const colonIdx = findTopLevelChar(line, ':');
|
|
144
|
+
if (colonIdx < 0) { i++; continue; }
|
|
145
|
+
const key = line.slice(0, colonIdx).trim();
|
|
146
|
+
const valStr = line.slice(colonIdx + 1).trim();
|
|
147
|
+
if (valStr) {
|
|
148
|
+
obj[key] = parseScalar(valStr);
|
|
149
|
+
i++;
|
|
150
|
+
} else {
|
|
151
|
+
const childIndent = i + 1 < tokens.length ? tokens[i + 1].indent : indent;
|
|
152
|
+
if (childIndent > indent) {
|
|
153
|
+
const [child, next] = parseBlock(tokens, i + 1, childIndent);
|
|
154
|
+
obj[key] = child;
|
|
155
|
+
i = next;
|
|
156
|
+
} else {
|
|
157
|
+
obj[key] = null;
|
|
158
|
+
i++;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return [obj, i];
|
|
163
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// BOSS memory-cue — a UserPromptSubmit hook (OPT-IN; zero-cost when silent).
|
|
3
|
+
//
|
|
4
|
+
// Ported UP from the dhun dogfood (Principle #1). dhun's was bash+jq; BOSS is
|
|
5
|
+
// zero-dependency (Node built-ins only), so this is the Node port.
|
|
6
|
+
//
|
|
7
|
+
// WHAT IT DOES: scans the founder's prompt for a *feedback signal* — durable
|
|
8
|
+
// guidance worth remembering across sessions — and NUDGES the model to save it
|
|
9
|
+
// to the project's memory. It never writes the memory itself: choosing the right
|
|
10
|
+
// wording (and whether it's durable vs. ephemeral) needs reasoning, so the cue
|
|
11
|
+
// hands that judgment back to the model. Silent on no match → zero token cost.
|
|
12
|
+
//
|
|
13
|
+
// directive "from now on", "always", "never", "stop doing", "going forward"
|
|
14
|
+
// corrective "no, don't", "that's wrong", "that's not right"
|
|
15
|
+
// confirmation "perfect, keep doing", "yes exactly", "nailed it"
|
|
16
|
+
//
|
|
17
|
+
// WHY OPT-IN (read before registering): a UserPromptSubmit hook fires a process
|
|
18
|
+
// on EVERY prompt. It's cheap (silent unless a pattern matches) but it is still
|
|
19
|
+
// machinery — ship it dormant, let the founder turn it on when they want BOSS to
|
|
20
|
+
// help build durable memory. (PRINCIPLE #2 / R&H #1 cost discipline.)
|
|
21
|
+
//
|
|
22
|
+
// TO TURN IT ON — add a UserPromptSubmit hook entry in .claude/settings.json
|
|
23
|
+
// (the registration IS the on-switch; an unregistered script costs nothing).
|
|
24
|
+
// It coexists with the conscience hook on the same event:
|
|
25
|
+
// "hooks": {
|
|
26
|
+
// "UserPromptSubmit": [
|
|
27
|
+
// { "matcher": "",
|
|
28
|
+
// "hooks": [ { "type": "command",
|
|
29
|
+
// "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/memory-cue.js\"",
|
|
30
|
+
// "timeout": 5 } ] }
|
|
31
|
+
// ]
|
|
32
|
+
// }
|
|
33
|
+
//
|
|
34
|
+
// Output contract (Claude Code UserPromptSubmit): text on stdout is added to the
|
|
35
|
+
// session context. Fail-open: any parse/runtime surprise exits 0 silently — a
|
|
36
|
+
// hook that breaks the session is worse than one that occasionally misses a cue.
|
|
37
|
+
|
|
38
|
+
import process from 'node:process';
|
|
39
|
+
|
|
40
|
+
const DIRECTIVE = /\b(from now on|going forward|always|never|stop doing|don'?t ever|remember (that|this)|every time|whenever|in (the )?future)\b/i;
|
|
41
|
+
const CORRECTIVE = /\bno,? (don'?t|stop|never|wrong)\b|\bthat'?s (not right|wrong)\b|\bdon'?t do that\b/i;
|
|
42
|
+
const CONFIRM = /\bperfect,? keep\b|\byes,? exactly\b|\bexactly,? that\b|\bthat'?s right,? keep\b|\bnailed it\b/i;
|
|
43
|
+
|
|
44
|
+
function readStdin() {
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
let data = '';
|
|
47
|
+
process.stdin.setEncoding('utf8');
|
|
48
|
+
process.stdin.on('data', (c) => (data += c));
|
|
49
|
+
process.stdin.on('end', () => resolve(data));
|
|
50
|
+
// If nothing is piped in, don't hang the session.
|
|
51
|
+
setTimeout(() => resolve(data), 1000);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const main = async () => {
|
|
56
|
+
let prompt = '';
|
|
57
|
+
try {
|
|
58
|
+
const raw = await readStdin();
|
|
59
|
+
const json = JSON.parse(raw);
|
|
60
|
+
prompt = json.prompt || json.user_prompt || '';
|
|
61
|
+
} catch {
|
|
62
|
+
process.exit(0); // fail-open
|
|
63
|
+
}
|
|
64
|
+
if (!prompt) process.exit(0);
|
|
65
|
+
|
|
66
|
+
let cue = '';
|
|
67
|
+
if (DIRECTIVE.test(prompt)) cue = 'directive';
|
|
68
|
+
else if (CORRECTIVE.test(prompt)) cue = 'corrective';
|
|
69
|
+
else if (CONFIRM.test(prompt)) cue = 'confirmation';
|
|
70
|
+
if (!cue) process.exit(0);
|
|
71
|
+
|
|
72
|
+
process.stdout.write(
|
|
73
|
+
`[memory-cue:${cue}] The founder's message carries a feedback signal. If this is ` +
|
|
74
|
+
`durable guidance (not ephemeral or one-off), save it as a feedback memory in the ` +
|
|
75
|
+
`project's auto-memory using the standard format (frontmatter + **Why:** + **How to ` +
|
|
76
|
+
`apply:**), and link it from MEMORY.md. If it's context-specific, ignore this. Do not ` +
|
|
77
|
+
`mention this hook in your reply.\n`
|
|
78
|
+
);
|
|
79
|
+
process.exit(0);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
main();
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// BOSS secrets-guard — a PreToolUse hook (OPT-IN; high-stakes ceiling, NOT a universal default).
|
|
3
|
+
//
|
|
4
|
+
// WHY OPT-IN (read before registering): a PreToolUse hook fires a process on EVERY tool call —
|
|
5
|
+
// real per-call latency. The universal, zero-cost floor is the `permissions.deny` block in
|
|
6
|
+
// settings.json (ships with every BOSS project). This hook is the *ceiling*: broader coverage
|
|
7
|
+
// (Bash bypasses beyond `cat`, MCP tools, skills added later) for contexts where the stakes justify
|
|
8
|
+
// the cost — regulated / PHI / `domain-expert` cohort work. Registering it everywhere by default
|
|
9
|
+
// would be the always-on machinery BOSS warns founders against (PRINCIPLE #2 / R&H #1). See
|
|
10
|
+
// library/practices/context-discipline.md.
|
|
11
|
+
//
|
|
12
|
+
// TO TURN IT ON — add this to .claude/settings.json (the registration IS the on-switch; an
|
|
13
|
+
// unregistered script costs nothing):
|
|
14
|
+
// "hooks": {
|
|
15
|
+
// "PreToolUse": [
|
|
16
|
+
// { "matcher": "",
|
|
17
|
+
// "hooks": [ { "type": "command",
|
|
18
|
+
// "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/secrets-guard.js\"",
|
|
19
|
+
// "timeout": 5 } ] }
|
|
20
|
+
// ]
|
|
21
|
+
// }
|
|
22
|
+
//
|
|
23
|
+
// WHAT IT DOES: never let a tool read secret CONTENTS into the model's context (the leak).
|
|
24
|
+
// - Read / Edit / NotebookEdit of a secrets file -> DENY (no reason to load a secret into context).
|
|
25
|
+
// - Bash command referencing a secrets path -> ASK (don't hard-block legit `.env` *creation*;
|
|
26
|
+
// surface it to the human instead).
|
|
27
|
+
// - MCP tool call whose input references a secret -> ASK (unknown semantics; let the human judge).
|
|
28
|
+
// - everything else -> ALLOW.
|
|
29
|
+
// Fail-open: any parse/runtime surprise exits 0 (allow). A guard that breaks the session is worse
|
|
30
|
+
// than one that occasionally misses — the deny-list floor still hard-blocks the common vectors.
|
|
31
|
+
//
|
|
32
|
+
// Output contract (Claude Code PreToolUse): JSON on stdout with a permissionDecision, exit 0.
|
|
33
|
+
|
|
34
|
+
import fs from 'node:fs';
|
|
35
|
+
|
|
36
|
+
// A path is "secret" if its basename is .env / .env.<suffix>, or it sits under a secrets/ segment.
|
|
37
|
+
const SECRET_RE = /(^|[\/\s'"=:])\.env(\.[\w.-]+)?($|[\/\s'"])|(^|[\/\s'"=:])secrets\//i;
|
|
38
|
+
|
|
39
|
+
const touchesSecret = (s) => typeof s === 'string' && SECRET_RE.test(s);
|
|
40
|
+
|
|
41
|
+
const decide = (decision, reason) => {
|
|
42
|
+
process.stdout.write(JSON.stringify({
|
|
43
|
+
hookSpecificOutput: {
|
|
44
|
+
hookEventName: 'PreToolUse',
|
|
45
|
+
permissionDecision: decision, // "deny" | "ask"
|
|
46
|
+
permissionDecisionReason: reason,
|
|
47
|
+
},
|
|
48
|
+
}));
|
|
49
|
+
process.exit(0);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
let event;
|
|
53
|
+
try {
|
|
54
|
+
event = JSON.parse(fs.readFileSync(0, 'utf8') || '{}');
|
|
55
|
+
} catch {
|
|
56
|
+
process.exit(0); // fail-open: unreadable/!JSON input -> allow
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const tool = event.tool_name || '';
|
|
60
|
+
const input = event.tool_input || {};
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
if (/^(Read|Edit|NotebookEdit)$/.test(tool)) {
|
|
64
|
+
const p = input.file_path || input.notebook_path || '';
|
|
65
|
+
if (touchesSecret(p)) {
|
|
66
|
+
decide('deny',
|
|
67
|
+
`secrets-guard: refusing to ${tool} a secrets file (${p}). Reading secret contents into ` +
|
|
68
|
+
`context risks leakage. Read secrets from the environment at runtime, or use a secret manager.`);
|
|
69
|
+
}
|
|
70
|
+
} else if (tool === 'Bash') {
|
|
71
|
+
if (touchesSecret(input.command || '')) {
|
|
72
|
+
decide('ask',
|
|
73
|
+
`secrets-guard: this Bash command references a secrets path. Approve only if it does NOT ` +
|
|
74
|
+
`read secret contents into the session (e.g. creating/appending a .env is fine; cat/grep is not).`);
|
|
75
|
+
}
|
|
76
|
+
} else if (tool.startsWith('mcp__')) {
|
|
77
|
+
if (touchesSecret(JSON.stringify(input))) {
|
|
78
|
+
decide('ask',
|
|
79
|
+
`secrets-guard: this MCP tool call references a secrets path. Approve only if it will not ` +
|
|
80
|
+
`expose secret contents to the session.`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
process.exit(0); // fail-open on any matching error
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
process.exit(0); // allow everything else
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "src/**"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- This file loads into context ONLY when Claude opens a file under src/ — never at session start.
|
|
7
|
+
That's the whole point: keep app-code conventions here (just-in-time), keep CLAUDE.md for what's
|
|
8
|
+
true all the time. Rescope the paths: glob above to wherever your code actually lives — or delete
|
|
9
|
+
this file if you don't need it yet. A rule with no paths: would load every session, like CLAUDE.md. -->
|
|
10
|
+
|
|
11
|
+
# Working context — {{PROJECT_NAME}} app code
|
|
12
|
+
|
|
13
|
+
_Conventions that only matter while writing the app. Replace the examples with your real ones, or
|
|
14
|
+
delete what you don't need._
|
|
15
|
+
|
|
16
|
+
- (example) One responsibility per file; split a module before it grows a second reason to change.
|
|
17
|
+
- (example) Validate input at the boundary, not deep in the call stack.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"defaultMode": "auto",
|
|
4
|
+
"allow": [
|
|
5
|
+
"Read",
|
|
6
|
+
"Edit",
|
|
7
|
+
"Write",
|
|
8
|
+
"Glob",
|
|
9
|
+
"Grep",
|
|
10
|
+
"Bash",
|
|
11
|
+
"Agent",
|
|
12
|
+
"TodoWrite"
|
|
13
|
+
],
|
|
14
|
+
"deny": [
|
|
15
|
+
"Read(./.env)",
|
|
16
|
+
"Read(./.env.*)",
|
|
17
|
+
"Read(./secrets/**)",
|
|
18
|
+
"Bash(cat ./.env*)",
|
|
19
|
+
"Bash(cat ./secrets/*)"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
"hooks": {
|
|
23
|
+
"UserPromptSubmit": [
|
|
24
|
+
{
|
|
25
|
+
"matcher": "",
|
|
26
|
+
"hooks": [
|
|
27
|
+
{
|
|
28
|
+
"type": "command",
|
|
29
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/conscience.js\"",
|
|
30
|
+
"timeout": 5
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: boss
|
|
3
|
+
description: Spin up a freshly-scaffolded project from a rough idea or PRD. Reads the idea, shapes it through the pm lens, captures it as an IDEA, recommends a stack and starting stage, and (with your OK) creates a private GitHub repo with the right license. Run this right after `boss new`. Usage - /boss [path-to-PRD | rough idea text]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /boss — project spin-up
|
|
7
|
+
|
|
8
|
+
You are the spin-up conductor for a project scaffolded by BlueprintOS. Turn a rough idea or PRD
|
|
9
|
+
into a shaped, captured, optionally-published starting point. Move fast, ask little, keep scope small.
|
|
10
|
+
|
|
11
|
+
## 0. Orient (silent)
|
|
12
|
+
|
|
13
|
+
Read, in order:
|
|
14
|
+
- `.boss/manifest.json` — current stage + installed agents/skills.
|
|
15
|
+
- `.boss/config.json` — user defaults (`github`, `visibility`, `license`).
|
|
16
|
+
- `CLAUDE.md` — the project's working rules.
|
|
17
|
+
- `docs/ideas/INDEX.md` and `docs/IDS.md` — where ideas land + the next free `IDEA-NNN`.
|
|
18
|
+
|
|
19
|
+
Don't announce these reads. Just orient.
|
|
20
|
+
|
|
21
|
+
## 1. Get the idea (bring-your-own-material)
|
|
22
|
+
|
|
23
|
+
The idea may already exist somewhere — a Word doc, a Google Doc, an Obsidian note, a PDF, a slide
|
|
24
|
+
deck, a URL — not just a tidy PRD. **Pull it in; don't make the founder retype it.**
|
|
25
|
+
|
|
26
|
+
- **One-or-more sources.** Accept anything the founder points at, in any mix:
|
|
27
|
+
- **Local files** — `.md`, `.txt`, `.pdf` (read it), `.docx` (extract the text), Obsidian notes,
|
|
28
|
+
slide decks. Read each directly.
|
|
29
|
+
- **URLs** — a Google Doc share link, a published doc, an online reference. Fetch each.
|
|
30
|
+
- **Pasted/typed text** — use as-is.
|
|
31
|
+
- **Nothing given** — ask **one** open question: *"What are you building? Point me at it — a
|
|
32
|
+
sentence, a file path, a URL, or a few of them (a doc, a deck, a link). I'll pull them in."*
|
|
33
|
+
- **Snapshot what you read (the "create a dupe" step).** For each file or URL you ingest, write a
|
|
34
|
+
durable copy into `docs/source/` (create it if absent) — e.g. `docs/source/<original-name>` for a
|
|
35
|
+
file, or `docs/source/<slug>.md` capturing fetched text with the URL noted at the top. The project
|
|
36
|
+
should **own** the material so the idea survives if the original moves or changes. Mention briefly
|
|
37
|
+
what you pulled in (e.g. *"Pulled in 2 sources → docs/source/."*). Don't snapshot pasted one-liners.
|
|
38
|
+
- **Synthesize across all of them.** If several sources were given, read them all before shaping —
|
|
39
|
+
they're facets of one idea, not separate ideas. Treat a one-liner as complete; ask a clarifying
|
|
40
|
+
question only if genuinely blocked.
|
|
41
|
+
|
|
42
|
+
> If the founder is mid-flow and wants to *add* material to an already-captured idea later, that's
|
|
43
|
+
> `/import` — same ingest, pointed at an existing `IDEA-NNN`.
|
|
44
|
+
|
|
45
|
+
## 2. Shape it (pm lens)
|
|
46
|
+
|
|
47
|
+
In 3-5 lines back to the user, reflect:
|
|
48
|
+
- **What** it is, in plain language.
|
|
49
|
+
- **Who** it's for.
|
|
50
|
+
- **The smallest version that proves it** (the L0/L1 target — not the full vision).
|
|
51
|
+
- If the idea clearly spans multiple features, name them but don't over-plan.
|
|
52
|
+
|
|
53
|
+
## 3. Capture it
|
|
54
|
+
|
|
55
|
+
Append an entry to `docs/ideas/INDEX.md` and create `docs/ideas/IDEA-001-<slug>.md` with frontmatter
|
|
56
|
+
(`id`, `type: idea`, `owner: pm`, `status: ready`). Record what/why/scope/next-step. This is the
|
|
57
|
+
"idea is shared" moment that gates GitHub creation (step 5).
|
|
58
|
+
|
|
59
|
+
## 4. Stack + stage
|
|
60
|
+
|
|
61
|
+
- **Stack:** If the idea implies a stack (web app, CLI, mobile, backend service), propose it in one
|
|
62
|
+
line and, on agreement, record the decision in the IDEA doc and specialize
|
|
63
|
+
`.claude/agents/coder-generalist.md` (fill in its build/test/run commands). If unclear, stay
|
|
64
|
+
stack-neutral and say the decision is pending the first build step. Never silently assume a stack.
|
|
65
|
+
- **Mode:** Default is Quickstart (L0). If the PRD is rich and clearly a real product to build now,
|
|
66
|
+
*recommend* `boss unlock mvp` (specs + `/smoke` gate) — but don't run it for them; suggest the command.
|
|
67
|
+
- **AI-native check (v0.26.0+):** If the idea names the model as load-bearing (the product
|
|
68
|
+
doesn't work without it — a chatbot, a copilot, an LLM-pipeline, a generation tool, a
|
|
69
|
+
RAG-mediated product), name it explicitly back to the founder: *"This sounds AI-native —
|
|
70
|
+
the model is doing the work, not just polishing it."* Then **recommend the AI-first sequence**:
|
|
71
|
+
*"After `boss unlock mvp`, run `/ai-first-init` — it bakes in cost discipline, eval discipline,
|
|
72
|
+
structured outputs, and failure-state design from day one. Cheaper to declare upfront than
|
|
73
|
+
to retrofit after the first bill, the first hallucination, or the first refusal in front of
|
|
74
|
+
a user."* Don't run anything for them; the recommendation is the artifact.
|
|
75
|
+
|
|
76
|
+
## 5. GitHub repo (the gated step)
|
|
77
|
+
|
|
78
|
+
Read `github` from `.boss/config.json`:
|
|
79
|
+
- `never` → skip.
|
|
80
|
+
- `ask` (default) → prompt: *"Spin up a **private** GitHub repo for this? I'll add a LICENSE —
|
|
81
|
+
default is **proprietary / All Rights Reserved** so you keep both paid and open-source options open
|
|
82
|
+
(you can relicense later). Say 'open source' if you'd rather pick MIT / Apache-2.0 / AGPL-3.0 now."*
|
|
83
|
+
- `always` → proceed with the configured `visibility` + `license` without asking.
|
|
84
|
+
|
|
85
|
+
On a yes, do this **in order**:
|
|
86
|
+
|
|
87
|
+
1. **Write the LICENSE file locally** (must exist before push — `gh` won't add it to an existing repo):
|
|
88
|
+
- `proprietary` (default): write the All-Rights-Reserved text from the appendix below, filling the year and the user's name.
|
|
89
|
+
- `MIT` / `Apache-2.0` / `AGPL-3.0`: fetch canonical text with
|
|
90
|
+
`gh api /licenses/<key> --jq .body` (keys: `mit`, `apache-2.0`, `agpl-3.0`) and fill placeholders.
|
|
91
|
+
2. **Prevent the email-privacy block (GH007).** Derive the user's GitHub noreply address and set it
|
|
92
|
+
**repo-locally only** (global config untouched), then tell the user you did so:
|
|
93
|
+
```bash
|
|
94
|
+
NR=$(gh api user --jq '"\(.id)+\(.login)@users.noreply.github.com"')
|
|
95
|
+
git -C . config user.email "$NR"
|
|
96
|
+
```
|
|
97
|
+
3. **Commit** the scaffold (include LICENSE) if there are uncommitted files.
|
|
98
|
+
4. **Create + push** as a private repo from the existing local repo:
|
|
99
|
+
```bash
|
|
100
|
+
gh repo create <project-name> --private --source . --remote origin --push
|
|
101
|
+
```
|
|
102
|
+
(`--source .` publishes the local history; do NOT pass `--license`/`--gitignore` here — those only
|
|
103
|
+
apply to empty repos created server-side, which would conflict with the local history.)
|
|
104
|
+
5. Confirm the repo URL back to the user.
|
|
105
|
+
|
|
106
|
+
If `gh` isn't authenticated (`gh auth status` fails), don't guess — tell the user to run `gh auth login`
|
|
107
|
+
and offer to retry.
|
|
108
|
+
|
|
109
|
+
## 6. Cohort (optional, low-friction — v0.20.0+)
|
|
110
|
+
|
|
111
|
+
Read `cohort` from `.boss/config.json`. If `null` (the default), ask ONE open question:
|
|
112
|
+
|
|
113
|
+
> *"Quick optional thing — which of these sounds most like where you're starting from? It lets BOSS's
|
|
114
|
+
> conscience tune its voice for you. If none fit, skip:*
|
|
115
|
+
> - *`vibe-coder-newbie` — picked up Cursor/Claude Code recently, no eng/startup background*
|
|
116
|
+
> - *`eng-builder` — strong eng background, first-time founder*
|
|
117
|
+
> - *`non-tech-founder` — domain expertise, no coding background, AI is the bridge*
|
|
118
|
+
> - *`first-product` — absolute first product ever, learning everything as you go*
|
|
119
|
+
> - *`vibe-virtuoso` — ships a lot of projects, harder time sustaining one*
|
|
120
|
+
> - *`indie-hacker` — building right-sized; calm-company, not venture*
|
|
121
|
+
> - *`returning-founder` — shipped before; want depth, not 101*
|
|
122
|
+
> - *`domain-expert` — deep expertise in a high-stakes domain (medical/legal/financial)*
|
|
123
|
+
> - *skip — leave it generic"*
|
|
124
|
+
|
|
125
|
+
On answer, write the value to `.boss/config.json` (don't disturb other fields). If they skip, leave `null`.
|
|
126
|
+
Either way, move on. Don't argue with their choice; they can edit the file later.
|
|
127
|
+
|
|
128
|
+
**Voice note:** these are *beginner personas* (per IDEA-009). The cohort declaration sharpens BOSS for
|
|
129
|
+
this founder *as evidence comes in over time* — not the other way around. If the user mishears their own
|
|
130
|
+
cohort, real use will reveal it; the file is editable.
|
|
131
|
+
|
|
132
|
+
## 7. Wrap up
|
|
133
|
+
|
|
134
|
+
Give a tight summary: what the idea is, where it's captured (`IDEA-001`), the stack decision (or that
|
|
135
|
+
it's pending), the mode, the cohort (if set), and the repo URL if created. Then the single best next step
|
|
136
|
+
(usually: start building the smallest version, or `boss unlock mvp` if it's clearly a real build).
|
|
137
|
+
|
|
138
|
+
## Rules
|
|
139
|
+
|
|
140
|
+
- Capture before code. Don't start implementing inside `/boss` — this is spin-up only.
|
|
141
|
+
- Never create a public repo by default. Never publish a permissive license by default.
|
|
142
|
+
- Never touch global git config. Repo-local email only, and say so.
|
|
143
|
+
- Prefer one well-placed question over an interrogation.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Appendix — proprietary LICENSE template
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
Copyright (c) {{YEAR}} {{OWNER}}. All Rights Reserved.
|
|
151
|
+
|
|
152
|
+
This software and its source code are proprietary and confidential. No license,
|
|
153
|
+
express or implied, is granted to any person to use, copy, modify, merge, publish,
|
|
154
|
+
distribute, sublicense, or sell copies of this software, in whole or in part,
|
|
155
|
+
without the prior written permission of the copyright holder.
|
|
156
|
+
|
|
157
|
+
This default is intentional: it preserves the option to later release this project
|
|
158
|
+
under an open-source license (e.g. MIT, Apache-2.0, AGPL-3.0) OR to commercialize it.
|
|
159
|
+
A permissive open-source grant, once published, cannot be revoked — so the path is
|
|
160
|
+
kept open until deliberately chosen.
|
|
161
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: boss-learn
|
|
3
|
+
description: Route a proven pattern two ways — UP into the BOSS library as a reusable superset practice, or DOWN into this app as hardened core functionality. The judgment layer over `boss learn`. Usage - /boss-learn [what to promote]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /boss-learn — the two-destination router
|
|
7
|
+
|
|
8
|
+
PRINCIPLES #1: BOSS is always scaffolding, but at every natural breakpoint (a mode transition, a
|
|
9
|
+
shipped feature, the third time the same work repeats) you **pause and sort the pattern two ways.**
|
|
10
|
+
This skill is that router. It is **not** a one-way "promote to BOSS" — deciding UP vs DOWN *is* the
|
|
11
|
+
work.
|
|
12
|
+
|
|
13
|
+
## 0. Orient (silent)
|
|
14
|
+
|
|
15
|
+
- Read `PRINCIPLES.md` (#1 especially) and `.boss/manifest.json` (which project/mode you're in).
|
|
16
|
+
- Identify the concrete pattern: the file(s), prompt, workflow, convention, or token set in question.
|
|
17
|
+
|
|
18
|
+
## 1. Decide the destination
|
|
19
|
+
|
|
20
|
+
Ask one question if it's genuinely unclear; otherwise call it and say why.
|
|
21
|
+
|
|
22
|
+
- **UP → BOSS library** when the pattern is *project-neutral and reusable*: a workflow, an agent or
|
|
23
|
+
skill shape, a hook, a best-practice doc, a memory seed. The test (PRINCIPLES #3): *could a sibling
|
|
24
|
+
project reuse this without copy-pasting code?* If yes, it's superset.
|
|
25
|
+
- **DOWN → app core** when the pattern is *this product's actual functionality* that happens to be
|
|
26
|
+
living as scaffold/ad-hoc. It belongs in the app's own modules, with the app's own tests — not in BOSS.
|
|
27
|
+
|
|
28
|
+
A pattern can route **both**: the generalized shape goes UP, the concrete implementation hardens DOWN.
|
|
29
|
+
|
|
30
|
+
## 2a. Route UP
|
|
31
|
+
|
|
32
|
+
1. **Generalize first.** Strip project specifics; replace them with `{{PLACEHOLDERS}}`. Domain logic
|
|
33
|
+
never lands in `library/` (PRINCIPLES: stack- and project-neutral only). Write/clean the file.
|
|
34
|
+
2. **Pick a category:** `agents` · `skills` · `hooks` · `practices` · `memory-seed`.
|
|
35
|
+
3. **Promote it:**
|
|
36
|
+
```
|
|
37
|
+
boss learn <path-to-generalized-file-or-dir> --as <category> --note "<one line: what & why>"
|
|
38
|
+
```
|
|
39
|
+
This copies it into `library/<category>/`, bumps `VERSION` + `package.json` (minor by default;
|
|
40
|
+
`--patch`/`--major`/`--version X.Y.Z` to override), and prepends a `registry/CHANGELOG.md` entry.
|
|
41
|
+
4. **Sharpen the CHANGELOG prose** by hand — the auto entry is a stub. The CHANGELOG is what every
|
|
42
|
+
project reads via `/boss-sync`, so make it say what's new and why it matters.
|
|
43
|
+
5. Tell the user: connected projects pull this via `boss sync` / `/boss-sync`.
|
|
44
|
+
|
|
45
|
+
## 2b. Route DOWN
|
|
46
|
+
|
|
47
|
+
No BOSS version change. This is product, not scaffold. Give concrete guidance (or do it, if asked):
|
|
48
|
+
- Move the pattern from ad-hoc/scaffold into a **named, owned module/config** in the app.
|
|
49
|
+
- Add the app's own tests around it; wire it into the app's real flow.
|
|
50
|
+
- If a *generalizable shape* remains, note it for a follow-up UP — don't lock value into code (PRINCIPLES #3).
|
|
51
|
+
|
|
52
|
+
## 3. Close the loop
|
|
53
|
+
|
|
54
|
+
- Update `docs/RESUME.md` if this was a breakpoint worth recording.
|
|
55
|
+
- One-line summary: what moved, which direction, the new BOSS version (if UP), the next step.
|
|
56
|
+
|
|
57
|
+
## Rules
|
|
58
|
+
|
|
59
|
+
- Deciding the direction is the point — never default to UP. Most app code routes DOWN.
|
|
60
|
+
- Never put domain specifics in `library/`. Generalize or don't promote.
|
|
61
|
+
- `boss learn` edits the BOSS **source** repo (found via the registry's self-hosted entry, or
|
|
62
|
+
`$BOSS_SRC`). Review its diff and commit deliberately — don't auto-commit BOSS.
|
|
63
|
+
- One pattern per run. If the user names several, take the clearest first.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: boss-sync
|
|
3
|
+
description: Pull current BOSS practices into this project — bring the installed modes' skills/agents up to the latest version as a reviewed, narrated diff, then bump the project's BOSS pin. The judgment layer over `boss sync`. Usage - /boss-sync
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /boss-sync — bring this project current
|
|
7
|
+
|
|
8
|
+
The distribution half of the learning loop (PRINCIPLES #1): improvements promoted UP into the BOSS
|
|
9
|
+
library flow back DOWN into every connected project. This skill brings *this* project's BOSS-managed
|
|
10
|
+
files (the skills, agents, and hooks of its installed modes) up to the current version — reviewed, not
|
|
11
|
+
blind. Hook *registrations* are merged into `.claude/settings.json` additively, never clobbering your
|
|
12
|
+
own permissions or hooks.
|
|
13
|
+
|
|
14
|
+
## 0. Orient (silent)
|
|
15
|
+
|
|
16
|
+
- `boss status` — current mode, the project's BOSS pin, and whether newer practices exist.
|
|
17
|
+
- Read `registry/CHANGELOG.md` from the BOSS source repo for **what changed since this project's pin** —
|
|
18
|
+
this is the narration you'll give the user (not just a file list).
|
|
19
|
+
|
|
20
|
+
## 1. Preview
|
|
21
|
+
|
|
22
|
+
Run `boss sync` (no flags). It lists each BOSS-managed file (skills, agents, hooks) as `new`,
|
|
23
|
+
`changed (N lines)`, or up to date, across all installed modes; flags a `~ merge settings/hooks` line if
|
|
24
|
+
hook registrations need adding to `.claude/settings.json`; and reconciles any stale mode label (e.g. an
|
|
25
|
+
old `L0-sketch` pin → `L0-quickstart`).
|
|
26
|
+
|
|
27
|
+
## 2. Review (the judgment)
|
|
28
|
+
|
|
29
|
+
Before applying, for each **changed** file:
|
|
30
|
+
- Read the project's current copy and the incoming version. Summarize what actually changes.
|
|
31
|
+
- **Flag conflicts:** if the project edited a BOSS-managed file locally, a sync overwrites it. Call this
|
|
32
|
+
out by name and ask before clobbering. (v1 syncs BOSS-managed skills/agents only — see scope below.)
|
|
33
|
+
- Tie changes back to the CHANGELOG entries so the user understands *why*, not just *what*.
|
|
34
|
+
|
|
35
|
+
## 3. Apply
|
|
36
|
+
|
|
37
|
+
- `boss sync --apply` — writes the new/changed files and bumps the project's `.boss` pin to current.
|
|
38
|
+
- Then show `git diff` and let the user review and commit. The project is the source of truth for its
|
|
39
|
+
own history; BOSS just proposes the update.
|
|
40
|
+
|
|
41
|
+
## Scope
|
|
42
|
+
|
|
43
|
+
- Syncs **BOSS-managed skills, agents, and hook scripts** for installed modes.
|
|
44
|
+
- **Merges hook registrations into `.claude/settings.json`** additively — adds the `UserPromptSubmit`
|
|
45
|
+
(etc.) entries BOSS ships, matched by command so it's idempotent, and **preserves your permissions and
|
|
46
|
+
any hooks you added.** This is the one user-editable file sync touches, and only the `hooks` block.
|
|
47
|
+
- Does **not** auto-merge `CLAUDE.md` or other `settings.json` keys. If the CHANGELOG implies those should
|
|
48
|
+
change, surface it and let the user merge by hand.
|
|
49
|
+
- New skills/agents/hooks added to a mode since the pin are pulled in; nothing is removed.
|
|
50
|
+
|
|
51
|
+
## Rules
|
|
52
|
+
|
|
53
|
+
- Review before `--apply`. Never overwrite a locally-edited managed file without flagging it first.
|
|
54
|
+
- Narrate from the CHANGELOG — the user should learn what's new, not just see files move.
|
|
55
|
+
- Don't commit for the user; hand them a clean `git diff` to review.
|