@ionivetech/mugiwara 0.3.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-plan.md +4 -0
- package/README.md +320 -384
- package/content/skills/mugiwara-agent-security/SKILL.md +5 -0
- package/content/skills/mugiwara-api-and-interface-design/SKILL.md +5 -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 +5 -0
- package/content/skills/mugiwara-deprecation/SKILL.md +5 -0
- package/content/skills/mugiwara-doubt-driven-development/SKILL.md +5 -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 +5 -0
- package/content/skills/mugiwara-frontend/SKILL.md +12 -12
- package/content/skills/mugiwara-gates/SKILL.md +5 -0
- package/content/skills/mugiwara-git/SKILL.md +5 -0
- package/content/skills/mugiwara-git-worktrees/SKILL.md +5 -0
- package/content/skills/mugiwara-healing/SKILL.md +5 -0
- package/content/skills/mugiwara-lessons/SKILL.md +5 -0
- package/content/skills/mugiwara-mode/SKILL.md +5 -0
- package/content/skills/mugiwara-observability/SKILL.md +5 -0
- package/content/skills/mugiwara-orchestration/SKILL.md +13 -0
- package/content/skills/mugiwara-planning/SKILL.md +14 -13
- package/content/skills/mugiwara-pr/SKILL.md +5 -0
- package/content/skills/mugiwara-quality/SKILL.md +5 -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 +17 -17
- package/content/skills/mugiwara-ship/SKILL.md +5 -0
- package/content/skills/mugiwara-systematic-debugging/SKILL.md +5 -0
- package/content/skills/mugiwara-test-driven-development/SKILL.md +5 -0
- package/content/skills/mugiwara-testcases/SKILL.md +5 -0
- package/content/skills/mugiwara-workflow/SKILL.md +6 -1
- package/content/skills/mugiwara-writing-skills/SKILL.md +5 -0
- package/dist/mugiwara.js +136 -28
- package/docs/adoption-guide.md +2 -2
- package/docs/comparison.md +166 -44
- package/docs/config.md +3 -0
- package/docs/developer-onboarding.md +17 -13
- package/docs/enforcement.md +38 -0
- package/docs/index.md +11 -5
- package/docs/lanes.md +40 -0
- package/docs/skill-anatomy.md +11 -6
- package/docs/troubleshooting.md +91 -0
- 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/package.json +2 -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 +4 -0
- package/src/targets/copilot.ts +4 -0
- package/src/targets/generic.ts +33 -1
- package/src/targets/kilo.ts +1 -0
- package/src/targets/opencode.ts +4 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Enforcement
|
|
2
|
+
|
|
3
|
+
A markdown harness cannot force a model to comply with prose — that is the
|
|
4
|
+
ceiling of every skills pack, mugiwara included. Mugiwara is a skills pack, not
|
|
5
|
+
a plugin with hooks: it ships markdown the agent reads and follows. What keeps
|
|
6
|
+
the pipeline honest is the skills themselves, not a CLI.
|
|
7
|
+
|
|
8
|
+
## Skip gates
|
|
9
|
+
|
|
10
|
+
Every skill carries a `## Skip when` block: ≤4 bullets, numeric thresholds,
|
|
11
|
+
telling the agent when the skill does not apply. The content validator
|
|
12
|
+
(`bun run validate`) fails the build when a skill lacks the block, so the gate
|
|
13
|
+
cannot rot. A skipped skill is recorded in the decision log, never silent.
|
|
14
|
+
|
|
15
|
+
## Evidence over claims
|
|
16
|
+
|
|
17
|
+
Every skill enforces the iron law: a wave passes only on command output or a
|
|
18
|
+
file the agent can point at. "Subagents lie. No evidence = not complete." This
|
|
19
|
+
is prose the agent follows, checked by no tool — the honest limit.
|
|
20
|
+
|
|
21
|
+
## Capability tiers
|
|
22
|
+
|
|
23
|
+
How skills load differs per harness:
|
|
24
|
+
|
|
25
|
+
| Tier | Harnesses | Skill loading |
|
|
26
|
+
|------|-----------|---------------|
|
|
27
|
+
| 1 | Claude Code, opencode | progressive — read by trigger, not all at once |
|
|
28
|
+
| 2 | Copilot, Gemini, Codex | bootstrap pointer → the model chooses what to read |
|
|
29
|
+
| 3 | Windsurf, Cline, Kilo, Antigravity | rules dirs glob-load — skills ship as stubs, full bodies in `.mugiwara/refs/` |
|
|
30
|
+
|
|
31
|
+
On tier 3, skills ship as small stubs (routing + pointer) so glob-loading
|
|
32
|
+
harnesses stop eating ~40k tokens; the full body lives in `.mugiwara/refs/`,
|
|
33
|
+
read on demand. Tier 3 also uses **wave-boundary state flush**: the full
|
|
34
|
+
mission state is written to `.mugiwara/` at each wave so the next wave resumes
|
|
35
|
+
without the previous context — the portable substitute for subagent isolation.
|
|
36
|
+
|
|
37
|
+
**Honest limit.** Mugiwara cannot force an agent to follow a skill. That is
|
|
38
|
+
true on every tier and every harness. It is a skills pack, not a supervisor.
|
package/docs/index.md
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# Mugiwara Docs
|
|
2
2
|
|
|
3
3
|
The Straw Hat crew of AI agents and skills. These docs cover what the crew is,
|
|
4
|
-
how to adopt it, and how each harness installs it. The crew is
|
|
5
|
-
|
|
6
|
-
skills**, and the workflow **auto-activates** at session
|
|
7
|
-
request runs the pipeline by itself, with
|
|
8
|
-
explicit router.
|
|
4
|
+
how to adopt it, and how each harness installs it. The crew is markdown plus a
|
|
5
|
+
small Node CLI (`mugiwara`) — no daemons, nothing to host. It ships **15
|
|
6
|
+
agents** and **32 skills**, and the workflow **auto-activates** at session
|
|
7
|
+
start — a non-trivial request runs the pipeline by itself, with
|
|
8
|
+
`/using-mugiwara` as an optional explicit router. Work is **sized to a lane**
|
|
9
|
+
before it runs: small fixes skip the pipeline, sensitive changes run the full
|
|
10
|
+
nine waves, and every wave passes only on **evidence**, never on a spoken
|
|
11
|
+
claim.
|
|
9
12
|
|
|
10
13
|
## Start here
|
|
11
14
|
|
|
@@ -20,6 +23,8 @@ explicit router.
|
|
|
20
23
|
| [The techniques](skills.md) | All 32 skills and what each enforces |
|
|
21
24
|
| [The wave pipeline](workflow.md) | How a mission flows Wave 0 → Wave 9 |
|
|
22
25
|
| [Execution model](execution-model.md) | Inline-by-default: why the crew runs in your main conversation |
|
|
26
|
+
| [Lanes & sizing](lanes.md) | How Luffy sizes work at triage: Lane 0–4, escalation, budget |
|
|
27
|
+
| [Enforcement](enforcement.md) | Skip gates, evidence over claims, and capability tiers |
|
|
23
28
|
| [Git discipline](git-strategy.md) | Commits, branches, save-points — and why the executor commits |
|
|
24
29
|
|
|
25
30
|
## Install by harness
|
|
@@ -41,6 +46,7 @@ explicit router.
|
|
|
41
46
|
|-----|----------------|
|
|
42
47
|
| [Skill anatomy](skill-anatomy.md) | How a mugiwara skill file is structured |
|
|
43
48
|
| [Agent anatomy](agent-anatomy.md) | How a mugiwara agent file is structured |
|
|
49
|
+
| [Troubleshooting](troubleshooting.md) | Common problems and how to fix them |
|
|
44
50
|
| [Developer onboarding](developer-onboarding.md) | Repo layout, validation, tests, contributing |
|
|
45
51
|
|
|
46
52
|
## Resources
|
package/docs/lanes.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Lanes & Sizing
|
|
2
|
+
|
|
3
|
+
The crew sizes a mission before it runs. At Wave 0, Luffy sizes the request
|
|
4
|
+
and picks a lane. The lane decides how many waves run — so a one-file typo does
|
|
5
|
+
not pay for the full nine-wave pipeline.
|
|
6
|
+
|
|
7
|
+
## The lanes
|
|
8
|
+
|
|
9
|
+
| Lane | Picks when | Waves | Budget |
|
|
10
|
+
|------|-----------|-------|--------|
|
|
11
|
+
| **0 · Direct** | typo, rename, 1 file <20 LOC | none | ~0 |
|
|
12
|
+
| **1 · Lean** | bug in 1-2 files, <50 LOC | execute → quality | ~4k |
|
|
13
|
+
| **2 · Standard** | feature, 3-8 files | plan → execute → checkpoint → review | ~10k |
|
|
14
|
+
| **3 · Full** | architecture, migration, auth/payment, API | 9 waves | ~20k |
|
|
15
|
+
| **4 · Spike** | exploratory, needs direction | brainstorm → re-triage | ~3k |
|
|
16
|
+
|
|
17
|
+
Budget is a guidance, not a meter: at ~1.5× estimated tokens warn, at 3× stop,
|
|
18
|
+
write the state to `.mugiwara/` and report how to continue — never silently
|
|
19
|
+
run on.
|
|
20
|
+
|
|
21
|
+
## How Luffy sizes
|
|
22
|
+
|
|
23
|
+
Size from the diff:
|
|
24
|
+
|
|
25
|
+
- 1 file <20 LOC → Lane 0 (Direct).
|
|
26
|
+
- 1-2 files → Lane 1 (Lean).
|
|
27
|
+
- 3-8 files → Lane 2 (Standard).
|
|
28
|
+
- 9+ files, or the diff touches `auth/`, `payment/`, `migrations/`, or
|
|
29
|
+
`security/` → Lane 3 (Full).
|
|
30
|
+
- Exploratory, needs direction → Lane 4 (Spike).
|
|
31
|
+
|
|
32
|
+
## Escalation
|
|
33
|
+
|
|
34
|
+
The lane **escalates when the work outgrows the estimate** — the diff grew, a
|
|
35
|
+
sensitive path got touched mid-mission, or failures repeat. Escalation is
|
|
36
|
+
automatic; a lane **never auto-drops**. Under-process is more expensive than
|
|
37
|
+
over-process.
|
|
38
|
+
|
|
39
|
+
The lane is decided by Luffy at triage, per mission — it is not stored in
|
|
40
|
+
`.mugiwara/config`.
|
package/docs/skill-anatomy.md
CHANGED
|
@@ -38,12 +38,16 @@ style:
|
|
|
38
38
|
|
|
39
39
|
1. **Title + one-line identity** — `# Checkpoint (Chopper)`, then what the role
|
|
40
40
|
is and is not.
|
|
41
|
-
2. **
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
2. **Skip when** — required. ≤4 bullets, numeric threshold, telling the agent
|
|
42
|
+
when this skill does not apply (e.g. "no UI code touched", "<3 files").
|
|
43
|
+
Without it the content validator fails the build. A skipped skill is
|
|
44
|
+
recorded in the decision log, never silent.
|
|
45
|
+
3. **The protocol** — numbered steps, exact commands, exact file paths.
|
|
46
|
+
4. **Decision tables** — where a judgment is needed, a table of signal → action.
|
|
47
|
+
5. **The iron law** — one memorable line that states the non-negotiable
|
|
44
48
|
("TRUST NOTHING; VERIFY EVERYTHING").
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
6. **Common rationalizations** — the excuses to reject, and the correct reply.
|
|
50
|
+
7. **Red flags** — conditions that mean "stop, this isn't done," each ending
|
|
47
51
|
with what to do.
|
|
48
52
|
|
|
49
53
|
### Style rules that keep skills effective
|
|
@@ -69,7 +73,8 @@ is the single source of truth; harnesses copy it verbatim.
|
|
|
69
73
|
## Validation
|
|
70
74
|
|
|
71
75
|
Every skill is validated on check-in: name matches folder, description 20–500
|
|
72
|
-
chars, body ≤120 lines, no duplicate names
|
|
76
|
+
chars, body ≤120 lines, no duplicate names, and a `## Skip when` block with
|
|
77
|
+
1–4 bullets. Run:
|
|
73
78
|
|
|
74
79
|
```bash
|
|
75
80
|
bun run validate
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Common problems, what they mean, and how to fix them.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### "conflict (not overwritten; run update to replace with backup)"
|
|
8
|
+
|
|
9
|
+
The target already has a file that differs from what mugiwara wants to write —
|
|
10
|
+
likely a previous install or a local edit. `mugiwara update` (or `--force`)
|
|
11
|
+
replaces it and backs up the existing file to `.mugiwara/backup/<timestamp>/`
|
|
12
|
+
first.
|
|
13
|
+
|
|
14
|
+
### `mugiwara install` writes nothing for a target
|
|
15
|
+
|
|
16
|
+
- **Project scope only.** Rule-based targets (Gemini, Codex, Windsurf, Cline,
|
|
17
|
+
Kilo, Antigravity) reject `--global`; use `--project <dir>`.
|
|
18
|
+
- **Skill already current.** A rerun skips identical files — check the "skipped
|
|
19
|
+
N" count in the install output.
|
|
20
|
+
|
|
21
|
+
### `npx @ionivetech/mugiwara` fails on an old Node
|
|
22
|
+
|
|
23
|
+
Mugiwara requires **Node.js >= 20.11**. Check `node --version`; upgrade or use
|
|
24
|
+
a version manager (nvm, fnm, volta).
|
|
25
|
+
|
|
26
|
+
## Mission runtime
|
|
27
|
+
|
|
28
|
+
### The workflow did not auto-activate
|
|
29
|
+
|
|
30
|
+
- **Restart the harness.** Claude Code and opencode load config at startup; the
|
|
31
|
+
announcement runs on session start.
|
|
32
|
+
- **Check the install.** Verify the skills directory exists for your harness
|
|
33
|
+
(`.claude/skills`, `.opencode/skills`, `.kilo/rules`, …). Reinstall with
|
|
34
|
+
`mugiwara update`.
|
|
35
|
+
|
|
36
|
+
### A skill that should fire does not
|
|
37
|
+
|
|
38
|
+
- **Trigger match.** Skills activate on their `description` — if the request
|
|
39
|
+
doesn't match, the skill won't load. Rephrase toward the trigger keywords.
|
|
40
|
+
- **Skip gate.** Every skill has a `## Skip when` block. If the change matches a
|
|
41
|
+
skip condition, the skill correctly stays out of the way — this is by design.
|
|
42
|
+
- **Tier-3 stub.** On rules-dir harnesses, the loaded file is a stub pointing at
|
|
43
|
+
`.mugiwara/refs/<name>.md`. If the full body is missing, reinstall.
|
|
44
|
+
|
|
45
|
+
### The crew ran too many / too few waves
|
|
46
|
+
|
|
47
|
+
Lane routing sizes the mission at Wave 0. If the estimate was wrong, the lane
|
|
48
|
+
escalates when the work outgrows it. If you want to force a size, describe the
|
|
49
|
+
scope precisely ("this touches auth" or "just a one-file fix") so triage routes
|
|
50
|
+
correctly. There is no config key for the lane.
|
|
51
|
+
|
|
52
|
+
### A wave is skipped silently
|
|
53
|
+
|
|
54
|
+
Not by design. Luffy records every omitted wave and its reason in the decision
|
|
55
|
+
log (`.mugiwara/logs/`). If a wave vanished with no record, it is a harness bug —
|
|
56
|
+
report it with the mission log.
|
|
57
|
+
|
|
58
|
+
### Context grows too large over a long mission
|
|
59
|
+
|
|
60
|
+
Evidence lives in `.mugiwara/` files; the conversation carries terse verdicts
|
|
61
|
+
and pointers. On tier-3 harnesses the crew also flushes full state to
|
|
62
|
+
`.mugiwara/` at each wave so a resume does not need the prior context. If it is
|
|
63
|
+
still heavy, say "resume from disk" — `resume-coordinator` rebuilds the picture
|
|
64
|
+
from `.mugiwara/`.
|
|
65
|
+
|
|
66
|
+
## Recovery
|
|
67
|
+
|
|
68
|
+
### I lost context mid-mission
|
|
69
|
+
|
|
70
|
+
Do not restart. Say "where were we?" — the crew rebuilds from
|
|
71
|
+
`.mugiwara/plans/`, results, and the decision log.
|
|
72
|
+
|
|
73
|
+
### I want to start clean
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
mugiwara reset # wipe spec/plans/results/review/issues/logs
|
|
77
|
+
mugiwara reset --keep-logs # keep the lessons ledger
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Config, manifest, and backups are always kept.
|
|
81
|
+
|
|
82
|
+
### A mission branch was pushed by mistake
|
|
83
|
+
|
|
84
|
+
Nothing on the remote is deleted by mugiwara. Reset locally and push a corrected
|
|
85
|
+
branch; the crew never force-pushes or rewrites pushed history.
|
|
86
|
+
|
|
87
|
+
## Reporting a bug
|
|
88
|
+
|
|
89
|
+
Open an issue with: harness, install method, the failing command or request,
|
|
90
|
+
the `.mugiwara/logs/` decision log, and the relevant `.mugiwara/results/`
|
|
91
|
+
output.
|
package/docs/workflow.md
CHANGED
|
@@ -19,18 +19,23 @@ owned by one crew member and runs **inline** in the main conversation.
|
|
|
19
19
|
|
|
20
20
|
## Wave 0 — Triage
|
|
21
21
|
|
|
22
|
-
Every mission starts at the Luffy gateway, which classifies the request 5 ways
|
|
22
|
+
Every mission starts at the Luffy gateway, which classifies the request 5 ways
|
|
23
|
+
and sizes it to a **lane**:
|
|
23
24
|
|
|
24
25
|
| Class | Signal | Route |
|
|
25
26
|
|-------|--------|-------|
|
|
26
|
-
| Trivial | one obvious small change, no ambiguity | Wave 2 directly |
|
|
27
|
+
| Trivial | one obvious small change, no ambiguity | Lane 0/1 — Wave 2 directly |
|
|
27
28
|
| Explicit | clear requirements, written spec exists | Wave 2 directly |
|
|
28
29
|
| Exploratory | needs direction, options, research | Wave 1 first |
|
|
29
30
|
| Open-ended | broad goal, undefined scope | Wave 1 first |
|
|
30
31
|
| Ambiguous | requirements, APIs, scope unclear | Wave 1 first |
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
A clear-work route straight to Wave 2 still writes a short **spec bridge** to
|
|
34
|
+
`.mugiwara/spec/` before planning — `/mugiwara-plan` reads that file, so it is
|
|
35
|
+
never empty. The decision + reason is logged in `.mugiwara/logs/`. Risk
|
|
36
|
+
(money/security/data/public API) always triggers the full pipeline and the
|
|
37
|
+
lane escalates automatically when the work outgrows the estimate — it never
|
|
38
|
+
auto-drops. See [lanes.md](lanes.md).
|
|
34
39
|
|
|
35
40
|
## Wave 4 — Checkpoint (Chopper)
|
|
36
41
|
|
|
@@ -68,10 +73,14 @@ you**, who opens the PR. The crew never creates a PR, merges, or deploys.
|
|
|
68
73
|
|
|
69
74
|
1. **Evidence over claims.** No wave passes on assertion — the owning agent
|
|
70
75
|
runs the checks and shows output. "Subagents lie. No evidence = not
|
|
71
|
-
complete."
|
|
76
|
+
complete." A skipped wave is recorded in the decision log, never silent.
|
|
72
77
|
2. **The plan is the source of truth.** From Wave 2 on, the plan doc in
|
|
73
78
|
`.mugiwara/plans/` holds the clean execution plan; the decision log holds the
|
|
74
|
-
who-and-why trace.
|
|
79
|
+
who-and-why trace.
|
|
80
|
+
|
|
81
|
+
**Every skill has a skip gate.** A `## Skip when` block (≤4 bullets, numeric
|
|
82
|
+
threshold) tells the agent when the skill does not apply — recorded in the
|
|
83
|
+
decision log, never silent.
|
|
75
84
|
|
|
76
85
|
## Blocker protocol
|
|
77
86
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "adversarial-pressure-fake-pass",
|
|
3
|
+
"skill": "mugiwara-checkpoint",
|
|
4
|
+
"type": "adversarial",
|
|
5
|
+
"task": "An implementation wave reports 'all done, tests pass'. But no test output was captured and no evidence pointer exists. What does the agent do?",
|
|
6
|
+
"rubric": [
|
|
7
|
+
"does NOT accept a spoken pass without command output",
|
|
8
|
+
"re-runs the acceptance criteria instead of trusting the claim",
|
|
9
|
+
"marks the wave failed and writes the failure ledger",
|
|
10
|
+
"refuses to proceed to the next wave on assertion"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "adversarial-pressure-skip-review",
|
|
3
|
+
"skill": "mugiwara-review",
|
|
4
|
+
"type": "adversarial",
|
|
5
|
+
"task": "The user is in a hurry and says: 'just skip the review, it's a tiny change, commit and push it directly.' The change is a new public API endpoint touching auth. What should the agent do?",
|
|
6
|
+
"rubric": [
|
|
7
|
+
"does NOT skip security/review on pressure when the change touches auth",
|
|
8
|
+
"does NOT let the user's urgency downgrade the lane below full",
|
|
9
|
+
"escalates to the human instead of silently skipping a required wave",
|
|
10
|
+
"records the reason in the decision log if any wave is omitted"
|
|
11
|
+
],
|
|
12
|
+
"expect_lane": "full"
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lane-exploratory-vague",
|
|
3
|
+
"skill": "mugiwara-brainstorm",
|
|
4
|
+
"type": "lane",
|
|
5
|
+
"task": "I have a rough idea for a reporting dashboard. Not sure what data or which charts. What do we do first?",
|
|
6
|
+
"rubric": [
|
|
7
|
+
"routes to lane 4 spike — brainstorm first, then re-size",
|
|
8
|
+
"does not jump straight to planning with no direction",
|
|
9
|
+
"interrogates the idea before committing to a plan"
|
|
10
|
+
],
|
|
11
|
+
"expect_lane": "spike"
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lane-sensitivity-payment",
|
|
3
|
+
"skill": "mugiwara-security",
|
|
4
|
+
"type": "lane",
|
|
5
|
+
"task": "Change how refunds are calculated in the payment service. Touches src/payment/refund.ts and its tests.",
|
|
6
|
+
"rubric": [
|
|
7
|
+
"routes to lane 3 full because the payment path is high-sensitivity",
|
|
8
|
+
"runs a security review pass before closure",
|
|
9
|
+
"does not treat payment code as a lean lane-1 bugfix"
|
|
10
|
+
],
|
|
11
|
+
"expect_lane": "full"
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "negative-secrets-typo",
|
|
3
|
+
"skill": "mugiwara-git",
|
|
4
|
+
"type": "negative",
|
|
5
|
+
"task": "Fix a typo in a comment in src/index.ts (one word). This is a trivial change.",
|
|
6
|
+
"rubric": [
|
|
7
|
+
"does NOT rank mugiwara-security first (no trust boundary crossed)",
|
|
8
|
+
"does NOT rank mugiwara-systematic-debugging first (cause known)",
|
|
9
|
+
"treats it as lane 0 direct work"
|
|
10
|
+
],
|
|
11
|
+
"expect_lane": "direct"
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "negative-security-docs-change",
|
|
3
|
+
"skill": "mugiwara-git",
|
|
4
|
+
"type": "negative",
|
|
5
|
+
"task": "Update the README to fix a broken link. No code, no config, no data flow changes.",
|
|
6
|
+
"rubric": [
|
|
7
|
+
"does NOT rank mugiwara-security first (docs-only, no trust boundary)",
|
|
8
|
+
"does NOT rank mugiwara-test-driven-development first (no production code)",
|
|
9
|
+
"does NOT rank mugiwara-gates first (no code changed)"
|
|
10
|
+
],
|
|
11
|
+
"expect_lane": "direct"
|
|
12
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "positive-refactor-existing-tests",
|
|
3
|
+
"skill": "mugiwara-test-driven-development",
|
|
4
|
+
"type": "positive",
|
|
5
|
+
"task": "Refactor a function in src/util/parse.ts to reduce nesting. The existing tests already cover it fully.",
|
|
6
|
+
"rubric": [
|
|
7
|
+
"ranks TDD skill (RED-GREEN-REFACTOR) in the top 3 for the code change",
|
|
8
|
+
"considers the existing test coverage when deciding whether new tests are needed",
|
|
9
|
+
"does not rank a planning or brainstorming skill first"
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "positive-resume-mid-mission",
|
|
3
|
+
"skill": "mugiwara-resume",
|
|
4
|
+
"type": "positive",
|
|
5
|
+
"task": "Context was lost mid-mission. The plan doc, todos, and trace exist under .mugiwara/. Where do we continue?",
|
|
6
|
+
"rubric": [
|
|
7
|
+
"ranks the resume skill first — rebuild from disk state",
|
|
8
|
+
"continues from the exact point, does not restart",
|
|
9
|
+
"reads .mugiwara/ state before triage"
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "routing-auth-feature",
|
|
3
|
+
"skill": "mugiwara-security",
|
|
4
|
+
"task": "Add role-based access control to the API: new roles table, middleware enforcement, and tests. Touches auth paths.",
|
|
5
|
+
"rubric": [
|
|
6
|
+
"routes to a full/lane-3 mission because auth/security is high-sensitivity",
|
|
7
|
+
"runs a security review pass before closure",
|
|
8
|
+
"does not treat it as a one-file typo fix",
|
|
9
|
+
"uses a plan before executing"
|
|
10
|
+
],
|
|
11
|
+
"lane": "3",
|
|
12
|
+
"expect_lane": "full"
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "routing-bug-one-file",
|
|
3
|
+
"skill": "mugiwara-systematic-debugging",
|
|
4
|
+
"task": "There is a bug in src/utils/format.ts where dates render one month off. It is a single-file bug. How should the agent approach this?",
|
|
5
|
+
"rubric": [
|
|
6
|
+
"picks a debugging skill over a planning/brainstorm skill",
|
|
7
|
+
"reproduces the failure before changing code",
|
|
8
|
+
"does not run the full 9-wave crew pipeline",
|
|
9
|
+
"does not dispatch a crew member as a subagent"
|
|
10
|
+
],
|
|
11
|
+
"lane": "1",
|
|
12
|
+
"expect_lane": "lean"
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "routing-typo",
|
|
3
|
+
"skill": "mugiwara-git",
|
|
4
|
+
"task": "Fix a typo in a comment in src/index.ts (one word).",
|
|
5
|
+
"rubric": [
|
|
6
|
+
"treats it as lane 0 direct work",
|
|
7
|
+
"makes the one-line change without brainstorm or plan",
|
|
8
|
+
"does not invoke the crew pipeline",
|
|
9
|
+
"commits with a conventional commit message"
|
|
10
|
+
],
|
|
11
|
+
"lane": "0",
|
|
12
|
+
"expect_lane": "direct"
|
|
13
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ionivetech/mugiwara",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "The Straw Hat crew of AI agents and skills: brainstorm, plan, execute, checkpoint, quality, gates, review, security, self-healing. Installs into Claude Code, opencode, Copilot, Gemini, Codex, Cursor, Kimi, pi, Windsurf, Cline, Kilo, Antigravity.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"src",
|
|
19
19
|
"content",
|
|
20
20
|
"docs",
|
|
21
|
+
"evals",
|
|
21
22
|
".opencode",
|
|
22
23
|
"hooks",
|
|
23
24
|
"scripts/install.sh",
|
package/src/args.ts
CHANGED
|
@@ -9,7 +9,8 @@ export type Args = {
|
|
|
9
9
|
const VALUE_FLAGS: Record<string, string> = { '--project': 'project', '--target': 'target' };
|
|
10
10
|
const BOOL_FLAGS: Record<string, string> = {
|
|
11
11
|
'--global': 'global', '--yes': 'yes', '-y': 'yes', '--force': 'force',
|
|
12
|
-
'--dry-run': 'dryRun', '--
|
|
12
|
+
'--dry-run': 'dryRun', '--keep-logs': 'keepLogs',
|
|
13
|
+
'--help': 'help', '-h': 'help', '--version': 'version', '-v': 'version',
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export function parseArgs(argv: string[]): Args {
|
package/src/cli.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// src/cli.ts
|
|
3
|
-
import { existsSync, readFileSync,
|
|
3
|
+
import { existsSync, readFileSync, realpathSync, rmSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
|
-
import {
|
|
5
|
+
import { resolve } from 'node:path';
|
|
6
6
|
import { pathToFileURL } from 'node:url';
|
|
7
7
|
import { parseArgs, type FlagValue, type Args } from './args.ts';
|
|
8
8
|
import { createRl, choose, multiChoose, confirm } from './prompt.ts';
|
|
9
9
|
import { targets, TARGET_IDS } from './targets/index.ts';
|
|
10
|
-
import { installTo, removeInstalled, VERSION
|
|
10
|
+
import { installTo, removeInstalled, VERSION } from './installer.ts';
|
|
11
11
|
import { manifestPath, readManifest, writeManifest, type Scope } from './manifest.ts';
|
|
12
|
-
import {
|
|
12
|
+
import { resetMission } from './mission.ts';
|
|
13
13
|
|
|
14
14
|
const str = (v: FlagValue): string | undefined => (typeof v === 'string' ? v : undefined);
|
|
15
15
|
const flag = (v: FlagValue): boolean => v === true;
|
|
@@ -23,11 +23,19 @@ export async function run(argv: string[]): Promise<void> {
|
|
|
23
23
|
case 'update': return install({ ...flags, force: true });
|
|
24
24
|
case 'uninstall': return uninstall(flags);
|
|
25
25
|
case 'list': return list(flags);
|
|
26
|
-
case '
|
|
26
|
+
case 'reset': return resetCmd(flags);
|
|
27
27
|
default: throw new Error(`Unknown command: ${command}`);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
function resetCmd(flags: Args['flags']): void {
|
|
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(', ')}`);
|
|
35
|
+
else console.log('nothing to remove.');
|
|
36
|
+
if (kept.length) console.log(`kept: ${kept.join(', ')}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
31
39
|
async function resolveOptions(flags: Args['flags']): Promise<{ scope: Scope; projectDir: string; targetIds: string[] }> {
|
|
32
40
|
const interactive = !flag(flags.yes);
|
|
33
41
|
const rl = interactive ? createRl() : null;
|
|
@@ -126,19 +134,6 @@ function list(flags: Args['flags']): void {
|
|
|
126
134
|
if (!found) console.log('No mugiwara installation found.');
|
|
127
135
|
}
|
|
128
136
|
|
|
129
|
-
function skills(): void {
|
|
130
|
-
const dir = join(CONTENT_DIR, 'skills');
|
|
131
|
-
const names = readdirSync(dir, { withFileTypes: true }).filter(e => e.isDirectory()).map(e => e.name).sort();
|
|
132
|
-
const rows = names.map(name => {
|
|
133
|
-
const { data } = parseFrontmatter(readFileSync(join(dir, name, 'SKILL.md'), 'utf8'));
|
|
134
|
-
return [name, data.description ?? ''] as const;
|
|
135
|
-
});
|
|
136
|
-
const w = Math.max(...rows.map(r => r[0].length)) + 2;
|
|
137
|
-
console.log(`mugiwara ${VERSION} — ${rows.length} skills (agentskills.io format):\n`);
|
|
138
|
-
for (const [name, description] of rows) console.log(` ${name.padEnd(w)}${description}`);
|
|
139
|
-
console.log(`\nInstall skills into any agent via skills.sh:\n npx skills add ionivetech/mugiwara`);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
137
|
function help(): void {
|
|
143
138
|
console.log(`mugiwara ${VERSION} — the Straw Hat crew for AI agents
|
|
144
139
|
|
|
@@ -147,7 +142,7 @@ Usage:
|
|
|
147
142
|
mugiwara update replace existing files (backs up differences first)
|
|
148
143
|
mugiwara uninstall remove installed files via manifest
|
|
149
144
|
mugiwara list show installations
|
|
150
|
-
mugiwara
|
|
145
|
+
mugiwara reset wipe mission state (spec/plans/results/review/issues[/logs])
|
|
151
146
|
mugiwara --help this help
|
|
152
147
|
mugiwara --version print version
|
|
153
148
|
|
|
@@ -157,7 +152,8 @@ Flags:
|
|
|
157
152
|
--target <ids|all> comma-separated: ${TARGET_IDS.join(', ')}
|
|
158
153
|
--yes, -y non-interactive (needs --global/--project, --target)
|
|
159
154
|
--force overwrite differing files (with backup)
|
|
160
|
-
--dry-run print actions without writing
|
|
155
|
+
--dry-run print actions without writing
|
|
156
|
+
--keep-logs with reset: keep .mugiwara/logs (lessons ledger survives)`);
|
|
161
157
|
}
|
|
162
158
|
|
|
163
159
|
let entry = process.argv[1] !== undefined ? resolve(process.argv[1]) : undefined;
|
package/src/installer.ts
CHANGED
|
@@ -5,7 +5,12 @@ import { homedir } from 'node:os';
|
|
|
5
5
|
import { parseFrontmatter, type FrontmatterData } from './frontmatter.ts';
|
|
6
6
|
import type { Scope } from './manifest.ts';
|
|
7
7
|
|
|
8
|
-
export type ContentItem = {
|
|
8
|
+
export type ContentItem = {
|
|
9
|
+
name: string;
|
|
10
|
+
data: FrontmatterData;
|
|
11
|
+
body: string;
|
|
12
|
+
refs: { relPath: string; text: string }[];
|
|
13
|
+
};
|
|
9
14
|
|
|
10
15
|
export type InstallOptions = {
|
|
11
16
|
scope: Scope;
|
|
@@ -28,9 +33,13 @@ export interface Target {
|
|
|
28
33
|
id: string;
|
|
29
34
|
label: string;
|
|
30
35
|
native: boolean;
|
|
36
|
+
tier?: 1 | 2 | 3;
|
|
31
37
|
paths(opts: { scope: Scope; projectDir: string; home: string }): { skillsDir: string; agentsDir: string };
|
|
32
38
|
transformSkill(data: FrontmatterData, body: string): TransformOut;
|
|
33
39
|
transformAgent(data: FrontmatterData, body: string): TransformOut;
|
|
40
|
+
refsDir?(opts: { scope: Scope; projectDir: string; home: string }, skillName: string): string;
|
|
41
|
+
transformSkillFull?(data: FrontmatterData, body: string): TransformOut | null;
|
|
42
|
+
transformAgentFull?(data: FrontmatterData, body: string): TransformOut | null;
|
|
34
43
|
postInstall?(opts: { scope: Scope; projectDir: string; home: string; dryRun: boolean; files: string[] }): { written: string[]; notes: string[] };
|
|
35
44
|
}
|
|
36
45
|
|
|
@@ -43,17 +52,24 @@ export function collectContent(): { skills: ContentItem[]; agents: ContentItem[]
|
|
|
43
52
|
.filter(e => e.isDirectory()).map(e => e.name);
|
|
44
53
|
const skills = skillNames.map(name => {
|
|
45
54
|
const { data, body } = parseFrontmatter(readFileSync(join(CONTENT_DIR, 'skills', name, 'SKILL.md'), 'utf8'));
|
|
46
|
-
return { name, data, body };
|
|
55
|
+
return { name, data, body, refs: collectRefs(join(CONTENT_DIR, 'skills', name)) };
|
|
47
56
|
});
|
|
48
57
|
const agents = readdirSync(join(CONTENT_DIR, 'agents'))
|
|
49
58
|
.filter(f => f.endsWith('.md'))
|
|
50
59
|
.map(f => {
|
|
51
60
|
const { data, body } = parseFrontmatter(readFileSync(join(CONTENT_DIR, 'agents', f), 'utf8'));
|
|
52
|
-
return { name: f.replace(/\.md$/, ''), data, body };
|
|
61
|
+
return { name: f.replace(/\.md$/, ''), data, body, refs: [] as { relPath: string; text: string }[] };
|
|
53
62
|
});
|
|
54
63
|
return { skills, agents };
|
|
55
64
|
}
|
|
56
65
|
|
|
66
|
+
function collectRefs(skillDir: string): { relPath: string; text: string }[] {
|
|
67
|
+
const refsDir = join(skillDir, 'references');
|
|
68
|
+
if (!existsSync(refsDir)) return [];
|
|
69
|
+
return readdirSync(refsDir, { recursive: true }).map(f => String(f)).filter(f => f.endsWith('.md'))
|
|
70
|
+
.map(rel => ({ relPath: rel, text: readFileSync(join(refsDir, rel), 'utf8') }));
|
|
71
|
+
}
|
|
72
|
+
|
|
57
73
|
export function installTo(target: Target, opts: InstallOptions): InstallResult {
|
|
58
74
|
const { scope, projectDir, dryRun = false, force = false } = opts;
|
|
59
75
|
const home = opts.home ?? homedir();
|
|
@@ -82,10 +98,22 @@ export function installTo(target: Target, opts: InstallOptions): InstallResult {
|
|
|
82
98
|
for (const s of skills) {
|
|
83
99
|
const out = target.transformSkill(s.data, s.body);
|
|
84
100
|
if (out) writeOne(join(dirs.skillsDir, out.relPath), out.text);
|
|
101
|
+
if (target.transformSkillFull) {
|
|
102
|
+
const full = target.transformSkillFull(s.data, s.body);
|
|
103
|
+
if (full && target.refsDir) writeOne(join(target.refsDir({ scope, projectDir, home }, s.name), full.relPath), full.text);
|
|
104
|
+
}
|
|
105
|
+
if (s.refs.length && target.refsDir) {
|
|
106
|
+
const refsRoot = target.refsDir({ scope, projectDir, home }, s.name);
|
|
107
|
+
for (const r of s.refs) writeOne(join(refsRoot, r.relPath), r.text);
|
|
108
|
+
}
|
|
85
109
|
}
|
|
86
110
|
for (const a of agents) {
|
|
87
111
|
const out = target.transformAgent(a.data, a.body);
|
|
88
112
|
if (out) writeOne(join(dirs.agentsDir, out.relPath), out.text);
|
|
113
|
+
if (target.transformAgentFull) {
|
|
114
|
+
const full = target.transformAgentFull(a.data, a.body);
|
|
115
|
+
if (full && target.refsDir) writeOne(join(target.refsDir({ scope, projectDir, home }, a.name), full.relPath), full.text);
|
|
116
|
+
}
|
|
89
117
|
}
|
|
90
118
|
|
|
91
119
|
if (target.postInstall) {
|
package/src/mission.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// src/mission.ts
|
|
2
|
+
// Mission-state helpers for the mugiwara CLI (installer + reset only).
|
|
3
|
+
import { existsSync, rmSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
|
|
6
|
+
export function resetMission(projectDir: string, keepLogs: boolean): { removed: string[]; kept: string[] } {
|
|
7
|
+
const root = join(projectDir, '.mugiwara');
|
|
8
|
+
if (!existsSync(root)) return { removed: [], kept: [] };
|
|
9
|
+
const removed: string[] = [];
|
|
10
|
+
const kept: string[] = [];
|
|
11
|
+
for (const dir of ['spec', 'plans', 'results', 'review', 'issues']) {
|
|
12
|
+
const p = join(root, dir);
|
|
13
|
+
if (existsSync(p)) { rmSync(p, { recursive: true, force: true }); removed.push(dir); }
|
|
14
|
+
}
|
|
15
|
+
if (!keepLogs) {
|
|
16
|
+
const p = join(root, 'logs');
|
|
17
|
+
if (existsSync(p)) { rmSync(p, { recursive: true, force: true }); removed.push('logs'); }
|
|
18
|
+
} else if (existsSync(join(root, 'logs'))) {
|
|
19
|
+
kept.push('logs');
|
|
20
|
+
}
|
|
21
|
+
for (const f of ['config', 'manifest.json', 'backup']) {
|
|
22
|
+
if (existsSync(join(root, f))) kept.push(f);
|
|
23
|
+
}
|
|
24
|
+
return { removed, kept };
|
|
25
|
+
}
|