# Inbox

> Conversational review of unread decisions in a roster workspace. Lists pending HITL items (roster/<function>/pending/ and <agent>/pending/), shows each in chat, collects approve/reject/defer by reply, and applies each via `roster review --approve/--reject <id>`. No TTY needed — this is the chat-native front door for `roster review`. Triggers on /inbox or when the user asks to review their inbox / pending decisions / HITL items.

- Skill: `firatcand/inbox` (Agent Skill)
- Install (CLI): `npx skillmds@latest add firatcand/inbox`
- Raw SKILL.md: https://api.skillmd.com/api/skills/firatcand/inbox/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: firatcand (https://skillmd.com/u/firatcand)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/firatcand/inbox

---


# inbox

The chat-native way to clear your roster decision queue. `roster review`'s interactive TUI needs a real terminal; `/inbox` does the same job **conversationally** — it lists the decisions, you reply in plain language, and it applies each through the non-interactive `roster review` backend. Works identically in Claude Code and Codex.

The skill is **stateless** — it re-reads the queue on every invocation.

## Working directory

Operate from the workspace root and classify it before running any command:

- If both `roster.yaml` and `config/project.yaml` exist, stop. This is a mixed workspace; preserve both markers and use the v2 migration flow when #363 lands.
- If `roster.yaml` exists, stop with: `This is a Roster v2 workspace. /inbox is a legacy queue workflow; do not run roster review or inspect legacy pending/ trees. Portable Brain evidence and Dreamer candidate decisions replace it in #356 and #358.`
- Otherwise, `config/project.yaml` alone identifies a legacy v1 workspace and the procedure below remains available. A missing `roster/` directory just means the legacy queue is empty (`roster review --json` returns `[]`), **not** an error.
- If neither identity file exists, stop and say:

> Run /inbox from a legacy Roster workspace root (must contain config/project.yaml); Roster v2 workspaces use roster.yaml and do not expose this queue.

(`.roster/` — dotted — is scaffold/schedule-spec metadata, not the runtime `roster/` queue; never treat one as the other.)

Use that root as `<root>` for every command below (pass it explicitly with `--cwd <root>`).

## Procedure

1. **List.** Run:
   ```
   roster review --json --cwd <root>
   ```
   Parse the JSON array. Each entry has `id`, `function`, `class`, `filename`, `path` (workspace-relative), `target_on_approve` (resolved — may be `null`), `frontMatter`, and `agent` on lesson-class items. If the `roster` CLI is not on PATH, tell the user to install it (`npm i -g @firatcand/roster`) or run `roster review` in a terminal, and stop.

   The queue spans **two surfaces**, and `--json` returns both:
   - `class: "error"` — `roster/<function>/pending/`, synthesized by `roster pending sync` from failed or stale scheduled fires. The approve target comes from `target_on_approve` front-matter.
   - `class: "lesson"` — `<function>/<agent>/pending/` (and `<agent>/pending/` for the cross-cutting peers `dreamer/` and `chief-of-staff/`), holding dreamer-drafted lesson candidates. These carry no `target_on_approve`: approving promotes the file to `<agent>/playbook/<filename>`, per conventions.md § "Lesson lifecycle". An explicit front-matter target still wins if present.

2. **Empty queue.** If the array is empty, reply `Inbox zero — no unread decisions.` and stop.

3. **Present.** For each item, show a compact, numbered block:
   - `N. [<agent or function>] <filename>`  ·  id `<id>`  ·  `<class>`
   - `on approve → <target_on_approve>` (or, when it is `null`, warn `⚠ no target — can't be approved, only rejected/deferred`)
   - the first ~6 lines of the body — read it yourself from `<path>` (you have Read access; `--json` returns front-matter only).

4. **Collect decisions.** Ask the user what to do, accepting free-form replies like "approve 1 and 3, reject 2, leave the rest." Map each to approve / reject / defer. If the user is unsure, summarize what approve (moves the item to its `target_on_approve`) vs reject (deletes it) vs defer (leaves it for later) does. For an error-class item (`error-<id>.md`, synthesized by `roster pending sync` from immutable failed-fire evidence), **reject is the durable skip**: `roster review --reject` also writes an acknowledgement sentinel (`pending/acknowledged/error-<id>`) so the next sync does not re-create the item from the same evidence — a hand-`rm` alone would come back.

5. **Apply**, one item at a time, using its `id`:
   - approve → `roster review --approve <id> --cwd <root> --json`
   - reject → `roster review --reject <id> --cwd <root> --json`
   - defer → do nothing (leave the file).

   Parse each result. On `ok: true`, note the outcome. On `ok: false` (e.g. `missing target_on_approve`, target exists, escapes workspace), tell the user the reason and treat the item as still pending (a failed approve changes nothing on disk).

6. **Summarize.** Report `X approved, Y rejected, Z deferred`, and list any that couldn't be applied and why. If anything is still pending, remind the user they can re-run `/inbox` later.

## Rules

- **Never move or delete decision files by hand.** Always go through `roster review --approve/--reject` so the path-safety checks (target must stay inside the workspace, no clobber) are enforced in one place.
- **Never edit a decision's body.** `/inbox` reviews and routes; it does not author.
- **One workspace at a time** — the root you detected in the working-directory step.
- **Identify by `id`, fall back to `path`.** The `id` is `roster review`'s stable handle; if it ever reports an ambiguous id, re-run the apply with the exact workspace-relative `path` instead.
- **The count must match the session-start banner.** Both read the same two surfaces (error + lesson). If they ever disagree, that is a bug worth reporting — never work around it by touching decision files directly.
- Do not invoke any model billing path other than the host tool's native subscription, and do not spawn subagents — `/inbox` only shells out to `roster` and converses.

## What this skill does NOT do

- Synthesize new decisions (that's `roster pending sync`, run by the session-start banner hook).
- Change the count logic or introduce read/seen state — "unread" simply means "still in the queue."
- Run the interactive `roster review` TUI (it needs a terminal; this skill is its headless, conversational equivalent).

