@ionivetech/mugiwara 0.2.0 → 0.4.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/.opencode/commands/mugiwara-execute.md +11 -0
- package/.opencode/commands/mugiwara-heal.md +11 -0
- package/.opencode/commands/mugiwara-mode.md +6 -0
- package/.opencode/commands/mugiwara-plan.md +15 -0
- package/.opencode/commands/mugiwara-review.md +11 -0
- package/.opencode/commands/mugiwara-security.md +11 -0
- package/.opencode/commands/mugiwara-ship.md +11 -0
- package/.opencode/commands/mugiwara.md +11 -0
- package/.opencode/plugins/mugiwara.mjs +126 -7
- package/README.md +338 -355
- package/content/agents/brook-healing.md +2 -2
- package/content/agents/luffy-orchestrator.md +3 -2
- package/content/agents/robin-reviewer.md +1 -1
- package/content/agents/skeptic-verifier.md +1 -1
- package/content/agents/using-mugiwara.md +5 -1
- package/content/agents/usopp-brainstorm.md +1 -1
- package/content/agents/zoro-execution.md +1 -1
- package/content/skills/mugiwara-agent-security/SKILL.md +5 -0
- package/content/skills/mugiwara-api-and-interface-design/SKILL.md +92 -0
- package/content/skills/mugiwara-backend/SKILL.md +5 -0
- package/content/skills/mugiwara-brainstorm/SKILL.md +5 -0
- package/content/skills/mugiwara-checkpoint/SKILL.md +5 -0
- package/content/skills/mugiwara-context-engineering/SKILL.md +64 -0
- package/content/skills/mugiwara-deprecation/SKILL.md +5 -0
- package/content/skills/mugiwara-doubt-driven-development/SKILL.md +70 -0
- package/content/skills/mugiwara-dynamic-workflow/SKILL.md +5 -0
- package/content/skills/mugiwara-eval/SKILL.md +5 -0
- package/content/skills/mugiwara-execution/SKILL.md +9 -0
- package/content/skills/mugiwara-frontend/SKILL.md +61 -59
- package/content/skills/mugiwara-frontend/references/checklist.md +37 -0
- package/content/skills/mugiwara-gates/SKILL.md +9 -0
- package/content/skills/mugiwara-git/SKILL.md +5 -0
- package/content/skills/mugiwara-git-worktrees/SKILL.md +67 -0
- package/content/skills/mugiwara-healing/SKILL.md +17 -0
- package/content/skills/mugiwara-lessons/SKILL.md +5 -0
- package/content/skills/mugiwara-mode/SKILL.md +18 -4
- package/content/skills/mugiwara-observability/SKILL.md +5 -0
- package/content/skills/mugiwara-orchestration/SKILL.md +32 -1
- package/content/skills/mugiwara-planning/SKILL.md +25 -26
- package/content/skills/mugiwara-pr/SKILL.md +22 -6
- package/content/skills/mugiwara-quality/SKILL.md +15 -0
- package/content/skills/mugiwara-resume/SKILL.md +5 -0
- package/content/skills/mugiwara-review/SKILL.md +5 -0
- package/content/skills/mugiwara-security/SKILL.md +51 -14
- package/content/skills/mugiwara-ship/SKILL.md +29 -1
- package/content/skills/mugiwara-systematic-debugging/SKILL.md +82 -0
- package/content/skills/mugiwara-test-driven-development/SKILL.md +89 -0
- package/content/skills/mugiwara-testcases/SKILL.md +5 -0
- package/content/skills/mugiwara-workflow/SKILL.md +14 -3
- package/content/skills/mugiwara-writing-skills/SKILL.md +65 -0
- package/dist/mugiwara.js +175 -51
- package/docs/adoption-guide.md +3 -3
- package/docs/agents.md +2 -2
- package/docs/claude-setup.md +9 -4
- package/docs/codex-setup.md +3 -1
- package/docs/comparison.md +166 -44
- package/docs/config.md +53 -0
- package/docs/copilot-setup.md +3 -1
- package/docs/cursor-setup.md +3 -1
- package/docs/developer-onboarding.md +17 -13
- package/docs/enforcement.md +38 -0
- package/docs/execution-model.md +33 -0
- package/docs/gemini-setup.md +4 -1
- package/docs/getting-started.md +16 -4
- package/docs/index.md +14 -3
- package/docs/lanes.md +40 -0
- package/docs/modes.md +22 -12
- package/docs/opencode-setup.md +9 -2
- package/docs/pr-summary.md +54 -0
- package/docs/skill-anatomy.md +16 -6
- package/docs/skills.md +17 -5
- package/docs/troubleshooting.md +91 -0
- package/docs/windsurf-setup.md +3 -1
- package/docs/workflow.md +15 -6
- package/evals/cases/adversarial-pressure-fake-pass.json +12 -0
- package/evals/cases/adversarial-pressure-skip-review.json +13 -0
- package/evals/cases/lane-exploratory-vague.json +12 -0
- package/evals/cases/lane-sensitivity-payment.json +12 -0
- package/evals/cases/negative-secrets-typo.json +12 -0
- package/evals/cases/negative-security-docs-change.json +12 -0
- package/evals/cases/positive-refactor-existing-tests.json +11 -0
- package/evals/cases/positive-resume-mid-mission.json +11 -0
- package/evals/cases/routing-auth-feature.json +13 -0
- package/evals/cases/routing-bug-one-file.json +13 -0
- package/evals/cases/routing-typo.json +13 -0
- package/hooks/hooks.json +15 -0
- package/hooks/session-start.ts +8 -0
- package/package.json +3 -1
- package/src/args.ts +2 -1
- package/src/cli.ts +16 -20
- package/src/installer.ts +31 -3
- package/src/mission.ts +25 -0
- package/src/targets/claude.ts +22 -1
- package/src/targets/codex.ts +1 -1
- package/src/targets/copilot.ts +4 -0
- package/src/targets/gemini.ts +1 -1
- package/src/targets/generic.ts +33 -1
- package/src/targets/kilo.ts +1 -0
- package/src/targets/opencode.ts +4 -0
|
@@ -5,12 +5,23 @@ description: Use at the start of any non-trivial mission to run the Mugiwara cre
|
|
|
5
5
|
|
|
6
6
|
# Mugiwara Workflow
|
|
7
7
|
|
|
8
|
+
## Skip when
|
|
9
|
+
|
|
10
|
+
- Lane 0 direct work: typo, rename, or single-file fix under 20 LOC.
|
|
11
|
+
- User explicitly declined the harness for this request.
|
|
12
|
+
|
|
8
13
|
The Straw Hat harness: Wave 0 triage + Waves 1-9, with an optional adversarial pass at Wave 4.5. Waves are phases of the mission, not files — Nami writes them into the plan doc, Zoro executes them. The main thread runs the harness and embodies each crew role inline (Execution model below); the harness always starts through Luffy unless the user summons a crew member directly.
|
|
9
14
|
|
|
10
15
|
## Execution model (every harness)
|
|
11
16
|
|
|
12
17
|
**Inline by default.** The main/primary agent runs the pipeline and plays each crew role itself using that member's skill. Every wave's work is performed in the main conversation so the user sees the process live — no hidden subagent jumps, no click-to-expand. The crew members are personas + skills the main thread embodies, not mandatory dispatch targets.
|
|
13
18
|
|
|
19
|
+
**Visible wave transitions.** Every wave opens with a main-thread banner `## Wave N — <crew> (<skill>)` and closes with the handoff line `→ Wave N+1 — <crew>` (Wave 9: `→ closure`). No wave starts without its banner; the conversation names who runs now and who takes over next so the user always sees the chain live.
|
|
20
|
+
|
|
21
|
+
**Auto-activation.** Any non-trivial request fires the harness without the user asking. Check first, before exploring or answering: if the request could benefit from the crew, start Wave 0 triage. The user does not need to invoke `using-mugiwara` explicitly — the workflow starts itself.
|
|
22
|
+
|
|
23
|
+
**Checkpoint-report presentation.** The banner marks a stage boundary; no wave passes silently. At each boundary the owning crew reports inline — one compact per-crew report: what ran, the result, the evidence pointer. No narration of every tool call. Each wave closes with a short progress summary (done / in-flight / blocked + next handoff). On failure or risk, PAUSE: report the problem and get a continue / retry / escalate decision before proceeding.
|
|
24
|
+
|
|
14
25
|
1. For each wave, the main thread loads the owning crew member's skill (e.g. `mugiwara-checkpoint` for Wave 4) and performs that role inline: triage, planning, execution, audit, quality, gates, review, closure — all in the main thread.
|
|
15
26
|
2. Dispatch a subagent ONLY when the work is genuinely parallel or background: an independent `[PARALLEL]` task batch (Zoro's WORKER subagents, Wave 3), parallel fixes (Brook, Wave 8), or a long-running check that would stall the conversation. Subagent results return to the main thread as a report; the main thread summarizes the outcome inline with evidence pointers.
|
|
16
27
|
3. Crew members NEVER dispatch another crew member. A crew role that must split work returns the split plan to the main thread, which spawns the workers.
|
|
@@ -45,7 +56,7 @@ At session start, after context loss, or on any "where were we?" — embody `res
|
|
|
45
56
|
|
|
46
57
|
## Wave 0 — Luffy Triage (always first)
|
|
47
58
|
|
|
48
|
-
Front door: embody `using-mugiwara` inline (the router) — it routes to the right crew member and records the route. For a full triage embody `luffy-orchestrator` inline. NEVER start directly with brainstorming or planning. Luffy classifies every request 5 ways (Trivial / Explicit / Exploratory / Open-ended / Ambiguous) and routes: Trivial and Explicit → Wave 2 directly; Exploratory, Open-ended, and Ambiguous → Wave 1 brainstorm first. The user may summon any crew member directly — Luffy still records the route.
|
|
59
|
+
Front door: embody `using-mugiwara` inline (the router) — it routes to the right crew member and records the route. For a full triage embody `luffy-orchestrator` inline. NEVER start directly with brainstorming or planning. Luffy classifies every request 5 ways (Trivial / Explicit / Exploratory / Open-ended / Ambiguous) and routes: Trivial and Explicit → Wave 2 directly; Exploratory, Open-ended, and Ambiguous → Wave 1 brainstorm first. Alongside the class, Luffy sizes the mission and picks a lane (0 Direct / 1 Lean / 2 Standard / 3 Full / 4 Spike) — small work skips the pipeline, sensitive work never sneaks through the lean path. The user may summon any crew member directly — Luffy still records the route.
|
|
49
60
|
|
|
50
61
|
Alongside triage, read the mode config per `mugiwara-mode`: `.mugiwara/config` (project) then `~/.mugiwara/config` (global); a key missing from both = `guided`. Lazy-create the project config on first WRITE only, never auto-create on read.
|
|
51
62
|
|
|
@@ -77,12 +88,12 @@ Never silently work around a blocker. Brook reads this ledger at Wave 8 to decid
|
|
|
77
88
|
|
|
78
89
|
## Cleanup
|
|
79
90
|
|
|
80
|
-
At closure (Wave 9),
|
|
91
|
+
At closure (Wave 9), after the terminal step, run the cleanup procedure in `mugiwara-ship`: delete consumed intermediates — superseded results, review, issues reports, the per-mission decision log in `logs/`, and the consumed spec. Keep the plan doc, the closure report, the PR verdict, `config`, and cross-mission state (`logs/lessons.md`, `backup/`, `manifest.json`). List candidates before deleting.
|
|
81
92
|
|
|
82
93
|
## Rules
|
|
83
94
|
|
|
84
95
|
1. Evidence over claims: no wave passes on assertion. The owning agent runs the checks and shows output.
|
|
85
|
-
2. No wave skipped without the reason recorded in the decision log (`.mugiwara/logs/`).
|
|
96
|
+
2. No wave skipped without the reason recorded in the decision log (`.mugiwara/logs/`) — name the wave, owner, and reason at the moment of omission.
|
|
86
97
|
3. Heal loop is bounded: Wave 8 → Wave 4, max 3 cycles. After that, escalate to the human with full history.
|
|
87
98
|
4. Any agent may consult Luffy mid-flight (embody `luffy-orchestrator` inline) for decisions and escalations.
|
|
88
99
|
5. Wave 7 runs Robin and Jinbe review passes in parallel — both are inline passes over the same diff, or parallel review subagents for large diffs.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mugiwara-writing-skills
|
|
3
|
+
description: Use when authoring a new mugiwara skill or revising an existing one. Enforces the skill anatomy (name/description 20-500 chars, when-to-use, process, rationalizations, red flags, verification), the 120-line body ceiling, and progressive disclosure of detail into a references/ file. Meta-skill: governs the other skills.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Writing Mugiwara Skills
|
|
7
|
+
|
|
8
|
+
## Skip when
|
|
9
|
+
|
|
10
|
+
- Not authoring or revising a mugiwara skill — plain application code change.
|
|
11
|
+
- Skill change is a one-line description fix with no anatomy impact.
|
|
12
|
+
|
|
13
|
+
A skill is a process workflow the agent runs on cue, not a reference guide. If it reads like a wiki page, it fails. The description decides when the skill loads; the body decides what happens next. Both must justify their size.
|
|
14
|
+
|
|
15
|
+
## Skill anatomy
|
|
16
|
+
|
|
17
|
+
Every skill is a single `SKILL.md` at `content/skills/<name>/`, plus an optional `references/` folder for pulled-out detail. The name is the directory name; the validator checks that exact match.
|
|
18
|
+
|
|
19
|
+
| Part | Requirement |
|
|
20
|
+
|------|-------------|
|
|
21
|
+
| name | equals the directory name, `mugiwara-<domain>` |
|
|
22
|
+
| description | one "Use when..." sentence, 20-500 chars, loads the right skill and rejects the wrong ones |
|
|
23
|
+
| body | `# title` + sections below, 120 lines max |
|
|
24
|
+
| references/ | overflow detail, linked from the body |
|
|
25
|
+
|
|
26
|
+
## When to use
|
|
27
|
+
|
|
28
|
+
Use this skill the moment you start authoring a new skill file or restructuring an existing one. Skip it only for edits so small they cannot touch anatomy, limits, or wording.
|
|
29
|
+
|
|
30
|
+
## Process
|
|
31
|
+
|
|
32
|
+
1. **Confirm the niche.** Grep `content/skills/` for overlap; a new skill must not duplicate an existing one. Name it `mugiwara-<domain>`.
|
|
33
|
+
2. **Write the description first.** One "Use when..." sentence naming the trigger, the behavior, and the boundary of what the skill is not for. Target 60-120 chars; the 500-char cap is a ceiling, not a goal.
|
|
34
|
+
3. **Draft the body as a workflow.** Concrete numbered steps the agent executes, in order, with decisions and branches embedded. Name the skills it reads or dispatches. Use tables for excusable patterns and quick comparisons.
|
|
35
|
+
4. **Cut to the ceiling.** Body must end at 120 lines or fewer. Section-by-section trim: merge subsections, kill throat-clearing, convert prose to tables. `ponytail` and `caveman` instincts apply — the body is command output, not a report.
|
|
36
|
+
5. **Disclose progressively.** If a section exceeds roughly 15-20 lines, move it to `references/<topic>.md`, drop a one-line pointer in the body, and keep the pointer actionable (what to read and why).
|
|
37
|
+
6. **Check the anatomy list.** Each required section present, in order: title, When to use, Process, Rationalizations, Red flags, Verification.
|
|
38
|
+
7. **Validate.** Run `bun scripts/validate-content.ts --check content/skills/<name>/SKILL.md` and leave it exiting 0.
|
|
39
|
+
|
|
40
|
+
## Rationalizations
|
|
41
|
+
|
|
42
|
+
| Excuse | Rebuttal |
|
|
43
|
+
|--------|----------|
|
|
44
|
+
| "It's a guide, not a checklist" | A skill the agent cannot execute is decoration. Rewrite every paragraph as a step or a criterion. |
|
|
45
|
+
| "The detail is essential" | Then move it to `references/` and keep the body a decision tree, not a dump. |
|
|
46
|
+
| "More lines mean more coverage" | 120 lines enforce focus. Cover the decision, not the encyclopedia. |
|
|
47
|
+
| "Long description catches more triggers" | A description that matches everything loads on nothing specific and trains the agent to ignore the skill. |
|
|
48
|
+
| "Patterns are the same everywhere, I'll mirror another skill's text" | Wording must be original. Mirror the shape, never the sentences. |
|
|
49
|
+
| "It's fine for now, I'll validate later" | Validation is the last step of the write, not a follow-up task. |
|
|
50
|
+
|
|
51
|
+
## Red flags
|
|
52
|
+
|
|
53
|
+
- Body over 120 lines or a description outside 20-500 chars.
|
|
54
|
+
- No "Use when..." trigger sentence, or a description that names no boundary.
|
|
55
|
+
- A section that reads as a lecture instead of steps the agent can run.
|
|
56
|
+
- Required sections missing or out of order.
|
|
57
|
+
- Text copied from another skill, superpowers, or agent-skills.
|
|
58
|
+
- A `references/` file that is unreferenced, or a body so crammed it needed none.
|
|
59
|
+
- An unvalidated file reported as done.
|
|
60
|
+
|
|
61
|
+
Any of these: revise the skill, re-run validation, and confirm both before reporting.
|
|
62
|
+
|
|
63
|
+
## Verification
|
|
64
|
+
|
|
65
|
+
Evidence of a complete skill: the file passes `--check` with exit 0; `wc -l` on the body is at or under 120; the description triggers only its intended cases; every required section is present and original; and any overflow sits in a linked `references/` file.
|
package/dist/mugiwara.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import { existsSync as
|
|
4
|
+
import { existsSync as existsSync6, realpathSync, rmSync as rmSync3 } from "node:fs";
|
|
5
5
|
import { homedir as homedir2 } from "node:os";
|
|
6
|
-
import {
|
|
6
|
+
import { resolve } from "node:path";
|
|
7
7
|
import { pathToFileURL } from "node:url";
|
|
8
8
|
|
|
9
9
|
// src/args.ts
|
|
@@ -14,6 +14,7 @@ var BOOL_FLAGS = {
|
|
|
14
14
|
"-y": "yes",
|
|
15
15
|
"--force": "force",
|
|
16
16
|
"--dry-run": "dryRun",
|
|
17
|
+
"--keep-logs": "keepLogs",
|
|
17
18
|
"--help": "help",
|
|
18
19
|
"-h": "help",
|
|
19
20
|
"--version": "version",
|
|
@@ -79,7 +80,9 @@ async function confirm(rl, question) {
|
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
// src/targets/claude.ts
|
|
82
|
-
import {
|
|
83
|
+
import { existsSync, mkdirSync, copyFileSync } from "node:fs";
|
|
84
|
+
import { dirname, join } from "node:path";
|
|
85
|
+
import { fileURLToPath } from "node:url";
|
|
83
86
|
|
|
84
87
|
// src/frontmatter.ts
|
|
85
88
|
function parseFrontmatter(text) {
|
|
@@ -107,6 +110,8 @@ ${body}`;
|
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
// src/targets/claude.ts
|
|
113
|
+
var here = dirname(fileURLToPath(import.meta.url));
|
|
114
|
+
var HOOK_SRC = join(here, "..", "..", "hooks", "session-start.ts");
|
|
110
115
|
var target = {
|
|
111
116
|
id: "claude",
|
|
112
117
|
label: "Claude Code",
|
|
@@ -126,6 +131,22 @@ var target = {
|
|
|
126
131
|
if (data.tools)
|
|
127
132
|
fm.tools = data.tools;
|
|
128
133
|
return { relPath: `${data.name}.md`, text: stringifyFrontmatter(fm, body) };
|
|
134
|
+
},
|
|
135
|
+
refsDir({ scope, projectDir, home }, skillName) {
|
|
136
|
+
const root = scope === "global" ? join(home, ".claude") : join(projectDir, ".claude");
|
|
137
|
+
return join(root, "skills", skillName, "references");
|
|
138
|
+
},
|
|
139
|
+
postInstall({ scope, projectDir, home, dryRun }) {
|
|
140
|
+
const root = scope === "global" ? join(home, ".claude") : join(projectDir, ".claude");
|
|
141
|
+
const hookFile = join(root, "hooks", "session-start.ts");
|
|
142
|
+
if (dryRun)
|
|
143
|
+
return { written: [], notes: [] };
|
|
144
|
+
if (existsSync(HOOK_SRC) && !existsSync(hookFile)) {
|
|
145
|
+
mkdirSync(dirname(hookFile), { recursive: true });
|
|
146
|
+
copyFileSync(HOOK_SRC, hookFile);
|
|
147
|
+
return { written: [hookFile], notes: [] };
|
|
148
|
+
}
|
|
149
|
+
return { written: [], notes: [] };
|
|
129
150
|
}
|
|
130
151
|
};
|
|
131
152
|
|
|
@@ -150,6 +171,10 @@ var target2 = {
|
|
|
150
171
|
if (data.tools)
|
|
151
172
|
fm.tools = data.tools;
|
|
152
173
|
return { relPath: `${data.name}.md`, text: stringifyFrontmatter(fm, body) };
|
|
174
|
+
},
|
|
175
|
+
refsDir({ scope, projectDir, home }, skillName) {
|
|
176
|
+
const root = scope === "global" ? join2(home, ".config", "opencode") : join2(projectDir, ".opencode");
|
|
177
|
+
return join2(root, "skills", skillName, "references");
|
|
153
178
|
}
|
|
154
179
|
};
|
|
155
180
|
|
|
@@ -174,18 +199,23 @@ var target3 = {
|
|
|
174
199
|
relPath: `${data.name}.md`,
|
|
175
200
|
text: stringifyFrontmatter({ name: data.name, description: data.description }, body)
|
|
176
201
|
};
|
|
202
|
+
},
|
|
203
|
+
refsDir(_opts, skillName) {
|
|
204
|
+
return join3(_opts.projectDir, ".mugiwara", "refs", skillName);
|
|
177
205
|
}
|
|
178
206
|
};
|
|
179
207
|
|
|
180
208
|
// src/targets/generic.ts
|
|
181
|
-
import { existsSync, writeFileSync } from "node:fs";
|
|
209
|
+
import { existsSync as existsSync2, writeFileSync } from "node:fs";
|
|
182
210
|
import { join as join4 } from "node:path";
|
|
183
211
|
function makeGeneric(opts) {
|
|
184
|
-
const { id, label, rulesDir, bootstrapFile, bootstrapPointer } = opts;
|
|
212
|
+
const { id, label, rulesDir, bootstrapFile, bootstrapPointer, tier = bootstrapPointer ? 2 : 3 } = opts;
|
|
213
|
+
const stubOnly = tier === 3;
|
|
185
214
|
return {
|
|
186
215
|
id,
|
|
187
216
|
label,
|
|
188
217
|
native: false,
|
|
218
|
+
tier,
|
|
189
219
|
paths({ scope, projectDir }) {
|
|
190
220
|
if (scope === "global")
|
|
191
221
|
throw new Error(`${label} supports project scope only`);
|
|
@@ -193,6 +223,27 @@ function makeGeneric(opts) {
|
|
|
193
223
|
return { skillsDir: dir, agentsDir: dir };
|
|
194
224
|
},
|
|
195
225
|
transformSkill(data, body) {
|
|
226
|
+
if (stubOnly) {
|
|
227
|
+
return {
|
|
228
|
+
relPath: `${data.name}.md`,
|
|
229
|
+
text: `# ${data.name}
|
|
230
|
+
|
|
231
|
+
> ${data.description}
|
|
232
|
+
|
|
233
|
+
## Skip when
|
|
234
|
+
|
|
235
|
+
Full skill: \`${data.name}\` — read \`.mugiwara/refs/${data.name}.md\` when the crew invokes this role.`
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
return { relPath: `${data.name}.md`, text: `# ${data.name}
|
|
239
|
+
|
|
240
|
+
> ${data.description}
|
|
241
|
+
|
|
242
|
+
${body}` };
|
|
243
|
+
},
|
|
244
|
+
transformSkillFull(data, body) {
|
|
245
|
+
if (!stubOnly)
|
|
246
|
+
return null;
|
|
196
247
|
return { relPath: `${data.name}.md`, text: `# ${data.name}
|
|
197
248
|
|
|
198
249
|
> ${data.description}
|
|
@@ -200,6 +251,16 @@ function makeGeneric(opts) {
|
|
|
200
251
|
${body}` };
|
|
201
252
|
},
|
|
202
253
|
transformAgent(data, body) {
|
|
254
|
+
if (stubOnly) {
|
|
255
|
+
return {
|
|
256
|
+
relPath: `agent-${data.name}.md`,
|
|
257
|
+
text: `# Agent: ${data.name}
|
|
258
|
+
|
|
259
|
+
> ${data.description}
|
|
260
|
+
|
|
261
|
+
Skills: ${data.skills ?? ""}. Read \`.mugiwara/refs/${data.name}.md\` when embodying this role.`
|
|
262
|
+
};
|
|
263
|
+
}
|
|
203
264
|
return { relPath: `agent-${data.name}.md`, text: `# Agent: ${data.name}
|
|
204
265
|
|
|
205
266
|
> ${data.description}
|
|
@@ -208,13 +269,27 @@ Skills used: ${data.skills ?? ""}
|
|
|
208
269
|
|
|
209
270
|
${body}` };
|
|
210
271
|
},
|
|
272
|
+
transformAgentFull(data, body) {
|
|
273
|
+
if (!stubOnly)
|
|
274
|
+
return null;
|
|
275
|
+
return { relPath: `${data.name}.md`, text: `# Agent: ${data.name}
|
|
276
|
+
|
|
277
|
+
> ${data.description}
|
|
278
|
+
|
|
279
|
+
Skills used: ${data.skills ?? ""}
|
|
280
|
+
|
|
281
|
+
${body}` };
|
|
282
|
+
},
|
|
283
|
+
refsDir({ projectDir }) {
|
|
284
|
+
return join4(projectDir, ".mugiwara", "refs");
|
|
285
|
+
},
|
|
211
286
|
postInstall({ projectDir, dryRun }) {
|
|
212
287
|
if (!bootstrapFile)
|
|
213
288
|
return { written: [], notes: [] };
|
|
214
289
|
const notes = [];
|
|
215
290
|
const written = [];
|
|
216
291
|
const file = join4(projectDir, bootstrapFile);
|
|
217
|
-
if (!
|
|
292
|
+
if (!existsSync2(file)) {
|
|
218
293
|
if (!dryRun)
|
|
219
294
|
writeFileSync(file, `${bootstrapPointer}
|
|
220
295
|
`);
|
|
@@ -233,7 +308,7 @@ var target4 = makeGeneric({
|
|
|
233
308
|
label: "Gemini",
|
|
234
309
|
rulesDir: ".gemini/mugiwara",
|
|
235
310
|
bootstrapFile: "GEMINI.md",
|
|
236
|
-
bootstrapPointer: "Mugiwara crew installed in .gemini/mugiwara/ — read .gemini/mugiwara/mugiwara-workflow.md to run the pipeline."
|
|
311
|
+
bootstrapPointer: "Mugiwara crew installed in .gemini/mugiwara/ — read .gemini/mugiwara/mugiwara-workflow.md to run the pipeline inline in the main conversation."
|
|
237
312
|
});
|
|
238
313
|
|
|
239
314
|
// src/targets/codex.ts
|
|
@@ -242,7 +317,7 @@ var target5 = makeGeneric({
|
|
|
242
317
|
label: "Codex",
|
|
243
318
|
rulesDir: ".codex/mugiwara",
|
|
244
319
|
bootstrapFile: "AGENTS.md",
|
|
245
|
-
bootstrapPointer: "Mugiwara crew installed in .codex/mugiwara/ — read .codex/mugiwara/mugiwara-workflow.md to run the pipeline."
|
|
320
|
+
bootstrapPointer: "Mugiwara crew installed in .codex/mugiwara/ — read .codex/mugiwara/mugiwara-workflow.md to run the pipeline inline in the main conversation."
|
|
246
321
|
});
|
|
247
322
|
|
|
248
323
|
// src/targets/windsurf.ts
|
|
@@ -273,7 +348,8 @@ var target8 = makeGeneric({
|
|
|
273
348
|
"instructions": [
|
|
274
349
|
".kilo/rules/*.md"
|
|
275
350
|
]
|
|
276
|
-
}
|
|
351
|
+
}`,
|
|
352
|
+
tier: 3
|
|
277
353
|
});
|
|
278
354
|
|
|
279
355
|
// src/targets/antigravity.ts
|
|
@@ -290,24 +366,30 @@ var targets = { claude: target, opencode: target2, copilot: target3, gemini: tar
|
|
|
290
366
|
var TARGET_IDS = Object.keys(targets);
|
|
291
367
|
|
|
292
368
|
// src/installer.ts
|
|
293
|
-
import { existsSync as
|
|
294
|
-
import { dirname, join as join5 } from "node:path";
|
|
369
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync, writeFileSync as writeFileSync2, copyFileSync as copyFileSync2, rmSync } from "node:fs";
|
|
370
|
+
import { dirname as dirname2, join as join5 } from "node:path";
|
|
295
371
|
import { homedir } from "node:os";
|
|
296
372
|
var CONTENT_DIR = join5(import.meta.dirname, "..", "content");
|
|
297
|
-
var pkg = JSON.parse(
|
|
373
|
+
var pkg = JSON.parse(readFileSync2(join5(import.meta.dirname, "..", "package.json"), "utf8"));
|
|
298
374
|
var VERSION = pkg.version;
|
|
299
375
|
function collectContent() {
|
|
300
376
|
const skillNames = readdirSync(join5(CONTENT_DIR, "skills"), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
301
377
|
const skills = skillNames.map((name) => {
|
|
302
|
-
const { data, body } = parseFrontmatter(
|
|
303
|
-
return { name, data, body };
|
|
378
|
+
const { data, body } = parseFrontmatter(readFileSync2(join5(CONTENT_DIR, "skills", name, "SKILL.md"), "utf8"));
|
|
379
|
+
return { name, data, body, refs: collectRefs(join5(CONTENT_DIR, "skills", name)) };
|
|
304
380
|
});
|
|
305
381
|
const agents = readdirSync(join5(CONTENT_DIR, "agents")).filter((f) => f.endsWith(".md")).map((f) => {
|
|
306
|
-
const { data, body } = parseFrontmatter(
|
|
307
|
-
return { name: f.replace(/\.md$/, ""), data, body };
|
|
382
|
+
const { data, body } = parseFrontmatter(readFileSync2(join5(CONTENT_DIR, "agents", f), "utf8"));
|
|
383
|
+
return { name: f.replace(/\.md$/, ""), data, body, refs: [] };
|
|
308
384
|
});
|
|
309
385
|
return { skills, agents };
|
|
310
386
|
}
|
|
387
|
+
function collectRefs(skillDir) {
|
|
388
|
+
const refsDir = join5(skillDir, "references");
|
|
389
|
+
if (!existsSync3(refsDir))
|
|
390
|
+
return [];
|
|
391
|
+
return readdirSync(refsDir, { recursive: true }).map((f) => String(f)).filter((f) => f.endsWith(".md")).map((rel) => ({ relPath: rel, text: readFileSync2(join5(refsDir, rel), "utf8") }));
|
|
392
|
+
}
|
|
311
393
|
function installTo(target10, opts) {
|
|
312
394
|
const { scope, projectDir, dryRun = false, force = false } = opts;
|
|
313
395
|
const home = opts.home ?? homedir();
|
|
@@ -316,8 +398,8 @@ function installTo(target10, opts) {
|
|
|
316
398
|
const backupRoot = join5(scope === "global" ? home : projectDir, ".mugiwara");
|
|
317
399
|
const result = { written: [], skipped: [], backedUp: [], notes: [] };
|
|
318
400
|
const writeOne = (absPath, text) => {
|
|
319
|
-
if (
|
|
320
|
-
if (
|
|
401
|
+
if (existsSync3(absPath)) {
|
|
402
|
+
if (readFileSync2(absPath, "utf8") === text) {
|
|
321
403
|
result.skipped.push(absPath);
|
|
322
404
|
return;
|
|
323
405
|
}
|
|
@@ -329,13 +411,13 @@ function installTo(target10, opts) {
|
|
|
329
411
|
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
330
412
|
const backupFile = join5(backupRoot, "backup", ts, absPath.replace(/[^a-zA-Z0-9]+/g, "_"));
|
|
331
413
|
if (!dryRun) {
|
|
332
|
-
|
|
333
|
-
|
|
414
|
+
mkdirSync2(dirname2(backupFile), { recursive: true });
|
|
415
|
+
copyFileSync2(absPath, backupFile);
|
|
334
416
|
}
|
|
335
417
|
result.backedUp.push(absPath);
|
|
336
418
|
}
|
|
337
419
|
if (!dryRun) {
|
|
338
|
-
|
|
420
|
+
mkdirSync2(dirname2(absPath), { recursive: true });
|
|
339
421
|
writeFileSync2(absPath, text);
|
|
340
422
|
}
|
|
341
423
|
result.written.push(absPath);
|
|
@@ -344,11 +426,26 @@ function installTo(target10, opts) {
|
|
|
344
426
|
const out = target10.transformSkill(s.data, s.body);
|
|
345
427
|
if (out)
|
|
346
428
|
writeOne(join5(dirs.skillsDir, out.relPath), out.text);
|
|
429
|
+
if (target10.transformSkillFull) {
|
|
430
|
+
const full = target10.transformSkillFull(s.data, s.body);
|
|
431
|
+
if (full && target10.refsDir)
|
|
432
|
+
writeOne(join5(target10.refsDir({ scope, projectDir, home }, s.name), full.relPath), full.text);
|
|
433
|
+
}
|
|
434
|
+
if (s.refs.length && target10.refsDir) {
|
|
435
|
+
const refsRoot = target10.refsDir({ scope, projectDir, home }, s.name);
|
|
436
|
+
for (const r of s.refs)
|
|
437
|
+
writeOne(join5(refsRoot, r.relPath), r.text);
|
|
438
|
+
}
|
|
347
439
|
}
|
|
348
440
|
for (const a of agents) {
|
|
349
441
|
const out = target10.transformAgent(a.data, a.body);
|
|
350
442
|
if (out)
|
|
351
443
|
writeOne(join5(dirs.agentsDir, out.relPath), out.text);
|
|
444
|
+
if (target10.transformAgentFull) {
|
|
445
|
+
const full = target10.transformAgentFull(a.data, a.body);
|
|
446
|
+
if (full && target10.refsDir)
|
|
447
|
+
writeOne(join5(target10.refsDir({ scope, projectDir, home }, a.name), full.relPath), full.text);
|
|
448
|
+
}
|
|
352
449
|
}
|
|
353
450
|
if (target10.postInstall) {
|
|
354
451
|
const post = target10.postInstall({ scope, projectDir, home, dryRun, files: result.written });
|
|
@@ -360,7 +457,7 @@ function installTo(target10, opts) {
|
|
|
360
457
|
function removeInstalled(manifest, { dryRun = false } = {}) {
|
|
361
458
|
const removed = [];
|
|
362
459
|
for (const f of manifest.files) {
|
|
363
|
-
if (
|
|
460
|
+
if (existsSync3(f)) {
|
|
364
461
|
if (!dryRun)
|
|
365
462
|
rmSync(f);
|
|
366
463
|
removed.push(f);
|
|
@@ -368,10 +465,10 @@ function removeInstalled(manifest, { dryRun = false } = {}) {
|
|
|
368
465
|
}
|
|
369
466
|
if (!dryRun) {
|
|
370
467
|
for (const f of manifest.files) {
|
|
371
|
-
let d =
|
|
372
|
-
while (
|
|
468
|
+
let d = dirname2(f);
|
|
469
|
+
while (existsSync3(d) && readdirSync(d).length === 0) {
|
|
373
470
|
rmSync(d, { recursive: true });
|
|
374
|
-
const parent =
|
|
471
|
+
const parent = dirname2(d);
|
|
375
472
|
if (parent === d)
|
|
376
473
|
break;
|
|
377
474
|
d = parent;
|
|
@@ -382,20 +479,52 @@ function removeInstalled(manifest, { dryRun = false } = {}) {
|
|
|
382
479
|
}
|
|
383
480
|
|
|
384
481
|
// src/manifest.ts
|
|
385
|
-
import { existsSync as
|
|
386
|
-
import { dirname as
|
|
482
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
483
|
+
import { dirname as dirname3, join as join6 } from "node:path";
|
|
387
484
|
function manifestPath({ scope, projectDir, home }) {
|
|
388
485
|
return scope === "global" ? join6(home, ".mugiwara", "manifest.json") : join6(projectDir, ".mugiwara", "manifest.json");
|
|
389
486
|
}
|
|
390
487
|
function readManifest(file) {
|
|
391
|
-
return
|
|
488
|
+
return existsSync4(file) ? JSON.parse(readFileSync3(file, "utf8")) : null;
|
|
392
489
|
}
|
|
393
490
|
function writeManifest(file, data) {
|
|
394
|
-
|
|
491
|
+
mkdirSync3(dirname3(file), { recursive: true });
|
|
395
492
|
writeFileSync3(file, JSON.stringify(data, null, 2) + `
|
|
396
493
|
`);
|
|
397
494
|
}
|
|
398
495
|
|
|
496
|
+
// src/mission.ts
|
|
497
|
+
import { existsSync as existsSync5, rmSync as rmSync2 } from "node:fs";
|
|
498
|
+
import { join as join7 } from "node:path";
|
|
499
|
+
function resetMission(projectDir, keepLogs) {
|
|
500
|
+
const root = join7(projectDir, ".mugiwara");
|
|
501
|
+
if (!existsSync5(root))
|
|
502
|
+
return { removed: [], kept: [] };
|
|
503
|
+
const removed = [];
|
|
504
|
+
const kept = [];
|
|
505
|
+
for (const dir of ["spec", "plans", "results", "review", "issues"]) {
|
|
506
|
+
const p = join7(root, dir);
|
|
507
|
+
if (existsSync5(p)) {
|
|
508
|
+
rmSync2(p, { recursive: true, force: true });
|
|
509
|
+
removed.push(dir);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (!keepLogs) {
|
|
513
|
+
const p = join7(root, "logs");
|
|
514
|
+
if (existsSync5(p)) {
|
|
515
|
+
rmSync2(p, { recursive: true, force: true });
|
|
516
|
+
removed.push("logs");
|
|
517
|
+
}
|
|
518
|
+
} else if (existsSync5(join7(root, "logs"))) {
|
|
519
|
+
kept.push("logs");
|
|
520
|
+
}
|
|
521
|
+
for (const f of ["config", "manifest.json", "backup"]) {
|
|
522
|
+
if (existsSync5(join7(root, f)))
|
|
523
|
+
kept.push(f);
|
|
524
|
+
}
|
|
525
|
+
return { removed, kept };
|
|
526
|
+
}
|
|
527
|
+
|
|
399
528
|
// src/cli.ts
|
|
400
529
|
var str = (v) => typeof v === "string" ? v : undefined;
|
|
401
530
|
var flag = (v) => v === true;
|
|
@@ -416,12 +545,22 @@ async function run(argv) {
|
|
|
416
545
|
return uninstall(flags);
|
|
417
546
|
case "list":
|
|
418
547
|
return list(flags);
|
|
419
|
-
case "
|
|
420
|
-
return
|
|
548
|
+
case "reset":
|
|
549
|
+
return resetCmd(flags);
|
|
421
550
|
default:
|
|
422
551
|
throw new Error(`Unknown command: ${command}`);
|
|
423
552
|
}
|
|
424
553
|
}
|
|
554
|
+
function resetCmd(flags) {
|
|
555
|
+
const projectDir = resolve(str(flags.project) ?? process.cwd());
|
|
556
|
+
const { removed, kept } = resetMission(projectDir, flag(flags.keepLogs));
|
|
557
|
+
if (removed.length)
|
|
558
|
+
console.log(`removed: ${removed.join(", ")}`);
|
|
559
|
+
else
|
|
560
|
+
console.log("nothing to remove.");
|
|
561
|
+
if (kept.length)
|
|
562
|
+
console.log(`kept: ${kept.join(", ")}`);
|
|
563
|
+
}
|
|
425
564
|
async function resolveOptions(flags) {
|
|
426
565
|
const interactive = !flag(flags.yes);
|
|
427
566
|
const rl = interactive ? createRl() : null;
|
|
@@ -433,7 +572,7 @@ async function resolveOptions(flags) {
|
|
|
433
572
|
scope = await choose(rl, "Install scope?", ["global (user-wide)", "project (this repo)"]) === 0 ? "global" : "project";
|
|
434
573
|
}
|
|
435
574
|
const projectDir = resolve(str(flags.project) ?? process.cwd());
|
|
436
|
-
if (scope === "project" && !
|
|
575
|
+
if (scope === "project" && !existsSync6(projectDir))
|
|
437
576
|
throw new Error(`Project dir not found: ${projectDir}`);
|
|
438
577
|
let targetIds = str(flags.target)?.split(",").map((s) => s.trim()) ?? null;
|
|
439
578
|
if (targetIds && targetIds.includes("all"))
|
|
@@ -517,7 +656,7 @@ async function uninstall(flags) {
|
|
|
517
656
|
}
|
|
518
657
|
const removed = removeInstalled(manifest, { dryRun: flag(flags.dryRun) });
|
|
519
658
|
if (!flag(flags.dryRun))
|
|
520
|
-
|
|
659
|
+
rmSync3(file);
|
|
521
660
|
console.log(`OK removed ${removed.length} files`);
|
|
522
661
|
}
|
|
523
662
|
function list(flags) {
|
|
@@ -537,22 +676,6 @@ function list(flags) {
|
|
|
537
676
|
if (!found)
|
|
538
677
|
console.log("No mugiwara installation found.");
|
|
539
678
|
}
|
|
540
|
-
function skills() {
|
|
541
|
-
const dir = join7(CONTENT_DIR, "skills");
|
|
542
|
-
const names = readdirSync2(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
543
|
-
const rows = names.map((name) => {
|
|
544
|
-
const { data } = parseFrontmatter(readFileSync3(join7(dir, name, "SKILL.md"), "utf8"));
|
|
545
|
-
return [name, data.description ?? ""];
|
|
546
|
-
});
|
|
547
|
-
const w = Math.max(...rows.map((r) => r[0].length)) + 2;
|
|
548
|
-
console.log(`mugiwara ${VERSION} — ${rows.length} skills (agentskills.io format):
|
|
549
|
-
`);
|
|
550
|
-
for (const [name, description] of rows)
|
|
551
|
-
console.log(` ${name.padEnd(w)}${description}`);
|
|
552
|
-
console.log(`
|
|
553
|
-
Install skills into any agent via skills.sh:
|
|
554
|
-
npx skills add ionivetech/mugiwara`);
|
|
555
|
-
}
|
|
556
679
|
function help() {
|
|
557
680
|
console.log(`mugiwara ${VERSION} — the Straw Hat crew for AI agents
|
|
558
681
|
|
|
@@ -561,7 +684,7 @@ Usage:
|
|
|
561
684
|
mugiwara update replace existing files (backs up differences first)
|
|
562
685
|
mugiwara uninstall remove installed files via manifest
|
|
563
686
|
mugiwara list show installations
|
|
564
|
-
mugiwara
|
|
687
|
+
mugiwara reset wipe mission state (spec/plans/results/review/issues[/logs])
|
|
565
688
|
mugiwara --help this help
|
|
566
689
|
mugiwara --version print version
|
|
567
690
|
|
|
@@ -571,7 +694,8 @@ Flags:
|
|
|
571
694
|
--target <ids|all> comma-separated: ${TARGET_IDS.join(", ")}
|
|
572
695
|
--yes, -y non-interactive (needs --global/--project, --target)
|
|
573
696
|
--force overwrite differing files (with backup)
|
|
574
|
-
--dry-run print actions without writing
|
|
697
|
+
--dry-run print actions without writing
|
|
698
|
+
--keep-logs with reset: keep .mugiwara/logs (lessons ledger survives)`);
|
|
575
699
|
}
|
|
576
700
|
var entry = process.argv[1] !== undefined ? resolve(process.argv[1]) : undefined;
|
|
577
701
|
if (entry !== undefined) {
|
package/docs/adoption-guide.md
CHANGED
|
@@ -16,7 +16,7 @@ markdown rule files everywhere else.
|
|
|
16
16
|
|
|
17
17
|
Native targets (Claude Code, opencode, Copilot) register the 15 agents directly.
|
|
18
18
|
Rule-based targets (Gemini, Codex, Cursor, Windsurf, Cline, Kilo, Antigravity)
|
|
19
|
-
get the same
|
|
19
|
+
get the same 32 skills as markdown rules plus a bootstrap pointer, so the crew
|
|
20
20
|
is still steered even where subagents don't exist.
|
|
21
21
|
|
|
22
22
|
## Pick your mode
|
|
@@ -43,8 +43,8 @@ mid-wave.
|
|
|
43
43
|
|
|
44
44
|
## Fit the crew to your workflow
|
|
45
45
|
|
|
46
|
-
- **Trivial one-liners** don't need the crew — Luffy routes them
|
|
47
|
-
|
|
46
|
+
- **Trivial one-liners** don't need the crew's full pipeline — Luffy routes them
|
|
47
|
+
to Lane 0 and they run with zero waves. The process scales to the work.
|
|
48
48
|
- **Medium features** run the standard pipeline: triage → plan → execute →
|
|
49
49
|
checkpoint → quality → gates → review → closure.
|
|
50
50
|
- **High-stakes work** (money, security, data, public API) always gets the full
|
package/docs/agents.md
CHANGED
|
@@ -44,8 +44,8 @@ check-ins. The harness stays coherent either way.
|
|
|
44
44
|
|
|
45
45
|
## The crew ships whole
|
|
46
46
|
|
|
47
|
-
Every install gets all 15 agents and all
|
|
47
|
+
Every install gets all 15 agents and all 32 skills. No project-type selection —
|
|
48
48
|
the harness routes each task to the right specialist.
|
|
49
49
|
|
|
50
|
-
See [skills.md](skills.md) for the
|
|
50
|
+
See [skills.md](skills.md) for the 32 techniques, or
|
|
51
51
|
[workflow.md](workflow.md) for the pipeline.
|
package/docs/claude-setup.md
CHANGED
|
@@ -20,19 +20,24 @@ npx @ionivetech/mugiwara@latest --global --target claude --yes
|
|
|
20
20
|
npx @ionivetech/mugiwara@latest --project ./my-app --target claude --yes
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
**Update** — re-install from the marketplace (or `mugiwara update` via CLI).
|
|
24
|
+
|
|
25
|
+
**Uninstall** — `/plugin uninstall mugiwara`, or `mugiwara uninstall` via CLI.
|
|
26
|
+
|
|
23
27
|
## What you get
|
|
24
28
|
|
|
25
|
-
-
|
|
29
|
+
- 32 skills in `~/.claude/skills/` (global) or `.claude/skills/` (project).
|
|
26
30
|
- 15 agents in `~/.claude/agents/` or `.claude/agents/`.
|
|
27
|
-
- A SessionStart hook that announces the crew
|
|
31
|
+
- A SessionStart hook that announces the crew and auto-activates the workflow —
|
|
32
|
+
a non-trivial request runs the pipeline by itself. `/using-mugiwara` is an
|
|
33
|
+
optional explicit router if you want to hand-route a mission.
|
|
28
34
|
|
|
29
35
|
## Use it
|
|
30
36
|
|
|
31
37
|
```
|
|
32
|
-
> use mugiwara
|
|
33
38
|
> add dark mode to the settings page
|
|
34
39
|
```
|
|
35
40
|
|
|
36
41
|
The crew runs inline in your main conversation; subagents only for parallel
|
|
37
42
|
batches. At closure the crew pushes the branch and hands you the PR verdict
|
|
38
|
-
file — you open the PR.
|
|
43
|
+
file with a ready PR summary block — you open the PR, in every mode.
|
package/docs/codex-setup.md
CHANGED
|
@@ -13,9 +13,11 @@ Or via the CLI:
|
|
|
13
13
|
npx @ionivetech/mugiwara@latest --project ./my-app --target codex --yes
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
**Update** — `codex plugin update mugiwara`. **Uninstall** — `codex plugin remove mugiwara`.
|
|
17
|
+
|
|
16
18
|
## What you get
|
|
17
19
|
|
|
18
|
-
-
|
|
20
|
+
- 32 skills as markdown rules in `.codex/mugiwara/`.
|
|
19
21
|
- An `AGENTS.md` bootstrap pointer (created if missing).
|
|
20
22
|
|
|
21
23
|
## Notes
|