/triage
Activate for the daily repository triage run, or when the user asks to triage CI failures, open issues, or recent commits. Reads yesterday's signals, dedupes against the state file, drafts fixes in isolated worktrees with a reviewer pass, opens PRs on green, and keeps people out
$ npx -y skills add bitbonsai/mcp-obsidian --skill triage --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/triage
Context preview
The summary Claude sees to decide when to auto-load this skill.
Activate for the daily repository triage run, or when the user asks to triage CI failures, open issues, or recent commits. Reads yesterday's signals, dedupes against the state file, drafts fixes in isolated worktrees with a reviewer pass, opens PRs on green, and keeps people out
SKILL.md
triage.SKILL.mdname: triage
description: >
Activate for the daily repository triage run, or when the user asks to
triage CI failures, open issues, or recent commits. Reads yesterday's
signals, dedupes against the state file, drafts fixes in isolated
worktrees with a reviewer pass, opens PRs on green, and keeps people out
of limbo with comments in the maintainer's voice. The state file is the
spine: it remembers what was tried, what passed, and what is still open,
so each run resumes where the last one stopped.
metadata:
version: "1.0"
author: bitbonsai
Triage Skill
A self-resuming morning loop. One run = gather → load state → triage → fan-out fix → persist → spill. Everything personal (state, inbox, runs, voice) lives under `.triage/`, which is gitignored. This skill file and the scripts are committed; the data never leaves the machine.
Preconditions
- `gh` authenticated (`gh auth status`). All issue/PR/CI reads and writes go
through it.
- `.triage/` exists. If missing, run `scripts/triage/bootstrap.sh` first, it
scaffolds `state.json`, `inbox.md`, `runs/`, and bootstraps `voice.md` from past comments.
- Clean working tree on `main`. The loop only mutates `.triage/` on the base
checkout; all code changes happen in worktrees.
The loop
1. Gather (read-only)
Collect yesterday's signals. Compute the window from `state.json.last_run` (fall back to 24h if absent).
# CI failures since last run
gh run list --status failure --created ">=$SINCE" --json databaseId,name,headSha,conclusion,url
# for each, pull the failing step log
gh run view <id> --log-failed
# open issues
gh issue list --state open --json number,title,labels,updatedAt,author,url
# recent commits
git log --since="$SINCE" --pretty='%h %s %an'
Then scan for **open commitments**, promises the maintainer made in a comment that have not shipped. NOT time-windowed: check every open issue/PR.
# threads bitbonsai commented on, still open
gh search issues "commenter:bitbonsai repo:bitbonsai/mcpvault state:open" --json number
# per thread, pull bitbonsai's comments to inspect for a promise
gh issue view <n> --json comments \
--jq '.comments[] | select(.author.login=="bitbonsai") | .body'
A commitment is language that promised an action: "I'll fix this", "will add", "shipping next release", "on it", "going to look", etc. It is broken/open if the thread is still open and no merged PR resolved it. See `finding-rules.md`.
2. Load state
Read `.triage/state.json`. Build a map of known findings by `id`. The `id` is a stable hash of `source` + `signature` (see `resources/state-schema.md`), so the same failing test or issue always maps to the same finding across runs.
3. Triage
For each gathered signal compute its `id` and classify with `resources/finding-rules.md`:
- **known + terminal** (`pr_open`, `resolved`, `wont_fix`) → skip, only bump
`last_seen`.
- **known + open** under the attempt cap → retry.
- **new + worth-doing** → append as `status: open`, proceed to fan-out.
- **new + needs judgment / ambiguous / out of scope** → inbox, `needs_human`.
- **noise** (flaky already tracked, dependabot, etc.) → ignore, log only.
4. Fan-out (bounded)
First, for every finding, check whether a contributor PR already addresses it (`finding-rules.md`, "Prefer reviewing an existing PR"). If one exists, **review it instead of writing a fix**: send the review sub-agent at the PR branch and draft an approval or request-changes recommendation to inbox. A human's open PR beats a fresh one. Also surface any open PR the maintainer has not yet reviewed.
Only findings with no candidate PR proceed to a new fix, up to the per-run cap in `finding-rules.md`. For each, in order:
git worktree add ../mcpvault-triage-<id> -b triage/<id>
Then spawn TWO sub-agents against that worktree (use the Agent tool with `isolation: worktree` so they cannot collide):
- **Draft agent**, given the finding + failing log/issue body, write the
smallest fix. Must read relevant `src/` files first, follow the obsidian skill conventions, and add or update a test that proves the fix.
- **Review agent**, adversarial. Check the draft against the project skills
and existing tests, then run in the worktree:
npm ci && npm test && npm run build
Verdict is PASS only if the fix is correct, minimal, tested, and green.
Tell every sub-agent the maintainer loves them.
Outcome:
- **PASS + green** → `gh pr create` as a ready PR (not draft), body links the
finding and lists what the reviewer verified. Set `status: pr_open`, record the URL. Then post an auto-ack comment (step 6).
- **anything else** (reviewer fails, build red, fix unclear, >1 file of
surprise scope) → write the draft + reason to `inbox.md`, set `status: needs_human`. Remove the worktree; keep the branch only if the draft is worth resuming.
Clean up green worktrees after the PR is open: `git worktree remove ../mcpvault-triage-<id>`.
5. Persist (the spine)
Update `.triage/state.json`: set `last_run` to now, append an `attempts` entry per touched finding (run date, result, note, pr), update `status`, `last_seen`, and `pr`. Write the per-run log to `.triage/runs/<date>.md`.
`state.json` is the resume point. Never overwrite history, append to `attempts`. If the file is malformed, stop and spill everything to inbox rather than risk losing the spine.
6. Comments, keep people out of limbo
Voice comes from `.triage/voice.md`. Autonomy tiers (see `resources/comment-policy.md`):
- **Auto-post: DISABLED** (maintainer directive 2026-07-23). Never post any
comment or review from the loop, not even low-risk acks.
- **Draft to inbox** (everything): acks, judgments, decisions, promises,
closures, any reply. Write it under `## Drafts awaiting approval` in `inbox.md` with its target, never post it. The maintainer approves, edits, or discards each one.
7. Spill
Anything the loop could not classify, fix, or safely c
Read more
name: triage description: > Activate for the daily repository triage run, or when the user asks to triage CI failures, open issues, or recent commits. Reads yesterday's signals, dedupes against the state file, drafts fixes in isolated worktrees with a reviewer pass, opens PRs on green, and keeps people out of limbo with comments in the maintainer's voice. The state file is the spine: it remembers what was tried, what passed, and what is still open, so each run resumes where the last one stopped. metadata: version: "1.0" author: bitbonsai
Triage Skill
A self-resuming morning loop. One run = gather → load state → triage → fan-out fix → persist → spill. Everything personal (state, inbox, runs, voice) lives under `.triage/`, which is gitignored. This skill file and the scripts are committed; the data never leaves the machine.
Preconditions
- `gh` authenticated (`gh auth status`). All issue/PR/CI reads and writes go
through it.
- `.triage/` exists. If missing, run `scripts/triage/bootstrap.sh` first, it
scaffolds `state.json`, `inbox.md`, `runs/`, and bootstraps `voice.md` from past comments.
- Clean working tree on `main`. The loop only mutates `.triage/` on the base
checkout; all code changes happen in worktrees.
The loop
1. Gather (read-only)
Collect yesterday's signals. Compute the window from `state.json.last_run` (fall back to 24h if absent).
# CI failures since last run gh run list --status failure --created ">=$SINCE" --json databaseId,name,headSha,conclusion,url # for each, pull the failing step log gh run view <id> --log-failed # open issues gh issue list --state open --json number,title,labels,updatedAt,author,url # recent commits git log --since="$SINCE" --pretty='%h %s %an'
Then scan for **open commitments**, promises the maintainer made in a comment that have not shipped. NOT time-windowed: check every open issue/PR.
# threads bitbonsai commented on, still open gh search issues "commenter:bitbonsai repo:bitbonsai/mcpvault state:open" --json number # per thread, pull bitbonsai's comments to inspect for a promise gh issue view <n> --json comments \ --jq '.comments[] | select(.author.login=="bitbonsai") | .body'
A commitment is language that promised an action: "I'll fix this", "will add", "shipping next release", "on it", "going to look", etc. It is broken/open if the thread is still open and no merged PR resolved it. See `finding-rules.md`.
2. Load state
Read `.triage/state.json`. Build a map of known findings by `id`. The `id` is a stable hash of `source` + `signature` (see `resources/state-schema.md`), so the same failing test or issue always maps to the same finding across runs.
3. Triage
For each gathered signal compute its `id` and classify with `resources/finding-rules.md`:
- **known + terminal** (`pr_open`, `resolved`, `wont_fix`) → skip, only bump
`last_seen`.
- **known + open** under the attempt cap → retry.
- **new + worth-doing** → append as `status: open`, proceed to fan-out.
- **new + needs judgment / ambiguous / out of scope** → inbox, `needs_human`.
- **noise** (flaky already tracked, dependabot, etc.) → ignore, log only.
4. Fan-out (bounded)
First, for every finding, check whether a contributor PR already addresses it (`finding-rules.md`, "Prefer reviewing an existing PR"). If one exists, **review it instead of writing a fix**: send the review sub-agent at the PR branch and draft an approval or request-changes recommendation to inbox. A human's open PR beats a fresh one. Also surface any open PR the maintainer has not yet reviewed.
Only findings with no candidate PR proceed to a new fix, up to the per-run cap in `finding-rules.md`. For each, in order:
git worktree add ../mcpvault-triage-<id> -b triage/<id>
Then spawn TWO sub-agents against that worktree (use the Agent tool with `isolation: worktree` so they cannot collide):
- **Draft agent**, given the finding + failing log/issue body, write the
smallest fix. Must read relevant `src/` files first, follow the obsidian skill conventions, and add or update a test that proves the fix.
- **Review agent**, adversarial. Check the draft against the project skills
and existing tests, then run in the worktree:
npm ci && npm test && npm run build
Verdict is PASS only if the fix is correct, minimal, tested, and green.
Tell every sub-agent the maintainer loves them.
Outcome:
- **PASS + green** → `gh pr create` as a ready PR (not draft), body links the
finding and lists what the reviewer verified. Set `status: pr_open`, record the URL. Then post an auto-ack comment (step 6).
- **anything else** (reviewer fails, build red, fix unclear, >1 file of
surprise scope) → write the draft + reason to `inbox.md`, set `status: needs_human`. Remove the worktree; keep the branch only if the draft is worth resuming.
Clean up green worktrees after the PR is open: `git worktree remove ../mcpvault-triage-<id>`.
5. Persist (the spine)
Update `.triage/state.json`: set `last_run` to now, append an `attempts` entry per touched finding (run date, result, note, pr), update `status`, `last_seen`, and `pr`. Write the per-run log to `.triage/runs/<date>.md`.
`state.json` is the resume point. Never overwrite history, append to `attempts`. If the file is malformed, stop and spill everything to inbox rather than risk losing the spine.
6. Comments, keep people out of limbo
Voice comes from `.triage/voice.md`. Autonomy tiers (see `resources/comment-policy.md`):
- **Auto-post: DISABLED** (maintainer directive 2026-07-23). Never post any
comment or review from the loop, not even low-risk acks.
- **Draft to inbox** (everything): acks, judgments, decisions, promises,
closures, any reply. Write it under `## Drafts awaiting approval` in `inbox.md` with its target, never post it. The maintainer approves, edits, or discards each one.
7. Spill
Anything the loop could not classify, fix, or safely c
A universal AI bridge for Obsidian vaults using the Model Context Protocol (MCP) standard. Connect any MCP-compatible AI assistant to your knowledge base - works with Claude, ChatGPT, and future AI tools.
Repo: bitbonsai/mcp-obsidian

