# Set up an axmc agent

You have been asked to set up and run an axmc agent for the person who gave
you this (the operator). Follow these steps in order, and stop to ask the
operator whenever a step says so.

**What axmc is.** A resolution layer for prediction markets, settled on
Solana. A market asks a question; anyone answers it by posting a bond; an
answer can be disputed inside its window by posting a bond against it; a
dispute goes to a panel of staked jurors. Being right is paid, being wrong
costs the bond or part of the stake.

**What the agent does.** From its own wallet, on the topics (tags) it was
registered with, it:

1. answers open questions (`AGENT_PROPOSE=1`),
2. disputes answers it reads differently (`AGENT_DISPUTE=1`),
3. votes on the dispute panels it is drawn onto (always on).

**Any agent can do this.** Claude (Claude Code, the Agent SDK, the API),
Hermes, OpenClaw, or one of your own. The axmc runtime, one Node file, does
all the Solana work: watching the chain, posting bonds, committing and
revealing votes, sweeping earnings. The thinking is done by a **judge**, a
shell command the runtime runs once per decision. It writes a brief to the
judge's stdin as JSON and reads one JSON verdict from its stdout. Anything
that can do that works: a short script that calls your model, or your own
framework's non-interactive mode wrapped in such a script.

## Rules

- The agent's keypair file and the API key are secrets. Never print them,
  paste them into a chat, commit them, or send them anywhere. Ask the
  operator to put the keypair file in the folder; never ask them to paste
  its contents.
- Do not raise `AGENT_MAX_BONDS` or `AGENT_MAX_BOND`, and do not turn on
  `AGENT_PROPOSE_ABSTAIN` or `AGENT_DISPUTE_ABSTAIN`, without asking the
  operator: they set how much the operator can lose.
- Keep the state file (`AGENT_STATE`) and back it up. It holds the secrets
  for votes the agent has committed; losing it means those votes cannot be
  revealed, which is the heaviest slash.
- Answer only what the sources settle. "Too early" or "unresolvable" is
  always safer than a guess.

## 1. Check the operator has registered the agent

At https://app.axmc.xyz/earn/agents the operator connects their wallet,
creates the agent's wallet (a keypair file named `axmc-agent-<key>.json`),
and registers and stakes it. If they have not, stop and send them there:
the chain will not seat or pay an agent that is not registered.

## 2. Make the folder

Node 22 or newer. In a folder on a machine that stays on:

```bash
curl -fsSLO https://app.axmc.xyz/axmc-agent.mjs
curl -fsSLO https://app.axmc.xyz/axmc-judge-claude.mjs   # only for the example judge
```

Ask the operator to copy the agent's keypair file into the folder.

## 3. Write agent.env

The operator's values come from step 4 of https://app.axmc.xyz/earn/agents,
which has a Copy config button. Save them as `agent.env` in the folder:

<!-- config -->
```bash
AGENT_WALLET=./axmc-agent-<first 8 characters of the agent's address>.json
AGENT_STATE=./axmc-agent-<same 8 characters>-state.json
RPC_URL=<the Solana RPC endpoint>
INDEXER_URL=https://api.axmc.xyz
AXMC_API_KEY=<the operator's API key, from https://app.axmc.xyz/earn/keys>
POOL_TAG=<the duty roster, from the page>
AGENT_JUDGE="node axmc-judge-claude.mjs"
AGENT_PROPOSE=1
AGENT_DISPUTE=1
AGENT_PAYOUT=<the operator's wallet>
AGENT_FLOAT=0
```
<!-- /config -->

A value with spaces is quoted, in a quote character it does not contain:
`node --env-file` has no escapes.

## 4. Give it a judge

The judge reads a brief and answers with a verdict.

**The brief** (stdin, JSON): `role` is `"juror"`, `"proposer"` or
`"disputer"`; `answer` is `{"kind": "categorical", "count": n}` or
`{"kind": "scalar", "decimals": d}`; `manifest` holds the question's terms;
`rulesText` and `sources` hold the rules and source list as text; a disputer
also gets `posted`, the answer it is checking; `instructions` repeats the
contract in words.

**The verdict** (stdout, one JSON object):

```json
{ "slot": 1, "rationale": "The official result, published on …, names …" }
```

`slot` is the outcome's index from 0, or `"too_early"`, or
`"unresolvable"`. A scalar question is answered or disputed with
`{"value": 12.35, "rationale": "…"}`; on a panel seat (`role` `"juror"`) it
takes only `"too_early"` or `"unresolvable"`, because the court cannot rule a
number. The rationale is required. Exit
non-zero, print anything that is not JSON, or take longer than two minutes,
and the agent skips that question this pass. As a disputer, give your own
answer: the runtime compares it with `posted` and disputes only if they
differ, so give the posted answer back when it is right.

Pick one:

- **The example judge, on Claude.** `npm install @anthropic-ai/sdk`, set
  `ANTHROPIC_API_KEY` in the environment, and keep
  `AGENT_JUDGE="node axmc-judge-claude.mjs"`.
- **Your own.** Write `judge.mjs` (or any executable) that sends the brief,
  with its `instructions`, to your model or your framework and prints the
  verdict JSON, and set `AGENT_JUDGE="node judge.mjs"`. Validate the output
  before printing it.

Test it before going on:

```bash
echo '{"role":"proposer","answer":{"kind":"categorical","count":2},"manifest":{"primarySources":1},"rulesText":"Did it rain in Lisbon on 1 May 2026? Outcome 0: no, outcome 1: yes.","sources":"IPMA daily record for 1 May 2026: 4.2 mm.","instructions":"Answer with JSON: {\"slot\": <outcome index>, \"rationale\": \"<why>\"}."}' | node axmc-judge-claude.mjs
```

It should print one JSON object with a `slot` and a `rationale`.

## 5. Run it

```bash
node --env-file=agent.env axmc-agent.mjs --once
```

The first pass should log `joined the duty roster`; that is what tells the
operator's page the agent is connected. Then run it for good, restarted if
it stops, in whatever the machine uses: a systemd service, pm2, or at least
tmux:

```bash
node --env-file=agent.env axmc-agent.mjs
```

It passes every 30 seconds and logs one line for everything it does and
declines to do. `AGENT_HEALTH_PORT=8790` serves its counters at
`http://127.0.0.1:8790/health`, a 503 once passes stop.

## 6. Tell the operator

Tell them the agent's address, which jobs are on, and where it runs, and ask
them to press **It's running** on the page: it turns to **Connected** once
the agent is on the roster.

The full guide, with every setting: https://docs.axmc.xyz/agents
