@ionivetech/mugiwara 0.5.1 → 0.5.3

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 (53) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.claude-plugin/marketplace.json +18 -0
  3. package/.claude-plugin/plugin.json +64 -0
  4. package/.claude-plugin/sync.sh +18 -0
  5. package/.codex-plugin/plugin.json +18 -0
  6. package/.cursor-plugin/plugin.json +19 -0
  7. package/.kimi-plugin/plugin.json +18 -0
  8. package/.opencode/commands/mugiwara.md +13 -7
  9. package/.opencode/commands/using-mugiwara.md +26 -0
  10. package/.opencode/plugins/mugiwara-helpers.mjs +90 -0
  11. package/.opencode/plugins/mugiwara.mjs +10 -107
  12. package/AGENTS.md +183 -0
  13. package/GEMINI.md +12 -0
  14. package/README.md +86 -56
  15. package/content/agents/luffy-orchestrator.md +1 -1
  16. package/content/agents/zoro-execution.md +1 -1
  17. package/content/skills/mugiwara-execution/SKILL.md +2 -5
  18. package/content/skills/{mugiwara-proof-order/SKILL.md → mugiwara-execution/references/tdd.md} +4 -7
  19. package/content/skills/using-mugiwara/SKILL.md +52 -0
  20. package/dist/mugiwara.js +35 -4
  21. package/docs/adoption-guide.md +1 -1
  22. package/docs/agents.md +5 -3
  23. package/docs/claude-setup.md +1 -1
  24. package/docs/developer-onboarding.md +1 -1
  25. package/docs/getting-started.md +1 -1
  26. package/docs/index.md +1 -1
  27. package/docs/install-antigravity.md +45 -0
  28. package/docs/install-claude.md +75 -0
  29. package/docs/install-cli.md +103 -0
  30. package/docs/install-codex.md +44 -0
  31. package/docs/install-copilot.md +45 -0
  32. package/docs/install-cursor.md +45 -0
  33. package/docs/install-gemini.md +44 -0
  34. package/docs/install-kimi.md +45 -0
  35. package/docs/install-opencode.md +129 -0
  36. package/docs/install-pi.md +46 -0
  37. package/docs/install.md +53 -0
  38. package/docs/opencode-setup.md +1 -1
  39. package/docs/skills.md +1 -1
  40. package/evals/cases/routing-claim-audit.json +1 -1
  41. package/evals/cases/routing-using-mugiwara.json +25 -0
  42. package/evals/floor.json +1 -1
  43. package/gemini-extension.json +6 -0
  44. package/hooks/hooks.json +11 -0
  45. package/hooks/mugiwara-mode-tracker.ts +80 -0
  46. package/hooks/session-start.ts +1 -1
  47. package/package.json +13 -2
  48. package/plugin.json +15 -0
  49. package/src/targets/opencode.ts +39 -3
  50. package/.opencode/commands/mugiwara-mode.md +0 -6
  51. package/content/agents/using-mugiwara.md +0 -44
  52. package/content/skills/mugiwara-proof-order/references/proof-order-examples.md +0 -62
  53. package/evals/cases/routing-proof-order.json +0 -25
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "mugiwara",
3
+ "interface": {
4
+ "displayName": "Mugiwara"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "mugiwara",
9
+ "source": {
10
+ "source": "url",
11
+ "url": "./"
12
+ },
13
+ "policy": {
14
+ "installation": "AVAILABLE",
15
+ "authentication": "ON_INSTALL"
16
+ },
17
+ "category": "Developer Tools"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "mugiwara",
3
+ "owner": {
4
+ "name": "ionive"
5
+ },
6
+ "metadata": {
7
+ "description": "The Straw Hat crew for AI agents",
8
+ "version": "0.5.3"
9
+ },
10
+ "plugins": [
11
+ {
12
+ "name": "mugiwara",
13
+ "description": "The Straw Hat crew of AI agents and skills: brainstorm, plan, execute, checkpoint, quality, gates, review, security, healing.",
14
+ "version": "0.5.3",
15
+ "source": "./"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "mugiwara",
3
+ "displayName": "Mugiwara",
4
+ "version": "0.5.3",
5
+ "description": "The Straw Hat crew of AI agents and skills: brainstorm, plan, execute, checkpoint, quality, gates, review, security, healing.",
6
+ "author": {
7
+ "name": "ionive"
8
+ },
9
+ "license": "MIT",
10
+ "homepage": "https://github.com/ionivetech/mugiwara",
11
+ "repository": "https://github.com/ionivetech/mugiwara",
12
+ "keywords": [
13
+ "agents",
14
+ "skills",
15
+ "workflow",
16
+ "multi-agent"
17
+ ],
18
+ "metadata": {
19
+ "agents": [
20
+ "luffy-orchestrator",
21
+ "usopp-brainstorm",
22
+ "nami-planner",
23
+ "zoro-execution",
24
+ "chopper-checkpoint",
25
+ "sanji-quality",
26
+ "franky-gates",
27
+ "robin-reviewer",
28
+ "jinbe-security",
29
+ "brook-healing",
30
+ "skeptic-verifier",
31
+ "eval-runner",
32
+ "resume-coordinator",
33
+ "memory-keeper"
34
+ ],
35
+ "skills": [
36
+ "mugiwara-agent-security",
37
+ "mugiwara-backend",
38
+ "mugiwara-brainstorm",
39
+ "mugiwara-checkpoint",
40
+ "mugiwara-claim-audit",
41
+ "mugiwara-context-budget",
42
+ "mugiwara-contract-first",
43
+ "mugiwara-execution",
44
+ "mugiwara-frontend",
45
+ "mugiwara-gates",
46
+ "mugiwara-git",
47
+ "mugiwara-healing",
48
+ "mugiwara-lessons",
49
+ "mugiwara-orchestration",
50
+ "mugiwara-planning",
51
+ "mugiwara-pr",
52
+ "mugiwara-quality",
53
+ "mugiwara-resume",
54
+ "mugiwara-review",
55
+ "mugiwara-root-cause",
56
+ "mugiwara-security",
57
+ "mugiwara-ship",
58
+ "mugiwara-sunset",
59
+ "mugiwara-testcases",
60
+ "mugiwara-workflow",
61
+ "using-mugiwara"
62
+ ]
63
+ }
64
+ }
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env sh
2
+ # content/ is the single source of truth. Root agents/ and skills/ are
3
+ # symlinks to it so the Claude Code marketplace plugin (which reads from the
4
+ # plugin root) and the npm package consumers see the same files.
5
+ set -eu
6
+ ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
7
+
8
+ for pair in "agents:content/agents" "skills:content/skills"; do
9
+ link="${pair%%:*}"
10
+ target="${pair#*:}"
11
+ if [ -L "$ROOT/$link" ]; then
12
+ echo "ok $link -> $target"
13
+ else
14
+ rm -rf "$ROOT/$link"
15
+ ln -s "$target" "$ROOT/$link"
16
+ echo "linked $link -> $target"
17
+ fi
18
+ done
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "mugiwara",
3
+ "version": "0.5.3",
4
+ "description": "The Straw Hat crew of AI agents and skills: brainstorm, plan, execute, checkpoint, quality, gates, review, security, healing.",
5
+ "author": {
6
+ "name": "ionive"
7
+ },
8
+ "homepage": "https://github.com/ionivetech/mugiwara",
9
+ "repository": "https://github.com/ionivetech/mugiwara",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "agents",
13
+ "skills",
14
+ "workflow",
15
+ "multi-agent"
16
+ ],
17
+ "skills": "./content/skills/"
18
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "mugiwara",
3
+ "displayName": "Mugiwara",
4
+ "description": "The Straw Hat crew of AI agents and skills: brainstorm, plan, execute, checkpoint, quality, gates, review, security, healing.",
5
+ "version": "0.5.3",
6
+ "author": {
7
+ "name": "ionive"
8
+ },
9
+ "homepage": "https://github.com/ionivetech/mugiwara",
10
+ "repository": "https://github.com/ionivetech/mugiwara",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "agents",
14
+ "skills",
15
+ "workflow",
16
+ "multi-agent"
17
+ ],
18
+ "skills": "./content/skills/"
19
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "mugiwara",
3
+ "version": "0.5.3",
4
+ "description": "The Straw Hat crew of AI agents and skills: brainstorm, plan, execute, checkpoint, quality, gates, review, security, healing.",
5
+ "author": {
6
+ "name": "ionive"
7
+ },
8
+ "homepage": "https://github.com/ionivetech/mugiwara",
9
+ "repository": "https://github.com/ionivetech/mugiwara",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "agents",
13
+ "skills",
14
+ "workflow",
15
+ "multi-agent"
16
+ ],
17
+ "skills": "./content/skills/"
18
+ }
@@ -1,11 +1,17 @@
1
1
  ---
2
- description: Run the mugiwara crew workflow for a task
2
+ description: Run the mugiwara crew workflow or switch runtime mode (guided | semi | auto)
3
3
  ---
4
- Mugiwara workflow:
4
+ Mugiwara mode: $ARGUMENTS
5
5
 
6
- 1. The crew runs inline in the main conversation. Start any non-trivial task through `using-mugiwara` (embodied inline) to route to the right crew member.
7
- 2. The pipeline flows: Luffy triage -> Usopp brainstorm (when needed) -> Nami planning -> Zoro execution -> Chopper checkpoint -> Sanji quality -> Franky gates -> Robin/Jinbe review -> Brook healing -> Luffy closure.
8
- 3. Subagents are used only for parallel work (Zoro's [PARALLEL] workers, Robin + Jinbe concurrent review, independent re-run checks).
9
- 4. Switch runtime mode with `/mugiwara-mode` (guided | semi | auto). Default is guided.
6
+ Run the crew pipeline inline. To switch autonomy mode:
10
7
 
11
- See skills/mugiwara-workflow for the full pipeline.
8
+ ```
9
+ /mugiwara guided # human decides every GO
10
+ /mugiwara semi # auto branch + commit, plan needs GO
11
+ /mugiwara auto # hands-off except high-risk
12
+ /mugiwara # show current mode
13
+ ```
14
+
15
+ The flip applies from the next wave. Valid modes: guided, semi, auto.
16
+
17
+ For workflow: embody `using-mugiwara` inline to classify and route. See skills/mugiwara-workflow for the full pipeline.
@@ -0,0 +1,26 @@
1
+ ---
2
+ description: Front-door router: explain how mugiwara works, classify a mission, or route to the right crew member
3
+ ---
4
+ Using Mugiwara: $ARGUMENTS
5
+
6
+ Mugiwara crew available. The workflow auto-activates for non-trivial requests.
7
+
8
+ ## How it works
9
+
10
+ - 14 agents: Luffy (triage), Usopp (brainstorm), Nami (plan), Zoro (execute), Chopper (audit), Sanji (quality), Franky (gates), Robin (review), Jinbe (security), Brook (heal), Skeptic (verify), Eval Runner, Resume, Memory
11
+ - 26 skills — one per crew role + domain skills (frontend, backend, git, security)
12
+ - 9-wave pipeline runs inline in the main conversation
13
+ - Evidence over claims at every wave
14
+ - Autonomy modes: guided, semi, auto
15
+
16
+ ## What to do
17
+
18
+ 1. If the user asks how mugiwara works — summarize in 3 lines.
19
+ 2. If the user gives a task — classify (Trivial/Explicit/Exploratory/Open-ended/Ambiguous) and route:
20
+ - Clear, small → route to nami-planner or zoro-execution directly.
21
+ - Vague, needs direction → route to usopp-brainstorm.
22
+ - Anything else → route to luffy-orchestrator (full triage).
23
+ - Specialized: review → robin-reviewer, security → jinbe-security, etc.
24
+ 3. Record the route in `.mugiwara/logs/`.
25
+
26
+ Skills: mugiwara-workflow, mugiwara-orchestration. See skills/mugiwara-workflow for the full pipeline.
@@ -0,0 +1,90 @@
1
+ // mugiwara helpers — extracted from mugiwara.mjs so the plugin module has a
2
+ // single export. OpenCode's legacy loader calls every exported function as a
3
+ // plugin; keeping helpers in a separate module avoids them being invoked with
4
+ // the plugin context as first argument (same pattern ponytail uses).
5
+
6
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, appendFileSync, lstatSync, renameSync } from 'node:fs';
7
+ import { homedir, tmpdir } from 'node:os';
8
+ import { dirname, join } from 'node:path';
9
+
10
+ export const VALID_MODES = new Set(['guided', 'semi', 'auto']);
11
+
12
+ export function readMode({ projectDir = process.cwd(), home = homedir() } = {}) {
13
+ const readValue = (dir) => {
14
+ const file = join(dir, '.mugiwara', 'config');
15
+ if (!existsSync(file)) return undefined;
16
+ for (const line of readFileSync(file, 'utf8').split(/\r?\n/)) {
17
+ const t = line.trim();
18
+ if (!t || t.startsWith('#')) continue;
19
+ const [k, v] = line.split('=').map((s) => s.trim());
20
+ if (k !== 'mode') continue;
21
+ return VALID_MODES.has(v) ? v : 'INVALID';
22
+ }
23
+ return undefined;
24
+ };
25
+ const proj = readValue(projectDir);
26
+ if (proj === 'INVALID') return 'guided';
27
+ if (proj) return proj;
28
+ const glob = readValue(home);
29
+ if (glob === 'INVALID') return 'guided';
30
+ if (glob) return glob;
31
+ return 'guided';
32
+ }
33
+
34
+ export function parseModeChange(promptRaw) {
35
+ if (typeof promptRaw !== 'string') return null;
36
+ let prompt = promptRaw.trim();
37
+ const wrapped = /^(["'`])([\s\S]*)\1$/.exec(prompt);
38
+ if (wrapped) prompt = wrapped[2].trim();
39
+ prompt = prompt.toLowerCase();
40
+ if (!prompt) return null;
41
+
42
+ const tplSet = /^(?:set |)mugiwara mode:[ \t]*(\S*)/.exec(prompt);
43
+ if (tplSet && VALID_MODES.has(tplSet[1])) return tplSet[1];
44
+
45
+ const slash = /^\/(?:mugiwara[-\s]?)?mode[ \t]+(\S*)/.exec(prompt);
46
+ if (slash && VALID_MODES.has(slash[1])) return slash[1];
47
+
48
+ const slashMain = /^\/mugiwara[ \t]+(\S*)/.exec(prompt);
49
+ if (slashMain && VALID_MODES.has(slashMain[1])) return slashMain[1];
50
+
51
+ const natural = /^mugiwara mode[ \t]+(\S*)/.exec(prompt);
52
+ if (natural && VALID_MODES.has(natural[1])) return natural[1];
53
+
54
+ return null;
55
+ }
56
+
57
+ function assertNotSymlink(file) {
58
+ if (!existsSync(file)) return;
59
+ try {
60
+ const st = lstatSync(file);
61
+ if (st.isSymbolicLink()) throw new Error(`refusing to follow symlink: ${file}`);
62
+ } catch (e) {
63
+ if (e.code === 'ENOENT') return;
64
+ throw e;
65
+ }
66
+ }
67
+
68
+ export function applyModeChange(mode, { projectDir = process.cwd(), home = homedir() } = {}) {
69
+ if (!VALID_MODES.has(mode)) return;
70
+ const dir = join(projectDir, '.mugiwara');
71
+ const file = join(dir, 'config');
72
+ assertNotSymlink(file);
73
+ mkdirSync(dir, { recursive: true });
74
+ const lines = [];
75
+ if (existsSync(file)) {
76
+ for (const line of readFileSync(file, 'utf8').split(/\r?\n/)) {
77
+ const t = line.trim();
78
+ if (t.startsWith('mode=')) continue;
79
+ lines.push(line);
80
+ }
81
+ }
82
+ lines.push(`mode=${mode}`);
83
+ const body = lines.filter((l, i) => !(l === '' && (i === lines.length - 1 || i === 0))).join('\n') + '\n';
84
+ const tmp = join(tmpdir(), `mugiwara-config-${process.pid}-${Date.now()}.tmp`);
85
+ writeFileSync(tmp, body);
86
+ renameSync(tmp, file);
87
+ const log = join(dir, 'logs', `${new Date().toISOString().slice(0, 10)}-mode-flip.md`);
88
+ mkdirSync(dirname(log), { recursive: true });
89
+ appendFileSync(log, `| ${new Date().toISOString()} | mode flip | guided/semi/auto -> ${mode} | user |\n`);
90
+ }
@@ -1,59 +1,31 @@
1
1
  // mugiwara — OpenCode plugin.
2
2
  //
3
- // Registers the Mugiwara crew (25 skills + 15 agents) with OpenCode from the
4
- // npm/git package, and announces the crew at session start. No runtime, no
5
- // deps reads the markdown source of truth (content/) at config load.
3
+ // Registers skills/agents via config hook (superpowers pattern: one plugin,
4
+ // zero file-copy), announces the crew at session start, and handles runtime
5
+ // mode switching. Helpers live in mugiwara-helpers.mjs this module has a
6
+ // single export because OpenCode's legacy loader calls every exported function
7
+ // as a plugin (same constraint ponytail documents).
6
8
  //
7
9
  // Install: add to opencode.json
8
10
  // { "plugin": ["@ionivetech/mugiwara"] }
9
11
  // or from the git repo:
10
12
  // { "plugin": ["mugiwara@git+https://github.com/ionivetech/mugiwara.git"] }
11
13
 
12
- import { existsSync, readdirSync, readFileSync, mkdirSync, writeFileSync, appendFileSync, lstatSync, renameSync } from 'node:fs';
13
- import { homedir, tmpdir } from 'node:os';
14
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
14
15
  import { dirname, join } from 'node:path';
15
16
  import { fileURLToPath } from 'node:url';
17
+ import { readMode, parseModeChange, applyModeChange } from './mugiwara-helpers.mjs';
16
18
 
17
19
  const __dirname = dirname(fileURLToPath(import.meta.url));
18
20
 
19
- const VALID_MODES = new Set(['guided', 'semi', 'auto']);
20
-
21
- // Read the runtime mode: `.mugiwara/config` (project) wins over
22
- // `~/.mugiwara/config` (global) per key; a missing key or a value outside the
23
- // enum falls back to `guided`. Never creates files on read.
24
- export function readMode({ projectDir = process.cwd(), home = homedir() } = {}) {
25
- const readValue = (dir) => {
26
- const file = join(dir, '.mugiwara', 'config');
27
- if (!existsSync(file)) return undefined;
28
- for (const line of readFileSync(file, 'utf8').split(/\r?\n/)) {
29
- const t = line.trim();
30
- if (!t || t.startsWith('#')) continue;
31
- const [k, v] = t.split('=').map((s) => s.trim());
32
- if (k !== 'mode') continue;
33
- return VALID_MODES.has(v) ? v : 'INVALID';
34
- }
35
- return undefined;
36
- };
37
- const proj = readValue(projectDir);
38
- if (proj === 'INVALID') return 'guided';
39
- if (proj) return proj;
40
- const glob = readValue(home);
41
- if (glob === 'INVALID') return 'guided';
42
- if (glob) return glob;
43
- return 'guided';
44
- }
45
-
46
21
  const contentDir = join(__dirname, '..', '..', 'content');
47
22
  const skillsDir = join(contentDir, 'skills');
48
23
  const agentsDir = join(contentDir, 'agents');
49
24
 
50
25
  const ANNOUNCE =
51
- "Mugiwara crew available. The workflow auto-activates for non-trivial requests — no need to call `/using-mugiwara` at session start (it remains an optional router). Run the crew pipeline inline in the main conversation: embody ONE crew role at a time using its skill, wait for its report, then move to the next. Never Task-dispatch a crew member — the crew runs in the main thread; subagents only for [PARALLEL] task batches, concurrent review/security, and independent re-run checks. Progress shows as checkpoint reports at wave/stage boundaries, pausing on failure or risk. Switch mode with `/mugiwara-mode` (guided|semi|auto). See skills/mugiwara-workflow.";
26
+ "Mugiwara crew available. The workflow auto-activates for non-trivial requests — no need to call `/using-mugiwara` at session start (it is an optional router). Run the crew pipeline inline in the main conversation: embody ONE crew role at a time using its skill, wait for its report, then move to the next. Never Task-dispatch a crew member — the crew runs in the main thread; subagents only for [PARALLEL] task batches, concurrent review/security, and independent re-run checks. Progress shows as checkpoint reports at wave/stage boundaries, pausing on failure or risk. Switch mode with `/mugiwara` (guided|semi|auto). See skills/mugiwara-workflow.";
52
27
 
53
- // OpenCode per-agent tuning. Content stays portable markdown; these knobs
54
- // (color, temperature, permission, steps) are opencode-only.
55
28
  const CREW = {
56
- 'using-mugiwara': { color: '#84cc16', temperature: 0.2, steps: 10 },
57
29
  'luffy-orchestrator': { color: '#ef4444', temperature: 0.2, steps: 15 },
58
30
  'usopp-brainstorm': { color: '#f59e0b', temperature: 0.6, steps: 15 },
59
31
  'nami-planner': { color: '#f97316', temperature: 0.2, steps: 15 },
@@ -106,73 +78,9 @@ function readAgents() {
106
78
  return agents;
107
79
  }
108
80
 
109
- // Parse a user prompt for a mugiwara mode change. Returns the new mode or null.
110
- // Mirrors the caveman plugin pattern: opencode expands `/mugiwara-mode <level>`
111
- // into the command file's body ("Set mugiwara mode: <level>...") before
112
- // chat.message fires, so parse the template's first line too. The slash command
113
- // and natural-language phrase must sit at the START of the prompt — a bare
114
- // mention mid-message (pasted untrusted content) never flips autonomy.
115
- export function parseModeChange(promptRaw) {
116
- if (typeof promptRaw !== 'string') return null;
117
- let prompt = promptRaw.trim();
118
- const wrapped = /^(["'`])([\s\S]*)\1$/.exec(prompt);
119
- if (wrapped) prompt = wrapped[2].trim();
120
- prompt = prompt.toLowerCase();
121
- if (!prompt) return null;
122
-
123
- const tpl = /^set mugiwara mode:[ \t]*(\S*)/.exec(prompt);
124
- if (tpl && VALID_MODES.has(tpl[1])) return tpl[1];
125
-
126
- const slash = /^\/(mugiwara[-\s]?)mode[ \t]+(\S*)/.exec(prompt);
127
- if (slash && VALID_MODES.has(slash[2])) return slash[2];
128
-
129
- const natural = /^mugiwara mode[ \t]+(\S*)/.exec(prompt);
130
- if (natural && VALID_MODES.has(natural[1])) return natural[1];
131
-
132
- return null;
133
- }
134
-
135
- // Refuse to follow a symlinked .mugiwara/config — a malicious repo could point
136
- // it at ~/.bashrc and any mode flip would overwrite the target.
137
- function assertNotSymlink(file) {
138
- if (!existsSync(file)) return;
139
- try {
140
- const st = lstatSync(file);
141
- if (st.isSymbolicLink()) throw new Error(`refusing to follow symlink: ${file}`);
142
- } catch (e) {
143
- if (e.code === 'ENOENT') return;
144
- throw e;
145
- }
146
- }
147
-
148
- // Write `.mugiwara/config` (project) and append a decision-log row.
149
- // Atomic: write a temp file next to the target, then rename over it, so a
150
- // crash mid-write never truncates the config (keeps branch/commit keys).
151
- export function applyModeChange(mode, { projectDir = process.cwd(), home = homedir() } = {}) {
152
- if (!VALID_MODES.has(mode)) return;
153
- const dir = join(projectDir, '.mugiwara');
154
- const file = join(dir, 'config');
155
- assertNotSymlink(file);
156
- mkdirSync(dir, { recursive: true });
157
- const lines = [];
158
- if (existsSync(file)) {
159
- for (const line of readFileSync(file, 'utf8').split(/\r?\n/)) {
160
- const t = line.trim();
161
- if (t.startsWith('mode=')) continue;
162
- lines.push(line);
163
- }
164
- }
165
- lines.push(`mode=${mode}`);
166
- const body = lines.filter((l, i) => !(l === '' && (i === lines.length - 1 || i === 0))).join('\n') + '\n';
167
- const tmp = join(tmpdir(), `mugiwara-config-${process.pid}-${Date.now()}.tmp`);
168
- writeFileSync(tmp, body);
169
- renameSync(tmp, file);
170
- const log = join(dir, 'logs', `${new Date().toISOString().slice(0, 10)}-mode-flip.md`);
171
- mkdirSync(dirname(log), { recursive: true });
172
- appendFileSync(log, `| ${new Date().toISOString()} | mode flip | guided/semi/auto -> ${mode} | user |\n`);
173
- }
174
-
175
81
  export default async () => ({
82
+ dispose: () => {},
83
+
176
84
  config: (config) => {
177
85
  config.skills = config.skills || {};
178
86
  config.skills.paths = config.skills.paths || [];
@@ -185,8 +93,6 @@ export default async () => ({
185
93
  }
186
94
  },
187
95
 
188
- // Intercept user messages to detect `/mugiwara-mode` and natural-language
189
- // mode toggles; write `.mugiwara/config` so the next wave reads the new level.
190
96
  'chat.message': async (_input, output) => {
191
97
  if (!output) return;
192
98
  if (typeof output === 'string') {
@@ -204,9 +110,6 @@ export default async () => ({
204
110
  }
205
111
  },
206
112
 
207
- // ponytail-proven hook; appends the announce string to the system prompt.
208
- // Dedupes: repeated transforms (model switch/compaction) must not grow the
209
- // prompt unbounded — only append once per string content.
210
113
  'experimental.chat.system.transform': async (_input, output) => {
211
114
  if (!output.system.some((s) => s.includes('Mugiwara crew available'))) {
212
115
  if (output.system.length > 0) {
package/AGENTS.md ADDED
@@ -0,0 +1,183 @@
1
+ # Mugiwara Development Standards
2
+
3
+ Rules for working on this repo. Follow these or validation fails.
4
+
5
+ ## Language
6
+
7
+ **All files must be English.** Skills, agents, docs, scripts, references — no
8
+ exceptions. Comments in source code should be English. This conversation is the
9
+ only place Indonesian is acceptable.
10
+
11
+ ## Trunk-based branching strategy
12
+
13
+ `main` is always stable and releasable. No commits directly to `main`.
14
+
15
+ | Branch | Purpose | Lifetime |
16
+ |--------|---------|----------|
17
+ | `main` | Source of truth. Always passes CI. | Permanent |
18
+ | `feat/*`, `fix/*`, `chore/*`, `docs/*`, `refactor/*` | Feature work from main, PR to main | Short-lived, delete after merge |
19
+ | `release/vX.Y.Z` | Created from main for publishing. Archival. | Short-lived, delete after tag |
20
+
21
+ ### Flow
22
+
23
+ 1. Branch from `main`
24
+ 2. Work + validate locally
25
+ 3. PR to `main` — CI must pass (all gates)
26
+ 4. Merge to `main`
27
+ 5. Run "Manual Release" workflow on GitHub Actions → creates tag + npm publish + GitHub Release
28
+ 6. Release branch (`release/vX.Y.Z`) created from the release commit — archival
29
+
30
+ ### Branch naming
31
+
32
+ | Type | Pattern | Example |
33
+ |------|---------|---------|
34
+ | Feature | `feat/<description>` | `feat/add-mcp-audit-skill` |
35
+ | Fix | `fix/<description>` | `fix/token-budget-overflow` |
36
+ | Chore | `chore/<description>` | `chore/update-deps` |
37
+ | Docs | `docs/<description>` | `docs/rewrite-readme` |
38
+ | Refactor | `refactor/<description>` | `refactor/split-checkpoint` |
39
+ | Release | `release/vX.Y.Z` | `release/v0.5.0` |
40
+
41
+ ### Version bumping
42
+
43
+ | Trigger | Bump |
44
+ |---------|------|
45
+ | Bug fix, no new features | `patch` |
46
+ | New feature, backward-compatible | `minor` |
47
+ | Breaking change | `major` |
48
+
49
+ All version bumps via the Manual Release workflow — never manually edited.
50
+
51
+ ## Validation before commit (CI gates)
52
+
53
+ All must pass on every PR. Run locally with:
54
+
55
+ ```bash
56
+ bun run gate # everything CI runs on a PR
57
+ ```
58
+
59
+ ### Per-PR gates
60
+
61
+ ```bash
62
+ bun run typecheck # TypeScript
63
+ bun run test # 70 tests
64
+ bun run build # dist/
65
+ bun scripts/validate-content.ts --check-manifest --check-docs # content + manifest + docs drift + budget + section length + description hygiene
66
+ bun scripts/run-evals.ts # behavioral evals
67
+ bun scripts/retrieval-eval.ts # retrieval ranking + floor ratchet
68
+ bun scripts/verify-install.ts # G1: resolve all references/*.md pointers after install
69
+ ```
70
+
71
+ ### Pre-release / weekly gates
72
+
73
+ | Gate | Script | Purpose |
74
+ |------|--------|---------|
75
+ | G3 meta-eval | `bun scripts/gate-selftest.ts` | Prove every gate can fail — catch rotted gates |
76
+
77
+ ### Where each gate runs
78
+
79
+ | Gate | Pre-commit | Every PR | Pre-release | Weekly |
80
+ |------|:---:|:---:|:---:|:---:|
81
+ | typecheck, test, build | ✅ | ✅ | ✅ | |
82
+ | validate-content (+manifest, docs, sections, descriptions) | ✅ | ✅ | ✅ | |
83
+ | run-evals | | ✅ | ✅ | |
84
+ | retrieval-eval + ratchet | | ✅ | ✅ | |
85
+ | **G1 verify-install** | | ✅ | ✅ | |
86
+ | **G2 computed fixtures** | ✅ | ✅ | ✅ | |
87
+ | **G3 gate-selftest** | | | ✅ | ✅ |
88
+
89
+ ### Gate design
90
+
91
+ **A gate that cannot fail is not a gate.** Every gate must have a corresponding
92
+ mutation in `scripts/gate-selftest.ts` proving it goes red. Adding a gate
93
+ without adding its mutation is an incomplete change.
94
+
95
+ **Every production defect adds a gate before the fix merges.** Record the defect
96
+ class, not just the instance. The fix closes one instance — the gate closes the
97
+ class.
98
+
99
+ No PR merges without all green CI.
100
+
101
+ ## Skill standards
102
+
103
+ Every skill is `content/skills/<name>/SKILL.md`:
104
+
105
+ | Rule | Limit | Validated |
106
+ |------|-------|:---:|
107
+ | Frontmatter `name` matches directory | exact match | ✅ |
108
+ | `description` length | 20–220 chars | ✅ |
109
+ | `description` content | trigger keywords + disambiguators only, no procedure | ✅ |
110
+ | Body lines | ≤120 | ✅ |
111
+ | `## Skip when` block | 1–4 bullets, numeric threshold | ✅ |
112
+ | Sections >15–20 lines | move to `references/<topic>.md`, one-line pointer in body | ✅ |
113
+ | Language | **English only** | ✅ |
114
+
115
+ ## Agent standards
116
+
117
+ Every agent is `content/agents/<name>.md`:
118
+
119
+ | Rule | Requirement |
120
+ |------|------------|
121
+ | Frontmatter `name` matches filename | exact match (without `.md`) |
122
+ | `description` | pointer line: "Persona for <skill>. <role summary>." |
123
+ | `skills` | list of held skills, comma-separated |
124
+ | `permissions` | optional: `read-only`, `can-write`, `no-network` |
125
+ | Language | **English only** |
126
+
127
+ ## Reference files
128
+
129
+ Two locations:
130
+ - `references/` — shared, linked from multiple skills. Installed to `_shared/references/` (tier 1) or `.mugiwara/refs/_shared/` (tier 2/3).
131
+ - `content/skills/<name>/references/` — skill-specific
132
+
133
+ Any `references/*.md` pointer in a skill body must resolve **after install**,
134
+ verified by `scripts/verify-install.ts`. A pointer correct in the repo but
135
+ broken after install is a defect, not a docs nit.
136
+
137
+ Body → one-line pointer: "Full checklist: `references/checklist.md` — 37 items;
138
+ unchecked boxes are not done." Never just a bare filename.
139
+
140
+ ## State fields
141
+
142
+ `state.json` is the audit trail. Every field in `state.json` is computed, never
143
+ model-supplied. Every field has a fixture assertion in `test/savepoint.test.ts`
144
+ with a non-trivial expected value. A field that can silently read `0` is worse
145
+ than an absent field — absence is visible, a wrong zero is not.
146
+
147
+ ## Index budget
148
+
149
+ Combined skill + agent description chars must be ≤5500. Enforced by validator.
150
+ Trimming descriptions = always drop procedure, keep trigger vocabulary.
151
+
152
+ ## Manifest sync
153
+
154
+ `.claude-plugin/plugin.json` `metadata.skills` and `metadata.agents` must
155
+ set-equal `content/skills/` and `content/agents/`. Enforced by
156
+ `--check-manifest`. If you add/remove/rename a skill or agent, update the
157
+ manifest.
158
+
159
+ ## Docs drift
160
+
161
+ `docs/skills.md` must mention every skill directory. `docs/agents.md` must
162
+ mention every agent file. Enforced by `--check-docs`.
163
+
164
+ ## Skill count
165
+
166
+ 26 is the ceiling. A new skill replaces an old one — never add to grow.
167
+
168
+ ## Commit style
169
+
170
+ Conventional Commits: `feat:`, `fix:`, `refactor:`, `docs:`, `chore:`.
171
+
172
+ ## Directory map
173
+
174
+ ```
175
+ content/skills/ — 26 skill dirs, each with SKILL.md + optional references/
176
+ content/agents/ — 15 agent .md files
177
+ references/ — shared reference files (definition-of-done, source-grounding, etc.)
178
+ docs/ — user-facing documentation
179
+ scripts/ — validation + tooling scripts
180
+ src/ — CLI TypeScript source
181
+ test/ — vitest tests
182
+ evals/cases/ — eval case JSON files
183
+ ```