Files
ai-workflow-skill/docs/inbox-cli.md
T

500 lines
11 KiB
Markdown

# Inbox CLI
## Purpose
`inbox` is the durable coordination bus for agent-to-agent communication. It is not the scheduler. It stores threads, messages, leases, and artifacts so workers and leaders can coordinate through reliable state instead of ad hoc multi-turn chat.
In normal operation:
- workers use `inbox` directly
- leaders use `inbox` mainly for inspection or manual override
- leader-side task planning and dispatch should happen through `orch`
## Responsibilities
`inbox` is responsible for:
- creating and updating communication threads
- sending directed messages between agents
- allowing a worker to claim one thread at a time through leases
- recording progress, blocked questions, results, and failures
- attaching artifact references such as files, logs, or patches
- listing, watching, waiting, and showing thread history
## Non-Responsibilities
`inbox` should not decide:
- how a large goal is decomposed into tasks
- whether a task is ready based on dependencies
- which worker should receive a task by policy
- when a failed task should be retried
Those decisions belong to `orch`.
## Core Objects
- `thread`: the durable container for one work conversation
- `message`: one event inside a thread
- `lease`: an exclusive worker claim for a thread
- `artifact`: a path or file reference attached to a message
- `event`: a monotonic record used to wake blocking waiters
## Required Fields
### Thread Fields
- `thread_id`
- `run_id`
- `task_id`
- `subject`
- `created_by`
- `assigned_to`
- `status`
- `priority`
- `created_at`
- `updated_at`
### Message Fields
- `message_id`
- `thread_id`
- `from_agent`
- `to_agent`
- `kind`
- `summary`
- `body`
- `payload_json`
- `created_at`
## Message Kinds
- `task`
- `progress`
- `question`
- `answer`
- `result`
- `control`
- `event`
## Thread Status Values
- `pending`
- `claimed`
- `in_progress`
- `blocked`
- `done`
- `failed`
- `cancelled`
## Worker Protocol
The normal worker flow is:
1. `fetch` candidate threads
2. `claim` one thread
3. `update --status in_progress`
4. continue with `update` messages as needed
5. if blocked, set `blocked` and ask a precise question
6. wait for a reply with `inbox wait-reply`
7. finish with `done` or `fail`
Rules:
- `fetch` does not grant ownership
- only `claim` grants ownership
- only one active lease may exist per thread
- blocked messages must say exactly what is missing
- terminal messages should include result or failure summary
- a blocked worker should wait on a reply event rather than sleeping blindly
## CLI Surface
The binary name is `inbox`.
### Global Flags
- `--db PATH`
- `--json`
- `--agent NAME`
### `inbox init`
Initialize the communication schema and SQLite pragmas.
Example:
```bash
inbox init --db .agents/coord.db
```
### `inbox send`
Create a new thread or append a message to an existing one.
Suggested flags:
- `--from AGENT`
- `--to AGENT`
- `--subject TEXT`
- `--thread THREAD_ID`
- `--run RUN_ID`
- `--task TASK_ID`
- `--kind task|question|answer|progress|result|control|event`
- `--summary TEXT`
- `--body TEXT`
- `--body-file PATH`
- `--payload-json STRING`
- `--priority low|normal|high`
- `--artifact PATH`
- `--artifact-kind KIND`
- `--artifact-metadata-json STRING`
### `inbox fetch`
List candidate threads for an agent without claiming them.
Suggested flags:
- `--agent AGENT`
- `--status pending,blocked`
- `--limit N`
- `--unread`
### `inbox claim`
Acquire a lease on a thread.
Suggested flags:
- `--agent AGENT`
- `--thread THREAD_ID`
- `--lease-seconds N`
### `inbox renew`
Extend an existing lease.
Suggested flags:
- `--agent AGENT`
- `--thread THREAD_ID`
- `--lease-seconds N`
### `inbox update`
Append a progress or blocked update.
Suggested flags:
- `--agent AGENT`
- `--thread THREAD_ID`
- `--status in_progress|blocked`
- `--summary TEXT`
- `--body TEXT`
- `--body-file PATH`
- `--payload-json STRING`
- `--artifact PATH`
- `--artifact-kind KIND`
- `--artifact-metadata-json STRING`
### `inbox reply`
Reply inside an existing thread.
Suggested flags:
- `--from AGENT`
- `--to AGENT`
- `--thread THREAD_ID`
- `--kind answer|question|progress|control`
- `--summary TEXT`
- `--body TEXT`
- `--body-file PATH`
- `--payload-json STRING`
- `--artifact PATH`
- `--artifact-kind KIND`
- `--artifact-metadata-json STRING`
### `inbox done`
Mark a thread complete and attach the final result.
Suggested flags:
- `--agent AGENT`
- `--thread THREAD_ID`
- `--summary TEXT`
- `--body TEXT`
- `--body-file PATH`
- `--payload-json STRING`
- `--artifact PATH`
- `--artifact-kind KIND`
- `--artifact-metadata-json STRING`
### `inbox fail`
Mark a thread failed.
Suggested flags:
- `--agent AGENT`
- `--thread THREAD_ID`
- `--summary TEXT`
- `--body TEXT`
- `--payload-json STRING`
- `--artifact PATH`
- `--artifact-kind KIND`
- `--artifact-metadata-json STRING`
### `inbox cancel`
Cancel a thread.
Suggested flags:
- `--agent AGENT`
- `--thread THREAD_ID`
- `--reason TEXT`
- `--artifact PATH`
- `--artifact-kind KIND`
- `--artifact-metadata-json STRING`
### `inbox list`
List threads with filters.
Suggested flags:
- `--agent AGENT`
- `--status pending,claimed,in_progress,blocked,done,failed,cancelled`
- `--created-by AGENT`
- `--assigned-to AGENT`
- `--limit N`
### `inbox show`
Show one thread with full message history.
Suggested flags:
- `--thread THREAD_ID`
- `--json`
`show` should include per-message artifact references when present.
### `inbox watch`
Block until new matching activity appears.
Suggested flags:
- `--agent AGENT`
- `--status pending,blocked,done,failed`
- `--timeout-seconds N`
### `inbox wait-reply`
Block until a new reply-like message appears for one thread.
This is the normal wait primitive for a blocked worker.
Suggested flags:
- `--thread THREAD_ID`
- `--after-message MESSAGE_ID`
- `--after-event EVENT_ID`
- `--kinds answer|control|result`
- `--timeout-seconds N`
Behavior:
- waits until a later matching message exists in the thread
- returns the new message and associated event cursor
- avoids blind `sleep` loops in worker logic
## JSON Contract
Every command should support `--json`.
Suggested success shape:
```json
{
"ok": true,
"command": "claim",
"thread": {
"thread_id": "thr_123",
"task_id": "T4",
"status": "claimed",
"assigned_to": "backend-worker"
}
}
```
Suggested error shape:
```json
{
"ok": false,
"error": {
"code": "lease_conflict",
"message": "thread already claimed by another worker"
}
}
```
Suggested `wait-reply` wake shape:
```json
{
"ok": true,
"command": "wait-reply",
"woke": true,
"next_event_id": 127,
"message": {
"message_id": "msg_901",
"thread_id": "thr_123",
"kind": "answer",
"summary": "Use email/password for MVP",
"body": "Use a simple credential flow for the first iteration."
}
}
```
## Exit Codes
- `0`: success
- `10`: no matching work
- `20`: conflict such as lease contention
- `30`: invalid input or invalid state transition
- `40`: not found
- `50`: storage or internal error
## SQLite Schema Draft
```sql
CREATE TABLE IF NOT EXISTS threads (
thread_id TEXT PRIMARY KEY,
run_id TEXT NOT NULL,
task_id TEXT NOT NULL,
subject TEXT NOT NULL,
created_by TEXT NOT NULL,
assigned_to TEXT NOT NULL,
status TEXT NOT NULL,
priority TEXT NOT NULL DEFAULT 'normal',
latest_message_id TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS messages (
message_id TEXT PRIMARY KEY,
thread_id TEXT NOT NULL,
from_agent TEXT NOT NULL,
to_agent TEXT NOT NULL,
kind TEXT NOT NULL,
summary TEXT NOT NULL,
body TEXT NOT NULL DEFAULT '',
payload_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
FOREIGN KEY(thread_id) REFERENCES threads(thread_id)
);
CREATE TABLE IF NOT EXISTS leases (
thread_id TEXT PRIMARY KEY,
agent_id TEXT NOT NULL,
lease_token TEXT NOT NULL,
claimed_at TEXT NOT NULL,
expires_at TEXT NOT NULL,
released_at TEXT
);
CREATE TABLE IF NOT EXISTS artifacts (
artifact_id TEXT PRIMARY KEY,
message_id TEXT NOT NULL,
path TEXT NOT NULL,
kind TEXT NOT NULL,
metadata_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
FOREIGN KEY(message_id) REFERENCES messages(message_id)
);
CREATE TABLE IF NOT EXISTS events (
event_id INTEGER PRIMARY KEY AUTOINCREMENT,
run_id TEXT NOT NULL,
task_id TEXT NOT NULL,
thread_id TEXT NOT NULL,
source TEXT NOT NULL,
event_type TEXT NOT NULL,
message_id TEXT,
summary TEXT NOT NULL DEFAULT '',
payload_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_threads_status_assigned
ON threads(status, assigned_to, updated_at);
CREATE INDEX IF NOT EXISTS idx_messages_thread_created
ON messages(thread_id, created_at);
CREATE INDEX IF NOT EXISTS idx_events_thread_event
ON events(thread_id, event_id);
```
## Concurrency Notes
- use `PRAGMA journal_mode=WAL`
- keep write transactions short
- make `claim` atomic
- never mutate state during `fetch`
- implement `watch` and `wait-reply` as blocking queries over message or event cursors, not as user-managed `sleep`
## Embedded Skill Draft
The following block is a draft `SKILL.md` for the `inbox` skill.
````markdown
```markdown
---
name: inbox
description: Use this skill when an agent needs durable communication through the local inbox CLI. It is for fetching work, claiming a thread, sending progress updates, raising blocked questions, waiting for replies, replying inside a thread, returning results, and watching inbox activity. Do not use it for task decomposition or scheduling decisions; use the orchestrator skill for that.
---
# Inbox
Use this skill when you need to communicate through the `inbox` CLI and its SQLite-backed thread store.
## When To Use
- a worker needs to fetch and claim work
- a worker needs to report progress
- a worker is blocked and must ask for clarification
- a leader needs to inspect or manually reply inside a thread
- an agent needs durable, machine-readable coordination instead of ad hoc chat
## Rules
- Prefer `--json` when another agent will consume the output.
- Never treat `fetch` as ownership; only `claim` grants ownership.
- Do not start work without a valid lease.
- When blocked, say exactly what is missing.
- If blocked, prefer `inbox wait-reply` instead of manual sleep loops.
- Use `result` for final output and `fail` for terminal failure.
- Keep scheduling decisions out of this layer.
## Typical Commands
```bash
inbox fetch --agent backend-worker --status pending --json
inbox claim --agent backend-worker --thread thr_123 --lease-seconds 900 --json
inbox update --agent backend-worker --thread thr_123 --status in_progress --summary "Implementing post CRUD routes" --json
inbox update --agent backend-worker --thread thr_123 --status blocked --summary "Need auth decision" --payload-json '{"question":"Should admin auth use email/password in MVP?"}' --json
inbox wait-reply --thread thr_123 --after-event 51 --timeout-seconds 1800 --json
inbox reply --from leader --to backend-worker --thread thr_123 --kind answer --summary "Use email/password for MVP" --body "Use a simple credential flow for the first iteration." --json
inbox done --agent backend-worker --thread thr_123 --summary "Post CRUD implemented" --body-file result.md --json
```
```
````