United barred unauthorized AI booking agents. I built a gate that asks one question first.

On 11 November 2026, United Airlines said it will bar unauthorized third-party AI agents from booking, changing, or buying tickets on its site and app, and through travel agencies and aggregators (CBS News, 11 November 2026; Skift, 11 November 2026; PhocusWire, 11 November 2026). Bookings made before that date will still be honored. Agents may still show flights and prices. The stated reasons: personal-data risk, transactions against the customer's intent (unintended purchases, account changes, MileagePlus miles use), and federal-rule risk (an agent checking in luggage without the passenger confirming in person that it holds no prohibited items). Per Skift, United is the first large US carrier to say this explicitly.

The technical detail is not the interesting part. The interesting part is the question underneath it: an agent that can book a flight is not an agent that may book a flight. Capability is not authority. And right now, most agent setups answer the capability question with a tool call and never answer the authority question at all.

I built a small tool that answers the authority question, deterministically, before the action runs. It is called deleguard, and it is a zero-dependency TypeScript CLI. MIT licensed. No server, no database, no API key, no cloud account.

What it does

deleguard is a pre-execution authorization gate for agent actions. You give it a policy and an action, and it answers one question: is this exact action delegated, in scope, within limits, and approved?

It checks, in order:

  • Delegation chain. Every hop from the principal to the acting agent must have a grant. A sub-agent acting without a grant is DENY. No implicit inheritance.
  • Scope. The tool must be granted on every hop, and each child grant must be a subset of its parent: tools, max amount, currency, merchants, data classes, expiry. A child can only narrow authority, never widen it.
  • Limits. A money tool without an amount is DENY (never assume 0). The amount must match the grant currency and fit every max amount. Merchants match by exact host: kayak.com is not united.com, and neither is www.united.com.
  • Exact-action approval. An amount above a grant's approval threshold needs a human approval, bound to the sha256 of the exact action. A generic user_confirmed: true flag is ignored: it is not an approval. Approvals expire (15 minutes by default) and are single-use, enforced by scanning the audit log.

The answer comes back as an exit code a shell or CI step can use directly: 0 = ALLOW, 1 = DENY, 2 = NEEDS-APPROVAL or POLICY_ERROR. A malformed policy fails closed. Anything not explicitly permitted is DENY, with the failing rule named.

deleguard init # exit 0 - writes deleguard.json + example actions deleguard check --policy deleguard.json --action examples/actions/search.json # VERDICT ALLOW, exit 0 deleguard check --policy deleguard.json --action examples/actions/book.json # VERDICT NEEDS-APPROVAL, exit 2 deleguard approve --policy deleguard.json --action examples/actions/book.json \ --by alice --out examples/approvals/appr-1.json # approval bound to the sha256 of the exact action, 15-minute default expiry deleguard check --policy deleguard.json --action examples/actions/book.json \ --approval examples/approvals/appr-1.json --log deleguard-audit.jsonl # VERDICT ALLOW, exit 0 - the decision is appended to the audit log deleguard verify --log deleguard-audit.jsonl # verify OK, exit 0 

The worked example in the README is real CLI output, not a mockup: booking $900 against a $500 limit returns VERDICT DENY, policy e1b4be1df043, action 91971f65c825, exit 1. The fixture is synthetic (Alice, the $500 limit, and the $450 / $900 amounts are invented to show the decision rules), and the README says so.

The hook demo: gating a real action, end to end

Answering is not enforcing. check answers; the hook in examples/hook/ enforces the answer for a scripted agent. It runs a real command ONLY on ALLOW (exit 0). The demo agent wants to book a $450 flight and may only act through the hook:

bash examples/hook/run-agent.sh # attempt 1, no approval: NEEDS-APPROVAL blocks the booking write # human approves the exact action; attempt 2: ALLOW writes the file # attempt 3, same approval reused: DENY (single-use) blocks the write 

The "booking" is a local file write, a stub for a booking command. No money moves, no network call, no real agent account. But the gate is real: on DENY and NEEDS-APPROVAL the gated command never starts, and the file is the witness. The hook behavior is asserted in the test suite (48/48 tests pass, including a hook-gating e2e test), so it is proved by CI on every push, not just by the demo script.

Time to first gated action, measured on 12 November 2026 from a source checkout: about 5 seconds of command time (npm install + build 4.0 s, hook demo 0.9 s), excluding the time to read the docs. deleguard is faster to a first gated action because it does less: no crypto, no proof-of-possession, no enforcement at a tool boundary, no MCP server. That trade is the whole point, and it is also the honest limit. More on that below.

Install (from source only)

The npm package is not published yet. Install from source:

git clone https://github.com/techdevfun/deleguard.git cd deleguard npm install npm run build npm link # makes `deleguard` available on your PATH 

Requires Node.js 20 or newer. Zero runtime dependencies. A clean install from source was timed at about 4 seconds on this machine. One decision (in-process, 1,000 evals) runs at median 0.014 ms, p95 0.044 ms. Run npm run bench to reproduce.

Where the rivals beat us

Honesty first: deleguard is the smallest tool in its neighborhood, and the bigger ones are better at the things they do.

  • tenuo (tenuo-ai/tenuo, 106 stars, v0.2) is a real delegation system: cryptographic warrants, subtractive delegation across hops, proof-of-possession, signed evidence, Rust/Python/TypeScript SDKs, MCP/A2A/HTTP enforcement. deleguard has no cryptography and no proof-of-possession: it trusts the caller-supplied identity and only decides.
  • Agent_Sudo (Kisyntra/Agent_Sudo, 5 stars) is an authorization, delegation, provenance, and verifiable-audit engine with an MCP adapter that enforces decisions at the tool boundary and catches prompt-injection by instruction provenance. deleguard does not enforce anything and does not track provenance.
  • DeleGuard (juliansprt/DeleGuard, 1 star) is a .NET 10 + PostgreSQL platform with an HTTP API, YAML policies, a console, and permits. deleguard is a single zero-dependency CLI with no server and no database.
  • AWS Bedrock AgentCore Policy (Cedar) gives deterministic Cedar policies with formal analysis tooling and managed scale. deleguard's JSON policy is less expressive and has no symbolic analysis; complex policies belong in Cedar or OPA.

Both tenuo and Agent_Sudo document their own evaluation paths as 5 minutes. deleguard's ~5 seconds is measured, theirs is their own documented label; I did not re-time their paths. The comparison is fair only if you also say why: deleguard is faster because it does less.

Honest limits

  • It decides; it does not enforce. There is no interception, proxy, sandbox, or credential brokering. A verdict is only as strong as the harness that respects it. A harness that ignores the exit code gets nothing from deleguard.
  • Identity is a trust assumption, not a feature. deleguard trusts the caller-supplied principal and agent names. It does not authenticate anyone. The harness must bind identity before calling deleguard.
  • Single-use approvals rely on the audit log. Reuse is detected by scanning the log file passed with --log at check time. Without --log, reuse cannot be checked at all: check then prints a stderr warning when --approval is used without --log, and the verdict is unchanged (ALLOW stays ALLOW). If the operator deletes the log, reuse becomes possible; verify reports the sequence gap, and the log must be kept append-only.
  • The audit chain is tamper-evidence, not tamper-proof. The log is a local file. Anyone who can rewrite the whole file can rebuild the chain.
  • The demo agent is scripted, not model-driven. The hook gates a real command through a real shell exit-code gate, but the agent is a deterministic script and the booking is a local stub. No LLM-driven agent and no production harness has been gated yet. Gating a real model-driven agent (for example a Claude Code PreToolUse hook) is the next step.
  • No bypass, ever. deleguard is a compliance tool: it helps a principal enforce their own policy and helps an operator respect a vendor's rules. It has no scraping, no browser automation, and no feature that works around a vendor's ban or terms of service. The United story is a news hook, not a partnership: deleguard has no relationship with United Airlines.

Why this shape

The agent world is splitting into two camps: platforms that enforce everything at a boundary (tenuo, Agent_Sudo, AgentCore) and nothing at all. deleguard is for the gap between them: a principal who wants a human-readable JSON policy in git, a deterministic answer before an action runs, and an exit code a shell hook can act on, without standing up a server, a database, or a key-management story.

If you need enforcement, provenance, or crypto, pick a rival. The README says so, and means it. If you need the smallest possible answer to "is this exact action authorized?", try deleguard:

github.com/techdevfun/deleguard

Feedback welcome in the repo issues. The roadmap (generic webhook on DENY, MCP gateway adapter, Cedar/Rego import) is in the README.