brief · diff
git:20261103.ca46d09 to git:20261104.d66d111
4 added, 4 removed. Audit A to A.
---
name: brief
description: "Use when the human asks where the work stands — \"현황 보고해줘\", \"상태 보고해줘\", \"브리핑해줘\", \"진행 상황 알려줘\", \"진행상황 표로\", \"status update\", `/brief` — or a turn for the human ends with a report spanning several items. \"어디까지 했지\" is recall; \"남은 작업 있어?\" is handoff-ticket."
---
# Brief
A status report has one job: the human reads it in under a minute and knows what is done, what is moving, and what is waiting on them. Its shape is fixed in code, not in memory: one renderer prints every report, and you add only judgment.
## 1. The report is the renderer's output
```bash
orch brief render [--telegram] --headline "<one sentence>" [--decision "…"]... [--insight "…"] --commit # on request
orch brief render --periodic [--telegram] --headline "<one sentence>" [--skipped "…"] [--decision "…"]... --commit # on a schedule
```
Send what it prints, whole and unchanged. Add `--telegram` when §2 says Telegram. A periodic report is one sent on a schedule: a heartbeat, a cron or `/loop` round, a "report every N hours" the human set. Every other report is on request.
- The renderer owns the shape. It prints the headline time from the system clock in the session's time zone, the legend, one table per repository or program with each row's PR state and `██████░░ 6/8` bar, then 진행 중, 다른 사람 대기, 결정 필요, 지금 오너가 할 일 (always, `없음` when empty) and 보류 (the ⏸️ rows' conditions; a row held by a to-do naming its PR reads 📅 in its table and is not listed there: the pointer line counts its to-do). One line, `단계표 N행 (접음 M) · <dashboard Stages URL, or orch stage show; on Telegram always orch stage show --telegram>`, points to the stage table (the `stage` skill): how many rows it prints and where they are. Under it, `📅 할 일 N건 · ⏸️ 보류 큐 K건 · <dashboard To-do URL, or orch board todo list --telegram; on Telegram always the command>` counts the to-dos whose time has not come and the held queue, neither of which the report lists; a part at 0 is left out, the line when both are. The `todo` skill prints them as tables. A periodic report adds the actions the round skipped. It builds the rows each time from what is live: the Orca cards and leads and their Runs, the last milestone in each card's report file, and the PR state on GitHub. It collects these again first when the saved copy is older than the dashboard config's `board.state_min` (5 minutes by default), and when it cannot, the headline says how old the copy it used is or that the PR list failed. The board adds only what those cannot give, and GitHub outranks it: a row whose own PR merged is ✅ and leaves 진행 중, one whose PR closed unmerged is ⏸️ `PR 닫힘`, and a PR the saved list lacks shows `?`, counted in the headline. A ✅ row with its merge sha is the Done item; there is no separate Done list. Only finished work folds, and the dashboard keeps all of it: a ✅ row merged more than `board.done_fold_h` hours ago (24) becomes its repository's `✅ 그 전 완료 N건` line and a held item written twice is one line. Every open row stays. A finished row the owner acked on the dashboard (`orch-dash ack`) leaves the report, with its count in the headline. What is over but never turns ✅ by itself (a doing item whose card's PR merged, an inbox item about a merged PR) the dashboard's collector closes on evidence; what it cannot settle shows as ❔ 확인 필요 with the reason, and a held item whose trigger fired moves to 진행 중. Close the rest with `orch board done <id>` (`orch board open` lists the ids; orchestrate's `references/dashboard.md`, "Closing what is over").
+ The renderer owns the shape. It prints the headline time from the system clock in the session's time zone, the legend, one table per repository or program with each row's PR state, `██████░░ 6/8` bar and next step (a row waiting on someone or held reads `↓ 오너`, `↓ 대기` or `↓ 보류`, pointing at the list that names what it waits on), then 표 밖 진행 (only work with no row), 다른 사람 대기, 결정 필요, 지금 오너가 할 일 (always, `없음` when empty) and 보류 (the ⏸️ rows' conditions; a row held by a to-do naming its PR reads 📅 in its table and is not listed there: the pointer line counts its to-do). One line, `단계표 N행 (접음 M) · <dashboard Stages URL, or orch stage show; on Telegram always orch stage show --telegram>`, points to the stage table (the `stage` skill): how many rows it prints and where they are. Under it, `📅 할 일 N건 · ⏸️ 보류 큐 K건 · <dashboard To-do URL, or orch board todo list --telegram; on Telegram always the command>` counts the to-dos whose time has not come and the held queue, neither of which the report lists; a part at 0 is left out, the line when both are. The `todo` skill prints them as tables. A periodic report adds the actions the round skipped. It builds the rows each time from what is live: the Orca cards and leads and their Runs, the last milestone in each card's report file, and the PR state on GitHub. It collects these again first when the saved copy is older than the dashboard config's `board.state_min` (5 minutes by default), and when it cannot, the headline says how old the copy it used is or that the PR list failed. The board adds only what those cannot give, and GitHub outranks it: a row whose own PR merged is ✅, one whose PR closed unmerged (even one the board marks done) is ⏸️ `PR 닫힘`, and a PR the saved list lacks shows `?`, counted in the headline. A ✅ row with its merge sha is the Done item; there is no separate Done list. Only finished work folds, and the dashboard keeps all of it: a ✅ row merged more than `board.done_fold_h` hours ago (24) becomes its repository's `✅ 그 전 완료 N건` line and a held item written twice is one line. Every open row stays. A finished row the owner acked on the dashboard (`orch-dash ack`) leaves the report, with its count in the headline. What is over but never turns ✅ by itself (a doing item whose card's PR merged, an inbox item about a merged PR) the dashboard's collector closes on evidence; what it cannot settle shows as ❔ 확인 필요 with the reason, and a held item whose trigger fired moves to 표 밖 진행. Close the rest with `orch board done <id>` (`orch board open` lists the ids; orchestrate's `references/dashboard.md`, "Closing what is over").
You give it four things:
- `--headline`: the conclusion the human most needs, one sentence, with no time. The renderer puts the time before it and keeps its own facts after it (a stale PR list, old board rows, a failed collect). Three of those facts ask for an act:
- `보고서에 없는 세션 N (names)`: working or waiting sessions with a parent Orca recorded that no row (a row of one of its subagents counts), board lead, doing item or close stands for. Find why the render missed them; do not write them onto the board. `누락 검사 안 함: <reason>` means the session list failed or was old, so nothing was counted.
- `오래된 결정 N (ids)`: open decisions nobody confirmed for `board.decision_stale_h` hours (12), counted from the later of `created_at` and `checked_at`. Check each: `orch decide keep <id>` if it still stands, `orch decide drop <id>` if not. Nothing closes one by itself.
- `응답 경로 없음 N (ids)`: open decisions whose answer reaches no one: the terminal the relay would type into (the registering one, else the root's) is gone or has no running, writable agent. Drop it and register it again from the terminal that now waits on it.
- `등록 터미널 없음 N (ids · 답은 오케스트레이터로)`: the registering terminal is gone, so the answer goes to the orchestrator's terminal instead. Relay it to whoever waits on it, or drop and register it again there.
- `--decision`, once per item: `<question>: <options> → 추천: <X> — <reason> · 답이 없으면 <default>`. The render refuses an item without `→ 추천:`. Numbers follow the decisions registered with `orch decide add`; register one that will stay open past this report, so it keeps its id and `(지난 보고와 동일)`.
- `--insight`: a block the human's settings or another skill add to the reply (an output style's insight box, a summary). It goes after 다른 사람 대기, so the report still ends on what the human acts on.
- `--skipped` (periodic): one line naming the periodic actions this round did not take and why (`21:00 이후라 Slack 미전송 · 머지 가능 PR 없음`).
What goes where:
- **Decision needed** is only a choice outside the scope the human approved: their budget, a permission they hold, another team's scope, or an irreversible or outward act the approval does not cover (`orchestrate` "What reaches the human"). Inside that scope, take the recommended default, act, and let the row show it.
- **Only you** (🙋 지금 오너가 할 일) is what only the owner can unblock: a permission dialog, a login, a payment, an approval or merge a ruleset gives to them, a review they were asked for, an answer only they have. One item per line: what, where, `→` the work it unblocks. Record what no row carries with `orch board now "<what> · <where> → <work>"...`, which replaces the whole list. One topic goes under Decision needed or Only you, not both.
- **Waiting on others** (⏳ 다른 사람 대기) is work stopped on another person's review, approval or reply. One item per line: who, what, since when, `→` the work, and the next step (when to remind). With a send-log configured, the renderer adds the last request or reminder that went out for that PR and person: `· 마지막 리마인드 rev-a 3h 전 (<channel> 스레드)`. The log is the one `"brief": {"sendlog": "<path>"}` in `~/.claude/agent-skills.json` names, in `watch-prs`'s send-log format; there is no default, and without the key or the file the item has no such part.
- - Which of the two a row is, the renderer decides from evidence and you only record it. A row is waiting on a person when its status is `waiting` (`--status owner` when only the owner can move it). The PR's requested reviewers come first: the owner among them (the gh login in the PR list, or `오너`/`owner`) is 🙋, anyone else ⏳. With no request, the row's `--owner <who>` decides the same way. With neither, a PR GitHub holds for a review nobody was asked for is 🙋 `리뷰 요청`; otherwise, or with no gh login to compare against, the row is ❔ 확인 필요 under 진행 중: set `--owner` rather than guess. A card session stopped at a prompt is 🙋, and a card gone with its draft PR open is 🙋 too (make it ready, or hold it). A held item naming a row's open PR folds the row into ⏸️ under that item only when the row would otherwise be ⏸️ or ❔, so the prompt-stopped card stays 🙋. A registered decision is the owner's and stays under Decision needed.
- - **To-do** is a promise kept on a date or a condition, by someone named: `orch board todo add <work> (--due <date> | --after <condition>) --who <who>`. Until then the report only counts it (the `todo` skill lists it). When the first of these comes (the date, a date in `--after`, or, with no date there, every PR it names merged), the renderer moves it to Only you when the owner does it, else to 진행 중, as `⏰ <work> … 도래`, until `orch board done do:<k>`; nothing closes it on its own. `orch board todo from-later <n> --who <who>` moves a held item there.
- - **Held** is a queue of work set aside with no date: its order is the turn, the first is next, and `--trigger` says what makes it next: `orch board later add <work> --trigger <condition> [--who W] [--at N]`, `orch board later move <n> --to N`. The report only counts it (the `todo` skill lists it), and an item whose trigger says merge moves to 진행 중 once every PR it names has merged; nothing else takes one out of the queue. A held item's `--due` only lifts its PR's hold in Needs you. A ⏸️ row is not a held item: its condition is listed under 보류. Work a session runs (a card, a worker or a subagent) is never a doing item: the report shows it as that card's row, and a subagent as a row of its own under its session's lead (🔄 `서브에이전트 작업 중`, or ❔ `확인 필요: 종료 기록 없음` once no stop was recorded for `board.subagent_stale_h` hours, 3), from the record the plugin's hook keeps. Moving work with no session (an investigation you run yourself) is `orch board doing add <title> --owner W --next E`. Work waiting on another person's reply that has no row is `orch board doing add <title> --owner <who> --next <remind when> --waiting`; one waiting on the owner is `--owner 오너`.
+ - Which status a row is, the renderer decides from evidence and you only record it. Its rules run in order and the first that applies decides: ✅ done; 🙋 only the owner moves it (a decision or a card prompt linked to it, a human gate waiting, the owner among the PR's requested reviewers, `--owner 오너`); ⏸️ a condition holds it (its PR closed unmerged, a held item naming its open PR, a preceding PR not merged, a machine-resource wait); ⏳ another person (a requested reviewer or team, `--owner <who>`); 🔴 its lead's session is gone; ❔ a fact is missing (an unknown PR, a draft no session works on, a ready PR nobody is recorded to merge, `waiting` with nobody named, or a fact a rule cannot read: the PR's details, the owner's login, the session list, the pressure queue, a program file — never guessed as 🔄 or ⏳), its 다음 cell saying `에이전트 조치 필요: <what is missing>`; else 🔄. A ready PR the agent merges (its program's merge policy, else a repository pattern in `board.agent_merges` of `~/.claude/agent-skills.json`, else a repository the owner owns) is 🔄 with the merge as its next step, whatever the row's word. Record what evidence cannot give: `orch board set <id> --owner 오너|<who>|-` for who a row waits on, `--after owner/repo#N|-` for a PR it must wait for (`-` clears either). Set them rather than guess.
+ - **To-do** is a promise kept on a date or a condition, by someone named: `orch board todo add <work> (--due <date> | --after <condition>) --who <who>`. Until then the report only counts it (the `todo` skill lists it). When the first of these comes (the date, a date in `--after`, or, with no date there, every PR it names merged), the renderer moves it to Only you when the owner does it, else to 표 밖 진행, as `⏰ <work> … 도래`, until `orch board done do:<k>`; nothing closes it on its own. `orch board todo from-later <n> --who <who>` moves a held item there.
+ - **Held** is a queue of work set aside with no date: its order is the turn, the first is next, and `--trigger` says what makes it next: `orch board later add <work> --trigger <condition> [--who W] [--at N]`, `orch board later move <n> --to N`. The report only counts it (the `todo` skill lists it), and an item whose trigger says merge moves to 표 밖 진행 once every PR it names has merged; nothing else takes one out of the queue. A held item's `--due` only lifts its PR's hold in Needs you. A ⏸️ row is not a held item: its condition is listed under 보류. Work a session runs (a card, a worker or a subagent) is never a doing item: the report shows it as that card's row, and a subagent as a row of its own under its session's lead (🔄 `서브에이전트 작업 중`, or ❔ `확인 필요: 종료 기록 없음` once no stop was recorded for `board.subagent_stale_h` hours, 3), from the record the plugin's hook keeps. Moving work with no session (an investigation you run yourself) is `orch board doing add <title> --owner W --next E`. Work waiting on another person's reply that has no row is `orch board doing add <title> --owner <who> --next <remind when> --waiting`; one waiting on the owner is `--owner 오너`.
A wrong or missing row is fixed in the record, then rendered again: `orch board set` for a phase split, progress or a correction (`--progress N/M` is stages passed out of the item's stages, or the epic's exit items; no basis, no number). Never edit the output: the next render would undo the edit. `--commit` saves what you sent as the last report, so the next one bolds what changed; render with it only for the copy you send. To fit 78 columns the render cuts a long name to `…[n]`, only where the cut saves at least the mark's width, and lists its whole text as `- [n] …` under the table; it never cuts a PR link or a stage cell, and exits 1 when the cells it does not cut alone pass 78: send it as printed.
Build a report by hand only in two cases, to the shape in `references/hand-format.md`:
- The render failed: a traceback, an error exit other than the width check, or no output. The headline says `렌더러 실패(<reason>)`, and the time comes from `date`.
- The report is one session's account of its own work, not of several cards or leads (a card reporting its ticket, `end-session` §6). That one is short and is the session's own.
Call each PR, branch or worker by a name the human already knows. No preamble and no closing offer, and never an invented item. Write your own words per `write-plainly`, in the language the human writes in. A skill that delegates its report here keeps its own required items and language (`end-session` §6).
## 2. Channel
A message that is only `/brief` is a request for this report: a bot command the Telegram plugin does not handle reaches the session as plain text (registering it in the bot's menu is in §3). In Claude Code the user types `/agent-skills:brief`; a bare `/brief` there is a built-in command and never reaches this skill.
The human's last message decides the channel. It came in as a Telegram `<channel source="plugin:telegram:...">` tag → `--telegram`, sent with the Telegram reply tool in its default plain-text format (its `markdownv2` format fails the whole send on one unescaped character). The tool splits text over 4096 characters mid-line; a report longer than that goes out as one reply per section. Anything else → the terminal form, as printed.
## 3. The `/brief` menu entry (once per bot)
Only the session that holds the bot token registers it, after the human approves: it changes the bot, and a card never gets the token. Check first with `getMyCommands` for the human's chat; if `brief` is there, stop. Otherwise call `setMyCommands` scoped to that chat (`{"type": "chat", "chat_id": …}`): the plugin resets the all-private-chats list on every start, and the narrower scope wins. A chat-scoped list replaces that chat's whole menu, so register `brief` together with the plugin's `start`, `help` and `status`. The token is in the `.env` of the channel's state directory (`$TELEGRAM_STATE_DIR` when the session set it, else the plugin's default). Read it into the environment of the one command that calls the API and pass the URL to `curl -K -` on standard input, so it is not in argv; never print it or put it in a file.