# AGENTS.md — Conduit

Guidance for AI agents that transact through Conduit via MCP.

## Production MCP (live)

```
POST/GET  https://mcp.aiconduit.app/mcp
```

Connect any MCP client:

```json
{
  "mcpServers": {
    "Conduit Agentic Commerce": {
      "type": "http",
      "url": "https://mcp.aiconduit.app/mcp"
    }
  }
}
```

Install hub: https://aiconduit.app/connect
UCP profile: https://aiconduit.app/.well-known/ucp
Capability manifest: https://aiconduit.app/.well-known/agent.json

### OpenClaw (recommended for headless / autonomous agents)

OpenClaw runs the **full** Conduit loop (MCP + Skill) with native Streamable HTTP — autonomous `payable_now`, AP2 mandates, and x402 — same as Cursor, Claude Code, or Codex.

```bash
openclaw mcp add conduit \
  --url https://mcp.aiconduit.app/mcp \
  --transport streamable-http
mkdir -p ~/.openclaw/skills/conduit && \
  curl -fsSL https://aiconduit.app/skills/conduit/SKILL.md \
    -o ~/.openclaw/skills/conduit/SKILL.md
openclaw mcp status
```

Manual config (`~/.openclaw/openclaw.json`):

```json
{
  "mcp": {
    "servers": {
      "conduit": {
        "url": "https://mcp.aiconduit.app/mcp",
        "transport": "streamable-http"
      }
    }
  }
}
```

### Hermes

Nous Research agent runtime with native remote MCP. One command, no API key, no proxy. Runs the **full** Conduit loop (MCP + Skill).

```bash
hermes mcp add conduit \
  --url https://mcp.aiconduit.app/mcp
hermes skills install \
  https://aiconduit.app/skills/conduit/SKILL.md
```

Two prompts default the wrong way for Conduit: answer `n` to **Does this server require authentication?** (Conduit needs no key), and `y` to **Enable all tools**. Tools register as `mcp_conduit_*`, so keep the server named `conduit`.

Manual config (`~/.hermes/config.yaml`):

```yaml
mcp_servers:
  conduit:
    url: "https://mcp.aiconduit.app/mcp"
```

### Codex (recommended among OpenAI clients)

Codex CLI / IDE / ChatGPT desktop Codex host can run the **full** Conduit loop (MCP + Skill): autonomous `payable_now`, AP2 mandates, and x402 — same as OpenClaw, Cursor, or Claude Code.

```bash
codex mcp add conduit --url https://mcp.aiconduit.app/mcp
mkdir -p ~/.agents/skills/conduit && \
  curl -fsSL https://aiconduit.app/skills/conduit/SKILL.md \
    -o ~/.agents/skills/conduit/SKILL.md
codex mcp list
```

Manual config (`~/.codex/config.toml`):

```toml
[mcp_servers.conduit]
url = "https://mcp.aiconduit.app/mcp"
```

ChatGPT web Apps are **limited** for Conduit: public Apps require external checkout and cannot use crypto rails. Prefer OpenClaw, Codex, Cursor, or Claude Code for checkout; ChatGPT Developer mode MCP is discovery/handoff only.

### Local development

```
POST/GET  http://localhost:4000/mcp
```

## Tools

| Tool | Purpose |
| --- | --- |
| `agent_create` | Register an agent (ES256 P-256 public JWK JSON string + payment rails + default destination). Returns `agent_id` + `persist` guide. **List ~/.conduit identity files first — do not recreate if any exist unless the human asked for a new agent.** |
| `agent_authenticate` | Re-authenticate by signing a server challenge. Load `agent_id` + `private_key` from the chosen ~/.conduit file (or CONDUIT_CREDENTIALS_PATH). Two-step: call without `nonce` to get a challenge, sign it, call again with `nonce` + `signature`. Keep session_token in memory. No filesystem? Give the human a terminal command to read/sign — never paste private_key into chat. |
| `agent_update` | Patch handle, payment rails, default destination (include **postcode**), optional avatar (invader/emoji+gradient or small image), business profile, or preferences. Prefer after signup before search. Omit avatar unless the human chose it. Does **not** accept `permissions`. |
| `agent_organization` | Read linked org (name, slug, default address) plus members (user_id, name, role, email). Returns `org_not_linked` when unset — do not invent join_org. |
| `agent_notify` | Email Hub users in the linked org (`to`: `all` or a member `user_id` / `role` / `email`). Channel is email. Optional Hub action buttons. Never addresses outside the org. |
| `agent_outreach` | Email outside addresses (suppliers, carriers). `to`: a string email, `{ email }`, or `{ emails }` (max 5). Linked agents set Reply-To to an org member (default OWNER). No action buttons. |
| `agent_report_issue` | Report unexpected tool errors / confusing outcomes for AX review (`message` required; optional `kind`, `tool`, `error`, correlation ids). Not `order_feedback` — does **not** change reputation. |
| `payment_methods` | List or enable agent payment methods (`action`: `list` \| `enable`). |
| `payment_mandate` | AP2 mandates (`action`: `request` \| `list` \| `update` \| `revoke`). `request` returns `approval_url`. |
| `supply_search` | Multi-provider fan-out; AES-ranked offers with `badge` + `action`. **Always pass `agent_id`**. Returns `search_id`. Catalog `delivery_options` often empty. Sandbox/demo merchants hidden by default — pass `include_sandbox=true` only when testing flows (`test_offer=true`, listed last). |
| `supply_details` | Full normalized product detail. Pass `search_id` + `agent_id` (refreshes badge/action). |
| `supply_options` | Size / color / pack axes when `has_options` is true. Each variant has its own `supply_id`. Buy that id, not the searched one. |
| `supply_delivery` | Non-committing checkout probe for shipping ETA/cost. Prefer over `order_execute` when comparing delivery. |
| `order_execute` | Handoff or autonomous completion. Handoff returns `bill_breakdown` (shipping). Use `idempotency_key`. |
| `order_list` | List orders for an agent (`{ orders }`). Optional `status` (CANCELLED→ABANDONED) or `open_only` for in-flight. |
| `order_track` | Honest deal-type-aware status. Owning `agent_id` required. |
| `order_events` | Lifecycle timeline — transitions only. Owning `agent_id` required. |
| `order_update_status` | Agent correction or degraded-handoff recovery. Owning `agent_id` required. |
| `order_dispute` | Refund/chargeback/report paths. Owning `agent_id` required. |
| `order_feedback` | Attest outcome (`on_time` \| `late` \| `never_arrived` \| `damaged` \| `wrong_item`). Owning `agent_id` required. |

Tool list: agent_create, agent_authenticate, agent_update, agent_organization, agent_notify, agent_outreach, agent_report_issue, payment_methods, payment_mandate, supply_search, supply_details, supply_options, supply_delivery, order_execute, order_list, order_track, order_events, order_update_status, order_dispute, order_feedback, inventory_levels, inventory_replenishment, inventory_suppliers, supply_availability, inventory_purchase_order

## Identity & payment model

- Agent holds an **ES256 P-256 keypair**; Conduit stores only the public JWK JSON string.
- Conduit is orchestrator only — never holds funds. Merchant is merchant-of-record.
- Badge `handoff` → open `continue_url` (Conduit `/handoff/{org_slug}/{order_id}`, which records then redirects to the merchant). Badge `payable_now` → autonomous with active AP2 mandate.

## Identity persistence

- Directory: `~/.conduit/` (`{handle}.credentials.json` plus legacy `credentials.json`). Optional `~/.conduit/active` is last-used `agent_id`. Override one file: env `CONDUIT_CREDENTIALS_PATH`.
- Required: `version`, `agent_id`, `public_key` (ES256 P-256 public JWK JSON string), `private_key` (matching private JWK — never send to Conduit). Also store `handle`, `friendly_name`, `role_description`, `human_description` for the local chooser. Sign once, keep `session_token` in memory.
- Bootstrap: list files first → reuse if any exist unless the human asked for a new agent. Several files: named handle/id, else `active`, else list roster fields (never keys) and ask once. After `agent_create`, write `persist.path` immediately, echo `agent_id` to `active`, then `agent_update` with `default_destination` + **postcode**. After auth/update: merge labels; never overwrite `private_key`.
- No filesystem? Fallback only — prefer loading private_key from disk when you can. Else: (1) `cat ~/.conduit/active` or list handle/name/role/agent_id from the json files (2) `agent_authenticate(agent_id)` → forward `terminal` verbatim (Node crypto ES256; never prints private_key) (3) paste `{agent_id,nonce,signature}` back. Never invent a script that encodes the key. Never paste `private_key` into chat.

## Permissions (Hub-granted)

`permissions` on the profile: `browse`, `orders`, `checkout`, `notify`, `outreach`. New agents get all except `outreach`. Hub Agent settings is the only writer — `agent_create` / `agent_update` do not accept `permissions`. Denied tools return `permission_denied` (not `auth_required`) with no `next`. Ask a human to enable the capability.

- Personalized `supply_*` → `browse` (omit `agent_id` to search anonymously)
- Order read / attest / dispute → `orders`
- `order_execute` and mandate request/update/revoke / rail enable → `checkout` (autonomous still needs an approved AP2 mandate)
- `agent_notify` → `notify`
- `agent_outreach` → `outreach`

## Delivery

Catalog `delivery_options` are often empty. Call `supply_delivery(supply_id, agent_id)` for authoritative `eta_text` / `options` / `shipping_cost` (non-committing checkout). Prefer that over `order_execute` when only comparing delivery.

## Hints

Every outcome includes `hint` and optional `next: { tool, args? }`. Structured errors: `{ error, hint, next? }`.

## Correlation

Carry `search_id` from `supply_search` through details, execute, feedback. Use `idempotency_key` on every `order_execute`.

## Typical sequences

**Handoff:** agent_create → write ~/.conduit/{handle}.credentials.json + active → agent_update(default_destination with postcode) → payment_methods(list) → supply_search(agent_id) → supply_details(agent_id, search_id) → supply_options (when has_options) → supply_delivery(agent_id) → order_execute → open continue_url → order_track → order_feedback

**Autonomous:** agent_create → write credentials → agent_update(postcode) → payment_mandate → human opens approval_url → supply_search → badge=payable_now → order_execute → order_track → order_feedback

**Returning session:** pick ~/.conduit identity (or active) → agent_authenticate once → keep session_token → supply_search(agent_id) …

**Degraded handoff:** order_execute (handoff_quality=degraded) → complete continue_url → order_update_status(agent_id, ..., external_checkout_id, handoff_endpoint) → order_track

**Outreach:** agent_outreach(to=email|{ email }|{ emails }, title, body). Optional reply_to { email } or { role } matching a member (default OWNER when linked). Not to=all / user_id / role.

List tools return envelopes (`{ methods }`, `{ mandates }`, `{ events }`, `{ orders }`). Mandate starts as `PENDING_HUMAN_APPROVAL` — open `approval_url` as returned (includes approve token). Wrong-agent revoke/status → `mandate_forbidden` / `order_forbidden`.

## Offer badges

Use **badge** / **action** (and **recommended**) to decide — not merchant autonomy.

| Badge | Action | Meaning |
| --- | --- | --- |
| `payable_now` | `execute_autonomous` | Autonomous order_execute is allowed: a covering mandate fits this offer. Confirm with the user first. |
| `needs_mandate` | `request_mandate` | Legacy enum. v1.4 and later emit handoff when there is no covering mandate. |
| `handoff` | `execute_handoff` | Call order_execute, then open continue_url. Any card works on the merchant site. Also used when a covering budget is spent. |
| `enable_rail_to_buy` | `enable_rail` | Call payment_methods(action=enable) for the rail first, then retry. |
| `coming_soon` | `skip` | The selected rail is not live for agent checkout yet. Pick another offer. |
| `discovery_only` | `skip` | Browse only. This merchant cannot be transacted through Conduit. Pick another offer. |

**Any card** (`bank_card`): Handoff only for now: a human pays with any card on the merchant site. The agent card vault is not live, so do not enable it.

**Invoice** (`invoice`): B2B invoice and net terms. Preview only until merchants accept the rail; use cod, x402 or handoff today.

## Rate limits

- ~300 MCP requests/min per IP (burst 100) — designed for parallel subagents
- ~120 REST /api requests/min per IP
- ~60 `supply_search` + ~180 tool calls/min per `agent_id` (anonymous search is IP-capped)
- Exact `/health` exempt; `/health/ucp-signer` rate-limited; HTTP 429 + Retry-After on Nest agent limits

Contact: founder@aiconduit.app · https://telegram.me/asmodeoux
