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

# Live Operator Onboarding

> Canonical self-hosted live path from clone to governed fetch readiness

This is the canonical self-hosted live path for AXON. It starts at clone and ends with a governed fetch reaching either settlement or the browser-signing/approval step required before settlement.

## What AXON Is and Is Not

AXON gives agents safe access to paid services over x402. It surfaces discovery and trust signals, and on the spend side it evaluates policy, budget, provider trust, approvals, and payment settlement before a request is retried.

AXON is **not** the autonomous agent runtime itself. You still need an agent host such as Claude Desktop, Claude Code, OpenClaw, or your own process that calls the MCP tools or REST endpoints.

AXON now splits MCP into two explicit surfaces:

* **Runtime** is the default story. It is the wallet-scoped path for `governed_fetch`, approvals, receipts, and other worker-agent actions.
* **Operator/manage** is the advanced story. It is for org-wide keys, admin automation, treasury actions, and other control-plane work.

If you are migrating an older mixed IDE setup, split it into two entries instead of broadening the runtime key. Runtime keeps the prepared wallet; operator/manage gets its own org-wide key. See [Two-Surface Migration](https://docs.axon402.com/docs/integrations/two-surface-migration.md) and [IDE Setup](https://docs.axon402.com/docs/integrations/ide-setup.md) for the exact client patterns.

AXON also splits responsibility across two product planes:

* **Control plane** is the dashboard and `@axon402/cli` (`axon-op`). This is where wallets, mandates, vault funding, key issuance, approvals, and emergency stops live.
* **Runtime plane** is MCP, OpenClaw, or direct runtime REST calls. A worker agent gets one wallet-scoped credential and spends through policy.

## Required Primitives

| Primitive | Required | Notes |
| :- | :- | :- |
| Node.js 20+ | Yes | All shipped workspaces require Node 20+ |
| Hosted Supabase project | Yes | AXON does not ship a local Supabase stack |
| AXON schema + migrations | Yes | Apply `setup_database.sql` then `migrations/` |
| Base RPC endpoint | Yes | Mainnet default path uses Base |
| `MASTER_MNEMONIC` | Yes | Derives the vault and pocket wallets |
| `SUPABASE_SERVICE_KEY` | Yes | Backend-only secret |
| `AXON_API_KEY_HASH_PEPPER` | Yes | Required for tenant API-key verification in live mode |
| `AXON_SECRETS_KEY` | Yes | Required for secret storage in live mode |
| `AXON_MCP_PUBLIC_URL` | Yes | Canonical public MCP URL returned in connect snippets |
| `AXON_DECISION_API_KEY` | Yes for static bearer flows | Static operator bearer for scripts, OpenClaw, and operator-only routes |
| `AXON_PLATFORM_AUTH_ENABLED=true` | Recommended | Enables dashboard live flows |
| USDC on Base | Yes | For real spending |
| ETH on Base | Usually | Needed unless gasless treasury is enabled |
| Agent host | Yes | Claude Desktop, Claude Code, OpenClaw, or custom |

## Clone, Install, and Build

From an AXON source checkout:

```bash theme={null}
npm install
npm run build
npm run verify:demo
```

`npm run verify:demo` is the repeatable CLI baseline. It validates onboarding docs, builds the repo, and runs the zero-secrets demo smoke flow.

## Apply the Supabase Schema

**1. Open your Supabase project**

Navigate to the SQL Editor in your Supabase dashboard.

**2. Run the base schema**

Execute `platform/supabase/setup_database.sql`.

**3. Apply migrations**

Run each file in `platform/supabase/migrations/` in order.

Alternatively, with the Supabase CLI:

```bash theme={null}
supabase db push --db-url "postgresql://postgres:YOUR_PASSWORD@db.YOUR_PROJECT.supabase.co:5432/postgres"
```

**4. Create the first operator**

In Supabase Dashboard under **Authentication > Users**, create:

* Email: `admin@axon.dev`
* Password: `password123`

> [!WARNING]
>
> These are development-only credentials for initial localhost setup. Replace with strong credentials before deploying to any shared environment.

> [!WARNING]
>
> Self-signup is not the assumed first-pass live path. Create the operator manually unless you have configured your own signup/email flows.

## Configure the Backend

The canonical backend env file is `axon-402-mcp/.env`. Copy the checked-in
example and populate the required live values.

```bash theme={null}
cp axon-402-mcp/.env.example axon-402-mcp/.env
```

Fill in at least:

```env theme={null}
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_KEY=your-service-role-key
BASE_RPC_URL=https://base-mainnet.g.alchemy.com/v2/your-key
MASTER_MNEMONIC=your twelve or twenty-four word seed phrase
AXON_API_KEY_HASH_PEPPER=32+ chars of random secret material
AXON_SECRETS_KEY=base64-encoded 32-byte key
AXON_MCP_PUBLIC_URL=https://api.axon402.com/v1/mcp
AXON_DECISION_API_KEY=your-static-daemon-bearer
AXON_PLATFORM_AUTH_ENABLED=true
AXON_PLATFORM_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
AXON_PLATFORM_URL=https://axon402.com/
```

See [Environment Variables](https://docs.axon402.com/docs/api-reference/environment-variables.md) for the full
live matrix and defaults.

Run readiness before bootstrap:

```bash theme={null}
npm run doctor
npm run verify:live
```

Expected pre-bootstrap result: `needs_bootstrap`.

## Configure the Dashboard

Create `platform/.env.local`:

```env theme={null}
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key
VITE_AXON_DECISION_API_URL=http://127.0.0.1:3030
VITE_AXON_LIVE_MODE=true
VITE_AXON_ENABLE_DEMO_MODE=false
```

Start both services:

```bash theme={null}
npm run dev:live       # Decision daemon on :3030
npm run dev:platform   # Dashboard on :5173
```

## Bootstrap the Live Organization

**Dashboard Bootstrap (Recommended)**

The recommended path if you want the operator to use the dashboard immediately.

1. Start the backend and dashboard.
2. Sign in as the operator you created in Supabase Auth.
3. Open `/onboarding`.
4. Create the organization.
5. Copy the vault deposit address.
6. Wait for readiness to pass the initial vault checks.
7. Deploy the first agent pocket and mandate.

After this you have:

* A real organization
* A live vault derived from the mnemonic at `m/44'/60'/0'/0/0`
* One live agent pocket and mandate
* Dashboard access bound to the organization

**CLI Bootstrap**

For headless/operator-first setup:

```bash theme={null}
npm run bootstrap:live
```

Copy the emitted `AGENT_WALLET_ID` into `axon-402-mcp/.env` and rerun:

```bash theme={null}
npm run doctor
```

> [!NOTE]
>
> The CLI bootstrap does not create a `user_organizations` row. If you want the dashboard to manage that org, add membership manually via SQL: `INSERT INTO user_organizations (user_id, organization_id, role) VALUES ('<USER_UUID>', '<ORG_UUID>', 'owner') ON CONFLICT (user_id, organization_id) DO UPDATE SET role = 'owner';`

## Deposit to the Vault, Allocate to the Agent

**1. Deposit USDC to the vault (external on-chain transfer)**

**Deposit to Wallet** = send USDC on Base (chain 8453) from any wallet you control to the vault's deposit address shown in the dashboard or bootstrap output. This is a normal on-chain transfer and is the universal funding path — it works for both `full` and `browser` signing modes.

**2. Allocate from vault to the agent pocket (internal transfer)**

**Allocate from Vault** = internal vault → pocket transfer, server-signed only. Available when `AXON_SIGNING_MODE=full` (the server holds the vault private key). Browser-signed orgs cannot allocate; fund the target pocket with **Deposit to Wallet** instead.

**Dashboard path:** Open `/vault` and use "Allocate to Pockets".

**REST path:**

```bash theme={null}
curl -X POST http://127.0.0.1:3030/v1/orgs/<ORG_UUID>/transfers/fund \
  -H "Authorization: Bearer <AXON_DECISION_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "vault_wallet_id": "<VAULT_WALLET_ID>",
    "pocket_wallet_id": "<POCKET_WALLET_ID>",
    "amount_usdc": 5,
    "memo": "Initial agent allocation"
  }'
```

> [!NOTE]
>
> If gasless treasury is disabled, the source wallet also needs ETH on Base for gas.

> [!NOTE]
>
> Browser-signed orgs skip the allocation step entirely. Their funding path is:
> open the target wallet, copy its **Deposit to Wallet** address, and send USDC
> there directly.

## Register MCP or OpenClaw

**MCP**

```json theme={null}
{
  "mcpServers": {
    "axon": {
      "command": "node",
      "args": ["/absolute/path/to/AXON/axon-402-mcp/dist/index.js"],
      "env": {
        "SUPABASE_URL": "https://your-project.supabase.co",
        "SUPABASE_SERVICE_KEY": "your-service-role-key",
        "BASE_RPC_URL": "https://base-mainnet.g.alchemy.com/v2/your-key",
        "MASTER_MNEMONIC": "your twelve or twenty-four word seed phrase",
        "AGENT_WALLET_ID": "wallet-id-from-bootstrap-or-workforce"
      }
    }
  }
}
```

**OpenClaw**

```json theme={null}
{
  "decisionApiUrl": "http://127.0.0.1:3030",
  "decisionApiKey": "your-static-daemon-bearer",
  "defaultWalletId": "wallet-id-from-bootstrap-or-workforce"
}
```

If the agent later hits `TOOL_NOT_AVAILABLE_IN_RUNTIME_SURFACE`, that is a surface mismatch, not a runtime failure. Move the action to the operator/manage surface or `axon-op` instead of giving the worker a broader key.

## Run the First Paid Flow

Start the daemon and run the live test:

```bash theme={null}
cd axon-402-mcp
npm run build
npm run start:decision-api
```

In another shell:

```bash theme={null}
npm run verify:live-test -- --organization-id <ORG_UUID> --apply-vault --write-env
```

Or via MCP, the minimum sequence:

1. `governed_fetch`
2. Complete any returned approval or browser-signing step
3. `get_receipt` after settlement completes

`read_spending_policy` and `get_financial_status` are useful context tools,
but `governed_fetch` is the default paid-call path. New integrations should not
expect a raw public signer tool.

## Final Success Checklist

> [!TIP]
>
> Backend is healthy and `/ready` is no longer `misconfigured` or `needs_bootstrap`

> [!TIP]
>
> Operator can log into `http://127.0.0.1:5173`

> [!TIP]
>
> Vault exists and has USDC on Base

> [!TIP]
>
> At least one agent pocket exists

> [!TIP]
>
> Pocket has received treasury allocation

> [!TIP]
>
> MCP or OpenClaw is configured against the live daemon

> [!TIP]
>
> One governed fetch reaches settlement, or returns the expected approval/browser-signing handoff before settlement

> [!TIP]
>
> Approval-required retries complete without changing the original `idempotency_key`

## Troubleshooting

> **misconfigured**
>
> Fix env or connectivity first. Common causes:
>
> * Missing `SUPABASE_URL`, `SUPABASE_SERVICE_KEY`, `BASE_RPC_URL`, or `MASTER_MNEMONIC`
> * Missing both `AXON_DECISION_API_KEY` and `AXON_PLATFORM_AUTH_ENABLED`

> **needs\_bootstrap**
>
> The env is valid, but the org/vault/mandate is not fully created yet. Use the dashboard onboarding flow or run `npm run bootstrap:live`.

> **Dashboard login works, but org pages are empty**
>
> The signed-in Supabase user probably does not have a `user_organizations` membership for that org. This is the common CLI-bootstrap follow-up step.

> **Vault exists, but treasury allocation stays blocked**
>
> Deposit USDC on Base to the vault address first. If gasless treasury is disabled, also make sure the source wallet has ETH for gas. Allocation is a vault → pocket internal transfer and requires a funded vault to move from.

> **Allocation rejected with `VAULT_ALLOCATION_UNAVAILABLE`**
>
> The org is browser-signed (`wallet_mode='browser'`). The server has no vault
> signer and therefore cannot perform internal allocations. Deposit USDC directly
> to the pocket's address instead, or use the dashboard's **Deposit to Wallet**
> flow.

> **Agent exists, but paid calls fail immediately**
>
> Check:
>
> * The pocket has been deposited to (external transfer) or allocated to (vault → pocket on server-signed orgs)
> * `AGENT_WALLET_ID` points to the intended pocket
> * The mandate allows the host/network/category you are using
> * The caller is keeping the same `idempotency_key` across approval retries


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.