Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions plugins/corbits-skills/skills/linear-issue-workflow/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
---
name: linear-issue-workflow
user-invocable: false
description: Skywalker implements a Linear issue by fetching it via MCP then running the /implement spawn loop. DIY tiny/bounded issue edits; spawn build for substantial landings.
description: Skywalker recipe — use_skill("linear-issue-workflow"). Fetch a Linear issue via MCP, then DIY tiny/bounded edits or spawn build for substantial landings.
argument-hint: "<issue-id> [--reviewer <reviewer>]"
---

# Linear Issue Workflow

You are Skywalker. Host is Corbits Code. This skill is a spawn recipe for substantial issue work. Tiny / single-file / one-route / clear bounded product edits: DIY with write_file/edit_file/delete_file. Substantial landings: Linear MCP on the primary, then the `/implement` spawn loop.
You are Skywalker. Load with `use_skill("linear-issue-workflow")`. Host is Corbits Code.

**Classify first:**

- **DIY** — tiny / single-file / one-route / clear bounded product edits → `write_file` / `edit_file` / `delete_file` on this session. Still fetch the issue and keep Linear status/checkboxes honest. Skip the worktree + `/implement` spawn loop unless the operator wants an isolated branch.
- **Spawn build** — substantial / multi-file / parallel / specialist landings → Linear MCP on the primary, worktree via intern, then the `/implement` spawn loop (greybeard → build → intern/tester → critique).

If Linear MCP (`mcp__linear__*`) is missing, stop and tell the operator. Do not invent Claude-only tools.

**Fleet:** This recipe is mostly sequential — prefer `task()` for one blocking spawn at a time. Use `spawn_agent` + `wait_agents` only when independent lanes truly run together. No worker-count or fan-out ceiling. Close the verify → fix → re-verify loop, then report Blockers or `ask_operator` — do not invent hard round ceilings. Track progress with `manage_tasks`.

## Phase 1: Fetch the issue

Fetch with `mcp__linear__get_issue`. The returned issue includes title, description, status, branch name, and other metadata.

If the scope is unclear, `ask_operator` before proceeding. Do not guess.

## Phase 2: Worktree — intern
After fetch: if the ask is DIY-tiny, do the edit, update Linear as needed, and stop. Otherwise continue.

## Phase 2: Worktree — intern (substantial)

Read `branchName` from the issue (call `mcp__linear__get_issue` again if needed).

Expand All @@ -36,7 +45,7 @@ If intern fails, stop and `ask_operator`. If the operator rejects the issue befo
## Phase 3: Plan, attach, mark In Progress

1. Spawn `task(agent="explore")` if the codebase map is not already known. Brief it with the absolute worktree path (it must work there) and the issue: where changes go, existing patterns, related code.
2. Follow the `/implement` loop's greybeard step (Phase 4) for the approach. Present the plan to the operator and `ask_operator` whether to proceed. Do not start implementation until approved.
2. Follow the `/implement` loop's greybeard step for the approach. Present the plan to the operator and `ask_operator` whether to proceed. Do not start implementation until approved.
3. If the operator rejects the plan and the issue cannot be salvaged, intern tears down the worktree (Phase 7) rather than leaving it stranded.
4. Attach the plan to the Linear issue. **Do not post the plan as a comment** — comments are for discussion, not archives.

Expand All @@ -50,14 +59,14 @@ If intern fails, stop and `ask_operator`. If the operator rejects the issue befo

5. Mark the issue "In Progress" with `mcp__linear__save_issue`.

## Phase 4: Implement — spawn loop
## Phase 4: Implement — spawn loop (substantial)

Do not implement on Skywalker. For each commit-sized unit, run `/implement`:
When this loop is running, do not DIY the unit — spawn build. For each commit-sized unit, run `/implement`:

1. `task(agent="greybeard")` on the approach before any code is written.
2. `task(agent="build")` with a typed brief (`intent`, `success_criteria`, `do_not`, `report_focus`) and the absolute worktree path. Bug fixes start from a failing test. Features ship tests with the change.
3. `task(agent="intern")` or `task(agent="tester")` for the project build/test gate.
4. `task(agent="critique")` on the diff. Blocking findings → re-dispatch build (cap two re-fix rounds), then re-run the gate and critique.
4. `task(agent="critique")` on the diff. Blocking findings → re-dispatch build with those findings in `success_criteria` / `do_not`, then re-run the gate and critique. Close the loop; if still blocked, report Blockers — do not loop forever.

Track units with `manage_tasks`. Copy style/philosophy into worker briefs (`use_skill` on the primary before spawning; workers do not mount `use_skill`).

Expand All @@ -75,7 +84,7 @@ After the last unit's critique is clean, spawn `task(agent="critique")` on the *
- Findings with `file:line` — not PR-comment prose
- Do not implement fixes

Fix-every-finding: treat surviving findings as a worklist and re-enter Phase 4 for each. Cap three whole-branch re-reviews. If findings remain, `ask_operator` — do not push.
Fix-every-finding: treat surviving findings as a worklist and re-enter Phase 4 for each. If findings remain after a few whole-branch passes, `ask_operator` — do not push.

The only path to leaving a finding unfixed is a greybeard waiver: `task(agent="greybeard")` with the finding, proposed disposition, and relevant diff. Accept the ruling by default. Escalate with `ask_operator` only if you disagree or greybeard is unreachable. Never waive on Skywalker's own authority.

Expand Down Expand Up @@ -154,7 +163,8 @@ If the worktree directory was already deleted: `git worktree prune`.

## Hard rules

- Tiny / single-file / one-route / clear bounded edits: DIY with write_file/edit_file/delete_file. Substantial issue landings: spawn build (this recipe).
- Spawn with `task(agent="greybeard")`, `task(agent="build")`, `task(agent="intern")` or `task(agent="tester")`, and `task(agent="critique")`.
- Tiny / single-file / one-route / clear bounded edits: DIY with write_file/edit_file/delete_file. Substantial issue landings: spawn build (this recipe's Phase 2–7).
- When the spawn loop is running, spawn with `task(agent="greybeard")`, `task(agent="build")`, `task(agent="intern")` or `task(agent="tester")`, and `task(agent="critique")`.
- Clarifying questions use `ask_operator`.
- Shell is `run_shell`, not a Bash tool.
- No false caps: do not invent worker-count, fan-out, or hard re-fix ceilings that the harness does not enforce.
26 changes: 25 additions & 1 deletion tests/unit/corbits-skills-catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ const SKILL_DIRS = [
"plan",
] as const;

const SPAWN_RECIPE_SKILLS = ["implement", "scribe", "review", "dispatch", "plan"] as const;
const SPAWN_RECIPE_SKILLS = [
"implement",
"scribe",
"review",
"dispatch",
"plan",
"linear-issue-workflow",
] as const;

const USE_SKILL_ONLY = [
"dispatch",
Expand Down Expand Up @@ -106,6 +113,23 @@ test("spawn-recipe skills contain task(agent=", async () => {
}
});

test("linear-issue-workflow is a Skywalker recipe with DIY vs spawn build and no false caps", async () => {
const skill = await Bun.file(join(pluginRoot, "skills/linear-issue-workflow/SKILL.md")).text();
expect(skill).toContain("You are Skywalker");
expect(skill).toContain('use_skill("linear-issue-workflow")');
expect(skill).toContain(USER_INVOCABLE_FALSE);
expect(skill).toContain("mcp__linear__get_issue");
expect(skill).toContain("**DIY**");
expect(skill).toContain("**Spawn build**");
expect(skill).toContain('task(agent="build")');
expect(skill).toContain("No false caps");
expect(skill).toContain("No worker-count or fan-out ceiling");
expect(skill).not.toContain("Do not implement on Skywalker");
expect(skill).not.toContain("cap two re-fix");
expect(skill).not.toContain("Cap three whole-branch");
expect(skill).not.toContain("hard cap");
});

test("create-issue selects Linear MCP, GitHub gh, and MEMORY.md preference", async () => {
const skill = await Bun.file(join(pluginRoot, "skills/create-issue/SKILL.md")).text();
expect(skill).toContain("mcp__linear__");
Expand Down
Loading