@ionivetech/mugiwara 0.4.0 → 0.5.1

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.
Files changed (128) hide show
  1. package/README.md +231 -371
  2. package/content/agents/brook-healing.md +2 -2
  3. package/content/agents/chopper-checkpoint.md +2 -1
  4. package/content/agents/eval-runner.md +4 -4
  5. package/content/agents/franky-gates.md +1 -1
  6. package/content/agents/jinbe-security.md +2 -1
  7. package/content/agents/luffy-orchestrator.md +3 -3
  8. package/content/agents/memory-keeper.md +1 -1
  9. package/content/agents/nami-planner.md +2 -2
  10. package/content/agents/resume-coordinator.md +8 -9
  11. package/content/agents/robin-reviewer.md +3 -2
  12. package/content/agents/sanji-quality.md +1 -1
  13. package/content/agents/skeptic-verifier.md +4 -3
  14. package/content/agents/using-mugiwara.md +3 -3
  15. package/content/agents/usopp-brainstorm.md +3 -3
  16. package/content/agents/zoro-execution.md +4 -3
  17. package/content/skills/mugiwara-agent-security/SKILL.md +14 -2
  18. package/content/skills/mugiwara-backend/SKILL.md +2 -8
  19. package/content/skills/mugiwara-backend/references/source-backed-example.md +77 -0
  20. package/content/skills/mugiwara-brainstorm/SKILL.md +2 -2
  21. package/content/skills/mugiwara-checkpoint/SKILL.md +2 -2
  22. package/content/skills/mugiwara-checkpoint/references/ledger-format.md +34 -0
  23. package/content/skills/{mugiwara-doubt-driven-development → mugiwara-claim-audit}/SKILL.md +2 -2
  24. package/content/skills/{mugiwara-context-engineering → mugiwara-context-budget}/SKILL.md +2 -2
  25. package/content/skills/mugiwara-context-budget/references/context-budget.md +37 -0
  26. package/content/skills/{mugiwara-api-and-interface-design → mugiwara-contract-first}/SKILL.md +4 -2
  27. package/content/skills/mugiwara-contract-first/references/versioning-playbook.md +36 -0
  28. package/content/skills/mugiwara-execution/SKILL.md +4 -2
  29. package/content/skills/mugiwara-execution/references/worked-example.md +88 -0
  30. package/content/skills/mugiwara-frontend/SKILL.md +13 -14
  31. package/content/skills/mugiwara-frontend/references/design-tokens.md +25 -0
  32. package/content/skills/mugiwara-frontend/references/slop-catalog.md +19 -0
  33. package/content/skills/mugiwara-gates/SKILL.md +4 -4
  34. package/content/skills/mugiwara-git/SKILL.md +1 -1
  35. package/content/skills/mugiwara-healing/SKILL.md +34 -7
  36. package/content/skills/mugiwara-healing/references/failure-taxonomy.md +23 -0
  37. package/content/skills/mugiwara-lessons/SKILL.md +1 -1
  38. package/content/skills/mugiwara-orchestration/SKILL.md +5 -5
  39. package/content/skills/mugiwara-planning/SKILL.md +2 -2
  40. package/content/skills/mugiwara-planning/references/anti-patterns.md +17 -0
  41. package/content/skills/mugiwara-planning/references/plan-template.md +46 -0
  42. package/content/skills/mugiwara-pr/SKILL.md +1 -1
  43. package/content/skills/{mugiwara-test-driven-development → mugiwara-proof-order}/SKILL.md +2 -2
  44. package/content/skills/mugiwara-proof-order/references/proof-order-examples.md +62 -0
  45. package/content/skills/mugiwara-quality/SKILL.md +3 -3
  46. package/content/skills/mugiwara-resume/SKILL.md +44 -33
  47. package/content/skills/mugiwara-review/SKILL.md +1 -1
  48. package/content/skills/mugiwara-review/references/five-axis-worksheet.md +36 -0
  49. package/content/skills/mugiwara-review/references/severity-rubric.md +20 -0
  50. package/content/skills/{mugiwara-systematic-debugging → mugiwara-root-cause}/SKILL.md +4 -2
  51. package/content/skills/mugiwara-root-cause/references/four-phase-worked.md +71 -0
  52. package/content/skills/mugiwara-security/SKILL.md +1 -1
  53. package/content/skills/mugiwara-security/references/owasp-mapping.md +30 -0
  54. package/content/skills/mugiwara-security/references/stride-worksheet.md +37 -0
  55. package/content/skills/mugiwara-ship/SKILL.md +1 -1
  56. package/content/skills/{mugiwara-deprecation → mugiwara-sunset}/SKILL.md +2 -2
  57. package/content/skills/mugiwara-testcases/SKILL.md +1 -1
  58. package/content/skills/mugiwara-testcases/references/intake-formats.md +42 -0
  59. package/content/skills/mugiwara-workflow/SKILL.md +20 -23
  60. package/dist/mugiwara.js +37 -8
  61. package/docs/agents.md +2 -2
  62. package/docs/audit-trail.md +65 -0
  63. package/docs/comparison.md +43 -170
  64. package/docs/compliance-matrix.md +81 -0
  65. package/docs/config.md +4 -2
  66. package/docs/cost.md +45 -0
  67. package/docs/enforcement.md +32 -35
  68. package/docs/getting-started.md +103 -41
  69. package/docs/harness-matrix.md +41 -0
  70. package/docs/lanes.md +65 -23
  71. package/docs/skill-anatomy.md +42 -54
  72. package/docs/skills.md +36 -54
  73. package/evals/cases/_no-skill.json +16 -0
  74. package/evals/cases/adversarial-pressure-fake-pass.json +21 -8
  75. package/evals/cases/adversarial-pressure-skip-review.json +19 -7
  76. package/evals/cases/lane-exploratory-vague.json +18 -6
  77. package/evals/cases/lane-sensitivity-payment.json +18 -6
  78. package/evals/cases/positive-refactor-existing-tests.json +22 -8
  79. package/evals/cases/positive-resume-mid-mission.json +20 -7
  80. package/evals/cases/routing-agent-security.json +25 -0
  81. package/evals/cases/routing-auth-feature.json +20 -7
  82. package/evals/cases/routing-backend.json +25 -0
  83. package/evals/cases/routing-bug-one-file.json +21 -8
  84. package/evals/cases/routing-claim-audit.json +25 -0
  85. package/evals/cases/routing-context-budget.json +25 -0
  86. package/evals/cases/routing-contract-first.json +25 -0
  87. package/evals/cases/routing-execution.json +25 -0
  88. package/evals/cases/routing-frontend.json +26 -0
  89. package/evals/cases/routing-gates.json +25 -0
  90. package/evals/cases/routing-git.json +25 -0
  91. package/evals/cases/routing-healing.json +25 -0
  92. package/evals/cases/routing-lessons.json +25 -0
  93. package/evals/cases/routing-orchestration.json +25 -0
  94. package/evals/cases/routing-planning.json +26 -0
  95. package/evals/cases/routing-pr.json +25 -0
  96. package/evals/cases/routing-proof-order.json +25 -0
  97. package/evals/cases/routing-quality.json +25 -0
  98. package/evals/cases/routing-ship.json +26 -0
  99. package/evals/cases/routing-sunset.json +25 -0
  100. package/evals/cases/routing-workflow.json +25 -0
  101. package/evals/floor.json +6 -0
  102. package/package.json +6 -4
  103. package/references/definition-of-done.md +42 -0
  104. package/references/multi-actor.md +44 -0
  105. package/references/skill-versioning.md +44 -0
  106. package/references/source-grounding.md +23 -0
  107. package/references/token-budget.md +34 -0
  108. package/scripts/evidence.sh +37 -0
  109. package/scripts/lane.sh +74 -0
  110. package/scripts/mission-report.sh +88 -0
  111. package/scripts/probe.ts +40 -0
  112. package/scripts/release-notes.ts +65 -0
  113. package/scripts/retrieval-eval.ts +261 -0
  114. package/scripts/run-evals.ts +149 -0
  115. package/scripts/savepoint.sh +166 -0
  116. package/scripts/sync-version.ts +30 -0
  117. package/scripts/validate-content.ts +226 -0
  118. package/src/cli.ts +8 -3
  119. package/src/mission.ts +26 -3
  120. package/content/skills/mugiwara-dynamic-workflow/SKILL.md +0 -90
  121. package/content/skills/mugiwara-eval/SKILL.md +0 -87
  122. package/content/skills/mugiwara-git-worktrees/SKILL.md +0 -67
  123. package/content/skills/mugiwara-mode/SKILL.md +0 -77
  124. package/content/skills/mugiwara-observability/SKILL.md +0 -59
  125. package/content/skills/mugiwara-writing-skills/SKILL.md +0 -65
  126. package/evals/cases/negative-secrets-typo.json +0 -12
  127. package/evals/cases/negative-security-docs-change.json +0 -12
  128. package/evals/cases/routing-typo.json +0 -13
@@ -0,0 +1,226 @@
1
+ #!/usr/bin/env bun
2
+ // scripts/validate-content.ts
3
+ import { readdirSync, readFileSync, existsSync, statSync } from 'node:fs';
4
+ import { join, basename } from 'node:path';
5
+ import { parseFrontmatter } from '../src/frontmatter.ts';
6
+
7
+ const root = join(import.meta.dirname, '..', 'content');
8
+ const errors: string[] = [];
9
+
10
+ function checkFile(file: string, wantName: string, kind: 'skill' | 'agent'): Record<string, string> | null {
11
+ let parsed;
12
+ try { parsed = parseFrontmatter(readFileSync(file, 'utf8')); }
13
+ catch (e) { errors.push(`${kind} ${file}: ${(e as Error).message}`); return null; }
14
+ const { data, body } = parsed;
15
+ if (data.name !== wantName) errors.push(`${kind} ${file}: name "${data.name}" != "${wantName}"`);
16
+ const d = data.description ?? '';
17
+ if (kind === 'skill' && (d.length < 20 || d.length > 500)) errors.push(`skill ${file}: description must be 20-500 chars (got ${d.length})`);
18
+ if (kind === 'agent' && d.length < 20) errors.push(`agent ${file}: description too short`);
19
+ if (kind === 'skill' && body.replace(/\r?\n$/, '').split(/\r?\n/).length > 120) errors.push(`skill ${file}: body exceeds 120 lines`);
20
+ if (kind === 'skill' && !body.includes('## Skip when')) errors.push(`skill ${file}: missing required "## Skip when" block (≤4 lines, numeric threshold)`);
21
+ if (kind === 'skill' && body.includes('## Skip when')) {
22
+ const lines = body.split(/\r?\n/);
23
+ const idx = lines.findIndex(l => l.startsWith('## Skip when'));
24
+ const gateLines = lines.slice(idx + 1).findIndex(l => l.startsWith('## '));
25
+ const end = gateLines === -1 ? lines.length : idx + 1 + gateLines;
26
+ const bullets = lines.slice(idx + 1, end).filter(l => l.trim().startsWith('-'));
27
+ if (bullets.length === 0) errors.push(`skill ${file}: "## Skip when" needs ≥1 bullet`);
28
+ if (bullets.length > 4) errors.push(`skill ${file}: "## Skip when" block exceeds 4 bullets`);
29
+ }
30
+ return data;
31
+ }
32
+
33
+ function listFiles(dir: string, prefix = ''): string[] {
34
+ if (!existsSync(dir)) return [];
35
+ const out: string[] = [];
36
+ for (const ent of readdirSync(dir, { withFileTypes: true })) {
37
+ const p = join(dir, ent.name);
38
+ if (ent.isDirectory()) out.push(...listFiles(p, join(prefix, ent.name)));
39
+ else out.push(join(prefix, ent.name));
40
+ }
41
+ return out;
42
+ }
43
+
44
+ const syncArg = process.argv.indexOf('--check-sync');
45
+ if (syncArg !== -1) {
46
+ const pairs = [['content/skills', 'skills'], ['content/agents', 'agents']] as const;
47
+ const diffs: string[] = [];
48
+ for (const [from, to] of pairs) {
49
+ const fromRoot = join(import.meta.dirname, '..', from);
50
+ const toRoot = join(import.meta.dirname, '..', to);
51
+ const fromFiles = listFiles(fromRoot).sort();
52
+ const toFiles = listFiles(toRoot).sort();
53
+ for (const rel of fromFiles) {
54
+ const f = join(fromRoot, rel), t = join(toRoot, rel);
55
+ if (!existsSync(t)) diffs.push(`missing copy: ${to}/${rel} (run .claude-plugin/sync.sh)`);
56
+ else if (readFileSync(f, 'utf8') !== readFileSync(t, 'utf8')) diffs.push(`out of sync: ${to}/${rel}`);
57
+ }
58
+ for (const rel of toFiles) {
59
+ if (!fromFiles.includes(rel)) diffs.push(`stale copy: ${to}/${rel} (not in content/, run .claude-plugin/sync.sh)`);
60
+ }
61
+ }
62
+ if (diffs.length) { console.error(diffs.map(d => `✗ ${d}`).join('\n')); process.exit(1); }
63
+ console.log('✓ plugin copies in sync with content/');
64
+ process.exit(0);
65
+ }
66
+
67
+ const skillDirs = existsSync(join(root, 'skills'))
68
+ ? readdirSync(join(root, 'skills')).filter(d => statSync(join(root, 'skills', d)).isDirectory())
69
+ : [];
70
+ const names = new Map<string, string>();
71
+ const usedSkills = new Set<string>();
72
+
73
+ const checkArg = process.argv.indexOf('--check');
74
+ if (checkArg !== -1) {
75
+ const file = process.argv[checkArg + 1];
76
+ const isSkill = file.includes('skills');
77
+ const want = isSkill ? basename(join(file, '..')) : basename(file).replace(/\.md$/, '');
78
+ checkFile(file, want, isSkill ? 'skill' : 'agent');
79
+ if (errors.length) { console.error(errors.map(e => `✗ ${e}`).join('\n')); process.exit(1); }
80
+ console.log(`✓ ${file}`);
81
+ process.exit(0);
82
+ }
83
+
84
+ for (const dir of skillDirs) {
85
+ const file = join(root, 'skills', dir, 'SKILL.md');
86
+ if (!existsSync(file)) { errors.push(`skill ${dir}: missing SKILL.md`); continue; }
87
+ const data = checkFile(file, dir, 'skill');
88
+ if (data) {
89
+ if (names.has(data.name)) errors.push(`duplicate name: ${data.name}`);
90
+ names.set(data.name, file);
91
+ }
92
+ }
93
+
94
+ const agentDir = join(root, 'agents');
95
+ const agentFiles = existsSync(agentDir) ? readdirSync(agentDir).filter(f => f.endsWith('.md')) : [];
96
+ for (const f of agentFiles) {
97
+ const data = checkFile(join(agentDir, f), f.replace(/\.md$/, ''), 'agent');
98
+ if (!data) continue;
99
+ if (names.has(data.name)) errors.push(`duplicate name: ${data.name}`);
100
+ names.set(data.name, f);
101
+ const skills = (data.skills ?? '').split(',').map(s => s.trim()).filter(Boolean);
102
+ if (skills.length === 0) errors.push(`agent ${f}: skills field missing/empty`);
103
+ for (const s of skills) {
104
+ usedSkills.add(s);
105
+ if (!skillDirs.includes(s)) errors.push(`agent ${f}: unknown skill "${s}"`);
106
+ }
107
+ }
108
+
109
+ for (const dir of skillDirs) {
110
+ if (dir !== 'mugiwara-workflow' && !usedSkills.has(dir)) errors.push(`skill ${dir}: not referenced by any agent`);
111
+ }
112
+
113
+ // --- manifest-sync check: .claude-plugin/plugin.json must set-equal content/ ---
114
+ const manifestArg = process.argv.indexOf('--check-manifest');
115
+ if (manifestArg !== -1) {
116
+ const manifests = ['.claude-plugin/plugin.json'];
117
+ let manifestErrors = 0;
118
+
119
+ for (const mp of manifests) {
120
+ const mpath = join(import.meta.dirname, '..', mp);
121
+ if (!existsSync(mpath)) { errors.push(`manifest ${mp}: file not found`); continue; }
122
+ let mdata;
123
+ try { mdata = JSON.parse(readFileSync(mpath, 'utf8')); }
124
+ catch (e) { errors.push(`manifest ${mp}: invalid JSON`); continue; }
125
+
126
+ const mSkills = mdata?.metadata?.skills;
127
+ const mAgents = mdata?.metadata?.agents;
128
+ if (!Array.isArray(mSkills)) { errors.push(`manifest ${mp}: missing metadata.skills array`); }
129
+ if (!Array.isArray(mAgents)) { errors.push(`manifest ${mp}: missing metadata.agents array`); }
130
+ if (!mSkills || !mAgents) continue;
131
+
132
+ const mSkillSet = new Set(mSkills);
133
+ const mAgentSet = new Set(mAgents);
134
+
135
+ // every skill in content/ must be in manifest
136
+ for (const dir of skillDirs) {
137
+ if (!mSkillSet.has(dir)) {
138
+ errors.push(`manifest ${mp}: missing skill "${dir}"`);
139
+ manifestErrors++;
140
+ }
141
+ }
142
+ // no stale entries in manifest
143
+ for (const s of mSkills) {
144
+ if (!skillDirs.includes(s)) {
145
+ errors.push(`manifest ${mp}: stale skill "${s}" (not in content/skills/)`);
146
+ manifestErrors++;
147
+ }
148
+ }
149
+ // every agent in content/ must be in manifest
150
+ for (const f of agentFiles) {
151
+ const name = f.replace(/\.md$/, '');
152
+ if (!mAgentSet.has(name)) {
153
+ errors.push(`manifest ${mp}: missing agent "${name}"`);
154
+ manifestErrors++;
155
+ }
156
+ }
157
+ for (const a of mAgents) {
158
+ if (!agentFiles.includes(`${a}.md`)) {
159
+ errors.push(`manifest ${mp}: stale agent "${a}" (not in content/agents/)`);
160
+ manifestErrors++;
161
+ }
162
+ }
163
+ }
164
+
165
+ if (manifestErrors === 0) console.log('✓ manifest in sync with content/');
166
+ }
167
+
168
+ // --- index budget gate ---
169
+ const INDEX_BUDGET = 5500; // chars, all skill + agent descriptions combined
170
+ let totalDescChars = 0;
171
+ for (const dir of skillDirs) {
172
+ const file = join(root, 'skills', dir, 'SKILL.md');
173
+ if (!existsSync(file)) continue;
174
+ const parsed = parseFrontmatter(readFileSync(file, 'utf8'));
175
+ totalDescChars += (parsed.data.description ?? '').length;
176
+ }
177
+ for (const f of agentFiles) {
178
+ const parsed = parseFrontmatter(readFileSync(join(agentDir, f), 'utf8'));
179
+ totalDescChars += (parsed.data.description ?? '').length;
180
+ }
181
+ if (totalDescChars > INDEX_BUDGET) {
182
+ errors.push(`index budget exceeded: ${totalDescChars}/${INDEX_BUDGET} chars (skill + agent descriptions)`);
183
+ } else {
184
+ console.log(`✓ index budget: ${totalDescChars}/${INDEX_BUDGET} chars`);
185
+ }
186
+
187
+ // --- docs-drift check: docs/skills.md and docs/agents.md must reference all content/ entries ---
188
+ const docsArg = process.argv.indexOf('--check-docs');
189
+ if (docsArg !== -1) {
190
+ const docsDir = join(import.meta.dirname, '..', 'docs');
191
+ const skillsDoc = join(docsDir, 'skills.md');
192
+ const agentsDoc = join(docsDir, 'agents.md');
193
+ let docErrors = 0;
194
+
195
+ if (existsSync(skillsDoc)) {
196
+ const content = readFileSync(skillsDoc, 'utf8');
197
+ for (const dir of skillDirs) {
198
+ if (!content.includes(dir)) {
199
+ errors.push(`docs/skills.md: missing skill "${dir}"`);
200
+ docErrors++;
201
+ }
202
+ }
203
+ } else {
204
+ errors.push('docs/skills.md: file not found');
205
+ docErrors++;
206
+ }
207
+
208
+ if (existsSync(agentsDoc)) {
209
+ const content = readFileSync(agentsDoc, 'utf8');
210
+ for (const f of agentFiles) {
211
+ const name = f.replace(/\.md$/, '');
212
+ if (!content.includes(name)) {
213
+ errors.push(`docs/agents.md: missing agent "${name}"`);
214
+ docErrors++;
215
+ }
216
+ }
217
+ } else {
218
+ errors.push('docs/agents.md: file not found');
219
+ docErrors++;
220
+ }
221
+
222
+ if (docErrors === 0) console.log('✓ docs in sync with content/');
223
+ }
224
+
225
+ if (errors.length) { console.error(errors.map(e => `✗ ${e}`).join('\n')); process.exit(1); }
226
+ console.log(`✓ content valid: ${skillDirs.length} skills, ${agentFiles.length} agents`);
package/src/cli.ts CHANGED
@@ -30,10 +30,15 @@ export async function run(argv: string[]): Promise<void> {
30
30
 
31
31
  function resetCmd(flags: Args['flags']): void {
32
32
  const projectDir = resolve(str(flags.project) ?? process.cwd());
33
- const { removed, kept } = resetMission(projectDir, flag(flags.keepLogs));
34
- if (removed.length) console.log(`removed: ${removed.join(', ')}`);
33
+ const force = flag(flags.force);
34
+ const result = resetMission(projectDir, flag(flags.keepLogs), force);
35
+ if (result.blocked) {
36
+ console.error(`✗ ${result.blocked}`);
37
+ process.exit(1);
38
+ }
39
+ if (result.removed.length) console.log(`removed: ${result.removed.join(', ')}`);
35
40
  else console.log('nothing to remove.');
36
- if (kept.length) console.log(`kept: ${kept.join(', ')}`);
41
+ if (result.kept.length) console.log(`kept: ${result.kept.join(', ')}`);
37
42
  }
38
43
 
39
44
  async function resolveOptions(flags: Args['flags']): Promise<{ scope: Scope; projectDir: string; targetIds: string[] }> {
package/src/mission.ts CHANGED
@@ -1,17 +1,40 @@
1
1
  // src/mission.ts
2
2
  // Mission-state helpers for the mugiwara CLI (installer + reset only).
3
- import { existsSync, rmSync } from 'node:fs';
3
+ import { existsSync, rmSync, readFileSync } from 'node:fs';
4
4
  import { join } from 'node:path';
5
5
 
6
- export function resetMission(projectDir: string, keepLogs: boolean): { removed: string[]; kept: string[] } {
6
+ function activeActor(projectDir: string): string | null {
7
+ const stateFile = join(projectDir, '.mugiwara', 'state.json');
8
+ if (!existsSync(stateFile)) return null;
9
+ try {
10
+ const state = JSON.parse(readFileSync(stateFile, 'utf8'));
11
+ return state.actor || null;
12
+ } catch { return null; }
13
+ }
14
+
15
+ export function resetMission(projectDir: string, keepLogs: boolean, force?: boolean): { removed: string[]; kept: string[]; blocked?: string } {
7
16
  const root = join(projectDir, '.mugiwara');
8
17
  if (!existsSync(root)) return { removed: [], kept: [] };
18
+
19
+ // safe multi-actor: refuse to wipe another actor's live mission
20
+ if (!force) {
21
+ const actor = activeActor(projectDir);
22
+ if (actor) {
23
+ return { removed: [], kept: [], blocked: `Active mission for '${actor}'. Use --force to override.` };
24
+ }
25
+ }
26
+
9
27
  const removed: string[] = [];
10
28
  const kept: string[] = [];
11
- for (const dir of ['spec', 'plans', 'results', 'review', 'issues']) {
29
+ for (const dir of ['spec', 'plans', 'results', 'review', 'issues', 'reports']) {
12
30
  const p = join(root, dir);
13
31
  if (existsSync(p)) { rmSync(p, { recursive: true, force: true }); removed.push(dir); }
14
32
  }
33
+ // mission state files
34
+ for (const f of ['state.json']) {
35
+ const p = join(root, f);
36
+ if (existsSync(p)) { rmSync(p); removed.push(f); }
37
+ }
15
38
  if (!keepLogs) {
16
39
  const p = join(root, 'logs');
17
40
  if (existsSync(p)) { rmSync(p, { recursive: true, force: true }); removed.push('logs'); }
@@ -1,90 +0,0 @@
1
- ---
2
- name: mugiwara-dynamic-workflow
3
- description: Use when a mission or subproblem has many independent subtasks, needs comparison, or risks agent bias - pick the right dynamic workflow pattern - fan-out-and-synthesize, tournament, loop-until-done, classify-and-act, generate-and-filter.
4
- ---
5
-
6
- # Dynamic Workflow Patterns (Luffy)
7
-
8
- ## Skip when
9
-
10
- - One linear pass suffices: <3 independent subtasks, no comparison, no known agent bias.
11
- - Standard wave pipeline already covers the work without pattern selection.
12
-
13
- Six primitives for missions too big or too biased for one linear pass. Choose the pattern BEFORE executing; record the choice in the decision log (.mugiwara/logs/). A mission may chain patterns (e.g. classify, then fan out, then tournament the outputs).
14
-
15
- ## Classify-and-act
16
-
17
- 1. Sort inputs into intent categories first, THEN route each category to its handler.
18
- 2. Never act before classifying — Luffy's Wave 0 triage is this pattern applied to the mission.
19
- 3. Unknown category → hold for judgment; never guess-assign.
20
-
21
- ## Fan-out-and-synthesize
22
-
23
- 1. Split work into independent tasks; run each in a parallel worker subagent (this is the one case that legitimately dispatches — parallel batches, never sequential work).
24
- 2. Prove disjointness first: each task touches distinct files or interfaces. No shared writes, no shared state.
25
- 3. A synthesizer merges results into ONE output with source attribution per part.
26
- 4. Conflicts resolve by evidence (re-run, inspect), never by vote count.
27
-
28
- ## Tournament / pairwise judgment
29
-
30
- 1. Ranking or selecting (options, designs, PRs) → compare in PAIRS, not all-at-once.
31
- 2. Fresh judge per match; match verdict only, no absolute scoring.
32
- 3. Winner advances; keep runner-up reasoning in the report.
33
- 4. Counters self-preferential bias: no judge argues for its own entry.
34
-
35
- ## Loop-until-done
36
-
37
- 1. Repeat one unit until a stopping criterion with evidence: test pass, threshold reached, user sign-off.
38
- 2. Bound the loop: max N (default 3). Exceeding N → escalate, never loop forever.
39
- 3. Record every iteration's evidence in `.mugiwara/results/`.
40
-
41
- ## Generate-and-filter
42
-
43
- 1. Produce many candidates first — no filtering during generation.
44
- 2. Filter against HARD constraints, then rank survivors.
45
- 3. Never filter before generating; never rank on soft preference before hard constraints.
46
-
47
- ## Adversarial verification
48
-
49
- 1. Every output gets a skeptic pass (dispatch `skeptic-verifier`): find what is wrong, do NOT validate.
50
- 2. Counters agentic laziness, self-preferential bias, goal drift.
51
- 3. Findings classified; loop bounded at 3 cycles.
52
-
53
- ## Selection guide
54
-
55
- - One route, unknown intent → classify-and-act
56
- - Many independent tasks, merge later → fan-out-and-synthesize
57
- - Rank or select among peers → tournament
58
- - Repetition with a stopping rule → loop-until-done
59
- - Many candidates, hard bar → generate-and-filter
60
- - Any high-stakes output about to ship → adversarial verification
61
-
62
- ## Failure modes fixed
63
-
64
- - Agentic laziness: generate-and-filter + adversarial verification
65
- - Self-preferential bias: tournament + adversarial verification
66
- - Goal drift: loop bounds + adversarial verification
67
- - Conflated judgments / order effects: tournament pairs
68
- - Premature filtering / culled solutions: generate-and-filter
69
-
70
- ## Pattern table
71
-
72
- | Pattern | Use when | Output |
73
- |---------|----------|--------|
74
- | classify-and-act | intent unknown, routes diverse | category → handler map + actions |
75
- | fan-out-and-synthesize | independent subtasks | one merged output, source-attributed |
76
- | tournament | rank / select peers | champion + runner-up reasoning |
77
- | loop-until-done | repeat until criterion | iterations + final evidence |
78
- | generate-and-filter | candidates + hard bar | ranked survivors |
79
- | adversarial verification | output / verdict ships | findings report, bounded |
80
-
81
- ## Red flags
82
-
83
- - Fan-out without a disjointness proof.
84
- - A synthesizer merging by vote instead of evidence.
85
- - A judge scoring absolutely instead of pairwise.
86
- - An unbounded loop.
87
- - Filtering before generating.
88
- - A skeptic pass that "validates" instead of doubting.
89
-
90
- All mean: stop, re-pick the pattern, record the change in the decision log.
@@ -1,87 +0,0 @@
1
- ---
2
- name: mugiwara-eval
3
- description: Use when verifying that a mugiwara skill, agent, or the whole crew actually works - write a task suite, run it with a judge agent, rubric-compare, and report pass/fail per case.
4
- ---
5
-
6
- # Eval (Self-Test)
7
-
8
- ## Skip when
9
-
10
- - No skill, agent, or crew behavior changed — pure docs, installer, or packaging.
11
- - Change is a version bump or manifest edit with zero behavioral delta.
12
-
13
- Skills rot silently. A skill that was never tested is a claim, not a capability. This is the harness's own test harness: write a task suite, run each case, score with a fresh judge against a rubric, report pass/fail.
14
-
15
- ## Why
16
-
17
- - Skill instructions drift from what agents actually do when followed.
18
- - Untested means unverified: "it reads fine" is not "it works".
19
- - The eval is the contract; the skill bends to it, never the reverse.
20
-
21
- ## Task suite format
22
-
23
- One case per skill-behavior at `evals/cases/<skill>-<case>.json`:
24
-
25
- ```json
26
- {
27
- "name": "rubric-threshold-honesty",
28
- "skill": "mugiwara-eval",
29
- "task": "The prompt to run through the skill's workflow.",
30
- "fixtures": ["evals/cases/fixtures/plan.md"],
31
- "rubric": ["a pass threshold is stated before scoring", "a pass needs explicit evidence"],
32
- "expected": "What pass looks like: all rubric items met, each with evidence."
33
- }
34
- ```
35
-
36
- - `name` unique per suite; `skill` matches the skill directory name.
37
- - `task` is the prompt run as-is — no extra guidance bolted on.
38
- - `rubric` = checked items; `expected` = the shape of a pass. `fixtures` optional, repo-relative paths.
39
-
40
- ## Judge-agent protocol
41
-
42
- Rubric comparison, not gold-answer matching (SWE-bench-style suites + rubric judges):
43
-
44
- 1. Run the case: host executes `task` with the skill under test loaded.
45
- 2. Dispatch a FRESH judge — never the implementer. Counters self-preferential bias.
46
- 3. Judge scores each `rubric` item pass/fail with evidence; no absolute scores.
47
- 4. Compare against the rubric's explicit pass threshold (all items, or ≥ N with none critical).
48
- 5. Ranking or selection → pairwise/tournament judging (`mugiwara-dynamic-workflow`), not all-at-once.
49
-
50
- ## Loop
51
-
52
- run → judge → fail → fix the SKILL (never the eval) → re-run.
53
-
54
- 1. Write cases before trusting a skill or changing it.
55
- 2. Run the suite; judge honestly.
56
- 3. A failing case means the skill's instructions are wrong or incomplete. Fix the skill.
57
- 4. A passing case gives no license to change the skill casually — re-run on change.
58
- 5. Never weaken the eval to clear a failure; that falsifies the test.
59
-
60
- ## Bound
61
-
62
- - Run the suite per release and on every skill change.
63
- - Report a pass/fail table to `.mugiwara/results/<mission>-eval.md`: case, judge, verdict, evidence, threshold.
64
- - Failing cases → rows in `.mugiwara/issues/YYYY-MM-DD-<mission>-blockers.md` (category `eval-fail`).
65
- - Keep the suite in sync with the skill dirs: at minimum one case per skill.
66
-
67
- ## Scope
68
-
69
- Test the SKILL, not the host agent. Host behavior is the host's problem. The eval checks that the skill's instructions, when followed, produce the intended workflow. Never assert on agent behavior, model quirks, or tooling the skill does not own.
70
-
71
- ## Common rationalizations
72
-
73
- - "I wrote it, it must work." → Fresh judge, always.
74
- - "The case passed last release." → Re-run; skills drift between runs.
75
- - "The eval is too strict." → Tighten the skill, never the rubric.
76
- - "It's an agent problem." → If following the skill causes it, it's the skill's.
77
-
78
- ## Red flags
79
-
80
- - The implementer judging its own case's skill.
81
- - A rubric with no pass threshold.
82
- - A case whose `task` leaks the expected answer.
83
- - Fixing the eval instead of the skill to clear a failure.
84
- - A suite run with no pass/fail report written.
85
- - A suite that no longer matches the skill's current behavior.
86
-
87
- All mean: the run is not a valid check. Stop, re-run with a fresh judge, write the report.
@@ -1,67 +0,0 @@
1
- ---
2
- name: mugiwara-git-worktrees
3
- description: Use when running parallel branch work, keeping the main workspace clean, or reviewing a branch without switching. Isolated worktrees via git worktree add, branch hygiene, and safe cleanup.
4
- ---
5
-
6
- # Git Worktrees — Isolated Parallel Branches
7
-
8
- ## Skip when
9
-
10
- - Single-branch sequential work: no parallel branches running at once.
11
- - Working tree stays clean and review happens on the current branch.
12
-
13
- Worktrees give each branch its own checkout, so parallel missions, reviews, and experiments never fight over one working tree. Companion to mugiwara-git, not a replacement for commit discipline.
14
-
15
- ## When to use
16
-
17
- - Parallel independent tasks on separate branches that must progress without blocking each other.
18
- - Keeping the main workspace clean: main checkout stays untouched while risky work lives in a worktree.
19
- - Reviewing or verifying a branch without switching: open it in a worktree, inspect, discard.
20
- - Any task so risky you want it physically separate from the current tree.
21
-
22
- Prefer a worktree over `git stash` juggling — each branch gets a real checkout, not a rescue from the reflog.
23
-
24
- ## Process
25
-
26
- 1. Create the worktree bound to a new branch:
27
- `git worktree add -b <branch> <path>` (e.g. `git worktree add -b feature/ABC-123-dark-mode ../dark-mode`).
28
- 2. Work entirely inside `<path>`: edit, commit, push there. Treat it as the only home of that branch.
29
- 3. Do not touch that branch from the main checkout, and vice versa. Two tasks never share one worktree.
30
- 4. Verify the work before it leaves the worktree: run the branch's checks and tests inside `<path>`.
31
- 5. Merge or rebase back into the main branch from the main checkout; push when done.
32
- 6. Clean up once the branch is merged or abandoned:
33
- - `git worktree remove <path>` (add `--force` only if it has uncommitted changes you accept losing).
34
- - `git worktree prune` to drop stale bookkeeping for worktrees removed outside git's book.
35
- 7. Check nothing is left behind: `git worktree list` should show only your active checkouts.
36
-
37
- ## Cleanup safety
38
-
39
- - Remove only worktrees you created. Host-owned worktrees — ones the repo or another agent set up — are not yours to delete; leave them.
40
- - Never remove a worktree that still has unmerged commits unless you have deliberately abandoned that branch.
41
- - Remove the worktree, not the branch directory with `rm -rf`; bypassing git leaves stale metadata that `prune` then has to guess about.
42
- - A worktree without a branch (`--detach`) is throwaway: verify, then remove with no branch to worry about.
43
-
44
- ## Rationalizations
45
-
46
- | Rationalization | Why it fails |
47
- | --- | --- |
48
- | "I'll just switch branches, it's faster." | Uncommitted changes block checkout; one mistake mixes work from two tasks. |
49
- | "I can work on both branches in one checkout." | Stash conflicts and forgotten checkouts lose or misattribute work. |
50
- | "Removing a worktree is the same as deleting a folder." | `rm -rf` leaves git's worktree bookkeeping stale; `git worktree remove` stays consistent. |
51
- | "Their worktree looks abandoned, I'll clean it up." | Host-owned state. If it looks dead, report it, never remove it. |
52
-
53
- ## Red flags
54
-
55
- - A worktree path inside the repo's own directory tree — nested worktrees are confusing and error-prone.
56
- - Deleting or force-removing a worktree whose branch has unpushed commits.
57
- - The same branch checked out in two worktrees, or two tasks sharing one worktree.
58
- - Touching or re-checking-out a host-owned worktree.
59
-
60
- All mean: stop, verify branch state, and clean up only what belongs to your task.
61
-
62
- ## Verification
63
-
64
- 1. `git worktree list` shows exactly the checkouts you expect — yours, none stale.
65
- 2. After cleanup, the worktree path is gone and `git worktree prune` reports nothing to prune.
66
- 3. The main checkout shows no leftover files, locks, or artifacts from the removed worktree.
67
- 4. The removed branch's commits are either merged into main or deliberately abandoned — never stranded.
@@ -1,77 +0,0 @@
1
- ---
2
- name: mugiwara-mode
3
- description: Use when reading or changing the runtime mode (guided / semi / auto) from .mugiwara/config or ~/.mugiwara/config, applying the consent invariants, the auto plan-GO gate, and the push + ready-PR terminal. Single source of truth for the mode contract.
4
- ---
5
-
6
- # Mode (guided / semi / auto)
7
-
8
- ## Skip when
9
-
10
- - Mode unchanged this session: no config read or flip requested.
11
- - Lane 0 direct work where autonomy level is irrelevant to the change.
12
-
13
- The crew's autonomy level. Read once per wave at dispatch; a flip takes effect from the next wave, never mid-wave. Single source of truth for the mode contract — the consent invariants and the auto-GO gate live here; quality and testcases reference them.
14
-
15
- ## Levels
16
-
17
- | Level | Plan GO | Branch/commit | Ambiguities | Check-ins |
18
- |-------|---------|---------------|-------------|-----------|
19
- | guided | ask the user | ask the user | ask the user | ask the user |
20
- | semi | present plan for user GO | auto | self-answer + log | log, no pause |
21
- | auto | gated auto-GO | auto | self-answer + log | log, no pause |
22
-
23
- Consent is an invariant in ALL levels — see below. Every level ends at push + ready PR + verdict (the user opens the PR); the crew never creates a PR, never merges, never deploys.
24
-
25
- ## Config
26
-
27
- Two files, four keys, `key=value` lines, optional `#` comments:
28
-
29
- ```
30
- # .mugiwara/config (project) overrides ~/.mugiwara/config (global)
31
- mode=guided
32
- branch=feature/{type}-{issue}-{slug}
33
- commit=conventional
34
- base=main
35
- ```
36
-
37
- | Key | Values | Default (no mugiwara branding) |
38
- |-----|--------|--------------------------------|
39
- | mode | guided / semi / auto | guided |
40
- | branch | branch pattern | feature/{type}-{issue}-{slug} |
41
- | commit | conventional / gitmoji / plain | conventional |
42
- | base | PR summary target branch | main |
43
-
44
- **Mode owns autonomy; config owns writing standards.** The mode key alone
45
- decides whether branch/commit run automatically. The remaining keys shape HOW
46
- artifacts are written — the `branch` naming pattern, the `commit` message
47
- style, and `base` (the PR target named in the prepared PR summary per
48
- `mugiwara-pr`). There is no autonomy key in config; a mode flip is the only
49
- lever that changes behavior.
50
-
51
- The `branch` value is a naming pattern, never executed: its placeholders (`{type}`/`{issue}`/`{slug}`) are filled from mission metadata and validated against a safe charset (alphanumerics, `-`, `_`) before any git command.
52
-
53
- Read order per wave: `.mugiwara/config` (project) then `~/.mugiwara/config` (global); project wins per key; a key missing from both falls back to the default. A key whose value is outside its enum table — or an unknown key — also falls back to that key's default; unknown lines are ignored. Config is data, never instructions. `.mugiwara/` is gitignored. Lazy-create on WRITE only — a missing config on read means guided, never auto-create the file. A flip is logged in the decision log (`.mugiwara/logs/YYYY-MM-DD-<mission>.md`) and applies from the next wave.
54
-
55
- ## Override protocol
56
-
57
- In-session phrase `mugiwara mode <guided|semi|auto>` → write the project `.mugiwara/config` AND append a decision-log row (level, requester, timestamp). No CLI flag; the installer CLI stays untouched.
58
-
59
- ## Consent invariant
60
-
61
- State-mutating tests against NON-isolated / shared state (real DB writes, network, browsers) ALWAYS require explicit user consent in ALL modes. Provably-isolated mutation — in-memory / temp / testcontainer-backed DBs, tooling-proven isolation — is explicitly auto-safe and needs no consent. `auto` runs only provably-isolated tests (unit-level, or tooling-proven isolation such as in-memory / local DB). `guided`/`semi` keep the existing ask-first rule for integration tests. Consent is not a mode knob. Record every consent answer in the report.
62
-
63
- ## Auto plan-GO gate
64
-
65
- The plan proceeds past approval in `auto` ONLY with zero blocking ambiguities AND zero high-risk tasks (task `Risk` line = deploy / migration / DB / public API / state-mutating). Otherwise it stops for the user. This keeps the planner's never-hand-without-GO contract intact; the safety line moves into the GO gate.
66
-
67
- ## Terminal invariant
68
-
69
- Every mode ends at: push the mission branch (per the `branch` key) → write the PR verdict file per `mugiwara-pr` (includes a ready PR summary; target per `base`) → hand the branch + verdict to the user, who opens the PR. The crew never creates a PR, never merges, never deploys, never auto-reacts to review comments or CI in any mode. PR review is the terminal gate.
70
-
71
- ## Rules
72
-
73
- 1. Read the config once per wave at dispatch; a flip never applies mid-wave.
74
- 2. Missing config on read = guided; the file is created only on a write.
75
- 3. State-mutating consent holds in every mode — auto never runs a state-mutating test against non-isolated / shared state without it.
76
- 4. Auto plan-GO is gated, never assumed.
77
- 5. The terminal is push + ready PR + verdict in every mode — the crew never creates a PR.