Releases: priyanshuN/triago
Release list
v0.3.4 — the trigger named a tool the agent wasn't holding
triago's whole premise is that an agent reaches for it without being told to. It wasn't doing that, and the reason turned out to be one sentence missing from the instructions.
What was wrong
A client carrying a large toolset can defer an MCP server's tools to a name-only listing — present as names, callable only once their schemas are loaded. The shipped policy read call triago_post_findings instead of printing them, which presumes the tool is already to hand.
So at the exact moment that matters — a review is finished, the list of findings exists, and the agent decides what to do with it — printing costs nothing and posting costs a lookup the agent was never told to make. It printed.
The instructions now say the tools may need loading, and to load them. The note sits inside When to use it rather than at the end, because the tail of a long instructions string is the first thing a host truncates, and a trigger that survives truncation is no use if the means of acting on it doesn't.
Measured, not assumed
The same prompt, in the same workspace, before and after:
| before | after | |
|---|---|---|
| findings produced | 7 | 11 |
| tool loaded | only when asked | unprompted |
| card posted | only when asked | unprompted |
Before, the agent printed a section headed "Findings, worst first" with seven numbered items and asked which to fix — the trigger condition stated about as plainly as it can be. After, it loaded the tool on its own and posted eleven findings, keeping the three most serious in the terminal and sending the rest to the card.
An earlier theory held that the trigger was losing because the instructions get truncated. That didn't survive checking: the five-findings threshold sat above the cut in both sessions. It was never a delivery problem — the rule arrived, and pointed at something the agent wasn't holding.
v0.3.3 — the asynchronous pickup path never worked
Two faults, both found by using triago on a real code review rather than by reading it.
wait_seconds: 0 never asked the server
triago_await_decisions answered pending for every card — including cards decided hours earlier. waitForDecisions guarded its polling loop with while (Date.now() < deadline), and a deadline of now + 0 is already in the past, so the loop body never ran and nothing ever contacted the server.
This is the whole asynchronous half of the product. The shipped instructions name wait_seconds: 0 as the cheap check an agent should run at the top of every turn while a card is outstanding, so in practice an agent could only ever collect decisions it had synchronously blocked for. Anything you triaged after the posting call returned was never picked up.
Zero now performs one real non-blocking read. The suite missed this because every other test waits with a real duration — the one value the policy actually recommends was the one value never exercised.
fix meant the wrong thing on someone else's pull request
The policy read fix — act on it now, in this session, which quietly assumes the agent owns the code. On a review of a pull request you did not write there is no branch the agent may edit, and acting on a finding means raising it as a review comment.
The card that exposed this was posted by an agent unprompted, reviewing a PR where the human was the reviewer rather than the author — and it signed off by offering to make edits it had no business making. It was being faithful to the policy; the policy was wrong. It now says where a fix goes in both cases.
Both are covered by tests, including a red-then-green check on the zero path.
v0.3.2 — stage the version pin
The release script rewrote the npx version pin in .mcp.json and then staged only .claude-plugin/plugin.json, so the pin never entered the release commit. The working tree read the new version while the tagged tree was one behind — a state where every local check passes and the published artifact is wrong.
CI caught it and refused to publish, so nothing broken reached the registry. The pin test added in 0.3.1 was written for exactly this and earned its place on its first real run.
0.3.1 was tagged but never published. Release tags are immutable in this repository on purpose, so the fix ships as a new version rather than by moving a tag. If you are on 0.3.0, this is the release that makes the plugin work.
/plugin marketplace add priyanshuN/triago
/plugin install triago@triago
Already installed? /plugin update triago@triago.
No schema, card-format or API change.
v0.3.1 — the installed plugin could not start
Fixes the plugin shipped hours ago in 0.3.0. Installing it succeeded and then claude mcp list reported the server as Connection closed.
Claude Code installs an npm-sourced plugin by extracting the tarball, and does not run npm install in the cache directory — so there is no node_modules beside the extracted dist. Running the entry point in place died on ERR_MODULE_NOT_FOUND for @modelcontextprotocol/sdk, which the MCP transport surfaces only as a closed connection, naming nothing.
The server now launches through npx, which fetches the package with its dependencies and runs the declared bin. The version is pinned, and the release script rewrites that pin alongside the manifest version — an unpinned npx would fetch whatever is newest when the server spawns, which is a different build than the manifest describes and undoes the point of syncing them.
Why 0.3.0 shipped broken, since it is the more useful part: it was verified with claude --plugin-dir ., which loaded the plugin and registered all four tools cleanly. That passes against a checkout because a checkout has node_modules. The working configuration and the broken one are indistinguishable under --plugin-dir, and only installing it for real tells them apart. The test that replaces that check now asserts the launch method rather than the load.
/plugin marketplace add priyanshuN/triago
/plugin install triago@triago
Already installed? /plugin update triago@triago.
No schema, card-format or API change.
v0.3.0 — install as a Claude Code plugin
Two commands instead of three, and the one it removes is the one that fails without telling you why.
/plugin marketplace add priyanshuN/triago
/plugin install triago@triago
Registering triago-mcp by bare name resolves against the agent's PATH, not your shell's. It works when you test it in a terminal and fails with a bare ENOENT in an editor or desktop app launched from a dock, because those never source your shell profile — so a version manager's bin directory is simply not there. The error names nothing.
As a plugin none of that applies: Claude Code fetches the package and resolves the server path itself, so there is no global install, no symlink and no version manager anywhere in the chain.
The plugin is the npm package, not a second artifact to keep in step. The same tarball now carries .claude-plugin/plugin.json and .mcp.json, and the marketplace entry uses an npm source pointing back at it, so both channels publish from one release and share one version number.
That matters more than it sounds, because the failure is silent: Claude Code uses the plugin's version as its update cache key, so a stale manifest would make /plugin update report already at the latest version while installed users never receive the release. Nothing would error. So npm version rewrites the manifest into the release commit, and a test fails if the two ever disagree.
An npm source is also the only one that can work here — dist/ is gitignored, so a git-sourced plugin would resolve ${CLAUDE_PLUGIN_ROOT}/dist/mcp.js against a clone with no dist in it.
The manual claude mcp add route still works and is still documented, below the plugin one.
npm i -g @triago/cliNo schema, card-format or API change.
v0.2.1 — triago --version
The new bug report template asks for triago --version as its first required field. Until now the package had no such flag — it printed a page of usage text instead, so a public form was asking for something the software could not produce.
The version was previously reachable only through triago status, which needs the server running. That made it unavailable in exactly the situation it is wanted: reporting a bug where the server will not start.
It is answered before the command switch rather than inside it, because argument parsing routes anything beginning with -- into flags, so --version never reached the switch at all. -v and a bare version work too — this is the first thing a stranger types, and being clever about which spelling is correct helps nobody.
Also in this release
- The changelog now ships in the package. It was on GitHub only, so anyone who found triago through npm had to leave for the repository to see what changed between versions.
- Prettier is enforced in CI, so style is settled by a formatter rather than in review. Rewrapping only; no behaviour changed.
- The repository grew a contribution guide, a code of conduct, issue and pull request templates, and an OpenSSF Best Practices passing badge — all 67 criteria answered, including two answered
Unmetbecause there is no coverage instrumentation and no dynamic analysis, which is the truth.
npm i -g @triago/cliRequires Node 20 or newer. No schema, card-format or API change.
v0.2.0 — a clickable notification, and counts for the silence
Two halves of the same problem, both from the first real card: when nothing opens a tab, nothing tells you the card exists — and nothing afterwards tells you it went unread.
The notification is now clickable. It offers an Open card action that launches the card with its token, so getting from "a card arrived" to reading it is a click rather than reading an id off a toast and typing it back. That notification is the only channel that reaches someone not looking at the screen, and in the case it exists for it is the only channel at all.
It is guarded, because the obvious version of this is a regression: --action and --wait arrived in libnotify 0.8, and 0.7.x rejects them as unknown options and prints nothing. Since the spawn is detached with errors swallowed, passing them blind on an older notify-send would have silently removed the notification altogether — trading the whole channel for a button. Support is probed once and cached; where it is missing the plain notification still carries the card id. macOS stays plain, which needs no third-party binary.
triago status now counts the invisible things:
2 cards · 1 open · 1 decided
1 never opened in a browser
1 submitted with nothing waiting
Both of those look identical to a healthy system from the outside, which is why they need counting rather than noticing. The first real card through this tool was both at once, and it took a person wondering where it had gone.
npm i -g @triago/cliAdditive: status --json gains a cards object. No schema, card-format or API breaking change.
v0.1.6 — pick the card back up, don't poll for it
A real triage outlasts the tool call that posted the card, so the timeout is the usual ending, not a failure. The instructions handled it in half a sentence and left an agent two bad readings:
- "keep waiting" → a polling loop that spends the turn doing nothing, blocks the agent from other work, and dies with the session anyway
- "read it later" → never said when later was, so in practice the human had to notice the card was never collected and ask
Neither is necessary. wait_seconds already accepts 0 and answers immediately, so the cheap move is to end the turn and check on the next one — whoever prompts it, whenever it comes. One instant call while a card is outstanding, nothing when none is. It survives the session ending, because the card id and the decisions are files on disk. triago_list_cards covers a lost id, or a different session entirely.
That is the difference between the human needing to know the magic words and simply typing anything and having the agent notice. It is exactly what went wrong on the first real card: the decisions were submitted, nothing collected them, and it took the human working out that they could ask.
npm i -g @triago/cliInstructions only — no schema, card-format or API change.
v0.1.5 — the comment outranks the verb
From the first real review through the tool: 9 discuss / 1 fix, and every discuss carried a comment that was an answer — the premise is wrong, that module is out of scope, that cannot happen while the route is assigned.
The instructions defined discuss as "stop and bring it back to the human before acting", so an agent following them faithfully would have gone back and asked nine questions that had just been answered in front of it.
Four verbs collapsing into one is the tell: the verb was not where the human put the information — the comment was — and the tool was reading the wrong field.
What changed. discuss now means "the human has something to say about this before you act", and the MCP instructions state plainly that the comment is the substance while the verb only says how to file it. A discuss with a comment is an answer; only an empty one means stop and ask. They also name what these comments overwhelmingly are — corrections from someone who knows the system — and say the right response is to withdraw the finding and check whether the same correction invalidates its neighbours, rather than defend it or re-raise it later.
Deliberately not a fifth verb. "Rejected" is the disposition the data shows, but skip-with-a-comment and discuss-with-a-comment already express it, decisions is the public contract shared by the schema, the stored cards and the tool shapes, and one card is one data point.
npm i -g @triago/cliInstructions and wording only — no schema, card-format or API change.
v0.1.4 — tell the truth about who is waiting
Fixes from the first real production review — ten findings across three repos, triaged long enough that the call which posted the card had already ended.
The page no longer claims a handoff that did not happen. Submitting said "decisions returned to agent" and the rail said "agent waiting" even when nothing was listening. That is the normal case, not an edge case: a review worth posting takes longer than any tool timeout, so most cards are submitted after the agent stopped waiting — often in a later session.
The server already tracked parked waiters and threw the answer away. It now reports waiting per card and delivered on submit. When nothing was listening the card says so, and offers the command that resumes it, to copy rather than retype an id by eye. Nothing was ever lost — decisions are files on disk — but you had to know that.
No tab, no explanation. The auto-open decision is now logged with its reason. Previously that reason was returned only to whoever posted the card, which for an MCP call is the agent, so a human who got no tab also got no clue why. The desktop notification carries the card id in that case.
Summaries stop hiding behind a hover. A finding's summary clipped to one line even on the row you had opened to read, and the tooltip then rendered over the detail beneath it. Open rows now show the summary in full; the collapsed list keeps one line, because that is what makes twelve findings scannable. Card titles wrap instead of ellipsing.
npm i -g @triago/cliNo schema, card-format or API breaking change. waiting and delivered are additive.