airlock publish ships both to the same self-hosted store —
airlockd from the deploy bundle — where they become one
per-user record.
There is no third-party service in this path: events land in the Postgres
you operate.
No schema setup
The backend applies its own embedded migrations when it starts. There is no table to create and no SQL to run —docker compose up then
airlock publish is the whole setup.
Identity: login and API tokens
Publishing is authenticated and identity-bound:- Your admin creates your account in the console (Airlock’s own user table — no external IdP required).
airlock loginexchanges the backend URL, your email, and your password for an ingest-scoped API token, cached in~/.airlock/auth.json(mode0600). The backend stores only the token’s hash.- Every publish carries the token, and the server attributes each event to the token’s user. A batch claiming any other identity is rejected. A token cannot write someone else’s history, and an ingest token cannot read anyone’s timeline.
received_at beside each event’s
client-reported timestamp, so backdating is visible rather than silent.
What gets shipped
airlock publish collects two sources into the same event stream:
Sandbox transcripts — each user or assistant message in
~/.airlock/agent/claude/projects/<project>/<session>.jsonl becomes one event:
content is a readable flattening of the message. What the dashboard displays
and what detection scans:
- Text blocks are included as-is.
- Tool calls become
[tool_use <name> <first 200 chars of input>]. - Tool results become
[tool_result <first 300 chars>]. - Thinking blocks are omitted.
- The whole field is capped at 8,000 characters.
~/.airlock/logs/<repo>/audit-*.jsonl becomes one access event:
A third kind — decision events from agents running outside any sandbox —
arrives over the push API rather than through
publish,
and lands in the same store and timeline.
Together: the conversation in which a document was read, and the network
attempts the same session made.
Publish
1
Preview without sending
-n.2
Publish
airlock login first — without it, publish
stops with not logged in.3
Or stream continuously
-w. Ctrl-C to stop.Re-running is safe
Ingest is insert-only and idempotent: every event carries a per-source dedupe key, and an event already received is skipped, never rewritten. Publishing the same session twice produces no duplicates, and a re-publish cannot alter history. If a batch fails under--watch, that file’s checkpoint is left stale
deliberately, so the next tick retries it rather than skipping the events.
Credentials
Your identity lives in~/.airlock/auth.json (mode 0600), written by
airlock login: the backend URL and an ingest-scoped
API token. It stays on your host: publish uses it directly, it is never
injected into a sandbox, and the sandbox’s allowlist does not include the
backend — the agent being audited cannot reach its own audit trail. Connector
credentials stay separately in ~/.airlock/secrets.toml; see
configuration.
