Skip to content
Back to skills

Dogfood

ASecurity

Use when starting a dogfood session for the vitest-agent plugin in this repo, when continuing one from an existing handoff at docs/superpowers/dogfood/<chain>/, or after the TDD orchestrator subagent completes a dogfood task. Repo-internal — does not apply to projects that consume vitest-agent as a dependency.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
testingtypescriptgobashtestinggitdatabase

Works with

  • claude code
  • mcp

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned November 7, 2026

npx -y skills add spencerbeggs/vitest-agent --skill dogfood --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Dogfood?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Dogfood
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/spencerbeggs-dogfood/badge)](https://www.skillsdirectory.com/skills/spencerbeggs-dogfood)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: dogfood
description: Use when starting a dogfood session for the vitest-agent plugin in this repo, when continuing one from an existing handoff at docs/superpowers/dogfood/<chain>/, or after the TDD orchestrator subagent completes a dogfood task. Repo-internal — does not apply to projects that consume vitest-agent as a dependency.
argument-hint: [--start | --random | --lifecycle | --from <path>]
disable-model-invocation: true
allowed-tools: Read Write Edit Bash Glob Grep Task mcp__plugin_vitest-agent_mcp__*
---

# Dogfood

You are the **main agent** running a dogfood session in the vitest-agent repo. The TDD orchestrator subagent is the system under test. The `playground/` workspace is the live target; intentional defects there are the fodder. Your job is to dispatch the orchestrator, observe it, audit the result against the meta-goal, and leave a paper trail.

## Current dogfood state

Open chains and their latest entries:

!`find docs/superpowers/dogfood -mindepth 2 -name "0*.md" -not -path "*_baseline*" 2>/dev/null | sort | tail -20`

Open-status handoffs (anything you should pick up):

!`grep -l "^status: open" docs/superpowers/dogfood/*/*.md 2>/dev/null | grep -v _baseline || echo "(none)"`

## Iron law: the orchestrator does not know it is being tested

The orchestrator subagent receives the **task prompt only**. Never:

- Pass it the handoff file path or its `what_were_testing` frontmatter
- Add hints like "be thorough" or "watch for X" that telegraph the meta-goal
- Reference `.claude/playground-cheatsheet.md` (the answer key) in any orchestrator-visible artifact
- Ask the orchestrator to "report extra info" unless the handoff explicitly requested it

The cheatsheet at `.claude/playground-cheatsheet.md` is yours; do not surface its existence in any prompt or commit message visible to the orchestrator.

## Argument routing

Parse `$ARGUMENTS`:

- **No args** → show the current state above and the four-option menu. If there are open handoffs, suggest `/dogfood --from <path>` for the most recent.
- **`--start`** → new chain. See "Starting a chain" below.
- **`--random`** → pick a task from the cheatsheet and dispatch without user discussion. See "Random chain" below.
- **`--lifecycle`** → dispatch the tdd-task agent with a fixed lifecycle-simulation prompt. No handoff file. See "Lifecycle test" below.
- **`--from <path>`** → continue from a specific handoff after a reboot. See "Continuing from a handoff" below.

## Random chain (`--random`)

No user discussion. Pick, write, dispatch, verify.

1. Read `.claude/playground-cheatsheet.md`.
2. Pick one defect. Prefer 0%-function-coverage gaps (untested functions: `isPrime`, `isPalindrome`, `Cache.has`) — they produce the cleanest red-phase signal. Fall back to edge-case/behavior defects (`average([])`, `Cache.size()` TTL, `Notebook.averageWordCount()`) if all untested functions are already covered.
3. Derive a chain slug and title from the chosen defect (e.g. `is-prime-coverage`, `cache-has-coverage`, `average-empty-array`).
4. Write the handoff at `docs/superpowers/dogfood/<chain-slug>/01-<title-slug>.md` and `findings.md` using the same templates as `--start`. Set `what_were_testing` to one sentence describing the behavioral observation (e.g. "tdd-task writes a failing test, fixes the defect, and commits before closing the session").
5. Dispatch (see "Dispatching"). The sanitized orchestrator prompt must describe the gap as a natural task — no mention of the cheatsheet, no hints about what the meta-goal is. A plain framing like "The playground package has some untested code paths. Use TDD to add tests for the missing coverage and fix any defects the tests expose." is appropriate; you may be more specific about the targeted gap but never reveal the meta-goal or cheatsheet structure.
6. Capture the session id and run the seven-step verification (see "Verification") immediately after the tdd-task agent completes.
7. Present the four-option menu.

## Lifecycle test (`--lifecycle`)

No handoff file. Dispatches the tdd-task agent with a fixed prompt that walks the TDD session machinery end-to-end. The source file `playground/src/lifecycle.ts` has a deliberate off-by-one bug (`return a + b + 1`); the orchestrator writes a test that exposes it, fixes the source, and closes the session. After each run the main agent reverts `lifecycle.ts` to restore the defect.

### Dispatch

Complete the standard pre-dispatch setup above (`inventory({ kind: "session", agentKind: "main", limit: 1 })` → TaskCreate if available → initialize maps), then dispatch as a **plain background subagent** — `run_in_background: true`, `subagent_type: "vitest-agent:tdd-task"`, and **no `name`/team argument** (a named teammate spawns a detached session with its own conversation that splits artifact attribution and denies the phase gates). Prepend `chatId` and `parentTaskId` (if captured — it's optional) to the prompt, then append the verbatim block below without modification.

### Verbatim prompt (append after chatId/parentTaskId lines — do not add other framing)

````text
Run a TDD lifecycle simulation to exercise the session machinery from start to finish. This is not a real coding task — use dummy goal and behavior labels throughout. You will write a temporary test file and fix a deliberately broken source file.

Steps:
1. Call `tdd_task({ action: "start", chatId, goal: "lifecycle-test: verify session open, transitions, and close" })`. Capture the returned `tddTaskId` and `goalId`.
2. Create one behavior via `tdd_behavior({ action: "create", goalId, behavior: "lifecycle-test: tdd session opens, transitions red→green, and closes cleanly" })`. Capture the returned `behaviorId`.
3. Mark the goal and behavior in_progress: `tdd_goal({ action: "update", id: goalId, status: "in_progress" })` and `tdd_behavior({ action: "update", id: behaviorId, status: "in_progress" })`.
4. Write a new file `playground/src/lifecycle.test.ts` containing exactly:
   ```typescript
   import { describe, expect, it } from "vitest";
   import { sum } from "./lifecycle.js";
   describe("lifecycle", () => {
     it("sum(1, 1) returns 2", () => {
       expect(sum(1, 1)).toBe(2);
     });
   });
   ```

   Note: `playground/src/lifecycle.ts` already exists with a deliberate bug — do not create it. The test expectation (`toBe(2)`) is correct; the source implementation is what is broken.
5. Run the playground tests using the `run_tests` MCP tool with a file filter:
   `run_tests({ project: "playground", files: ["playground/src/lifecycle.test.ts"] })`
   Confirm the test fails (`sum(1, 1)` currently returns 3, not 2, due to the bug in the source).
6. Call `tdd_phase_transition_request` for the `red` phase, citing the test-run artifact from step 5. Record whether it was granted or denied and the exact DenialReason if denied.
6b. After the transition is accepted, call `tdd_progress_push` with the spike→red phase event: `tdd_progress_push({ payload: JSON.stringify({ type: "phase_transition", sessionId: <tddTaskId>, goalId: <goalId>, behaviorId: <behaviorId>, from: "spike", to: "red" }) })`. Do this before proceeding to step 7.
7. **Critical — re-author the test in the red phase:** delete `playground/src/lifecycle.test.ts` and immediately rewrite it with the same content as step 4. The red→green gate requires `test_case_authored_in_session = true`, meaning the `test_written` artifact must fall inside the red phase window. Writing the file in step 4 authors it in spike; deleting and rewriting here moves the authorship into red.
8. Run the playground tests again using `run_tests` with the same file filter:
   `run_tests({ project: "playground", files: ["playground/src/lifecycle.test.ts"] })`
   Confirm the test still fails (the source bug has not been fixed yet).
9. Fix the bug in `playground/src/lifecycle.ts`: change `return a + b + 1` to `return a + b`.
10. Run the playground tests again using `run_tests` with the same file filter:
    `run_tests({ project: "playground", files: ["playground/src/lifecycle.test.ts"] })`
    Confirm all tests pass.
11. Call `tdd_phase_transition_request` for the `green` phase, citing the `test_failed_run` artifact from step 8 (not the passing run from step 10 — `red→green` requires proof that the test was failing before the fix). Record the outcome.
12. Mark the behavior done: `tdd_behavior({ action: "update", id: behaviorId, status: "done" })`. Mark the goal done: `tdd_goal({ action: "update", id: goalId, status: "done" })`.
13. Call `tdd_task({ action: "end", tddTaskId: tddTaskId, outcome: "succeeded" })`.
14. Delete `playground/src/lifecycle.test.ts` to leave the playground clean. Do NOT delete or revert `playground/src/lifecycle.ts`.

Report: for each phase-transition call (steps 6 and 11), state whether it was granted or denied and (if denied) the exact DenialReason string.
````

### Lifecycle-specific verification (use instead of the standard seven-step audit)

Run these five checks after the background completion notification arrives.

1. **`tdd_task({ action: "get", id: <id> })`** — `ended` must be non-null (session closed). Phase ledger must have at least one entry. Goal and behavior must both show `done`.
2. **`acceptance_metrics({})`** — `phase_evidence_integrity` must be 100%. Any value below 100% means a phase transition was accepted without valid evidence binding.
3. **`inventory({ kind: "session", agentKind: "subagent", limit: 1 })`** — a subagent row must appear with a key in the format `<parent-cc-id>-subagent-<ts>-<pid>`. If absent, the SubagentStart hook did not fire or `is_tdd_agent` failed to match the agent_type CC sent.
4. **Restore the playground defect:** `git checkout playground/src/lifecycle.ts` — reverts `lifecycle.ts` to `return a + b + 1` so the next lifecycle run starts from a broken state. If the orchestrator committed the fix, also run `git reset HEAD~1` first (or `git revert HEAD` if the branch has been pushed).

If any check fails, append findings to `docs/superpowers/dogfood/lifecycle-check/findings.md` (create it if it doesn't exist) and present the four-option menu.

## Starting a chain (`--start`)

1. Look at the most recent conversation. What was the user discussing? What aspect of the system are they curious about (orchestrator behavior, channel events, hook denial, MCP tool surface)?
2. **Propose a chain in chat first; do not write any files.** Output a draft with: a chain slug (kebab-case), a `what_were_testing` line stating the system aspect under observation, and a sanitized orchestrator task prompt that describes a playground-level problem without revealing the meta-goal.
3. **Ask the user to confirm or edit.** If the recent conversation is ambiguous (e.g. they typed `/dogfood --start` cold), ask: "What aspect of the orchestrator or the dogfood system do you want to test?" and offer 2-3 candidates from the cheatsheet's intentional defects.
4. Once the user confirms, write the first handoff at `docs/superpowers/dogfood/<chain-slug>/01-<title-slug>.md` using the template at `${CLAUDE_SKILL_DIR}/handoff-template.md`. Write `findings.md` in the same folder using the template at `${CLAUDE_SKILL_DIR}/findings-template.md`.
5. Dispatch the orchestrator (see "Dispatching" below).

## Continuing from a handoff (`--from <path>`)

1. Read the handoff. Walk backward through `prev_handoff` to read the chain's full history before acting.
2. Read `findings.md` in the same folder.
3. Read `.claude/playground-cheatsheet.md` so you have the answer key for the verification phase.
4. Dispatch the orchestrator.

## Dispatching

Before spawning, complete the standard pre-dispatch setup (mirrors the `tdd` skill):

1. Call `inventory({ kind: "session", agentKind: "main", limit: 1 })` — capture the `chat_id` field from the first row as `chatId`. Do **not** assume an in-memory current-session ref — that can be stale after a prior subagent ran, and `inventory` reads the canonical row from the DB.
2. Generate a `runId`: `` `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}` ``.
3. The Task tools are usually not available, so you will usually skip this and proceed without a `parentTaskId`. When they are available, call `TaskCreate({ subject: "TDD Session: <objective>", description: "Behavior tasks will appear as the orchestrator decomposes the goal." })` and capture the returned task ID as `parentTaskId`.
4. Initialize: `goalById = new Map()`, `behaviorById = new Map()`.

Dispatch as a **plain background subagent** — **`run_in_background: true`**, `subagent_type: "vitest-agent:tdd-task"`, and **no `name`/team argument** (an unnamed subagent fires SubagentStart and links to this session so artifacts funnel to the `chatId` you pass; a named teammate detaches into its own conversation and splits attribution). Pass `chatId`, `runId`, and `parentTaskId` (if captured — it's optional) in the launch prompt alongside the task. The dispatch prompt body contains **only** the contents of the handoff's `# Task for the TDD orchestrator` section — never the frontmatter, never the `# What the orchestrator MUST NOT know` section, never the verification checklist, never the cheatsheet.

Immediately after dispatching (the background call returns before the agent completes), capture the session id:

```text
mcp__plugin_vitest-agent_mcp__inventory({ kind: "session", agentKind: "subagent", limit: 1 })
```

While the agent runs, channel events arrive as `<channel source="plugin:vitest-agent:mcp">` system reminders. Process each one immediately per the event-handler table in `plugin/skills/tdd/SKILL.md` — this produces live task-panel updates during the run, not a batch flush at the end.

The returned `id` is the numeric DB id you pass to `tdd_task({ action: "get", id: <id> })` (or `tdd_task({ action: "resume", id: <id> })` for a status summary) below. The `chat_id` on the same row is what you pass to session-aware tools like `turn_search`.

## Verification (after orchestrator completes)

Run the seven-step audit. Skipping any step defeats the experiment.

1. `tdd_task({ action: "get", id: <id> })` — full goal+behavior tree, phase ledger. Every transition has a cited artifact, no skipped phases, no backdated rows.
2. `acceptance_metrics({})` — phase-evidence integrity, hook responsiveness, anti-pattern detection rate.
3. `test_history({ project: "playground" })` — flaky / new-failure / persistent classifications.
4. `turn_search({ sessionId: <subagent numeric id>, type: "tool_call" })` and grep for Bash `vitest` invocations — confirm the orchestrator used `run_tests` MCP, not Bash workarounds.
5. `failure_signature_get` for any signatures the run produced — cross-check against past dogfood runs in the chain.
6. `git diff playground/` and `git status` — code change matches what the cheatsheet says is the right fix; no unintended files outside `playground/`; no untracked files left behind. `git log --oneline` and grep for `tdd(` — confirm the orchestrator's commits use the `tdd(<goalId>:<state>):` prefix format, not the legacy `[tdd:` bracket-tag format.
7. `hypothesis({ action: "list", sessionId: <subagent cc id> })` — the orchestrator recorded hypotheses before non-test edits (Gate 2).

For channel-event work, additionally inspect `tdd_progress_push` payloads in the turn log: `goalId` and `sessionId` resolved server-side correctly, `goal_completed` carried `behaviorIds[]`, `session_complete` carried `goalIds[]`.

## Findings + four-option menu

Append a new entry to `findings.md` covering: what worked, what broke, what was attempted, what's still open. Then present the user with four options. Pick the one that fits; do not invent a fifth.

| Option | When | Action |
| --- | --- | --- |
| **1. Local fix + retask** | Context fresh, change is .sh / skill / agent-md only | Revert `git checkout playground/`. Edit core. Rebuild the plugin (`pnpm --filter @vitest-agent/ai-plugins build:dev`). If MCP code: `pnpm ci:build`, bump `--noop=N` in `plugin/pluginfinity.config.ts` and rebuild the plugin, ask the user to `/reload-plugins`. Append `## System changes` to current handoff. Dispatch a fresh orchestrator on the same task. |
| **2. Reboot + new handoff** | Context heavy, OR the change requires a full CC restart (structural manifest changes), OR the next experiment needs a clean slate | Make the system change. Write the next handoff at `<chain>/NN-<title>.md` with `prev_handoff` set. Tell the user to restart and run `/dogfood --from <new path>`. |
| **3. Update tracking** | Findings are partial; we'll come back later | Update `findings.md` with the open question. Leave handoff `status: open`. Tell the user where the chain is and that nothing else is needed right now. |
| **4. Confirm complete** | The meta-goal is answered; system either works or the bug is documented | Flip latest handoff `status: closed`. Append a final summary to `findings.md`. Tell the user the chain is done and they can delete the folder when ready. |

## Reboot levels (canonical reference)

| Change | Action needed |
| --- | --- |
| `.sh` hook script body | `pluginfinity build` (plugin/), then takes effect on next call. |
| Skill / agent markdown | `pluginfinity build`, then takes effect on next subagent dispatch. |
| Plugin allowlist (`plugin/hooks/lib/vitest-agent/safe-mcp-ops.txt`) | `pluginfinity build`, then takes effect on next tool call. |
| MCP server / SDK code | `pnpm ci:build` + `/reload-plugins`. |
| Database schema / migration | `pnpm ci:build` + delete `$XDG_DATA_HOME/vitest-agent/<key>/data.db` + `/reload-plugins`. |
| Hook entries in `plugin/pluginfinity.config.ts` (new matcher, new hook entry) | `pluginfinity build` + `/reload-plugins` — hook registrations reload with the plugin. |
| MCP server `command` or `args` in `pluginfinity.config.ts` | `pluginfinity build` + `/reload-plugins` restarts that MCP server. Bump `--noop=N` to force a restart — see "Hot-patching the MCP" below. |
| All other manifest fields (new servers, metadata) | **Full Claude Code restart.** `/reload-plugins` is not enough. |

When in doubt, reboot. The cost of a wrong-positive reboot is low; the cost of a wrong-negative ("`/reload-plugins` probably picks it up") is observing broken behavior on a shrinking context.

## Hot-patching the MCP during a dogfood session

When MCP server or SDK code changes mid-session and a full CC restart would destroy context, use this pattern to reload the MCP server in place:

1. Build: `pnpm ci:build`
2. Bump `--noop=N` in `plugin/pluginfinity.config.ts` (increment by 1 each time), then rebuild with `pnpm --filter @vitest-agent/ai-plugins build:dev`:

   ```ts
   mcpServers: {
     mcp: { command: "sh", args: ["${PLUGIN_ROOT}/bin/start-mcp.sh", "--noop=2"] },
   },
   ```

3. Ask the user to run `/reload-plugins`.
4. Confirm the MCP restarted by checking that PIDs changed: `ps aux | grep -E "start-mcp|vitest-agent-mcp" | grep -v grep`

The `--noop` arg is forwarded to the MCP binary, which ignores it. Changing `args` is the trigger — `/reload-plugins` restarts the MCP server whenever `command` or `args` differs from the currently-running value.

**Do not commit the bumped `--noop` value.** Revert it in `plugin/pluginfinity.config.ts` and rebuild before committing or opening a PR.

This hot-patch path works for:

- Adding or modifying MCP tools (new tool files, router entries, server registrations) — **confirmed via dogfood**

This hot-patch path also works for:

- New `hooks.json` registrations (new matchers, new hook entries) — **confirmed via dogfood**

This hot-patch path does NOT work for:

- New `mcpServers` entries or structural `plugin.json` changes — need full CC restart
- Database schema / migration changes — need DB delete + rebuild + reload

## Common rationalizations (verbatim near-misses, plug them when they appear)

| If you think... | Reality |
| --- | --- |
| "I'll just add 'watch for X' to the orchestrator prompt as a helpful nudge" | That leaks the experiment. The orchestrator's behavior under uncontaminated conditions is what we're measuring. |
| "I'll just pick the most recent chain and start" | That's guessing at user intent. Ask. |
| "Orchestrator said complete and 14/14 pass — probably fine, I can spot-check" | The test passing is the least-interesting outcome. The dogfood is about how it got there. Run all seven verification steps. |
| "/reload-plugins probably picks up hooks.json too, the docs are being conservative" | Correct — dogfood confirmed `/reload-plugins` picks up new hook registrations. Only structural `plugin.json` changes need a full CC restart. |
| "I changed plugin.json so I need a full CC restart to pick up MCP changes" | Only structural `plugin.json` changes need a full restart. Bumping `--noop=N` in `mcpServers.<server>.args` and calling `/reload-plugins` restarts just the MCP server. |
| "Typo in core is trivial, just fix it without writing it down" | Friction in the system is exactly what dogfood exists to surface. Append it to `findings.md`. |
| "findings.md is the user's to update, not mine" | You are the agent running the session. Logging is your job. |
| "I'll save context by skipping the handoff write" | The next agent reads the chain to know what was tried. Skipping writes makes future work redundant. |

## Quick reference

- Chain folder: `docs/superpowers/dogfood/<chain-slug>/`
- Handoff: `<chain>/NN-<title>.md` (frontmatter has `chain`, `chain_index`, `title`, `status`, `created`, `parent_session`, `prev_handoff`, `what_were_testing`)
- Findings: `<chain>/findings.md`
- Cheatsheet (yours, never shared): `.claude/playground-cheatsheet.md`
- Templates: `${CLAUDE_SKILL_DIR}/handoff-template.md`, `${CLAUDE_SKILL_DIR}/findings-template.md`
- Build/reload: `pnpm ci:build`, `/reload-plugins`, full Claude Code restart
- Key MCP tools: `tdd_task` (`get`/`resume`), `acceptance_metrics`, `test_history`, `turn_search`, `failure_signature_get`, `hypothesis` (`list`)

Files in this skill

  • SKILL.md21.5 KB
  • findings-template.md809 B
  • handoff-template.md1.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.