Skip to main content
The comis trace command is your one-stop tool for going from a user complaint to a diagnostic bundle. Five subcommands cover every correlation pattern: search by messageId, search by traceId, live-tail a chat, scan failures by time, and export a bundle.
The comis CLI is not on PATH by default. All invocations on this page use the canonical form:
node packages/cli/dist/cli.js trace ...
If you’ve aliased comis to that path, the shorter form works too.

Subcommands at a Glance

SubcommandUse caseRPC
--message-id <uuid>A user said “my message didn’t get a reply” and quoted the messageIdobs.trace.search
--trace-id <uuid>You have a traceId from a log line and want the full causal chainobs.trace.search
--chat <id> --tailWatch a chat live while debugging an active issueobs.trace.tail
--since <dur> --where <filter>”Show me failures in the last 10 minutes”obs.trace.search
export <sessionId>Produce a self-contained bundle for engineer handoffobs.trace.export
All subcommands support --json for machine-readable output.

--message-id <uuid>

Search for all trace events associated with a specific inbound message. Use this when a user can give you the messageId from their chat — it’s the fastest path from complaint to trace.
node packages/cli/dist/cli.js trace --message-id 7f6a4b2c-9e3d-4a1b-8c7e-5d9f3e2a1b4c
Returns the channel → queue → agent → delivery row sequence for that message. On a 100-turn session the result is available in under 2 seconds (LRU O(1) lookup, falling back to a bounded 2-day session-index scan on miss).

Default (human-readable) output

ts                          event              sessionId   traceId
2026-05-24T07:46:21.899Z    channel.inbound    a1b2c3d4    74db9c8d-...
2026-05-24T07:46:21.901Z    queue.enqueued     a1b2c3d4    74db9c8d-...
2026-05-24T07:46:21.980Z    execution.started  a1b2c3d4    74db9c8d-...
2026-05-24T07:46:24.112Z    execution.complete a1b2c3d4    74db9c8d-...
2026-05-24T07:46:24.201Z    delivery.sent      a1b2c3d4    74db9c8d-...

JSON mode

node packages/cli/dist/cli.js trace --message-id 7f6a4b2c-9e3d-4a1b-8c7e-5d9f3e2a1b4c --json
Returns:
{
  "rows": [
    { "ts": "2026-05-24T07:46:21.899Z", "event": "channel.inbound", "sessionId": "a1b2c3d4", "traceId": "74db9c8d-..." },
    { "ts": "2026-05-24T07:46:21.901Z", "event": "queue.enqueued",  "sessionId": "a1b2c3d4", "traceId": "74db9c8d-..." }
  ]
}

--trace-id <uuid>

Search all log and trajectory events by traceId. Use this when you’ve found a traceId in a log line and want the full causal chain across the channel / queue / agent / delivery stages.
node packages/cli/dist/cli.js trace --trace-id 74db9c8d-4f2a-4b3c-9e1d-8a7f6e5d4c3b
Returns every row sharing the traceId. The traceId is injected via AsyncLocalStorage for the entire request lifecycle, so all events from inbound parse through final delivery share the same value — including error events and retry attempts.

JSON mode

node packages/cli/dist/cli.js trace --trace-id 74db9c8d-4f2a-4b3c-9e1d-8a7f6e5d4c3b --json
Same {"rows": [...]} structure as --message-id --json.

--chat <chatId> --tail

Stream trace events live for a specific chat. Use this when a user reports an issue while it’s happening — open a terminal, start --tail on their chat, and watch the next message in real time.
node packages/cli/dist/cli.js trace --chat -1001234567890 --tail
Polls the obs.trace.tail RPC approximately every second. Press Ctrl+C to exit cleanly (handled via AbortController; the connection closes gracefully).
--tail requires --chat. Running --tail without specifying a chat exits immediately with: --tail requires --chat <chatId>

Tail output (human-readable)

Three space-separated fields per line:
2026-05-24T07:46:21.899Z    channel.inbound    a1b2c3d4
2026-05-24T07:46:21.901Z    queue.enqueued     a1b2c3d4
2026-05-24T07:46:21.980Z    execution.started  a1b2c3d4

JSON tail mode (NDJSON)

Emits one JSON object per line (newline-delimited JSON). Suitable for piping into jq or another consumer:
node packages/cli/dist/cli.js trace --chat -1001234567890 --tail --json | jq 'select(.event | startswith("queue."))'
Each line is a JSON object with the same shape as a rows[] entry.

--since <dur> --where <filter>

Scan the session index for recent failures. Use this when you need a quick overview of what went wrong in the last N minutes across all chats.
node packages/cli/dist/cli.js trace --since 10m --where error
The --since argument accepts duration suffixes: 10m, 1h, 2d. The --where argument is a filter expression — error matches sessions that have a non-null lastError in the session index.

Common queries

# Failures in the last 10 minutes (across all chats)
node packages/cli/dist/cli.js trace --since 10m --where error

# All sessions in the last hour
node packages/cli/dist/cli.js trace --since 1h

# Machine-readable list of failed sessionIds
node packages/cli/dist/cli.js trace --since 10m --where error --json | jq '.rows[].sessionId' | sort -u

JSON mode

node packages/cli/dist/cli.js trace --since 10m --where error --json
Returns {"rows": [...]} with the same 4-field shape (ts, event, sessionId, traceId).

export <sessionId>

Export a self-contained diagnostic bundle for a session. Invokes the bundle pipeline, applies platform-aware-v1 redaction, and prints the bundle directory path.
node packages/cli/dist/cli.js trace export 7a9b1c2d-3e4f-5a6b-7c8d-9e0f1a2b3c4d
Output:
Bundle written to: /workspace/.comis/trace-exports/comis-trace-7a9b1c2d-20260525T074621Z/

JSON mode

node packages/cli/dist/cli.js trace export <sessionId> --json
Returns:
{"bundlePath": "/workspace/.comis/trace-exports/comis-trace-7a9b1c2d-20260525T074621Z/"}
JSON mode is useful in scripts:
BUNDLE=$(node packages/cli/dist/cli.js trace export <sessionId> --json | jq -r '.bundlePath')
tar czf bundle.tar.gz -C "$(dirname "$BUNDLE")" "$(basename "$BUNDLE")"
Full bundle export documentation — 8-file shape, hard limits, redaction policy, /export-trajectory slash command — is at Incident Bundle.

Output Format Reference

Human-readable — search modes (--message-id, --trace-id, --since/--where)

Four-column space-padded table. Column widths auto-fit content:
ts                          event              sessionId   traceId
2026-05-24T07:46:21.899Z    channel.inbound    a1b2c3d4    74db9c8d-...
Fields: ts (ISO 8601), event (dot-notation event name), sessionId (first 8 chars of UUID), traceId (full UUID).

Human-readable — tail mode (--chat --tail)

Three space-separated fields per line:
2026-05-24T07:46:21.899Z    channel.inbound    a1b2c3d4

Human-readable — export mode

Single line:
Bundle written to: <path>

JSON — search modes

{
  "rows": [
    {
      "ts": "2026-05-24T07:46:21.899Z",
      "event": "channel.inbound",
      "sessionId": "a1b2c3d4-...",
      "traceId": "74db9c8d-..."
    }
  ]
}

JSON — tail mode (NDJSON)

One JSON object per line. Each object has the same shape as a rows[] entry:
{"ts":"2026-05-24T07:46:21.899Z","event":"channel.inbound","sessionId":"a1b2c3d4","traceId":"74db9c8d-..."}
{"ts":"2026-05-24T07:46:21.901Z","event":"queue.enqueued","sessionId":"a1b2c3d4","traceId":"74db9c8d-..."}
The tail RPC also returns a nextSinceMs cursor internally (used by the polling loop); it is not surfaced in the per-line JSON objects.

JSON — export mode

{"bundlePath": "/workspace/.comis/trace-exports/comis-trace-a1b2c3d4-20260525T074621Z/"}

Worked Example — User Complaint to Bundle in 3 Commands

A user reports: “I asked the bot a question 10 minutes ago and it never replied.”
The acceptance gate — under 5 minutes from complaint to bundle. Command 1 — Find sessions with recent errors:
node packages/cli/dist/cli.js trace --since 10m --where error --json | jq '.rows[].sessionId' | sort -u
Output: a list of distinct sessionIds with errors in the last 10 minutes. Pick the one that matches the user’s chat (you can cross-reference channelType in the session-index JSONL if needed). Command 2 — Verify the failure mode:
node packages/cli/dist/cli.js trace --message-id <messageId-from-user>
Output: channel / queue / agent / delivery rows for that exact message. Look for:
  • Missing delivery rows — execution completed but delivery failed
  • Retry events — message was retried (check for queue.retry events)
  • Dedup events — message was seen before (dedup.duplicate_inbound)
  • Execution absent — message enqueued but no execution.started (queue stall or gate rejection)
Command 3 — Export the bundle:
node packages/cli/dist/cli.js trace export <sessionId>
Output: Bundle written to: <path>. Compress, share with engineer per Incident Bundle. Three commands. Under 5 minutes from complaint to bundle. This is the acceptance gate.

Performance Bounds

SubcommandBound
--message-idUnder 2 s on a 100-turn session (LRU O(1) + bounded 2-day index scan on miss)
--trace-idUnder 2 s (same backend as --message-id)
--chat --tail~1 s poll cadence; events appear within 1–2 polls of bus emission
--since --whereBounded by session index size (2-day scan window)
exportBounded by bundle pipeline; refuses sessions exceeding 50 MB
The backend uses an LRU bounded at 1024 entries for messageId lookups, falling back to a 2-day session-index scan on miss. The LRU starts cold on daemon restart — if a restart just happened, --message-id may return empty rows for messages processed before the restart. Use --since <dur> --where error as a fallback in that case.

Incident Bundle

Bundle export workflow — 8-file shape, hard limits, redaction policy, and the /export-trajectory slash command.

Observability

Bridge mapping, lifecycle envelopes, INFO promotions, and the dedup detector.

Logging

Log levels, field dictionary, and log rotation policy.

Daemon

The process that serves the RPCs — startup, shutdown, and configuration.