# Architecture overview

## How Keychains works.

Your agent gets the access. Never the keys.

### Step 1

## Drop-in replacement

Use `keychains curl` as a drop-in replacement for `curl`, or the Keychains SDK as a drop-in replacement for your favorite HTTP library (`fetch` for Node.js, `requests` for Python, etc).

The only difference: replace any hard-coded credentials with a template variable.

#### Template variables

- `{{OAUTH*_TOKEN}}` OAuth1 and OAuth2 access/refresh/request token (provider auto-detected from URL)
- `{{ANY_NAME}}` Any non-OAUTH\* string is treated as an API key name (e.g. {{STRIPE_PRIVATE_KEY}})

### Example Usage

Before — plain curl

```bash
$ curl https://api.github.com/user/repos \
 -H "Authorization: Bearer ghp_R3aLs3cR3tT0k3n..."
```

After — keychains curl

```bash
$keychains curl https://api.github.com/user/repos \
 -H "Authorization: Bearer {{GITHUB_TOKEN}}"
```

No secrets in code — credentials injected server-side.

### Permission Request

from "research-agent"

Gmail  
Read emails  
gmail::readonly

Notion  
Create pages  
notion::write

Approve  
Deny

### Step 2

## User authorizes the action

When your agent runs the request, if the required credentials haven't been authorized yet, Keychains returns a 403 with an authorization URL. Forward this URL to the user — they see exactly what access is being requested and approve with one click.

- User sees the agent name, the APIs, and the exact scope  
- One-click approval — no OAuth dance for the user  
- Permissions are task-scoped, not blanket access

### Step 3

## Next call just works

Once the user has approved, retry the same request. Keychains injects the right credentials server-side and forwards the request to the target API. The agent never sees the raw secrets.

- Credentials injected server-side — invisible to prompt injection  
- Every call logged in a complete audit trail  
- Users can revoke access at any time from the dashboard

### Terminal

Same call again — works instantly

```bash
$keychains curl https://api.github.com/user/repos \
-H "Authorization: Bearer {{GITHUB_TOKEN}}"
```

> 200 OK — 42 repositories

## Machine identity & permissions

Each machine automatically gets an SSH key pair on first run. This key pair is used to cryptographically identify the machine and can emit multiple permission requests — one per task if needed — each with its own scoped rights.

### Automatic SSH keypair

Ed25519 keypair generated locally on first run. Private key never leaves the machine. No manual setup required.

### Per-task permissions

Each machine can emit multiple permission requests — one per task if desired. Each permission has its own scoped rights, independent of others.

### Stateful fingerprinting

A rolling hash chain detects stolen keys on first unauthorized use. Both real and attacker machines are flagged immediately.

## Delegation for multi-agent systems

When your agent needs to spawn sub-agents, Keychains gives you two patterns:

### Scoped delegation

Create a delegate token with a subset of your permissions. The sub-agent can only access the APIs you explicitly allow.

```bash
$ keychains delegates add pr_a1b2c3 \
--scopes github::repo,notion::read \
--name "code-reviewer"
```

### Zero-permission tokens

Spawn a sub-agent with no initial access. It must request approval from the user for each API it needs — maximum security.

```bash
$ keychains delegates add pr_a1b2c3 \
--wildcard \
--name "untrusted-plugin"
```

## Users stay in control. Always.

The Keychains dashboard gives users complete visibility into what agents have access to. They can review permissions, see activity, and revoke access — at any time, with one click.

- See all active machines and their permissions  
- View which APIs each agent has accessed  
- Revoke any permission instantly

### Active Machines

- research-agent  
  Gmail, Notion  
  Revoke  
- code-reviewer  
  GitHub  
  Revoke  
- data-analyst  
  Stripe, Airtable  
  Revoke

## Ready to build secure agents?

Get started in under a minute. Just prefix curl with keychains — that's it.
