Plan builtin tool #10
Merged@k33g wants to merge
feature/tasks-builtin into mainMerged as
2db607d6c817.29 files changed
modified
.tickets/issues/0004-do-we-need-mcp.yaml +1 -2 | @@ -6,9 +6,8 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-15T22:38:45.129Z |
| 9 | -updatedAt: 2026-09-21T19:04:58.320Z | |
| 9 | +updatedAt: 2026-09-22T20:57:39.912Z | |
| 10 | 10 | labels: [] |
| 11 | -milestone: v0.04 | |
| 12 | 11 | body: | |
| 13 | 12 | I would say no - use a CLI |
| 14 | 13 | |
| @@ -6,9 +6,8 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-15T22:38:45.129Z | 8 | createdAt: 2026-09-15T22:38:45.129Z |
| 9 | -updatedAt: 2026-09-21T19:04:58.320Z | 9 | +updatedAt: 2026-09-22T20:57:39.912Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | -milestone: v0.04 | ||
| 12 | body: | | 11 | body: | |
| 13 | I would say no - use a CLI | 12 | I would say no - use a CLI |
| 14 | 13 | ||
modified
.tickets/issues/0025-tasks-plan-builtin.yaml +26 -5 | @@ -1,14 +1,35 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | 2 | id: 25 |
| 3 | 3 | title: Tasks / Plan builtin |
| 4 | -state: open | |
| 4 | +state: closed | |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-19T16:06:33.119Z |
| 9 | -updatedAt: 2026-09-19T16:06:33.119Z | |
| 10 | -labels: [] | |
| 11 | -milestone: v0.04 | |
| 12 | -body: "" | |
| 9 | +updatedAt: 2026-09-22T20:54:40.140Z | |
| 10 | +labels: | |
| 11 | + - kind::feature | |
| 12 | + - builtin tool | |
| 13 | + - priority::medium | |
| 14 | +milestone: v0.0.4 | |
| 15 | +body: | | |
| 16 | + ## Implementation note (Mistral Vibe, 2026-09-22) | |
| 17 | + | |
| 18 | + Model-driven plan management: when user gives a list of tasks, the agent autonomously creates and tracks a plan. | |
| 19 | + | |
| 20 | + **Components:** | |
| 21 | + - `internal/tools/plan.go`: plan tool with in-memory PlanStore (session-scoped) | |
| 22 | + - Actions: create, get, update, next, status, list, delete | |
| 23 | + - `skills/plan-manager/SKILL.md`: detection patterns and usage guidelines | |
| 24 | + - Config: `planTool: true/false` in agent.yaml (default: true) | |
| 25 | + - Integration: plans cleared on `/new` command | |
| 26 | + | |
| 27 | + **Storage:** Option A (in-memory, per-session). Lost on restart. | |
| 28 | + | |
| 29 | + **Display:** Status line in responses (e.g., `[2/5] Task 2: Fix bugs (in_progress)`) | |
| 30 | + | |
| 31 | + **Tests:** `internal/tools/plan_test.go` - all passing | |
| 32 | + | |
| 33 | + **Docs:** EN+FR how-to guides in `docs/en/how-to/manage-plans-and-tasks.md` and `docs/fr/how-to/manage-plans-and-tasks.md` | |
| 13 | 34 | tasks: [] |
| 14 | 35 | comments: [] |
| @@ -1,14 +1,35 @@ | |||
| 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | id: 25 | 2 | id: 25 |
| 3 | title: Tasks / Plan builtin | 3 | title: Tasks / Plan builtin |
| 4 | -state: open | 4 | +state: closed |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-19T16:06:33.119Z | 8 | createdAt: 2026-09-19T16:06:33.119Z |
| 9 | -updatedAt: 2026-09-19T16:06:33.119Z | 9 | +updatedAt: 2026-09-22T20:54:40.140Z |
| 10 | -labels: [] | 10 | +labels: |
| 11 | -milestone: v0.04 | 11 | + - kind::feature |
| 12 | -body: "" | 12 | + - builtin tool |
| 13 | + - priority::medium | ||
| 14 | +milestone: v0.0.4 | ||
| 15 | +body: | | ||
| 16 | + ## Implementation note (Mistral Vibe, 2026-09-22) | ||
| 17 | + | ||
| 18 | + Model-driven plan management: when user gives a list of tasks, the agent autonomously creates and tracks a plan. | ||
| 19 | + | ||
| 20 | + **Components:** | ||
| 21 | + - `internal/tools/plan.go`: plan tool with in-memory PlanStore (session-scoped) | ||
| 22 | + - Actions: create, get, update, next, status, list, delete | ||
| 23 | + - `skills/plan-manager/SKILL.md`: detection patterns and usage guidelines | ||
| 24 | + - Config: `planTool: true/false` in agent.yaml (default: true) | ||
| 25 | + - Integration: plans cleared on `/new` command | ||
| 26 | + | ||
| 27 | + **Storage:** Option A (in-memory, per-session). Lost on restart. | ||
| 28 | + | ||
| 29 | + **Display:** Status line in responses (e.g., `[2/5] Task 2: Fix bugs (in_progress)`) | ||
| 30 | + | ||
| 31 | + **Tests:** `internal/tools/plan_test.go` - all passing | ||
| 32 | + | ||
| 33 | + **Docs:** EN+FR how-to guides in `docs/en/how-to/manage-plans-and-tasks.md` and `docs/fr/how-to/manage-plans-and-tasks.md` | ||
| 13 | tasks: [] | 34 | tasks: [] |
| 14 | comments: [] | 35 | comments: [] |
modified
.tickets/issues/0030-how-to-use-mini-me-with-claude.yaml +1 -2 | @@ -6,9 +6,8 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-21T04:00:56.971Z |
| 9 | -updatedAt: 2026-09-21T19:03:27.354Z | |
| 9 | +updatedAt: 2026-09-22T20:57:22.310Z | |
| 10 | 10 | labels: [] |
| 11 | -milestone: v0.04 | |
| 12 | 11 | body: | |
| 13 | 12 | ## Analysis (Claude, 2026-09-21 — not implemented) |
| 14 | 13 | |
| @@ -6,9 +6,8 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-21T04:00:56.971Z | 8 | createdAt: 2026-09-21T04:00:56.971Z |
| 9 | -updatedAt: 2026-09-21T19:03:27.354Z | 9 | +updatedAt: 2026-09-22T20:57:22.310Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | -milestone: v0.04 | ||
| 12 | body: | | 11 | body: | |
| 13 | ## Analysis (Claude, 2026-09-21 — not implemented) | 12 | ## Analysis (Claude, 2026-09-21 — not implemented) |
| 14 | 13 | ||
modified
.tickets/issues/0031-how-to-use-mini-me-with-gemini.yaml +1 -2 | @@ -6,9 +6,8 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-21T04:01:15.166Z |
| 9 | -updatedAt: 2026-09-21T19:04:28.691Z | |
| 9 | +updatedAt: 2026-09-22T20:56:55.345Z | |
| 10 | 10 | labels: [] |
| 11 | -milestone: v0.04 | |
| 12 | 11 | body: | |
| 13 | 12 | ## Analysis (Claude, 2026-09-21 — not implemented) |
| 14 | 13 | |
| @@ -6,9 +6,8 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-21T04:01:15.166Z | 8 | createdAt: 2026-09-21T04:01:15.166Z |
| 9 | -updatedAt: 2026-09-21T19:04:28.691Z | 9 | +updatedAt: 2026-09-22T20:56:55.345Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | -milestone: v0.04 | ||
| 12 | body: | | 11 | body: | |
| 13 | ## Analysis (Claude, 2026-09-21 — not implemented) | 12 | ## Analysis (Claude, 2026-09-21 — not implemented) |
| 14 | 13 | ||
modified
.tickets/issues/0032-add-prompt-flag.yaml +2 -2 | @@ -6,9 +6,9 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-21T04:47:19.089Z |
| 9 | -updatedAt: 2026-09-21T04:58:31.828Z | |
| 9 | +updatedAt: 2026-09-22T20:54:40.140Z | |
| 10 | 10 | labels: [] |
| 11 | -milestone: v0.04 | |
| 11 | +milestone: v0.0.4 | |
| 12 | 12 | epic: CLI |
| 13 | 13 | body: "" |
| 14 | 14 | tasks: [] |
| @@ -6,9 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-21T04:47:19.089Z | 8 | createdAt: 2026-09-21T04:47:19.089Z |
| 9 | -updatedAt: 2026-09-21T04:58:31.828Z | 9 | +updatedAt: 2026-09-22T20:54:40.140Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | -milestone: v0.04 | 11 | +milestone: v0.0.4 |
| 12 | epic: CLI | 12 | epic: CLI |
| 13 | body: "" | 13 | body: "" |
| 14 | tasks: [] | 14 | tasks: [] |
modified
.tickets/issues/0033-invoke-another-mini-me.yaml +1 -2 | @@ -6,9 +6,8 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-21T04:48:03.596Z |
| 9 | -updatedAt: 2026-09-21T04:58:54.762Z | |
| 9 | +updatedAt: 2026-09-22T20:56:40.361Z | |
| 10 | 10 | labels: [] |
| 11 | -milestone: v0.04 | |
| 12 | 11 | epic: Builtin tools |
| 13 | 12 | body: | |
| 14 | 13 | Should I use ACP ? I think yes |
| @@ -6,9 +6,8 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-21T04:48:03.596Z | 8 | createdAt: 2026-09-21T04:48:03.596Z |
| 9 | -updatedAt: 2026-09-21T04:58:54.762Z | 9 | +updatedAt: 2026-09-22T20:56:40.361Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | -milestone: v0.04 | ||
| 12 | epic: Builtin tools | 11 | epic: Builtin tools |
| 13 | body: | | 12 | body: | |
| 14 | Should I use ACP ? I think yes | 13 | Should I use ACP ? I think yes |
modified
.tickets/issues/0035-create-sbx-template-kit-for-mini-me.yaml +2 -2 | @@ -1,12 +1,12 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | 2 | id: 35 |
| 3 | 3 | title: Create SBX Template + Kit for Mini-Me |
| 4 | -state: open | |
| 4 | +state: closed | |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-21T04:51:17.051Z |
| 9 | -updatedAt: 2026-09-21T19:06:52.839Z | |
| 9 | +updatedAt: 2026-09-22T20:55:22.352Z | |
| 10 | 10 | labels: [] |
| 11 | 11 | milestone: v0.0.3 |
| 12 | 12 | body: | |
| @@ -1,12 +1,12 @@ | |||
| 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | id: 35 | 2 | id: 35 |
| 3 | title: Create SBX Template + Kit for Mini-Me | 3 | title: Create SBX Template + Kit for Mini-Me |
| 4 | -state: open | 4 | +state: closed |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-21T04:51:17.051Z | 8 | createdAt: 2026-09-21T04:51:17.051Z |
| 9 | -updatedAt: 2026-09-21T19:06:52.839Z | 9 | +updatedAt: 2026-09-22T20:55:22.352Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | milestone: v0.0.3 | 11 | milestone: v0.0.3 |
| 12 | body: | | 12 | body: | |
modified
.tickets/issues/0036-hooks.yaml +2 -2 | @@ -6,9 +6,9 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-21T06:32:48.566Z |
| 9 | -updatedAt: 2026-09-21T06:32:48.566Z | |
| 9 | +updatedAt: 2026-09-22T20:54:40.140Z | |
| 10 | 10 | labels: [] |
| 11 | -milestone: v0.04 | |
| 11 | +milestone: v0.0.4 | |
| 12 | 12 | body: "" |
| 13 | 13 | tasks: [] |
| 14 | 14 | comments: [] |
| @@ -6,9 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-21T06:32:48.566Z | 8 | createdAt: 2026-09-21T06:32:48.566Z |
| 9 | -updatedAt: 2026-09-21T06:32:48.566Z | 9 | +updatedAt: 2026-09-22T20:54:40.140Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | -milestone: v0.04 | 11 | +milestone: v0.0.4 |
| 12 | body: "" | 12 | body: "" |
| 13 | tasks: [] | 13 | tasks: [] |
| 14 | comments: [] | 14 | comments: [] |
modified
.tickets/milestones.yaml +2 -2 | @@ -4,8 +4,8 @@ milestones: | ||
| 4 | 4 | state: closed |
| 5 | 5 | dueOn: 2026-09-18 |
| 6 | 6 | - title: v0.0.3 |
| 7 | - state: open | |
| 7 | + state: closed | |
| 8 | 8 | dueOn: 2026-09-30 |
| 9 | - - title: v0.04 | |
| 9 | + - title: v0.0.4 | |
| 10 | 10 | state: open |
| 11 | 11 | dueOn: 2026-10-15 |
| @@ -4,8 +4,8 @@ milestones: | |||
| 4 | state: closed | 4 | state: closed |
| 5 | dueOn: 2026-09-18 | 5 | dueOn: 2026-09-18 |
| 6 | - title: v0.0.3 | 6 | - title: v0.0.3 |
| 7 | - state: open | 7 | + state: closed |
| 8 | dueOn: 2026-09-30 | 8 | dueOn: 2026-09-30 |
| 9 | - - title: v0.04 | 9 | + - title: v0.0.4 |
| 10 | state: open | 10 | state: open |
| 11 | dueOn: 2026-10-15 | 11 | dueOn: 2026-10-15 |
added
.vibe/AGENTS.md +80 -0 | new file mode 100644 | ||
| @@ -0,0 +1,80 @@ | ||
| 1 | +# Working in this sandbox | |
| 2 | + | |
| 3 | +Instructions installed by the `dev-toolkit` kit. They apply to **every** session, whatever the project. | |
| 4 | + | |
| 5 | +## Always start by reading the project memory | |
| 6 | + | |
| 7 | +Before planning, before asking the user anything, before touching a file — check for a `.memory/` directory at the repository root: | |
| 8 | + | |
| 9 | +```bash | |
| 10 | +ls .memory/ 2>/dev/null | |
| 11 | +``` | |
| 12 | + | |
| 13 | +**If it exists, read it before doing anything else:** | |
| 14 | + | |
| 15 | +| Read | Why | | |
| 16 | +| --- | --- | | |
| 17 | +| `.memory/summary.md` | What the project is, its architecture, the decisions currently in force, the real build/test/run commands. | | |
| 18 | +| the tail of `.memory/history.md` | What has already been done, and why it was done that way. | | |
| 19 | +| the most recent file in `.memory/handoffs/` | Where the last session stopped: work in flight, next steps, blockers, traps. | | |
| 20 | + | |
| 21 | +Then, before you propose anything: | |
| 22 | + | |
| 23 | +- **Do not ask the user for information that is already recorded there.** Re-deriving state that is written down wastes the user's time and is the main reason this record exists. | |
| 24 | +- **Do not re-litigate a decision recorded in `summary.md`** without saying you are doing so and why. If you think a decision in force is wrong, say so explicitly and let the user decide. | |
| 25 | +- **Surface unfinished work.** If a handoff records work in flight, report it and ask whether to resume it or start something new — do not silently start something else on top of it. | |
| 26 | +- **Reuse the commands the memory documents.** Do not invent a parallel way to build or test a project that already has one. | |
| 27 | + | |
| 28 | +If `.memory/` does not exist yet, carry on — you will create it when you write your handoff (see below). | |
| 29 | + | |
| 30 | +## Always finish by updating the project memory | |
| 31 | + | |
| 32 | +**Every session ends with all three files below brought up to date. No exceptions** — not for a one-line fix, not for a session that only read code, not for a session that failed to achieve anything. | |
| 33 | + | |
| 34 | +You cannot detect the moment a session actually ends, so use this trigger instead: **do this as the last action before you hand control back, having finished or abandoned what the user asked for.** If the work then continues, extend what you already wrote instead of adding a second set of entries. | |
| 35 | + | |
| 36 | +Two rules govern all three files. **Match the length to the work** — a one-line fix earns a few lines, not a filled-in template; padding with "N/A" makes the record unreadable, which is the one way this mandate defeats itself. And **record what the next person cannot re-derive** — where you stopped, what you tried that failed, the trap you hit, the decision still waiting on the user. Not a diff summary; git already has that. | |
| 37 | + | |
| 38 | +### 1. `summary.md` — edit in place, never regenerate | |
| 39 | + | |
| 40 | +- **Change only the parts your session actually establishes or invalidates.** Leave the rest byte-for-byte alone. You have seen a slice of this project; the file holds what every previous session established, and rewriting it wholesale from your slice silently destroys accurate content you never looked at. This is the single biggest risk in this whole mandate. | |
| 41 | +- **Only from what you verified** — a command you ran, a file you read. Never a plausible guess. | |
| 42 | +- **If nothing about the project's state changed, leave the file untouched.** That is what "update" means; it is not an exception to the mandate. | |
| 43 | +- What you could not check goes under an explicit `## Not yet established` heading. A summary that states unknowns as unknown is useful; one that states guesses as fact is worse than none, because the next session will trust it. | |
| 44 | + | |
| 45 | +### 2. `history.md` — append exactly one entry | |
| 46 | + | |
| 47 | +- One dated entry per session, appended at the end. **Never rewrite or delete an existing entry**, including your own from an earlier turn. | |
| 48 | +- Cover: what was asked, what changed, decisions made and alternatives rejected, tests, quality gate result, docs touched — dropping the lines that have no content. | |
| 49 | +- A read-only or failed session gets an entry too. One line stating that, and why, is a complete entry. | |
| 50 | + | |
| 51 | +### 3. `handoffs/YYYY-MM-DD-<slug>.md` — write or update today's | |
| 52 | + | |
| 53 | +- The slug names the topic. If a file for today already covers this topic, **update it**; if today's work is a different topic, write a new file under a different slug. Never overwrite another session's handoff. | |
| 54 | +- **A session that achieved nothing still gets a handoff**, and it is one of the valuable ones: it stops the next agent walking into the same wall. | |
| 55 | + | |
| 56 | +### If `.memory/` does not exist | |
| 57 | + | |
| 58 | +Create the whole skeleton — `README.md`, `summary.md`, `history.md`, and `handoffs/` with your handoff in it. All four, even if your session touched one file, so a later session finds a record to read and extend rather than a bare directory. `summary.md` is then written under the same rules as above: only what you verified, the rest under `## Not yet established`. `history.md` starts with its first dated entry: this session. | |
| 59 | + | |
| 60 | +The full templates for all three files are in the `methodical-dev` skill (Phase 7). Use them as a menu, not a form to fill in. | |
| 61 | + | |
| 62 | +## Keep the memory true | |
| 63 | + | |
| 64 | +`.memory/` is **committed to the repository**, not gitignored. It only stays useful if it stays accurate, and the three files stay accurate in different ways: `summary.md` is a **snapshot** — it describes the present and carries no history. `history.md` and `handoffs/` are the **record** — they only ever grow, and are never tidied up, condensed, or corrected after the fact. A history you edit is not a history. | |
| 65 | + | |
| 66 | +`.memory/` is for whoever *continues building* the project. `docs/` is for whoever *uses* it. Keep the two apart rather than duplicating content between them. | |
| 67 | + | |
| 68 | +## Skills installed by this kit | |
| 69 | + | |
| 70 | +Prefer these over doing the same work by hand: | |
| 71 | + | |
| 72 | +| Skill | Use it for | | |
| 73 | +| --- | --- | | |
| 74 | +| `methodical-dev` | Any non-trivial change. Approval-gated: requirements → plan → implementation with tests → quality gate → EN+FR docs → `.memory/` update. Start here. | | |
| 75 | +| `quality` | Measuring code quality with qlty and refactoring until the gate passes. Never invoke qlty ad hoc instead. | | |
| 76 | +| `diataxis-doc` | Writing or restructuring documentation with the Diátaxis four-quadrant method. | | |
| 77 | + | |
| 78 | +Never make a check pass by weakening it — no new `exclude_patterns`, no lowered thresholds, no disabled plugins, no deleted or skipped tests. Fix the code, or report that you could not. | |
| 79 | + | |
| 80 | +The `quality` skill defines two narrow exceptions, both conditioned on evidence and on the user's agreement: excluding a vendored `kits/` directory (the measurement tool cannot measure itself), and removing a plugin proven to analyse nothing. Neither is a licence to trim a number — read the skill before invoking either, and never widen them. | |
| new file mode 100644 | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | +# Working in this sandbox | ||
| 2 | + | ||
| 3 | +Instructions installed by the `dev-toolkit` kit. They apply to **every** session, whatever the project. | ||
| 4 | + | ||
| 5 | +## Always start by reading the project memory | ||
| 6 | + | ||
| 7 | +Before planning, before asking the user anything, before touching a file — check for a `.memory/` directory at the repository root: | ||
| 8 | + | ||
| 9 | +```bash | ||
| 10 | +ls .memory/ 2>/dev/null | ||
| 11 | +``` | ||
| 12 | + | ||
| 13 | +**If it exists, read it before doing anything else:** | ||
| 14 | + | ||
| 15 | +| Read | Why | | ||
| 16 | +| --- | --- | | ||
| 17 | +| `.memory/summary.md` | What the project is, its architecture, the decisions currently in force, the real build/test/run commands. | | ||
| 18 | +| the tail of `.memory/history.md` | What has already been done, and why it was done that way. | | ||
| 19 | +| the most recent file in `.memory/handoffs/` | Where the last session stopped: work in flight, next steps, blockers, traps. | | ||
| 20 | + | ||
| 21 | +Then, before you propose anything: | ||
| 22 | + | ||
| 23 | +- **Do not ask the user for information that is already recorded there.** Re-deriving state that is written down wastes the user's time and is the main reason this record exists. | ||
| 24 | +- **Do not re-litigate a decision recorded in `summary.md`** without saying you are doing so and why. If you think a decision in force is wrong, say so explicitly and let the user decide. | ||
| 25 | +- **Surface unfinished work.** If a handoff records work in flight, report it and ask whether to resume it or start something new — do not silently start something else on top of it. | ||
| 26 | +- **Reuse the commands the memory documents.** Do not invent a parallel way to build or test a project that already has one. | ||
| 27 | + | ||
| 28 | +If `.memory/` does not exist yet, carry on — you will create it when you write your handoff (see below). | ||
| 29 | + | ||
| 30 | +## Always finish by updating the project memory | ||
| 31 | + | ||
| 32 | +**Every session ends with all three files below brought up to date. No exceptions** — not for a one-line fix, not for a session that only read code, not for a session that failed to achieve anything. | ||
| 33 | + | ||
| 34 | +You cannot detect the moment a session actually ends, so use this trigger instead: **do this as the last action before you hand control back, having finished or abandoned what the user asked for.** If the work then continues, extend what you already wrote instead of adding a second set of entries. | ||
| 35 | + | ||
| 36 | +Two rules govern all three files. **Match the length to the work** — a one-line fix earns a few lines, not a filled-in template; padding with "N/A" makes the record unreadable, which is the one way this mandate defeats itself. And **record what the next person cannot re-derive** — where you stopped, what you tried that failed, the trap you hit, the decision still waiting on the user. Not a diff summary; git already has that. | ||
| 37 | + | ||
| 38 | +### 1. `summary.md` — edit in place, never regenerate | ||
| 39 | + | ||
| 40 | +- **Change only the parts your session actually establishes or invalidates.** Leave the rest byte-for-byte alone. You have seen a slice of this project; the file holds what every previous session established, and rewriting it wholesale from your slice silently destroys accurate content you never looked at. This is the single biggest risk in this whole mandate. | ||
| 41 | +- **Only from what you verified** — a command you ran, a file you read. Never a plausible guess. | ||
| 42 | +- **If nothing about the project's state changed, leave the file untouched.** That is what "update" means; it is not an exception to the mandate. | ||
| 43 | +- What you could not check goes under an explicit `## Not yet established` heading. A summary that states unknowns as unknown is useful; one that states guesses as fact is worse than none, because the next session will trust it. | ||
| 44 | + | ||
| 45 | +### 2. `history.md` — append exactly one entry | ||
| 46 | + | ||
| 47 | +- One dated entry per session, appended at the end. **Never rewrite or delete an existing entry**, including your own from an earlier turn. | ||
| 48 | +- Cover: what was asked, what changed, decisions made and alternatives rejected, tests, quality gate result, docs touched — dropping the lines that have no content. | ||
| 49 | +- A read-only or failed session gets an entry too. One line stating that, and why, is a complete entry. | ||
| 50 | + | ||
| 51 | +### 3. `handoffs/YYYY-MM-DD-<slug>.md` — write or update today's | ||
| 52 | + | ||
| 53 | +- The slug names the topic. If a file for today already covers this topic, **update it**; if today's work is a different topic, write a new file under a different slug. Never overwrite another session's handoff. | ||
| 54 | +- **A session that achieved nothing still gets a handoff**, and it is one of the valuable ones: it stops the next agent walking into the same wall. | ||
| 55 | + | ||
| 56 | +### If `.memory/` does not exist | ||
| 57 | + | ||
| 58 | +Create the whole skeleton — `README.md`, `summary.md`, `history.md`, and `handoffs/` with your handoff in it. All four, even if your session touched one file, so a later session finds a record to read and extend rather than a bare directory. `summary.md` is then written under the same rules as above: only what you verified, the rest under `## Not yet established`. `history.md` starts with its first dated entry: this session. | ||
| 59 | + | ||
| 60 | +The full templates for all three files are in the `methodical-dev` skill (Phase 7). Use them as a menu, not a form to fill in. | ||
| 61 | + | ||
| 62 | +## Keep the memory true | ||
| 63 | + | ||
| 64 | +`.memory/` is **committed to the repository**, not gitignored. It only stays useful if it stays accurate, and the three files stay accurate in different ways: `summary.md` is a **snapshot** — it describes the present and carries no history. `history.md` and `handoffs/` are the **record** — they only ever grow, and are never tidied up, condensed, or corrected after the fact. A history you edit is not a history. | ||
| 65 | + | ||
| 66 | +`.memory/` is for whoever *continues building* the project. `docs/` is for whoever *uses* it. Keep the two apart rather than duplicating content between them. | ||
| 67 | + | ||
| 68 | +## Skills installed by this kit | ||
| 69 | + | ||
| 70 | +Prefer these over doing the same work by hand: | ||
| 71 | + | ||
| 72 | +| Skill | Use it for | | ||
| 73 | +| --- | --- | | ||
| 74 | +| `methodical-dev` | Any non-trivial change. Approval-gated: requirements → plan → implementation with tests → quality gate → EN+FR docs → `.memory/` update. Start here. | | ||
| 75 | +| `quality` | Measuring code quality with qlty and refactoring until the gate passes. Never invoke qlty ad hoc instead. | | ||
| 76 | +| `diataxis-doc` | Writing or restructuring documentation with the Diátaxis four-quadrant method. | | ||
| 77 | + | ||
| 78 | +Never make a check pass by weakening it — no new `exclude_patterns`, no lowered thresholds, no disabled plugins, no deleted or skipped tests. Fix the code, or report that you could not. | ||
| 79 | + | ||
| 80 | +The `quality` skill defines two narrow exceptions, both conditioned on evidence and on the user's agreement: excluding a vendored `kits/` directory (the measurement tool cannot measure itself), and removing a plugin proven to analyse nothing. Neither is a licence to trim a number — read the skill before invoking either, and never widen them. | ||
added
.vibe/skills/diataxis-doc/SKILL.md +520 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
.vibe/skills/methodical-dev/SKILL.md +603 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
.vibe/skills/quality/SKILL.md +266 -0 | new file mode 100644 | ||
| @@ -0,0 +1,266 @@ | ||
| 1 | +--- | |
| 2 | +name: quality | |
| 3 | +description: Audit and improve this project's code quality with qlty. Sets qlty up on first use, measures lint issues / code smells / complexity, writes a timestamped Markdown report under .quality/, tracks progression across runs, and refactors until the quality gate passes. Use when asked to check code quality, run a quality report, review technical debt, see whether quality is improving, or clean up / refactor the codebase. | |
| 4 | +--- | |
| 5 | + | |
| 6 | +# Quality | |
| 7 | + | |
| 8 | +Measure this project's code quality with [qlty](https://docs.qlty.sh), report it, and | |
| 9 | +refactor until the gate passes. | |
| 10 | + | |
| 11 | +The measurement is a script, not a judgement call — run it, then act on what it says. | |
| 12 | +It is read-only with respect to the source tree (`qlty check` runs with `--no-fix`), so | |
| 13 | +measuring never quietly rewrites the code you are about to reason about. | |
| 14 | + | |
| 15 | +## 1. Set up (only if needed) | |
| 16 | + | |
| 17 | +The setup is self-healing; just run the script. It verifies `qlty` is on `PATH`, that | |
| 18 | +the workspace is a git repository, and runs `qlty init --yes` when there is no | |
| 19 | +`.qlty/qlty.toml` yet. | |
| 20 | + | |
| 21 | +If `qlty` is missing entirely, the sandbox was not created with the `dev-toolkit` | |
| 22 | +kit. Say so and stop — do not install qlty by hand. | |
| 23 | + | |
| 24 | +**If the project vendors this kit** — a `kits/` directory holding the sources that get | |
| 25 | +installed into `~/.claude/` — add it to `exclude_patterns` in `.qlty/qlty.toml` on the | |
| 26 | +first run: | |
| 27 | + | |
| 28 | +```toml | |
| 29 | +exclude_patterns = [ | |
| 30 | + # … the defaults qlty init wrote … | |
| 31 | + "kits/**", # the kit's own sources, including this skill's quality_report.py | |
| 32 | +] | |
| 33 | +``` | |
| 34 | + | |
| 35 | +This is **not** an exception to "do not game the gate" below. The reason is narrower and | |
| 36 | +holds regardless of what the numbers say: `quality_report.py` is the script that | |
| 37 | +*produces* the measurement, so leaving it in scope means measuring the instrument with | |
| 38 | +itself. Two of its findings are structurally unfixable — a script whose job is to run | |
| 39 | +`qlty` must import and call `subprocess`, which every Python security linter flags. | |
| 40 | + | |
| 41 | +Two conditions make this legitimate rather than convenient, and both must hold: | |
| 42 | + | |
| 43 | +- **It is the project's decision, not yours.** Say what the exclusion hides and why, and | |
| 44 | + let the user choose. Adding it unilaterally is the forbidden move. | |
| 45 | +- **Write down what it hides.** Put the actual findings in a comment next to the pattern. | |
| 46 | + Some of them are usually real defects in the script — over-complex functions, unused | |
| 47 | + imports — and they should be fixed at the kit's source rather than forgotten. An | |
| 48 | + exclusion that records what it silences stays honest; one that just makes a number | |
| 49 | + drop is the start of the drift. | |
| 50 | + | |
| 51 | +## 2. Measure | |
| 52 | + | |
| 53 | +From the project root: | |
| 54 | + | |
| 55 | +```bash | |
| 56 | +python3 ~/.claude/skills/quality/scripts/quality_report.py --workspace . | |
| 57 | +``` | |
| 58 | + | |
| 59 | +On a cold cache the first run takes several minutes: qlty downloads its plugin | |
| 60 | +definitions and the linter binaries. Subsequent runs are fast (the cache lives on a | |
| 61 | +persistent volume at `~/.qlty`). | |
| 62 | + | |
| 63 | +The script: | |
| 64 | + | |
| 65 | +- runs `qlty check --all`, `qlty smells --all`, and `qlty metrics --all` | |
| 66 | +- writes `.quality/report-<timestamp>.md` and `.quality/report-latest.md` | |
| 67 | +- appends one JSON line to `.quality/history.jsonl` | |
| 68 | +- prints the report to stdout | |
| 69 | +- **exits `0` if the gate passed, `1` if it failed, `2` on a tooling error** | |
| 70 | + | |
| 71 | +Use the exit code as the loop condition. Do not re-derive the verdict yourself. | |
| 72 | + | |
| 73 | +## 3. Read the report | |
| 74 | + | |
| 75 | +The report contains: | |
| 76 | + | |
| 77 | +| Section | What to do with it | | |
| 78 | +| --- | --- | | |
| 79 | +| **Gate violations** | The work list. Each line is a threshold that was breached. | | |
| 80 | +| **Lint issues** by level, top rules, most affected files | Where to start — but read the count correctly first, see below. | | |
| 81 | +| **Code smells** | Duplication and over-complex structure — these need real refactoring, not a formatter. | | |
| 82 | +| **Metrics** | `complex` / `cyclo` per file; the "Most complex files" table names refactoring targets. | | |
| 83 | +| **Trend** | Last 10 runs. This is how you show progression. | | |
| 84 | +| **Tooling notes** | Present only when a qlty invocation failed — investigate before trusting the numbers. | | |
| 85 | + | |
| 86 | +### Read the count before you trust it | |
| 87 | + | |
| 88 | +"Fix the highest-count rule first" is the right instinct and the wrong first step. A | |
| 89 | +count is `occurrences`, not `distinct problems`, and the two diverge badly in two common | |
| 90 | +cases: | |
| 91 | + | |
| 92 | +- **One finding, repeated per manifest.** `osv-scanner` reports a dependency CVE once per | |
| 93 | + `go.mod` / `package.json` it appears in. A monorepo with a dozen manifests turns one | |
| 94 | + vulnerable version into a hundred-plus findings, and adding a three-line example | |
| 95 | + manifest multiplies the total without degrading anything. | |
| 96 | +- **One finding, repeated per file.** A linter that fails to parse the language emits one | |
| 97 | + finding per source file. That looks like the largest cluster in the report and is worth | |
| 98 | + exactly nothing. | |
| 99 | + | |
| 100 | +And before treating a *delta* as a regression: **re-run.** A count that moves while the | |
| 101 | +tree is untouched is measuring the tool, not the code. The usual cause is a linter | |
| 102 | +answering from its own partially-populated cache — qlty invokes several with | |
| 103 | +`--allow-parallel-runners`, and an invocation returning in a fraction of a second did | |
| 104 | +not re-analyse anything. That failure mode **under-reports**: the low number is the | |
| 105 | +wrong one, so it looks like an improvement. | |
| 106 | + | |
| 107 | +When you suspect it, clear that linter's cache and run its binary directly, several | |
| 108 | +times, until the result is stable; `.qlty/out/invoke-*.yaml` records the exact command, | |
| 109 | +environment and duration qlty used. Work from that figure, not from the report, and say | |
| 110 | +in your report which number you trust and why. Remember too that **a gate threshold | |
| 111 | +pinned to an unstable measurement will trip on its own** — give it margin, and write | |
| 112 | +down that the margin is the tool's fault, so it gets removed rather than inherited. | |
| 113 | + | |
| 114 | +So before picking a target, check **how many distinct rules and how many distinct files** | |
| 115 | +a count spans: | |
| 116 | + | |
| 117 | +```bash | |
| 118 | +# qlty check has no --json; SARIF is the machine-readable form | |
| 119 | +qlty check --all --no-fix --no-upgrade-check --sarif > /tmp/qlty.sarif | |
| 120 | +``` | |
| 121 | + | |
| 122 | +Then group the results by `ruleId` and by file URI. A rule spanning many files with one | |
| 123 | +occurrence each, or many rules spanning the same short file list, means the count is | |
| 124 | +telling you about the *shape of the scan*, not the state of the code. Say so in your | |
| 125 | +report — a total nobody can interpret gets ignored, and then a real regression hides in | |
| 126 | +it. | |
| 127 | + | |
| 128 | +## 4. Refactor until the gate passes | |
| 129 | + | |
| 130 | +If the gate failed, refactor. Loop: | |
| 131 | + | |
| 132 | +1. Pick the largest cluster of violations from the report (one rule, or one file). | |
| 133 | +2. Fix formatting mechanically first — `qlty fmt` handles it, and it clears a lot of | |
| 134 | + noise cheaply: | |
| 135 | + ```bash | |
| 136 | + qlty fmt --all --no-upgrade-check | |
| 137 | + ``` | |
| 138 | +3. Fix the remaining issues by editing the code. For smells, prefer extracting a | |
| 139 | + function or collapsing a duplicated block over suppressing the finding. | |
| 140 | +4. Verify nothing broke, using **this project's own** build and test commands. The | |
| 141 | + repository's tooling is the authority on what those are — check for a `Makefile`, | |
| 142 | + `Taskfile.yml`, `package.json` scripts, `pyproject.toml`, or the CI workflow before | |
| 143 | + assuming. Common cases: | |
| 144 | + | |
| 145 | + | Stack | Verification | | |
| 146 | + | --- | --- | | |
| 147 | + | Go | `go build ./... && go test ./...` | | |
| 148 | + | Go targeting WebAssembly | also `tinygo build -target=wasip1 ./...` — TinyGo rejects some constructs the standard toolchain accepts, so a passing `go build` is not sufficient | | |
| 149 | + | Node / TypeScript | `npm test` (or the script the project defines), plus `tsc --noEmit` if the project is typed | | |
| 150 | + | Python | `pytest` | | |
| 151 | + | Rust | `cargo build && cargo test && cargo clippy -- -D warnings` | | |
| 152 | + | Rust targeting WebAssembly | also `cargo build --target wasm32-wasip2` — and note the asymmetry below | | |
| 153 | + | VS Code extension | the compile script, then `vsce package` — packaging validates the manifest, which `tsc` does not | | |
| 154 | + | Zed extension | `cargo build --release --target wasm32-wasip2` | | |
| 155 | + | |
| 156 | + If the project has no tests, say so in the report rather than letting a green build | |
| 157 | + stand in as proof the refactoring was safe. | |
| 158 | + | |
| 159 | + **Two traps specific to WebAssembly targets.** Both let a refactoring look verified | |
| 160 | + when it is not: | |
| 161 | + | |
| 162 | + - A **wasm build passing does not mean the tests ran.** `cargo build --target | |
| 163 | + wasm32-wasip2` links with rustc's own bundled `rust-lld`, so it succeeds even | |
| 164 | + with no C toolchain present, while `cargo test` — which builds for the *host* — | |
| 165 | + fails at link time with ``error: linker `cc` not found``. If you see that error, | |
| 166 | + the tests did not run; do not report the wasm build as verification. | |
| 167 | + - An **extension cannot be exercised here.** No editor runs in this sandbox, so | |
| 168 | + neither VS Code's Extension Development Host nor Zed's *Install Dev Extension* | |
| 169 | + is available, and `@vscode/test-electron` needs an X server this kit does not | |
| 170 | + install. Compile, unit-test and package — then say plainly that the integration | |
| 171 | + path is untested rather than implying it passed. | |
| 172 | +5. Re-run the measurement from step 2 and compare against the previous run. | |
| 173 | + | |
| 174 | +Stop when any of these is true: | |
| 175 | + | |
| 176 | +- **The gate passes.** Report the before/after numbers from the Trend table. | |
| 177 | +- **Five iterations have run.** Stop and report honestly: what improved, what remains, | |
| 178 | + and why the rest is hard. | |
| 179 | +- **Two consecutive runs show no improvement.** You are stuck — stop and explain what | |
| 180 | + the blocker is rather than churning the code. | |
| 181 | + | |
| 182 | +Commit as you go, one focused commit per cluster of fixes, so the progression is | |
| 183 | +visible in git as well as in `.quality/history.jsonl`. | |
| 184 | + | |
| 185 | +## Do not game the gate | |
| 186 | + | |
| 187 | +The gate is only worth something if it is measuring the code. All of the following make | |
| 188 | +the number go down while making the project worse — never do them, even if the gate is | |
| 189 | +the only thing standing between you and "done": | |
| 190 | + | |
| 191 | +- Adding `exclude_patterns`, disabling a plugin, setting a plugin to `mode = "monitor"`, | |
| 192 | + or raising a threshold in `.qlty/qlty.toml`. | |
| 193 | +- Loosening `.quality/gate.json`. | |
| 194 | +- Deleting, skipping, or emptying tests. | |
| 195 | +- Adding blanket lint suppressions (`//nolint`, `// qlty-ignore`) to silence a finding | |
| 196 | + you could fix. | |
| 197 | + | |
| 198 | +A narrowly-scoped suppression with a comment explaining why the finding is a false | |
| 199 | +positive is legitimate. If you believe a threshold is genuinely wrong for this project, | |
| 200 | +say so and let the user decide — do not change it yourself. | |
| 201 | + | |
| 202 | +### The one plugin you may remove: a broken one | |
| 203 | + | |
| 204 | +"Disabling a plugin" above means a plugin that *finds things you would rather not fix*. A | |
| 205 | +plugin that **analyses nothing** is a different object, and keeping it is not rigour: its | |
| 206 | +findings crowd out the ones that matter and make the total unreadable. | |
| 207 | + | |
| 208 | +The two are indistinguishable from the report alone, so removal requires a **reproducible | |
| 209 | +diagnosis**, never an impression. Establish all four of these before touching the config: | |
| 210 | + | |
| 211 | +1. **It is not the language version or a specific construct.** Put a trivially small, | |
| 212 | + unambiguously valid file of that language in a *fresh* git repository, enable only | |
| 213 | + that plugin, and run it. If a five-line hello-world fails, no source construct is to | |
| 214 | + blame. | |
| 215 | +2. **It is not this project.** Same point — the probe repository shares nothing with the | |
| 216 | + codebase under measurement. | |
| 217 | +3. **It is not the environment qlty gives plugins.** qlty runs plugins with a stripped | |
| 218 | + environment (empty `PATH` and `HOME`). Run the plugin's own binary directly, with your | |
| 219 | + full environment, on the same probe file. Read the invocation qlty used from | |
| 220 | + `.qlty/out/invoke-*.yaml`, which records the exact `script`, `env` and `stderr`. | |
| 221 | +4. **It is not the plugin family.** If sibling plugins sharing the same runtime produce | |
| 222 | + real findings, the failure is specific rather than environmental. | |
| 223 | + | |
| 224 | +If all four hold, remove the plugin — and **write the diagnosis as a comment where you | |
| 225 | +removed it**, so the next session finds the evidence instead of re-adding it on instinct. | |
| 226 | +Note in your report which other tooling still covers that ground; if nothing does, the | |
| 227 | +answer is to replace the plugin, not merely to drop it. | |
| 228 | + | |
| 229 | +`mode = "monitor"` is *not* the remedy here. It does not stop a plugin's findings from | |
| 230 | +counting; it only changes how they are surfaced. A broken plugin left in monitor mode | |
| 231 | +keeps polluting the total, which is how one ends up unnoticed for months. | |
| 232 | + | |
| 233 | +**Do not encode "plugin X is broken" into this skill.** Such a failure belongs to one | |
| 234 | +version, one platform and one moment; a list of known-bad plugins ages badly and, worse, | |
| 235 | +tempts the next agent to skip the diagnosis. The method above is what belongs here — its | |
| 236 | +results belong in the project's own config and notes. | |
| 237 | + | |
| 238 | +## Tuning the gate | |
| 239 | + | |
| 240 | +Defaults are strict: zero error-level issues, zero warning-level issues, zero smells. | |
| 241 | +Override any subset by writing `.quality/gate.json`: | |
| 242 | + | |
| 243 | +```json | |
| 244 | +{ | |
| 245 | + "max_error": 0, | |
| 246 | + "max_warning": 0, | |
| 247 | + "max_note": null, | |
| 248 | + "max_smells": 0, | |
| 249 | + "max_file_complexity": 60, | |
| 250 | + "max_total_complexity": null | |
| 251 | +} | |
| 252 | +``` | |
| 253 | + | |
| 254 | +`null` disables a check. `max_file_complexity` flags individual files whose `complex` | |
| 255 | +metric exceeds the limit, which is the most useful knob for a codebase with existing | |
| 256 | +debt: it lets you hold the line on the worst files without demanding a perfect score | |
| 257 | +everywhere at once. | |
| 258 | + | |
| 259 | +## Reference | |
| 260 | + | |
| 261 | +- `qlty check --help`, `qlty smells --help`, `qlty metrics --help` for the full flag set. | |
| 262 | +- Note `qlty check` has **no** `--json`; machine-readable output is `--sarif`. | |
| 263 | +- Pass `--no-upgrade-check` to every qlty command — the sandbox blocks its update host. | |
| 264 | +- Reports and history under `.quality/` are meant to be committed so progression | |
| 265 | + survives sandbox recreation. Add `.quality/` to `.gitignore` if the user prefers them | |
| 266 | + to stay local. | |
| new file mode 100644 | |||
| @@ -0,0 +1,266 @@ | |||
| 1 | +--- | ||
| 2 | +name: quality | ||
| 3 | +description: Audit and improve this project's code quality with qlty. Sets qlty up on first use, measures lint issues / code smells / complexity, writes a timestamped Markdown report under .quality/, tracks progression across runs, and refactors until the quality gate passes. Use when asked to check code quality, run a quality report, review technical debt, see whether quality is improving, or clean up / refactor the codebase. | ||
| 4 | +--- | ||
| 5 | + | ||
| 6 | +# Quality | ||
| 7 | + | ||
| 8 | +Measure this project's code quality with [qlty](https://docs.qlty.sh), report it, and | ||
| 9 | +refactor until the gate passes. | ||
| 10 | + | ||
| 11 | +The measurement is a script, not a judgement call — run it, then act on what it says. | ||
| 12 | +It is read-only with respect to the source tree (`qlty check` runs with `--no-fix`), so | ||
| 13 | +measuring never quietly rewrites the code you are about to reason about. | ||
| 14 | + | ||
| 15 | +## 1. Set up (only if needed) | ||
| 16 | + | ||
| 17 | +The setup is self-healing; just run the script. It verifies `qlty` is on `PATH`, that | ||
| 18 | +the workspace is a git repository, and runs `qlty init --yes` when there is no | ||
| 19 | +`.qlty/qlty.toml` yet. | ||
| 20 | + | ||
| 21 | +If `qlty` is missing entirely, the sandbox was not created with the `dev-toolkit` | ||
| 22 | +kit. Say so and stop — do not install qlty by hand. | ||
| 23 | + | ||
| 24 | +**If the project vendors this kit** — a `kits/` directory holding the sources that get | ||
| 25 | +installed into `~/.claude/` — add it to `exclude_patterns` in `.qlty/qlty.toml` on the | ||
| 26 | +first run: | ||
| 27 | + | ||
| 28 | +```toml | ||
| 29 | +exclude_patterns = [ | ||
| 30 | + # … the defaults qlty init wrote … | ||
| 31 | + "kits/**", # the kit's own sources, including this skill's quality_report.py | ||
| 32 | +] | ||
| 33 | +``` | ||
| 34 | + | ||
| 35 | +This is **not** an exception to "do not game the gate" below. The reason is narrower and | ||
| 36 | +holds regardless of what the numbers say: `quality_report.py` is the script that | ||
| 37 | +*produces* the measurement, so leaving it in scope means measuring the instrument with | ||
| 38 | +itself. Two of its findings are structurally unfixable — a script whose job is to run | ||
| 39 | +`qlty` must import and call `subprocess`, which every Python security linter flags. | ||
| 40 | + | ||
| 41 | +Two conditions make this legitimate rather than convenient, and both must hold: | ||
| 42 | + | ||
| 43 | +- **It is the project's decision, not yours.** Say what the exclusion hides and why, and | ||
| 44 | + let the user choose. Adding it unilaterally is the forbidden move. | ||
| 45 | +- **Write down what it hides.** Put the actual findings in a comment next to the pattern. | ||
| 46 | + Some of them are usually real defects in the script — over-complex functions, unused | ||
| 47 | + imports — and they should be fixed at the kit's source rather than forgotten. An | ||
| 48 | + exclusion that records what it silences stays honest; one that just makes a number | ||
| 49 | + drop is the start of the drift. | ||
| 50 | + | ||
| 51 | +## 2. Measure | ||
| 52 | + | ||
| 53 | +From the project root: | ||
| 54 | + | ||
| 55 | +```bash | ||
| 56 | +python3 ~/.claude/skills/quality/scripts/quality_report.py --workspace . | ||
| 57 | +``` | ||
| 58 | + | ||
| 59 | +On a cold cache the first run takes several minutes: qlty downloads its plugin | ||
| 60 | +definitions and the linter binaries. Subsequent runs are fast (the cache lives on a | ||
| 61 | +persistent volume at `~/.qlty`). | ||
| 62 | + | ||
| 63 | +The script: | ||
| 64 | + | ||
| 65 | +- runs `qlty check --all`, `qlty smells --all`, and `qlty metrics --all` | ||
| 66 | +- writes `.quality/report-<timestamp>.md` and `.quality/report-latest.md` | ||
| 67 | +- appends one JSON line to `.quality/history.jsonl` | ||
| 68 | +- prints the report to stdout | ||
| 69 | +- **exits `0` if the gate passed, `1` if it failed, `2` on a tooling error** | ||
| 70 | + | ||
| 71 | +Use the exit code as the loop condition. Do not re-derive the verdict yourself. | ||
| 72 | + | ||
| 73 | +## 3. Read the report | ||
| 74 | + | ||
| 75 | +The report contains: | ||
| 76 | + | ||
| 77 | +| Section | What to do with it | | ||
| 78 | +| --- | --- | | ||
| 79 | +| **Gate violations** | The work list. Each line is a threshold that was breached. | | ||
| 80 | +| **Lint issues** by level, top rules, most affected files | Where to start — but read the count correctly first, see below. | | ||
| 81 | +| **Code smells** | Duplication and over-complex structure — these need real refactoring, not a formatter. | | ||
| 82 | +| **Metrics** | `complex` / `cyclo` per file; the "Most complex files" table names refactoring targets. | | ||
| 83 | +| **Trend** | Last 10 runs. This is how you show progression. | | ||
| 84 | +| **Tooling notes** | Present only when a qlty invocation failed — investigate before trusting the numbers. | | ||
| 85 | + | ||
| 86 | +### Read the count before you trust it | ||
| 87 | + | ||
| 88 | +"Fix the highest-count rule first" is the right instinct and the wrong first step. A | ||
| 89 | +count is `occurrences`, not `distinct problems`, and the two diverge badly in two common | ||
| 90 | +cases: | ||
| 91 | + | ||
| 92 | +- **One finding, repeated per manifest.** `osv-scanner` reports a dependency CVE once per | ||
| 93 | + `go.mod` / `package.json` it appears in. A monorepo with a dozen manifests turns one | ||
| 94 | + vulnerable version into a hundred-plus findings, and adding a three-line example | ||
| 95 | + manifest multiplies the total without degrading anything. | ||
| 96 | +- **One finding, repeated per file.** A linter that fails to parse the language emits one | ||
| 97 | + finding per source file. That looks like the largest cluster in the report and is worth | ||
| 98 | + exactly nothing. | ||
| 99 | + | ||
| 100 | +And before treating a *delta* as a regression: **re-run.** A count that moves while the | ||
| 101 | +tree is untouched is measuring the tool, not the code. The usual cause is a linter | ||
| 102 | +answering from its own partially-populated cache — qlty invokes several with | ||
| 103 | +`--allow-parallel-runners`, and an invocation returning in a fraction of a second did | ||
| 104 | +not re-analyse anything. That failure mode **under-reports**: the low number is the | ||
| 105 | +wrong one, so it looks like an improvement. | ||
| 106 | + | ||
| 107 | +When you suspect it, clear that linter's cache and run its binary directly, several | ||
| 108 | +times, until the result is stable; `.qlty/out/invoke-*.yaml` records the exact command, | ||
| 109 | +environment and duration qlty used. Work from that figure, not from the report, and say | ||
| 110 | +in your report which number you trust and why. Remember too that **a gate threshold | ||
| 111 | +pinned to an unstable measurement will trip on its own** — give it margin, and write | ||
| 112 | +down that the margin is the tool's fault, so it gets removed rather than inherited. | ||
| 113 | + | ||
| 114 | +So before picking a target, check **how many distinct rules and how many distinct files** | ||
| 115 | +a count spans: | ||
| 116 | + | ||
| 117 | +```bash | ||
| 118 | +# qlty check has no --json; SARIF is the machine-readable form | ||
| 119 | +qlty check --all --no-fix --no-upgrade-check --sarif > /tmp/qlty.sarif | ||
| 120 | +``` | ||
| 121 | + | ||
| 122 | +Then group the results by `ruleId` and by file URI. A rule spanning many files with one | ||
| 123 | +occurrence each, or many rules spanning the same short file list, means the count is | ||
| 124 | +telling you about the *shape of the scan*, not the state of the code. Say so in your | ||
| 125 | +report — a total nobody can interpret gets ignored, and then a real regression hides in | ||
| 126 | +it. | ||
| 127 | + | ||
| 128 | +## 4. Refactor until the gate passes | ||
| 129 | + | ||
| 130 | +If the gate failed, refactor. Loop: | ||
| 131 | + | ||
| 132 | +1. Pick the largest cluster of violations from the report (one rule, or one file). | ||
| 133 | +2. Fix formatting mechanically first — `qlty fmt` handles it, and it clears a lot of | ||
| 134 | + noise cheaply: | ||
| 135 | + ```bash | ||
| 136 | + qlty fmt --all --no-upgrade-check | ||
| 137 | + ``` | ||
| 138 | +3. Fix the remaining issues by editing the code. For smells, prefer extracting a | ||
| 139 | + function or collapsing a duplicated block over suppressing the finding. | ||
| 140 | +4. Verify nothing broke, using **this project's own** build and test commands. The | ||
| 141 | + repository's tooling is the authority on what those are — check for a `Makefile`, | ||
| 142 | + `Taskfile.yml`, `package.json` scripts, `pyproject.toml`, or the CI workflow before | ||
| 143 | + assuming. Common cases: | ||
| 144 | + | ||
| 145 | + | Stack | Verification | | ||
| 146 | + | --- | --- | | ||
| 147 | + | Go | `go build ./... && go test ./...` | | ||
| 148 | + | Go targeting WebAssembly | also `tinygo build -target=wasip1 ./...` — TinyGo rejects some constructs the standard toolchain accepts, so a passing `go build` is not sufficient | | ||
| 149 | + | Node / TypeScript | `npm test` (or the script the project defines), plus `tsc --noEmit` if the project is typed | | ||
| 150 | + | Python | `pytest` | | ||
| 151 | + | Rust | `cargo build && cargo test && cargo clippy -- -D warnings` | | ||
| 152 | + | Rust targeting WebAssembly | also `cargo build --target wasm32-wasip2` — and note the asymmetry below | | ||
| 153 | + | VS Code extension | the compile script, then `vsce package` — packaging validates the manifest, which `tsc` does not | | ||
| 154 | + | Zed extension | `cargo build --release --target wasm32-wasip2` | | ||
| 155 | + | ||
| 156 | + If the project has no tests, say so in the report rather than letting a green build | ||
| 157 | + stand in as proof the refactoring was safe. | ||
| 158 | + | ||
| 159 | + **Two traps specific to WebAssembly targets.** Both let a refactoring look verified | ||
| 160 | + when it is not: | ||
| 161 | + | ||
| 162 | + - A **wasm build passing does not mean the tests ran.** `cargo build --target | ||
| 163 | + wasm32-wasip2` links with rustc's own bundled `rust-lld`, so it succeeds even | ||
| 164 | + with no C toolchain present, while `cargo test` — which builds for the *host* — | ||
| 165 | + fails at link time with ``error: linker `cc` not found``. If you see that error, | ||
| 166 | + the tests did not run; do not report the wasm build as verification. | ||
| 167 | + - An **extension cannot be exercised here.** No editor runs in this sandbox, so | ||
| 168 | + neither VS Code's Extension Development Host nor Zed's *Install Dev Extension* | ||
| 169 | + is available, and `@vscode/test-electron` needs an X server this kit does not | ||
| 170 | + install. Compile, unit-test and package — then say plainly that the integration | ||
| 171 | + path is untested rather than implying it passed. | ||
| 172 | +5. Re-run the measurement from step 2 and compare against the previous run. | ||
| 173 | + | ||
| 174 | +Stop when any of these is true: | ||
| 175 | + | ||
| 176 | +- **The gate passes.** Report the before/after numbers from the Trend table. | ||
| 177 | +- **Five iterations have run.** Stop and report honestly: what improved, what remains, | ||
| 178 | + and why the rest is hard. | ||
| 179 | +- **Two consecutive runs show no improvement.** You are stuck — stop and explain what | ||
| 180 | + the blocker is rather than churning the code. | ||
| 181 | + | ||
| 182 | +Commit as you go, one focused commit per cluster of fixes, so the progression is | ||
| 183 | +visible in git as well as in `.quality/history.jsonl`. | ||
| 184 | + | ||
| 185 | +## Do not game the gate | ||
| 186 | + | ||
| 187 | +The gate is only worth something if it is measuring the code. All of the following make | ||
| 188 | +the number go down while making the project worse — never do them, even if the gate is | ||
| 189 | +the only thing standing between you and "done": | ||
| 190 | + | ||
| 191 | +- Adding `exclude_patterns`, disabling a plugin, setting a plugin to `mode = "monitor"`, | ||
| 192 | + or raising a threshold in `.qlty/qlty.toml`. | ||
| 193 | +- Loosening `.quality/gate.json`. | ||
| 194 | +- Deleting, skipping, or emptying tests. | ||
| 195 | +- Adding blanket lint suppressions (`//nolint`, `// qlty-ignore`) to silence a finding | ||
| 196 | + you could fix. | ||
| 197 | + | ||
| 198 | +A narrowly-scoped suppression with a comment explaining why the finding is a false | ||
| 199 | +positive is legitimate. If you believe a threshold is genuinely wrong for this project, | ||
| 200 | +say so and let the user decide — do not change it yourself. | ||
| 201 | + | ||
| 202 | +### The one plugin you may remove: a broken one | ||
| 203 | + | ||
| 204 | +"Disabling a plugin" above means a plugin that *finds things you would rather not fix*. A | ||
| 205 | +plugin that **analyses nothing** is a different object, and keeping it is not rigour: its | ||
| 206 | +findings crowd out the ones that matter and make the total unreadable. | ||
| 207 | + | ||
| 208 | +The two are indistinguishable from the report alone, so removal requires a **reproducible | ||
| 209 | +diagnosis**, never an impression. Establish all four of these before touching the config: | ||
| 210 | + | ||
| 211 | +1. **It is not the language version or a specific construct.** Put a trivially small, | ||
| 212 | + unambiguously valid file of that language in a *fresh* git repository, enable only | ||
| 213 | + that plugin, and run it. If a five-line hello-world fails, no source construct is to | ||
| 214 | + blame. | ||
| 215 | +2. **It is not this project.** Same point — the probe repository shares nothing with the | ||
| 216 | + codebase under measurement. | ||
| 217 | +3. **It is not the environment qlty gives plugins.** qlty runs plugins with a stripped | ||
| 218 | + environment (empty `PATH` and `HOME`). Run the plugin's own binary directly, with your | ||
| 219 | + full environment, on the same probe file. Read the invocation qlty used from | ||
| 220 | + `.qlty/out/invoke-*.yaml`, which records the exact `script`, `env` and `stderr`. | ||
| 221 | +4. **It is not the plugin family.** If sibling plugins sharing the same runtime produce | ||
| 222 | + real findings, the failure is specific rather than environmental. | ||
| 223 | + | ||
| 224 | +If all four hold, remove the plugin — and **write the diagnosis as a comment where you | ||
| 225 | +removed it**, so the next session finds the evidence instead of re-adding it on instinct. | ||
| 226 | +Note in your report which other tooling still covers that ground; if nothing does, the | ||
| 227 | +answer is to replace the plugin, not merely to drop it. | ||
| 228 | + | ||
| 229 | +`mode = "monitor"` is *not* the remedy here. It does not stop a plugin's findings from | ||
| 230 | +counting; it only changes how they are surfaced. A broken plugin left in monitor mode | ||
| 231 | +keeps polluting the total, which is how one ends up unnoticed for months. | ||
| 232 | + | ||
| 233 | +**Do not encode "plugin X is broken" into this skill.** Such a failure belongs to one | ||
| 234 | +version, one platform and one moment; a list of known-bad plugins ages badly and, worse, | ||
| 235 | +tempts the next agent to skip the diagnosis. The method above is what belongs here — its | ||
| 236 | +results belong in the project's own config and notes. | ||
| 237 | + | ||
| 238 | +## Tuning the gate | ||
| 239 | + | ||
| 240 | +Defaults are strict: zero error-level issues, zero warning-level issues, zero smells. | ||
| 241 | +Override any subset by writing `.quality/gate.json`: | ||
| 242 | + | ||
| 243 | +```json | ||
| 244 | +{ | ||
| 245 | + "max_error": 0, | ||
| 246 | + "max_warning": 0, | ||
| 247 | + "max_note": null, | ||
| 248 | + "max_smells": 0, | ||
| 249 | + "max_file_complexity": 60, | ||
| 250 | + "max_total_complexity": null | ||
| 251 | +} | ||
| 252 | +``` | ||
| 253 | + | ||
| 254 | +`null` disables a check. `max_file_complexity` flags individual files whose `complex` | ||
| 255 | +metric exceeds the limit, which is the most useful knob for a codebase with existing | ||
| 256 | +debt: it lets you hold the line on the worst files without demanding a perfect score | ||
| 257 | +everywhere at once. | ||
| 258 | + | ||
| 259 | +## Reference | ||
| 260 | + | ||
| 261 | +- `qlty check --help`, `qlty smells --help`, `qlty metrics --help` for the full flag set. | ||
| 262 | +- Note `qlty check` has **no** `--json`; machine-readable output is `--sarif`. | ||
| 263 | +- Pass `--no-upgrade-check` to every qlty command — the sandbox blocks its update host. | ||
| 264 | +- Reports and history under `.quality/` are meant to be committed so progression | ||
| 265 | + survives sandbox recreation. Add `.quality/` to `.gitignore` if the user prefers them | ||
| 266 | + to stay local. | ||
added
.vibe/skills/quality/scripts/quality_report.py +463 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
agent.dmr.yaml +4 -0 | @@ -27,6 +27,10 @@ bashTool: true | ||
| 27 | 27 | # The built-in file tools: read_file, write_file, edit_file. |
| 28 | 28 | editTools: true |
| 29 | 29 | |
| 30 | +# The built-in plan tool for managing multi-step plans. | |
| 31 | +# Set to false to disable plan creation and tracking via the `plan` tool. | |
| 32 | +planTool: true | |
| 33 | + | |
| 30 | 34 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). |
| 31 | 35 | # The file extension picks the server. A server missing from the PATH is skipped with a warning. |
| 32 | 36 | # No server listed = no `lsp` tool. Examples (uncomment what you have installed): |
| @@ -27,6 +27,10 @@ bashTool: true | |||
| 27 | # The built-in file tools: read_file, write_file, edit_file. | 27 | # The built-in file tools: read_file, write_file, edit_file. |
| 28 | editTools: true | 28 | editTools: true |
| 29 | 29 | ||
| 30 | +# The built-in plan tool for managing multi-step plans. | ||
| 31 | +# Set to false to disable plan creation and tracking via the `plan` tool. | ||
| 32 | +planTool: true | ||
| 33 | + | ||
| 30 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). | 34 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). |
| 31 | # The file extension picks the server. A server missing from the PATH is skipped with a warning. | 35 | # The file extension picks the server. A server missing from the PATH is skipped with a warning. |
| 32 | # No server listed = no `lsp` tool. Examples (uncomment what you have installed): | 36 | # No server listed = no `lsp` tool. Examples (uncomment what you have installed): |
modified
agent.llamacpp.yaml +4 -0 | @@ -23,6 +23,10 @@ bashTool: true | ||
| 23 | 23 | # The built-in file tools: read_file, write_file, edit_file. |
| 24 | 24 | editTools: true |
| 25 | 25 | |
| 26 | +# The built-in plan tool for managing multi-step plans. | |
| 27 | +# Set to false to disable plan creation and tracking via the `plan` tool. | |
| 28 | +planTool: true | |
| 29 | + | |
| 26 | 30 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). |
| 27 | 31 | # The file extension picks the server. A server missing from the PATH is skipped with a warning. |
| 28 | 32 | # No server listed = no `lsp` tool. Examples (uncomment what you have installed): |
| @@ -23,6 +23,10 @@ bashTool: true | |||
| 23 | # The built-in file tools: read_file, write_file, edit_file. | 23 | # The built-in file tools: read_file, write_file, edit_file. |
| 24 | editTools: true | 24 | editTools: true |
| 25 | 25 | ||
| 26 | +# The built-in plan tool for managing multi-step plans. | ||
| 27 | +# Set to false to disable plan creation and tracking via the `plan` tool. | ||
| 28 | +planTool: true | ||
| 29 | + | ||
| 26 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). | 30 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). |
| 27 | # The file extension picks the server. A server missing from the PATH is skipped with a warning. | 31 | # The file extension picks the server. A server missing from the PATH is skipped with a warning. |
| 28 | # No server listed = no `lsp` tool. Examples (uncomment what you have installed): | 32 | # No server listed = no `lsp` tool. Examples (uncomment what you have installed): |
modified
agent.lsp.yaml +4 -0 | @@ -34,6 +34,10 @@ bashTool: true | ||
| 34 | 34 | # The built-in file tools: read_file, write_file, edit_file. |
| 35 | 35 | editTools: true |
| 36 | 36 | |
| 37 | +# The built-in plan tool for managing multi-step plans. | |
| 38 | +# Set to false to disable plan creation and tracking via the `plan` tool. | |
| 39 | +planTool: true | |
| 40 | + | |
| 37 | 41 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). |
| 38 | 42 | # The file extension picks the server. A server missing from the PATH is skipped with a warning at start-up; |
| 39 | 43 | # with no server on the PATH the tool is not declared. Install what you use, uncomment its entry. |
| @@ -34,6 +34,10 @@ bashTool: true | |||
| 34 | # The built-in file tools: read_file, write_file, edit_file. | 34 | # The built-in file tools: read_file, write_file, edit_file. |
| 35 | editTools: true | 35 | editTools: true |
| 36 | 36 | ||
| 37 | +# The built-in plan tool for managing multi-step plans. | ||
| 38 | +# Set to false to disable plan creation and tracking via the `plan` tool. | ||
| 39 | +planTool: true | ||
| 40 | + | ||
| 37 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). | 41 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). |
| 38 | # The file extension picks the server. A server missing from the PATH is skipped with a warning at start-up; | 42 | # The file extension picks the server. A server missing from the PATH is skipped with a warning at start-up; |
| 39 | # with no server on the PATH the tool is not declared. Install what you use, uncomment its entry. | 43 | # with no server on the PATH the tool is not declared. Install what you use, uncomment its entry. |
added
demo/README.md +9 -0 | new file mode 100644 | ||
| @@ -0,0 +1,9 @@ | ||
| 1 | +# Mini Me Project | |
| 2 | + | |
| 3 | +## What is Mini Me? | |
| 4 | + | |
| 5 | +[Insert a detailed explanation of what Mini Me is here.] | |
| 6 | + | |
| 7 | +## License | |
| 8 | + | |
| 9 | +This project is licensed under the WTF License. | |
| new file mode 100644 | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | +# Mini Me Project | ||
| 2 | + | ||
| 3 | +## What is Mini Me? | ||
| 4 | + | ||
| 5 | +[Insert a detailed explanation of what Mini Me is here.] | ||
| 6 | + | ||
| 7 | +## License | ||
| 8 | + | ||
| 9 | +This project is licensed under the WTF License. | ||
modified
demo/agent.dmr.2.yaml +4 -0 | @@ -29,6 +29,10 @@ bashTool: true | ||
| 29 | 29 | # The built-in file tools: read_file, write_file, edit_file. |
| 30 | 30 | editTools: true |
| 31 | 31 | |
| 32 | +# The built-in plan tool for managing multi-step plans. | |
| 33 | +# Set to false to disable plan creation and tracking via the `plan` tool. | |
| 34 | +planTool: true | |
| 35 | + | |
| 32 | 36 | lsp: |
| 33 | 37 | servers: |
| 34 | 38 | - name: gopls # go install golang.org/x/tools/gopls@latest |
| @@ -29,6 +29,10 @@ bashTool: true | |||
| 29 | # The built-in file tools: read_file, write_file, edit_file. | 29 | # The built-in file tools: read_file, write_file, edit_file. |
| 30 | editTools: true | 30 | editTools: true |
| 31 | 31 | ||
| 32 | +# The built-in plan tool for managing multi-step plans. | ||
| 33 | +# Set to false to disable plan creation and tracking via the `plan` tool. | ||
| 34 | +planTool: true | ||
| 35 | + | ||
| 32 | lsp: | 36 | lsp: |
| 33 | servers: | 37 | servers: |
| 34 | - name: gopls # go install golang.org/x/tools/gopls@latest | 38 | - name: gopls # go install golang.org/x/tools/gopls@latest |
modified
demo/agent.dmr.yaml +4 -0 | @@ -29,6 +29,10 @@ bashTool: true | ||
| 29 | 29 | # The built-in file tools: read_file, write_file, edit_file. |
| 30 | 30 | editTools: true |
| 31 | 31 | |
| 32 | +# The built-in plan tool for managing multi-step plans. | |
| 33 | +# Set to false to disable plan creation and tracking via the `plan` tool. | |
| 34 | +planTool: true | |
| 35 | + | |
| 32 | 36 | lsp: |
| 33 | 37 | servers: |
| 34 | 38 | - name: gopls # go install golang.org/x/tools/gopls@latest |
| @@ -29,6 +29,10 @@ bashTool: true | |||
| 29 | # The built-in file tools: read_file, write_file, edit_file. | 29 | # The built-in file tools: read_file, write_file, edit_file. |
| 30 | editTools: true | 30 | editTools: true |
| 31 | 31 | ||
| 32 | +# The built-in plan tool for managing multi-step plans. | ||
| 33 | +# Set to false to disable plan creation and tracking via the `plan` tool. | ||
| 34 | +planTool: true | ||
| 35 | + | ||
| 32 | lsp: | 36 | lsp: |
| 33 | servers: | 37 | servers: |
| 34 | - name: gopls # go install golang.org/x/tools/gopls@latest | 38 | - name: gopls # go install golang.org/x/tools/gopls@latest |
modified
demo/agent.lsp.yaml +4 -0 | @@ -39,6 +39,10 @@ bashTool: true | ||
| 39 | 39 | # The built-in file tools: read_file, write_file, edit_file. |
| 40 | 40 | editTools: true |
| 41 | 41 | |
| 42 | +# The built-in plan tool for managing multi-step plans. | |
| 43 | +# Set to false to disable plan creation and tracking via the `plan` tool. | |
| 44 | +planTool: true | |
| 45 | + | |
| 42 | 46 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). |
| 43 | 47 | # The file extension picks the server. A server missing from the PATH is skipped with a warning at start-up; |
| 44 | 48 | # with no server on the PATH the tool is not declared. Install what you use, uncomment its entry. |
| @@ -39,6 +39,10 @@ bashTool: true | |||
| 39 | # The built-in file tools: read_file, write_file, edit_file. | 39 | # The built-in file tools: read_file, write_file, edit_file. |
| 40 | editTools: true | 40 | editTools: true |
| 41 | 41 | ||
| 42 | +# The built-in plan tool for managing multi-step plans. | ||
| 43 | +# Set to false to disable plan creation and tracking via the `plan` tool. | ||
| 44 | +planTool: true | ||
| 45 | + | ||
| 42 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). | 46 | # Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename). |
| 43 | # The file extension picks the server. A server missing from the PATH is skipped with a warning at start-up; | 47 | # The file extension picks the server. A server missing from the PATH is skipped with a warning at start-up; |
| 44 | # with no server on the PATH the tool is not declared. Install what you use, uncomment its entry. | 48 | # with no server on the PATH the tool is not declared. Install what you use, uncomment its entry. |
added
docs/en/how-to/manage-plans-and-tasks.md +440 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
docs/fr/how-to/manage-plans-and-tasks.md +440 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
internal/agent/agent.go +3 -0 | @@ -21,6 +21,7 @@ import ( | ||
| 21 | 21 | "mm/internal/skills" |
| 22 | 22 | "mm/internal/spinner" |
| 23 | 23 | "mm/internal/store" |
| 24 | + "mm/internal/tools" | |
| 24 | 25 | |
| 25 | 26 | "github.com/firebase/genkit/go/ai" |
| 26 | 27 | ) |
| @@ -443,6 +444,8 @@ func startNewSession(e *engine.Engine, d *detector.LoopDetector, system string, | ||
| 443 | 444 | forgotten := session.Forgotten(old) |
| 444 | 445 | e.ForgetInputTokens() |
| 445 | 446 | d.Reset() |
| 447 | + // Clear any active plans when starting a new session | |
| 448 | + tools.ClearAllPlans() | |
| 446 | 449 | dimln(fmt.Sprintf("🆕 new session: %d message(s) forgotten", forgotten)) |
| 447 | 450 | return session.Fresh(system) |
| 448 | 451 | } |
| @@ -21,6 +21,7 @@ import ( | |||
| 21 | "mm/internal/skills" | 21 | "mm/internal/skills" |
| 22 | "mm/internal/spinner" | 22 | "mm/internal/spinner" |
| 23 | "mm/internal/store" | 23 | "mm/internal/store" |
| 24 | + "mm/internal/tools" | ||
| 24 | 25 | ||
| 25 | "github.com/firebase/genkit/go/ai" | 26 | "github.com/firebase/genkit/go/ai" |
| 26 | ) | 27 | ) |
| @@ -443,6 +444,8 @@ func startNewSession(e *engine.Engine, d *detector.LoopDetector, system string, | |||
| 443 | forgotten := session.Forgotten(old) | 444 | forgotten := session.Forgotten(old) |
| 444 | e.ForgetInputTokens() | 445 | e.ForgetInputTokens() |
| 445 | d.Reset() | 446 | d.Reset() |
| 447 | + // Clear any active plans when starting a new session | ||
| 448 | + tools.ClearAllPlans() | ||
| 446 | dimln(fmt.Sprintf("🆕 new session: %d message(s) forgotten", forgotten)) | 449 | dimln(fmt.Sprintf("🆕 new session: %d message(s) forgotten", forgotten)) |
| 447 | return session.Fresh(system) | 450 | return session.Fresh(system) |
| 448 | } | 451 | } |
modified
internal/config/config.go +5 -0 | @@ -96,6 +96,10 @@ type Config struct { | ||
| 96 | 96 | // One binary, two set-ups: that is what lets the two be compared. |
| 97 | 97 | EditTools bool `yaml:"editTools"` |
| 98 | 98 | |
| 99 | + // PlanTool: declare the built-in plan tool for managing multi-step plans. | |
| 100 | + // On by default. Off to disable plan creation and tracking via the `plan` tool. | |
| 101 | + PlanTool bool `yaml:"planTool"` | |
| 102 | + | |
| 99 | 103 | // Sampling: generation settings (OpenAI API keys; the plugin converts them.) |
| 100 | 104 | Sampling map[string]any `yaml:"sampling"` |
| 101 | 105 | |
| @@ -251,6 +255,7 @@ var Cfg = Config{ | ||
| 251 | 255 | SkillsDir: "skills", |
| 252 | 256 | BashTool: true, |
| 253 | 257 | EditTools: true, |
| 258 | + PlanTool: true, | |
| 254 | 259 | System: `You are a coding agent working in a terminal. |
| 255 | 260 | You have a "bash" tool to run shell commands. |
| 256 | 261 | Use it to explore files, run tests, inspect the repository, etc. |
| @@ -96,6 +96,10 @@ type Config struct { | |||
| 96 | // One binary, two set-ups: that is what lets the two be compared. | 96 | // One binary, two set-ups: that is what lets the two be compared. |
| 97 | EditTools bool `yaml:"editTools"` | 97 | EditTools bool `yaml:"editTools"` |
| 98 | 98 | ||
| 99 | + // PlanTool: declare the built-in plan tool for managing multi-step plans. | ||
| 100 | + // On by default. Off to disable plan creation and tracking via the `plan` tool. | ||
| 101 | + PlanTool bool `yaml:"planTool"` | ||
| 102 | + | ||
| 99 | // Sampling: generation settings (OpenAI API keys; the plugin converts them.) | 103 | // Sampling: generation settings (OpenAI API keys; the plugin converts them.) |
| 100 | Sampling map[string]any `yaml:"sampling"` | 104 | Sampling map[string]any `yaml:"sampling"` |
| 101 | 105 | ||
| @@ -251,6 +255,7 @@ var Cfg = Config{ | |||
| 251 | SkillsDir: "skills", | 255 | SkillsDir: "skills", |
| 252 | BashTool: true, | 256 | BashTool: true, |
| 253 | EditTools: true, | 257 | EditTools: true, |
| 258 | + PlanTool: true, | ||
| 254 | System: `You are a coding agent working in a terminal. | 259 | System: `You are a coding agent working in a terminal. |
| 255 | You have a "bash" tool to run shell commands. | 260 | You have a "bash" tool to run shell commands. |
| 256 | Use it to explore files, run tests, inspect the repository, etc. | 261 | Use it to explore files, run tests, inspect the repository, etc. |
added
internal/tools/plan.go +694 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
internal/tools/plan_test.go +542 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
main.go +4 -0 | @@ -233,6 +233,10 @@ func assembleTools(e *engine.Engine, d *detector.LoopDetector) toolSet { | ||
| 233 | 233 | tools.EditFile(e.G, d)) |
| 234 | 234 | set.names = append(set.names, "read_file", "write_file", "edit_file") |
| 235 | 235 | } |
| 236 | + if config.Cfg.PlanTool { | |
| 237 | + set.tools = append(set.tools, tools.PlanTool(e.G, d)) | |
| 238 | + set.names = append(set.names, "plan") | |
| 239 | + } | |
| 236 | 240 | assembleLSP(e, d, &set) |
| 237 | 241 | return set |
| 238 | 242 | } |
| @@ -233,6 +233,10 @@ func assembleTools(e *engine.Engine, d *detector.LoopDetector) toolSet { | |||
| 233 | tools.EditFile(e.G, d)) | 233 | tools.EditFile(e.G, d)) |
| 234 | set.names = append(set.names, "read_file", "write_file", "edit_file") | 234 | set.names = append(set.names, "read_file", "write_file", "edit_file") |
| 235 | } | 235 | } |
| 236 | + if config.Cfg.PlanTool { | ||
| 237 | + set.tools = append(set.tools, tools.PlanTool(e.G, d)) | ||
| 238 | + set.names = append(set.names, "plan") | ||
| 239 | + } | ||
| 236 | assembleLSP(e, d, &set) | 240 | assembleLSP(e, d, &set) |
| 237 | return set | 241 | return set |
| 238 | } | 242 | } |
added
skills/plan-manager/SKILL.md +472 -0 Large diff collapsed to keep the page fast — load it when you need it.