> ## Documentation Index
> Fetch the complete documentation index at: https://docs.try-airlock.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Welcome

> What Airlock looks like running inside Polymarket.

<div id="airlock-x-polymarket" style={{ display: 'flex', alignItems: 'center', gap: '0.7rem', margin: '0.4rem 0 1.6rem' }}>
  <img src="https://mintcdn.com/airlock-3c3996d3/K1tOtXjSswUE_HoJ/images/airlock-wordmark-dark.png?fit=max&auto=format&n=K1tOtXjSswUE_HoJ&q=85&s=7dc9e4da532cb76fa5ee7a6899026e12" alt="Airlock" height="26" style={{ height: '26px', width: 'auto', margin: 0 }} className="block dark:hidden" noZoom data-path="images/airlock-wordmark-dark.png" />

  <img src="https://mintcdn.com/airlock-3c3996d3/K1tOtXjSswUE_HoJ/images/airlock-wordmark-light.png?fit=max&auto=format&n=K1tOtXjSswUE_HoJ&q=85&s=e1078e8b646fbc2c2ec58d0b3e6dd524" alt="Airlock" height="26" style={{ height: '26px', width: 'auto', margin: 0 }} className="hidden dark:block" noZoom data-path="images/airlock-wordmark-light.png" />

  <span style={{ opacity: 0.45, fontSize: '1.05rem' }}>×</span>

  <img src="https://mintcdn.com/airlock-3c3996d3/K1tOtXjSswUE_HoJ/images/polymarket-wordmark-dark.png?fit=max&auto=format&n=K1tOtXjSswUE_HoJ&q=85&s=d948031171422a7f02dc635cd740645f" alt="Polymarket" height="25" style={{ height: '25px', width: 'auto', margin: 0 }} className="block dark:hidden" noZoom data-path="images/polymarket-wordmark-dark.png" />

  <img src="https://mintcdn.com/airlock-3c3996d3/K1tOtXjSswUE_HoJ/images/polymarket-wordmark-light.png?fit=max&auto=format&n=K1tOtXjSswUE_HoJ&q=85&s=b12d040b5134ca48ae4856932722e102" alt="Polymarket" height="25" style={{ height: '25px', width: 'auto', margin: 0 }} className="hidden dark:block" noZoom data-path="images/polymarket-wordmark-light.png" />
</div>

The events, findings, and records your team would work from.
Feel free to peruse the other docs as well for insight into what Airlock can offer out-of-the-box.

<Note>
  Airlock deploys **observe-first**: nothing below blocks an agent or gates an
  engineer on day one. Enforcement is a dial
  you turn once the data has earned it — with one deliberate exception:
  fund-moving actions pass the [resolution guard](#resolution-you-can-replay)
  from day one, because that boundary is where observation alone is not enough.
</Note>

## One event shape, every actor resolved

Airlock's unit of record: **an identity reached a resource, through a tool, on
someone's behalf**. Humans, managed agents, and your in-house agents all land
in the same store, in the same shape.

<Tabs>
  <Tab title="An agent reaches the network">
    ```json theme={null}
    {
      "kind":       "access",
      "user_id":    "u-design-14",          // whoever the session runs as
      "agent_session_id": "a41c9f02",
      "host":       "internal-kb.polymarket.com",
      "method":     "CONNECT",
      "allowed":    true,
      "bytes_received": 48211,
      "duration_ms": 402,
      "occurred_at": "2026-07-30T14:02:11Z"
    }
    ```
  </Tab>

  <Tab title="An agent retrieves a memo">
    ```json theme={null}
    {
      "kind":       "chat",
      "user_id":    "u-design-14",          // the human the agent acts for
      "agent_session_id": "a41c9f02",
      "event_type": "tool_result",
      "content":    "Case SEC-4471 — …subject resides at 4██ ██████ St, phone +1 (███) ███-████…",
      "occurred_at": "2026-07-30T14:02:39Z"
    }
    ```
  </Tab>

  <Tab title="Your resolver reports a decision">
    ```bash theme={null}
    # An agent outside any sandbox reports what it concluded — one authenticated POST.
    curl -X POST https://airlock.internal:4747/api/v1/events \
      -H "Authorization: Bearer $AIRLOCK_TOKEN" \
      -d '{"events":[{"kind":"decision","dedupe_key":"res-8821-001",
           "agent_session_id":"res-8821",
           "target":"will-the-senate-confirm-the-next-fed-chair-before-oct-1",
           "decision":"YES","confidence":0.97,
           "sources":[{"url":"https://apnews.com/article/…",
                       "quote":"The Senate voted 68–29 on Tuesday to confirm…"}],
           "occurred_at":"2026-07-30T15:16:02Z"}]}'
    ```
  </Tab>
</Tabs>

Every token is bound server-side to one identity — a person's CLI login or a
named agent like `market-resolver-7` — so an event claiming anyone else is
rejected, and every row carries a server-assigned `received_at` so backdating
is visible. An agent session is never just "the bot": the record names who it
acted for. The full push contract is one page:
[decision events](/decision-events).

## The over-broad answer, after the fact

Consolidated knowledge means an agent can assemble an answer its requester was
never cleared to see — the second event above already carried PII from an
active case. Airlock does not block that request; it makes it reviewable
within seconds of happening.

```mermaid theme={null}
flowchart LR
    A["u-design-14 asks<br/>internal agent"] --> B["agent searches<br/>knowledge base"]
    B --> C["returns case notes"]
    C --> D["event captured:<br/>user · session · content"]
    D --> E["Josep filters the console<br/>by user or session"]
```

What Josep opens is the session itself: the prompt, the documents the agent
reached, the content it returned, and the person the session ran as. The
conversation with the requester starts from a verbatim record rather than an
accusation.

<Note>
  Content-based alerting on access events isn't built — access is logged in
  enough detail to catch this on review, not to interrupt it. Alerting today
  is limited to [agent decisions](/exposure). Which of these should fire
  automatically, and on what, is exactly what a design partner would shape.
</Note>

## Resolution you can replay

The highest-stakes agent decision in the building: evaluate a real-world
event, and funds move, across more markets than any human team can
hand-check. The claim: **no fund-moving action executes unless its stated
evidence independently verifies against the market's declared resolution
source.** Claims verified against sources.

A **resolution guard** wraps the propose step. The resolver drafts an
outcome with cited evidence; the guard independently re-fetches what was
cited, runs its checks, and emits **ALLOW** or **HOLD** — only an ALLOW lets
the separate submission backend run. Alongside it, every market produces a
**resolution evidence record**, assembled *before* an outcome goes anywhere
near the oracle:

```mermaid theme={null}
%%{init: {"sequence": {"messageAlign": "left", "actorMargin": 190}}}%%
sequenceDiagram
    participant R as resolver-07
    participant X as egress proxy
    participant G as resolution guard
    participant M as Marc (reviewer)
    participant U as UMA Optimistic Oracle
    R->>X: GET apnews.com/…<br/>· reuters.com/…
    X-->>R: 200 · captured + hashed
    R->>X: GET x.com/…
    X--xR: 403 DENY — not a<br/>declared source (logged)
    R->>G: proposal YES +<br/>cited evidence
    G->>X: independently re-fetch<br/>every cited URL
    X-->>G: sources state YES —<br/>claims match
    Note over G: declared-source · re-fetch compare ·<br/>price sanity · dispute state — all pass
    Note over G,M: notional $2.3M ≥ gate → human signs
    M->>G: disposition: approved<br/>(34s review)
    G->>U: ALLOW → backend<br/>proposes · bond posted
    Note over U: liveness window —<br/>open to dispute
    U-->>G: undisputed →<br/>market settles
```

The record that gate produces — and the reply to any challenge raised in the
oracle's dispute window:

<Accordion title="resolution record RES-2026-0730-114 · complete">
  ```json theme={null}
  {
    "market":       "will-the-senate-confirm-the-next-fed-chair-before-oct-1",
    "notional_usd": 2300000,
    "outcome":      "YES",
    "session":      "res-8821",
    "agent":        "resolver-07",
    "acts_for":     "u-marketops-2",
    "sources": [
      { "url": "apnews.com/article/…",  "fetched": "15:11:04Z",
        "quote": "The Senate voted 68–29 on Tuesday to confirm…", "sha256": "9c41e8aa…" },
      { "url": "reuters.com/world/us/…", "fetched": "15:11:31Z",
        "quote": "…was sworn in Wednesday morning…",              "sha256": "b07d3f21…" }
    ],
    "denied_attempts": [
      { "host": "x.com", "ts": "15:12:02Z", "verdict": "not on resolution-source allowlist" }
    ],
    "checks": {
      "declared_source": "pass",
      "refetch_compare": "match — sources state YES",
      "corroboration":   "2/2 independent",
      "price_sanity":    "pass — YES last $0.97",
      "dispute_state":   "none",
      "decision":        "ALLOW"
    },
    "review": {
      "gate":        "notional ≥ $1,000,000",
      "reviewer":    "u-marc",
      "disposition": "approved",
      "ts":          "15:14:47Z"
    },
    "oracle": {
      "protocol":    "uma-optimistic-oracle",
      "proposed_at": "15:16:02Z",
      "status":      "settled-undisputed"
    },
    "record_sha256": "4e77aa0c…"
  }
  ```
</Accordion>

### What holds a proposal

Every check is a deterministic comparison against a source, a price, a
number, or a status. This means that every HOLD arrives with a specific,
auditable reason. All checks always run, and a proposal citing no evidence holds
automatically:

| Check                    | Verifies, mechanically                                                                                                                                                          | Catches                                         |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| **Declared source**      | Every cited URL belongs to a resolution source the market's own rules declare — exact host match, path prefix at segment boundaries (`apnews.com.evil.net` is not `apnews.com`) | Look-alike domains, out-of-scope citations      |
| **Independent re-fetch** | The guard re-fetches each cited URL itself and parses the source's declared structure — the agent's reading is never trusted                                                    | Prompt-injected misreadings, fabricated quotes  |
| **Claim ↔ source**       | The value the proposal claims is the value the source states                                                                                                                    | The mismatch that moves funds to the wrong side |
| **Corroboration**        | Where the rules name multiple sources, at least two independent ones agree                                                                                                      | Single-source error, stale pages                |
| **Price sanity**         | The proposed side is not priced out by the market itself                                                                                                                        | Proposing YES on a market trading it at \$0.02  |
| **Dispute state**        | The oracle status carries no open dispute                                                                                                                                       | Auto-proposing into a contest already underway  |
| **Notional gate**        | Above your threshold, a human disposition is required regardless of every other pass                                                                                            | The million-dollar mistake                      |

<Tip>
  A realistic example of a failure this can catch: a resolution page whose **prose**
  carries an injected "notice to automated readers" claiming the table is
  stale and the other side won. A resolver that trusts prose proposes the
  wrong outcome. The guard, which never interprets prose, re-fetches the
  page, parses the declared table structure, and holds the claim/source
  mismatch. Ask us to run this one live.
</Tip>

The source of truth is not vendor-chosen. **The market's own rules text
declares its resolution source**, and the guard's source set derives from it
(per-category defaults cover markets whose rules name none). The network
enforces the same list during resolution — the `403 DENY` above — so an
unapproved input does not quietly influence decisions.

**Model output can classify, never authorize.** Anything model-scored runs after the decision is final and
lands as an advisory. Every evaluation is appended to the audit log before
any backend runs.

Every ingested decision is [checked as it arrives](/exposure#decision-flags) — no sources cited, low or
missing confidence, or two decisions on the same market that disagree — and
flagged ones reach the [review queue](/dashboard#the-flags-queue) before the
ingest request returns. Running two independent resolvers on the same markets
and letting `disagreement` catch the deltas costs nothing and shares no
failure mode.

### The oracle clock is the deadline

Say that settlement runs through UMA's optimistic oracle: an outcome is proposed with
a bond behind it, and the dispute clock might run in **hours**. That
window is why the record exists *before* the proposal — when a challenge
lands, "stand or concede" is answered by reading the record rather than
re-running the investigation against the clock. It works in reverse too: an
externally proposed outcome that contradicts your agent's evidence is a
**divergence finding**, so the decision to dispute arrives documented.

<Note>
  Smart-contract risk is the code-review and audit lane; the guard's lane is
  the agent layer above the contracts.
</Note>

## The deny log is the exfil story

For agents near sensitive infrastructure, observation isn't enough.
Agents in Airlock's runtime sit on a network whose
only route out is the proxy. Repos handling sensitive systems run it
allowlist-first; ordinary development can run it as a blocklist so nobody
waits on a policy edit, and the record is identical either way. This is what
a prompt-injected exfiltration attempt looks like from the outside:

```json theme={null}
{"ts":"2026-07-30T16:40:12Z","user_id":"u-eng-31","repo":"payments-service","host":"api.anthropic.com","method":"CONNECT","allowed":true,"bytes_sent":18204,"bytes_recv":91544,"duration_ms":2311}
{"ts":"2026-07-30T16:40:19Z","user_id":"u-eng-31","repo":"payments-service","host":"paste.debian.net","method":"CONNECT","allowed":false,"duration_ms":0}
```

One allowed model call, one denied paste-site attempt. Everything is attributed,
timestamped, and in the store, with byte counts on everything
allowed. A process that ignores proxy settings fares no better: the network
it is on has nowhere else to go.

## Where it sits

```mermaid theme={null}
flowchart LR
    subgraph VPC["Your VPC — nothing content-bearing leaves"]
      direction LR
      S1["Agent runtime<br/>(sandbox + proxy)"] --> ID["Identity<br/>resolver"]
      S2["SaaS audit<br/>connectors"] --> ID
      S3["Custom agents<br/>→ ingest API"] --> ID
      ID --> ST[("Postgres<br/>events · flags")]
      ST --> DET["Detection<br/>flagging · guard checks"]
      DET --> ST
      ST --> CON["Console<br/>Josep · Marc · Ali"]
    end
    DET -. "guard re-fetches declared sources —<br/>no internal content outbound" .-> SRC["Public sources<br/>(named allowlist)"]
```

Endpoint and network tooling watches machines. An agent assembling an answer
from eleven internal documents on someone's behalf is invisible to endpoint
telemetry and ordinary as traffic — that layer is this product. It
complements your stack rather than replacing it (events export cleanly to a
SIEM).

<CardGroup cols={2}>
  <Card title="Self-hosted, verifiable" icon="server">
    Runs in your VPC. No vendor telemetry, license checks offline, and the
    backend's own egress is an enumerated list you can read — with a live deny
    log to prove it.
  </Card>

  <Card title="Evidence-grade by default" icon="file-shield">
    Insert-only history, server-assigned timestamps, hash-sealed captures,
    legal holds, append-only export into your existing archive.
  </Card>
</CardGroup>

## A pilot, visualized

<Steps>
  <Step title="Week one — onboard">
    Bundle in your VPC, team enrolled, in-house agents emitting to ingest (we
    pair on the integration; it is the POST above). No enforcement, no
    workflow changes. Your first artifact is the coverage report resolving every
    enrolled identity, and which ones are producing **no** record.
  </Step>

  <Step title="Week two — watch">
    Point your resolution agents at the ingest API. Decision flags start
    arriving with their evidence; your team evaluates them and tells us
    what is noise. Interface with other Airlock features (exfil prevention, proxy, etc).
  </Step>

  <Step title="Data review">
    The record is the evaluation — what we caught, what we missed, what we
    should watch next.
  </Step>
</Steps>

Working with us during the pilot means a shared channel with the founders,
incident-responsive support, and ASAP delivery dates. You have first priority
in what features ought to be built next.

Ready to scope it: **[mrenaaljain@berkeley.edu](mailto:mrenaaljain@berkeley.edu)**, **[ronit.kapur@duke.edu](mailto:ronit.kapur@duke.edu)**, **[nalinn2@illinois.edu](mailto:nalinn2@illinois.edu)**
