chitra · docs

DocsDaemons & ToolsDelivery

dispatchd — Delivery Daemon

Dispatchd is chitra's always-on delivery engine. It drains a JSON order queue, delivers messages to tmux sessions, and logs each delivery to a signed ledger.

What it does

On each pass:

  1. Reclaim stale in-flight orders (if an order failed halfway through, restart it).
  2. Read orders from the queue in FIFO order (sorted by file modification time).
  3. For each order:
    • Check if a result file already exists. If yes, skip (idempotent).
    • Verify the target session exists and is in scope.
    • Acquire an exclusive file lock (LaneLock) for that session.
    • Check the rate-limit freeze status. If the session is paused, defer the order.
    • Paste the message text into the tmux session via tmux load-buffer and tmux paste-buffer.
    • Verify delivery by grepping the session's transcript for the exact text.
    • Write a result file and sign a ledger entry.

Dispatchd is single-threaded per session. The LaneLock prevents two writers from racing. It is idempotent: once a result file exists, the order is never redelivered, even across a restart. It is crash-safe: if a crash happens between paste and ledger write, the send-nonce marker plus transcript-grep check reconcile the state on the next run.

CLI usage

dispatchd \
  --queue-dir /var/lib/chitra/queue \
  --ledger-path /var/lib/chitra/ledger.jsonl \
  --state-dir /var/lib/chitra \
  --poll-seconds 5 \
  --once

Run with --once for a single pass (used in cron/systemd timer). Omit it to run continuously.

Key flags

Flag Default Notes
--queue-dir $CHITRA_STATE_DIR/queue Order queue directory.
--ledger-path $CHITRA_STATE_DIR/ledger.jsonl Append-only ledger file.
--state-dir /var/lib/chitra Base state directory.
--lock-dir $CHITRA_STATE_DIR/locks Directory for LaneLock files.
--routing-config-path Unset Optional routing config (YAML).
--policy-config-path Unset Optional policy config (YAML).
--allow-session-prefix All allowed Allowlist of session name prefixes to deliver to.
--deny-session-prefix None Denylist of session name prefixes.
--post-paste-wait-seconds 0.5 Time to wait after paste before transcript grep.
--transcript-recency-seconds 60 How fresh the transcript copy must be.
--poll-seconds 5 Seconds between passes (if running continuously).
--once False Run one pass and exit.

Environment variables

Variable Default Notes
CHITRA_STATE_DIR /var/lib/chitra Base directory for queue, ledger, locks.
CHITRA_LANE_LOCK_DIR $CHITRA_STATE_DIR/locks Directory for lock files.
CHITRA_ROUTING_CONFIG Unset Path to routing config.
CHITRA_POLICY_CONFIG Unset Path to policy config.
CHITRA_ALLOWED_SESSION_PREFIXES All allowed Comma-separated allowlist.
CHITRA_DENIED_SESSION_PREFIXES None Comma-separated denylist.

Order and result format

Order (JSON):

{
  "order_id": "task-123",
  "lane_id": "session-name",
  "text": "command to send",
  "task_type": "optional routing key",
  "routing_hint": "optional explicit hint"
}

Result (JSON):

{
  "order_id": "task-123",
  "lane_id": "session-name",
  "status": "sent",
  "delivery_timestamp": "2025-01-15T12:34:56Z",
  "nonce": "send-nonce-value"
}

Common tasks

Deliver a single message:

cat > /var/lib/chitra/queue/msg-001.json << 'EOF'
{
  "order_id": "msg-001",
  "lane_id": "my-session",
  "text": "echo 'Hello'"
}
EOF

dispatchd --queue-dir /var/lib/chitra/queue --once

Run as a systemd service (continuous):

See packaging/systemd/chitra-dispatchd.service.example in the repo.

Check delivered messages:

# View ledger
cat /var/lib/chitra/ledger.jsonl | jq .

# Verify a specific delivery (requires ledger signing key)
python -c "from chitra.ledger import verify_delivery; verify_delivery(ledger_path, order_id, signing_key)"

Reliability guarantees

  • Atomicity: Each delivery acquires a lock, completes, and releases it. No partial deliveries.
  • Durability: Ledger entries are HMAC-signed and appended. Crash-safe.
  • Idempotency: Once a result file exists, the order is never redelivered.
  • Single-writer: LaneLock prevents concurrent writes to the same session.