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

11 KiB

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:

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

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

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

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

inbox fail

Mark a thread failed.

Suggested flags:

  • --agent AGENT
  • --thread THREAD_ID
  • --summary TEXT
  • --body TEXT
  • --payload-json STRING

inbox cancel

Cancel a thread.

Suggested flags:

  • --agent AGENT
  • --thread THREAD_ID
  • --reason TEXT

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

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:

{
  "ok": true,
  "command": "claim",
  "thread": {
    "thread_id": "thr_123",
    "task_id": "T4",
    "status": "claimed",
    "assigned_to": "backend-worker"
  }
}

Suggested error shape:

{
  "ok": false,
  "error": {
    "code": "lease_conflict",
    "message": "thread already claimed by another worker"
  }
}

Suggested wait-reply wake shape:

{
  "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

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
---
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
```
```