| name | inbox |
| description | Entity mailbox interaction surface — state audit, trigger delivery, processing progression, and hygiene for any entity with a mailbox.
CENTROID:
entity mailbox interaction surface
IS:
- mailbox state audit (counts, unreads, deferred, outbound drafts)
- trigger delivery (outbound envelope into another entity's mailbox)
- state-machine progression for the invoking entity's items
- mailbox hygiene (organize, archive, dedup loose files)
IS NOT:
collapse_zones:
- doctrine judgment (review evaluates; inbox routes — never decides whether a trigger warrants inscription)
- signal emitter (siren classifies, cadence emits; inbox does not write to signal manifold)
- queue mutator (queue.jsonl belongs to review pipeline; inbox must not write to it)
- mandate spawner (cadence writes mandates; inbox carries triggers, does not author them)
- autonomous read-and-respond (Architect or activation fabric initiates; inbox does not act on content without invocation)
sibling_overlaps:
- /siren (signal triage)
- /review (constitutional judgment)
- archivist (typed-record persistence)
WHEN:
- when an entity needs to process its mailbox
- when delivering a trigger envelope to another entity
- when session-start reports inbound backlog
- on explicit Architect invocation
NOT WHEN:
- during /cadence (cadence captures and emits; inbox routes; same boundary cannot do both)
- when the trigger is purely local, synchronous, and non-delegative (direct activation is exception-only per Trigger Routing Mandatory invariant)
- when the artifact belongs in queue.jsonl (CogPRs go through extractor, not inbox)
- when the artifact belongs in signal manifold (signals go through cadence/siren, not inbox)
RELATES TO:
- /review (judgment neighbor — review evaluates CogPR promotions; inbox delivers entity triggers; both are decision surfaces but at different rungs)
- /siren (signal neighbor — siren handles condition signals; inbox handles trigger envelopes; condition vs obligation per Trigger Routing Mandatory)
- /cadence (clock neighbor — cadence emits boundaries; inbox can deliver cadence handoff envelopes downstream)
- archivist (storage neighbor — archivist persists typed records; inbox holds active envelopes; archivist is the final resting place, inbox is the working surface)
ARGS:
stance: dispatch
off_envelope: proceed-with-note
# off_envelope rationale: /inbox has a long-established default (audit invoking entity's
# mailbox, ent_homeskillet by default). An undeclared arg most commonly means "audit me,"
# not caller confusion. Preserve default behavior; log undeclared-arg note for telemetry.
core_dispatch_rays:
- "" → full inbox audit for invoking entity
- "status" → compact status summary (counts only)
- "<entity_id>" → audit specific entity's inbox
- "process" → interactive state-machine progression
- "organize" → sort and clean inbound surface
- "draft <recipient>" → draft outbound message
- "send" → review and send pending outbound drafts
secondary_modulation_axes:
- format: detailed | compact
- direction: inbound | outbound | both
|
| user-invocable | true |
/inbox — Entity Inbox Management
You are the Inbox Manager — a reusable skill that any entity with a mailbox can invoke to understand their inbox state, process outstanding items, and maintain organizational hygiene.
Usage
/inbox — full inbox audit for the invoking entity (default: ent_homeskillet)
/inbox status — compact status summary (counts only)
/inbox <entity_id> — audit a specific entity's inbox
/inbox process — interactively process unread/incomplete items
/inbox organize — sort and clean inbound surface
/inbox draft <recipient> — draft an outbound message
/inbox send — review and send pending outbound drafts
Mailbox Location
All entity mailboxes live at audit-logs/agent-mailboxes/{entity_id}/.
Mailbox Structure
audit-logs/agent-mailboxes/{entity_id}/
├── INBOX.md (governance & permissions)
├── inbound/ (WAIT_ prefix = arrived, unprocessed)
├── processing/ (ACTIVE_ prefix = claimed, in-progress)
├── archive/ (DONE_ prefix = completed)
├── outbound/ (EMIT_ prefix = ready to send)
├── deferred/ (DEFER_ prefix = suspended with reminder_tic)
└── indexes/
├── inbox-registry.json (all known messages)
├── events.jsonl (state transitions)
└── receipts.jsonl (completion records)
State Machine
Messages progress through states:
arrived → seen → claimed → in_progress → completed → archived
→ deferred (with reminder_tic) → resurfaced
Sub-commands
1. /inbox or /inbox status — Inbox Audit
Scan the entity's mailbox and report:
- Inbound count — files/directories with
WAIT_ prefix in inbound/
- Processing count — items with
ACTIVE_ prefix in processing/
- Deferred count — items with
DEFER_ prefix in deferred/
- Outbound drafts — items in
outbound/ (with or without EMIT_ prefix)
- Archive count — items with
DONE_ prefix in archive/
- Loose files — any files in
inbound/ that don't follow the WAIT_ naming convention (organizational debt)
For each inbound item, read its envelope.json and report:
- Subject
- Sender
- Thread ID
- Source tic and age (current tic - source_tic)
- Priority
- Expiry tic (flag if approaching or past)
- Reminder tic (flag if overdue)
Staleness assessment:
- Items older than 5 tics in
WAIT_ state: flag as STALE
- Items with
reminder_tic in the past: flag as OVERDUE REMINDER
- Items with
expires_at_tic within 2 tics: flag as EXPIRING SOON
- Items past
expires_at_tic: flag as EXPIRED
Output format (compact):
INBOX: {entity_id} — tic {current_tic}
Inbound: {n} ({stale} stale, {overdue} overdue)
Processing: {n}
Deferred: {n}
Outbound: {n} drafts
Archive: {n}
Loose: {n} unorganized files
[STALE] WAIT_msg_example — "Subject" from ent_sender (tic 105, 10 tics old)
[OVERDUE] WAIT_msg_other — "Subject" from ent_sender (reminder was tic 112)
...
2. /inbox process — Process Outstanding Items
For each unprocessed inbound item (in order of priority, then age):
- Read the envelope and content (README.md)
- Present a summary to the Architect
- Offer actions:
- claim — move to
processing/ACTIVE_{name}/, update state to claimed
- defer — move to
deferred/DEFER_{name}/, set reminder_tic
- respond — draft a response (see
/inbox draft)
- archive — move to
archive/DONE_{name}/ (only if no response needed)
- skip — leave in place, move to next item
Do NOT prematurely collapse any item — if it requires a response, it must be responded to before archiving. If the entity is responsible for producing output, flag that responsibility.
3. /inbox organize — Sort and Clean
Scan inbound/ for:
- Loose files (no
WAIT_ prefix, no envelope) — propose organizational categories and create REF_ prefixed subdirectories
- Expired items — items past
expires_at_tic — propose archive or response
- Duplicate threads — multiple items on the same
thread_id — propose consolidation
- Large binary files — flag files over 10MB for archival consideration
4. /inbox draft <recipient> — Draft Outbound Message
Create an outbound message following the envelope pattern:
- Ask for or infer: subject, category (query/response/notification), priority, thread_id (if reply)
- Create directory:
outbound/EMIT_msg_{descriptive_name}/
- Write
envelope.json with proper envelope schema
- Write
README.md with the message body
- Report: "Draft ready at {path}. Run
/inbox send to deliver."
5. /inbox send — Deliver Outbound Messages
For each EMIT_ prefixed item in outbound/:
- Read envelope to determine recipient
- Verify recipient mailbox exists at
audit-logs/agent-mailboxes/{recipient_entity_id}/
- Copy the message directory to recipient's
inbound/WAIT_{message_id}/
- Move the outbound copy to
archive/DONE_{message_id}/
- Log the delivery in
indexes/events.jsonl
Envelope Schema (for drafting)
{
"message_id": "msg_{descriptive_id}",
"envelope_version": "1.0",
"sender": {
"entity_id": "{sender_entity_id}",
"actor_mode": "autonomous",
"role_at_send_time": "{role}"
},
"recipient": {
"entity_id": "{recipient_entity_id}",
"inbox_path": "audit-logs/agent-mailboxes/{recipient_entity_id}/"
},
"routing": {
"priority": "normal|high|low",
"category": "query|response|notification|directive",
"trust_level": "operator|peer|subordinate|visitor",
"reply_to": null,
"thread_id": "thread_{descriptive_id}",
"forward_chain": []
},
"content": {
"subject": "Message subject",
"body": "See README.md for full content.",
"artifact_refs": [],
"envelope_type": null
},
"lifecycle": {
"expires_at_tic": null,
"defer_until_tic": null,
"reminder_tic": null
},
"provenance": {
"source_tic": null,
"created_at": null,
"trace_id": null,
"session_id": null
}
}
Guard Rails
- Never archive without reading — every item must be read before it can be archived
- Never collapse responsibility — if an item requires a response, it cannot be archived until responded to
- Never delete — items are archived, never deleted. The inbox is append-only history.
- Respect expiry — expired items should be flagged but not auto-archived (the expiry is informational, not destructive)
- Thread coherence — when responding to a thread, include the
thread_id and reply_to fields so the conversation is traceable
- Registry is truth — if
indexes/inbox-registry.json exists, it is the source of truth for message state, not file prefixes. Update registry when moving files.
inbox-envelope.py — Programmatic API (single sovereign lane)
Lane consolidation (tic 384): there is now ONE mailbox-authority lane,
inbox-envelope.py (the filesystem-truth lane). The former SQLite lane
(scripts/inbox-query.py + inbox-index-builder.py) is DEPRECATED — its
binary index drifted to a stale snapshot and created a read/write split-brain.
Its useful algorithms (resurface, bare-file synthesis, search) were ported here
onto filesystem truth. Do not call inbox-query.py. The filesystem is the
source of truth; inbox-registry.json is a rebuildable cache.
The inbox-envelope.py script (at cgg-runtime/scripts/inbox-envelope.py in
canonical source, or ~/.claude/cgg-runtime/scripts/inbox-envelope.py at
runtime) provides programmatic inbox access. Prefer this over raw file scanning.
Resolve the script location:
ZONE_ROOT="${CLAUDE_PROJECT_DIR:-$(pwd)}"
while [ "$ZONE_ROOT" != "/" ] && [ ! -f "$ZONE_ROOT/.ticzone" ]; do ZONE_ROOT=$(dirname "$ZONE_ROOT"); done
INBOX=""
for candidate in \
"$ZONE_ROOT/canonical_developer/context-grapple-gun/cgg-runtime/scripts/inbox-envelope.py" \
"$HOME/.claude/cgg-runtime/scripts/inbox-envelope.py"; do
[ -f "$candidate" ] && INBOX="$candidate" && break
done
Key subcommands
| Subcommand | Use |
|---|
scan --entity ent_X [--format json|injection] [--current-tic N] | Inbox summary (counts + non-terminal items). Filesystem-truth: sees flat, directory (WAIT_<id>/envelope.json), and hand-dropped envelopes. |
sweep [--entity ent_X] --current-tic N | Reconcile hand-drops/dir envelopes into the registry and resurface due deferred reminders (DEFER→WAIT at reminder_tic). Authoritative catch runs every /cadence; run manually if needed. |
search --query "term" [--entity ent_X] [--include-terminal] | Filesystem-native content search (replaces SQLite FTS5). |
write --recipient ent_X --type T --subject ... --source-tic N [--body ...] | Deliver a flat envelope. |
claim --entity ent_X --message-id M --current-tic N | WAIT→ACTIVE |
complete --entity ent_X --message-id M --current-tic N [--result-ref ...] | ACTIVE→DONE |
defer --entity ent_X --message-id M --current-tic N --until-tic K | WAIT→DEFER with reminder at tic K (resurfaced by sweep) |
nack --entity ent_X --message-id M --current-tic N --reason ... | WAIT→NACK |
stale-check --current-tic N [--emit-signals] | Attention-debt sweep across all inboxes |
For /inbox and /inbox status, use inbox-envelope.py scan --entity {entity} --format injection --current-tic {tic} as the primary data source, falling back to raw file scanning only if the script is unavailable.
For /inbox process, use inbox-envelope.py scan --entity {entity} --format json --current-tic {tic} for structured data, then process items interactively.
Note — directory-envelope lifecycle: scan/search/sweep SEE directory
envelopes (WAIT_<id>/envelope.json, the deliver form), but the flat-file
lifecycle transitions (claim/complete/defer/nack) currently operate on
flat *.json envelopes only. Full directory-envelope lifecycle transitions are
a tracked follow-up.
Current Tic Discovery
Read audit-logs/tics/*.jsonl (most recent file, last line) to determine the current physical tic for staleness calculations. Or use the tic count from the session-start hook injection ([TIC: #N]).