/stale-proposals
Audits the local proposal queue for proposals that have gone stale — work that already shipped (visible in a plugin CHANGELOG or merged PR) but is still open as a proposal task (awaiting consent or approved), plus proposals old enough to be inert. Auto-resolves only unambiguous
Claude Code
$ npx -y skills add gtapps/hermitd --skill stale-proposals --agent claude-code
Codex
$ npx skills add gtapps/hermitd --skill stale-proposals -a codex -y
Cursor
$ npx skills add gtapps/hermitd --skill stale-proposals -a cursor -y
Gemini CLI
$ npx skills add gtapps/hermitd --skill stale-proposals -a gemini-cli -y
GitHub Copilot
$ npx skills add gtapps/hermitd --skill stale-proposals -a github-copilot -y
OpenCode
$ npx skills add gtapps/hermitd --skill stale-proposals -a opencode -y
Windsurf
$ npx skills add gtapps/hermitd --skill stale-proposals -a windsurf -y
SKILL.md
stale-proposals.SKILL.mdname: stale-proposals
description: Audits the local proposal queue for proposals that have gone stale — work that already shipped (visible in a plugin CHANGELOG or merged PR) but is still open as a proposal task (awaiting consent or approved), plus proposals old enough to be inert. Auto-resolves only unambiguous matches and asks before anything else. Use this whenever the operator says "check for stale proposals", "which proposals are stale", "are any proposals already done", "reconcile the proposal queue", "clean up the proposals", "prune proposals", "did we already ship any of these", or notices the heartbeat re-firing the same proposal-pending items every wake. Also trigger proactively when the operator is confused about why an old PROP is still open, or before a release when the queue is about to be reviewed. Monorepo-internal — assumes plugins/*/CHANGELOG.md.
Stale Proposals
An open proposal is a claim that something still needs doing. That claim decays two ways: the work quietly shipped under a different name and nobody flipped the status, or the idea simply stopped mattering. Both leave the queue lying, and the lie is expensive here — the heartbeat re-fires every open proposal on each wake, so a stale entry costs tokens forever and trains the operator to ignore the whole list.
This skill reconciles the queue against what actually shipped. It is deliberately asymmetric about trust: **shipping evidence can close a proposal automatically, age cannot.** Evidence is checkable and a wrong flip is recoverable by reading the changelog; "this feels inert" is a judgement about the operator's intentions, and getting it wrong silently buries live work.
Usage
`/stale-proposals [--no-apply] [--from PROP-NNN] [--status proposed,accepted]`
- **No arg** — full audit; auto-resolves unambiguous matches, asks about everything else.
- **`--no-apply`** — report only, write nothing. Use when you want to see the verdicts before trusting them.
- **`--from PROP-NNN`** — only proposals numbered NNN and up. Operator phrasings like "just PROP-100+" or "the newer ones" mean this flag.
- **`--status <list>`** — `proposed` (awaiting consent) and/or `accepted` (approved, not closed). "Only the proposed ones" means `--status proposed`. `--from` filters legacy `PROP-NNN` ids only; proposals opened since the task-record change are identified by their `T-` id and are always in scope.
Scope flags go to the collector in Step 1, so the bundle itself is narrowed and the evidence floor moves with it. Never scope by prose in the subagent contract: a hint the subagent may or may not honour is how an in-scope proposal goes unreviewed.
Natural companion to `/release-status` when the queue has drifted, and worth a run before any release where proposals get reviewed.
Step 1 — Collect the evidence
bun .claude/skills/stale-proposals/scripts/collect-evidence.ts [--hermit-dir <hermit-dir>] [--from PROP-NNN] [--status <list>]
`<hermit-dir>` is the state folder that holds `tasks/`; a proposal is a task record with `kind: proposal` (see `plugins/hermitd/docs/task-records.md`), and migrated ones keep their `PROP-NNN` id as dedupe key `proposal:PROP-NNN`. It defaults to `<repo>/.hermit`, which is only right in the resident's own checkout. In a checkout whose `.hermit` is a projection (a core checkout under a resident workspace, a worktree), pass the resident's absolute `.hermit` path. Use that same path in Steps 3 and 4.
This writes a bundle containing every in-scope open proposal (with an excerpt of its Problem section) alongside every CHANGELOG bullet, closed task record naming a PROP id, and first-parent commit dated after the oldest open proposal — nothing can have shipped before the proposal that asked for it existed, so that date is a sound floor.
Output is `OK|<bundle-path>|<open>|<bullets>|<commits>|<cutoff>|<tasks>`, or `NONE|no-open-proposals` (report "Queue is clean — no open proposals." and stop). A non-zero exit means a wrong path or an unmigrated state folder: report the stderr message and stop, never treat it as a clean queue. Unmigrated means `proposals/*.md` still exist; the operator runs `proposal.ts migrate <hermit-dir>` once, this skill does not.
**Do not read the bundle.** It is on the order of 40k tokens and belongs in a subagent, not in the operator's session. You only need its path.
Step 2 — Match, in a subagent
Dispatch one `general-purpose` subagent. Its whole job is to turn that bundle into verdicts, so the corpus stays in its context and only the conclusions come back.
Give it the bundle path and this contract verbatim:
> Read the evidence bundle at `<path>`. It lists open proposals (each headed by its `PROP-NNN` or `T-` id), then CHANGELOG bullets, closed task records, then first-parent commits. > > For each open proposal, decide whether the thing it asked for has already shipped. Emit exactly one line per proposal, and nothing else: > > - `SHIPPED-STRONG|<ID>|<plugin> <version> / <commit or "changelog">|<one sentence: what the evidence says, in the changelog's own words>` > - `SHIPPED-WEAK|<ID>|<evidence ref>|<one sentence: what matches and what you could not confirm>` > - `AGED|<ID>|<age in days>|<one sentence: why nothing has moved on this>` > - `OPEN|<ID>` > > **STRONG requires all three:** the evidence names the same component the proposal targets; it describes the same behavior change the proposal asked for; and no distinct part of the proposal's ask is left unaddressed. A proposal asking for three things where the changelog delivers two is **WEAK**, not strong — partial delivery is the single most likely way this audit closes live work by mistake, so when you notice yourself arguing for why a gap "probably doesn't matter," that is WEAK. > > Ignore date order at your peril: evidence dated before a proposal was created cannot be that proposal shipping. It is usually the prior art the proposal was written against. Changelog dates have day granularity while
Read more
name: stale-proposals description: Audits the local proposal queue for proposals that have gone stale — work that already shipped (visible in a plugin CHANGELOG or merged PR) but is still open as a proposal task (awaiting consent or approved), plus proposals old enough to be inert. Auto-resolves only unambiguous matches and asks before anything else. Use this whenever the operator says "check for stale proposals", "which proposals are stale", "are any proposals already done", "reconcile the proposal queue", "clean up the proposals", "prune proposals", "did we already ship any of these", or notices the heartbeat re-firing the same proposal-pending items every wake. Also trigger proactively when the operator is confused about why an old PROP is still open, or before a release when the queue is about to be reviewed. Monorepo-internal — assumes plugins/*/CHANGELOG.md.
Stale Proposals
An open proposal is a claim that something still needs doing. That claim decays two ways: the work quietly shipped under a different name and nobody flipped the status, or the idea simply stopped mattering. Both leave the queue lying, and the lie is expensive here — the heartbeat re-fires every open proposal on each wake, so a stale entry costs tokens forever and trains the operator to ignore the whole list.
This skill reconciles the queue against what actually shipped. It is deliberately asymmetric about trust: **shipping evidence can close a proposal automatically, age cannot.** Evidence is checkable and a wrong flip is recoverable by reading the changelog; "this feels inert" is a judgement about the operator's intentions, and getting it wrong silently buries live work.
Usage
`/stale-proposals [--no-apply] [--from PROP-NNN] [--status proposed,accepted]`
- **No arg** — full audit; auto-resolves unambiguous matches, asks about everything else.
- **`--no-apply`** — report only, write nothing. Use when you want to see the verdicts before trusting them.
- **`--from PROP-NNN`** — only proposals numbered NNN and up. Operator phrasings like "just PROP-100+" or "the newer ones" mean this flag.
- **`--status <list>`** — `proposed` (awaiting consent) and/or `accepted` (approved, not closed). "Only the proposed ones" means `--status proposed`. `--from` filters legacy `PROP-NNN` ids only; proposals opened since the task-record change are identified by their `T-` id and are always in scope.
Scope flags go to the collector in Step 1, so the bundle itself is narrowed and the evidence floor moves with it. Never scope by prose in the subagent contract: a hint the subagent may or may not honour is how an in-scope proposal goes unreviewed.
Natural companion to `/release-status` when the queue has drifted, and worth a run before any release where proposals get reviewed.
Step 1 — Collect the evidence
bun .claude/skills/stale-proposals/scripts/collect-evidence.ts [--hermit-dir <hermit-dir>] [--from PROP-NNN] [--status <list>]
`<hermit-dir>` is the state folder that holds `tasks/`; a proposal is a task record with `kind: proposal` (see `plugins/hermitd/docs/task-records.md`), and migrated ones keep their `PROP-NNN` id as dedupe key `proposal:PROP-NNN`. It defaults to `<repo>/.hermit`, which is only right in the resident's own checkout. In a checkout whose `.hermit` is a projection (a core checkout under a resident workspace, a worktree), pass the resident's absolute `.hermit` path. Use that same path in Steps 3 and 4.
This writes a bundle containing every in-scope open proposal (with an excerpt of its Problem section) alongside every CHANGELOG bullet, closed task record naming a PROP id, and first-parent commit dated after the oldest open proposal — nothing can have shipped before the proposal that asked for it existed, so that date is a sound floor.
Output is `OK|<bundle-path>|<open>|<bullets>|<commits>|<cutoff>|<tasks>`, or `NONE|no-open-proposals` (report "Queue is clean — no open proposals." and stop). A non-zero exit means a wrong path or an unmigrated state folder: report the stderr message and stop, never treat it as a clean queue. Unmigrated means `proposals/*.md` still exist; the operator runs `proposal.ts migrate <hermit-dir>` once, this skill does not.
**Do not read the bundle.** It is on the order of 40k tokens and belongs in a subagent, not in the operator's session. You only need its path.
Step 2 — Match, in a subagent
Dispatch one `general-purpose` subagent. Its whole job is to turn that bundle into verdicts, so the corpus stays in its context and only the conclusions come back.
Give it the bundle path and this contract verbatim:
> Read the evidence bundle at `<path>`. It lists open proposals (each headed by its `PROP-NNN` or `T-` id), then CHANGELOG bullets, closed task records, then first-parent commits. > > For each open proposal, decide whether the thing it asked for has already shipped. Emit exactly one line per proposal, and nothing else: > > - `SHIPPED-STRONG|<ID>|<plugin> <version> / <commit or "changelog">|<one sentence: what the evidence says, in the changelog's own words>` > - `SHIPPED-WEAK|<ID>|<evidence ref>|<one sentence: what matches and what you could not confirm>` > - `AGED|<ID>|<age in days>|<one sentence: why nothing has moved on this>` > - `OPEN|<ID>` > > **STRONG requires all three:** the evidence names the same component the proposal targets; it describes the same behavior change the proposal asked for; and no distinct part of the proposal's ask is left unaddressed. A proposal asking for three things where the changelog delivers two is **WEAK**, not strong — partial delivery is the single most likely way this audit closes live work by mistake, so when you notice yourself arguing for why a gap "probably doesn't matter," that is WEAK. > > Ignore date order at your peril: evidence dated before a proposal was created cannot be that proposal shipping. It is usually the prior art the proposal was written against. Changelog dates have day granularity while
Run an always-on Claude Code agent on your own machine, for you or your team. Start and orchestrate sessions from chat in any project it can reach. Take over the same session in the Claude app or the CLI.
Other skills on hermitd.
More skills from other plugins.
browser-use
Direct browser control via CDP for web interaction: automation, scraping, testing, screenshots, and site/app work. Also covers…
agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling…
Questions about stale-proposals.
- Which coding agents can use stale-proposals?
- stale-proposals installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

