# Point your agent at it

> Set up a coding agent (Claude Code, Codex, Cursor, Gemini CLI, Aider, Windsurf, Copilot) to use megachad, or make megachad a runtime agent's decision step. Markdown copy of https://megachadcua.com/agents.

Two kinds of agents use megachad. Coding agents (Claude Code, Codex, Cursor, Gemini CLI, Aider, Windsurf, Copilot) add it to a project. Runtime agents (a computer-use agent, a voice bot, a triage agent) call it as their decision step. Both start from https://megachadcua.com/llms.txt.

## Coding agents

One-line prompt for any coding agent:

```text
Read https://megachadcua.com/llms.txt and add megachad to this project: <what it should decide, e.g. route each support ticket to Billing, Bug or Other>. Use the API key from the MEGACHAD_API_KEY env var; if it's unset, ask me. Never hardcode or commit the key. Call the HTTP API directly unless the project already uses a megachad SDK.
```

What the agent should do:

1. Check the key: `test -n "$MEGACHAD_API_KEY"`. If it's unset, stop and ask the user to sign up at https://megachadcua.com/login?signup=1 and set `MEGACHAD_API_KEY`. Never hardcode, commit, print or log it.
2. Prove the key works with one call (the curl under "Runtime agents" below). 401: wrong key. 403 `email_unverified`: the user confirms their email. 402: the user adds a card.
3. Write the integration. Raw HTTP is the default: no dependency, nothing to break (https://megachadcua.com/docs.md, "Retries and idempotency", has Python and JavaScript versions with retries). Use the SDK if the project already depends on it or needs live voice.
4. Design the schema with the rules under "Schema design".
5. Act on an answer only above a confidence threshold; below it, confirm with the user or hand off to a human.
6. In tests, mock the HTTP call. Real calls cost credits; run them only when the user asks.

### Claude Code

Install the skill (Claude Code loads it when a task matches; it also shows up as `/megachad`):

```bash
mkdir -p ~/.claude/skills/megachad && curl -fsSL https://megachadcua.com/agents/megachad/SKILL.md -o ~/.claude/skills/megachad/SKILL.md
```

For one repo only, put it in `.claude/skills/megachad/SKILL.md` instead and commit it. The skill: https://megachadcua.com/agents/megachad/SKILL.md.

MCP server, so Claude can call megachad itself (`choose` and `decide` tools):

```bash
claude mcp add megachad -e MEGACHAD_API_KEY=$MEGACHAD_API_KEY -- npx -y megachad-mcp
```

### Codex and any repo: AGENTS.md

Append the megachad block to the repo's `AGENTS.md`:

```bash
curl -fsSL https://megachadcua.com/agents/AGENTS.md >> AGENTS.md
```

Codex, Cursor, GitHub Copilot's coding agent, Windsurf, Jules, Zed and others read `AGENTS.md` (list: https://agents.md). Gemini CLI reads it with `{"context": {"fileName": "AGENTS.md"}}` in `.gemini/settings.json`. Aider reads it with `read: AGENTS.md` in `.aider.conf.yml`. The block: https://megachadcua.com/agents/AGENTS.md.

### Cursor

Project rule (type "Apply Intelligently": Cursor pulls it in when the task matches its description):

```bash
mkdir -p .cursor/rules && curl -fsSL https://megachadcua.com/agents/megachad.mdc -o .cursor/rules/megachad.mdc
```

MCP server: add this to `~/.cursor/mcp.json` or `.cursor/mcp.json`. Cursor fills `${env:MEGACHAD_API_KEY}` from your environment, so the file holds no key:

```json
{
  "mcpServers": {
    "megachad": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "megachad-mcp"
      ],
      "env": {
        "MEGACHAD_API_KEY": "${env:MEGACHAD_API_KEY}"
      }
    }
  }
}
```

## Runtime agents

Use megachad as the decision step: the agent has a fixed set of possible next moves, a person said or wrote something, and the agent needs to know which move they mean, fast, with a number that says how sure.

```bash
curl https://api.megachadcua.com/v1/decide \
  -H "Authorization: Bearer $MEGACHAD_API_KEY" \
  -H "content-type: application/json" \
  -d '{"schema": {"action": {"question": "Which on-screen control does the user want the agent to use?", "options": ["Sign in", "Pricing", "Docs", "Nothing yet", "Not sure"]}}, "text": "take me to sign in"}'
```

Response (200):

```json
{"session_id": "dcd_7KFTWwTLLOmXjo5N", "fields": {"action": {"value": "Sign in", "confidence": 0.97, "probabilities": {"Sign in": 0.97, "Pricing": 0.006, "Docs": 0.004, "Nothing yet": 0.012, "Not sure": 0.008}}}, "transcript": "take me to sign in", "latency_ms": 104, "model_ms": 15.3, "usage": {"credits": 1}}
```

A computer-use agent's step: the controls on screen become the options, plus two ways out.

```python cua_step.py
import os
import requests

API = os.environ.get("MEGACHAD_BASE_URL", "https://api.megachadcua.com") + "/v1/decide"
THRESHOLD = 0.85  # tune it on your own cases (console: Evals)

def next_action(utterance, controls):
    schema = {"action": {"question": "Which on-screen control does the user want the agent to use?",
                         "options": controls + ["Nothing yet", "Not sure"]}}
    r = requests.post(API, headers={"Authorization": f"Bearer {os.environ['MEGACHAD_API_KEY']}"},
                      json={"schema": schema, "text": utterance}, timeout=20)
    r.raise_for_status()
    f = r.json()["fields"]["action"]
    if f["value"] == "Nothing yet":
        return ("wait", None)  # the user is still talking, or asked for nothing
    if f["value"] in controls and (f["confidence"] or 0) >= THRESHOLD:
        return ("click", f["value"])
    return ("ask", f["value"])  # "Not sure" or low confidence: confirm with the user

print(next_action("take me to sign in", ["Sign in", "Pricing", "Docs"]))
```

Prints `('click', 'Sign in')`.

### Schema design

- One question per field. "Which team, and how urgent?" is two fields, `team` and `urgency`, answered in one call.
- Options are short, distinct and mutually exclusive. Use the label the user sees ("Sign in", not `btn_auth_2`); the value comes back verbatim, so map it to your ids with a dict.
- Always add a way out. "Nothing yet" for "the user hasn't asked for anything" (mid-sentence, small talk); "Not sure" or "Other" for "none of these fit". Without one the model must pick one of your actions.
- Use `"type": "yes_no"` for binary questions ("Did the user confirm?") and `"scale"` for ordered levels, listed low to high.
- Write the `question` as the decision the agent faces: "Which on-screen control does the user want the agent to use?", "Which queue should this call go to?".
- Options can change on every `/v1/decide` call: send what's on screen now. On a socket the schema is fixed; open a new session when the screen changes.
- Two speakers: send `text` as `[{"speaker": "user", "text": ...}, {"speaker": "other", "text": ...}]`.
- No cap on fields or options besides the 64 KB schema limit. Input over 4,000 tokens costs more than one decision.

### Confidence and thresholds

- `confidence` is calibrated, 0 to 1. Pick a threshold per field: at or above it, act; below it, confirm ("Did you mean Sign in?") or hand off.
- Start at 0.85 to 0.9 for actions. Then measure: the console's Evals (https://megachadcua.com/app) runs your own cases and recommends the lowest threshold that is right at least 97% of the time on the cases it answers.
- Read `probabilities` (options fields) for the runner-up: when the top two are close, ask between them.
- `confidence` can be `null` (rare fallback path): treat it as below threshold.
- Destructive, irreversible, financial, medical or safety-critical actions need a human to confirm, whatever the confidence. Medical: megachad routes and structures for a clinician to review; it doesn't diagnose.

### Batching

Many independent texts with the same questions (a ticket queue, a dataset): `POST /v1/decide/batch`, up to 50 items per request, results in order, billed per answered item. Resend items that come back `batch_timeout` or with a retryable error (`at_capacity`, `concurrency_limit`, `server_error`, `timeout`, `model_closed`, `model_error`) in a new batch.

```python triage_batch.py
import os
import requests

API = os.environ.get("MEGACHAD_BASE_URL", "https://api.megachadcua.com") + "/v1/decide/batch"
RETRYABLE = {"batch_timeout", "at_capacity", "concurrency_limit", "server_error", "timeout", "model_closed", "model_error"}
schema = {"team": {"question": "Which team should handle this ticket?", "options": ["Billing", "Bug", "Account", "Other"]}}

def decide_all(texts, size=50):
    out, todo = [None] * len(texts), list(range(len(texts)))
    for _ in range(3):
        retry = []
        for i in range(0, len(todo), size):
            items = [{"id": n, "text": texts[n]} for n in todo[i:i + size]]
            r = requests.post(API, headers={"Authorization": f"Bearer {os.environ['MEGACHAD_API_KEY']}"},
                              json={"schema": schema, "items": items}, timeout=120)
            r.raise_for_status()
            for res in r.json()["results"]:
                if res["ok"]:
                    out[res["id"]] = res["fields"]["team"]["value"]
                elif res["error"]["code"] in RETRYABLE:
                    retry.append(res["id"])
                else:
                    out[res["id"]] = "error: " + res["error"]["code"]
        if not retry:
            break
        todo = retry
    return out

tickets = ["I was charged twice this month", "the app crashes when I log in", "how do I change my email?"]
for ticket, team in zip(tickets, decide_all(tickets)):
    print(team, "|", ticket)
```

### Voice

Live speech goes over `WS /v1/listen` (https://megachadcua.com/docs.md, "WS /v1/listen"): stream 16 kHz PCM16, get `fields` events while the person talks. Act on a `fields` event when `confidence` is 0.9 or more and the pick has held for 300 ms; wait for `done` when the words hedge ("no", "actually", "wait").

### As a tool for an LLM agent

Give the model one tool that wraps `/v1/decide`. The tool input is the request body: send it unchanged and return `fields` as the tool result.

Anthropic (Messages API `tools`):

```json
{
  "name": "megachad_decide",
  "description": "Make fast, calibrated decisions about a piece of text with megachad (the model decides in ~17 ms). Give a schema of fields; each field is one question answered by picking one of its options, yes/no, or a level on a scale. Returns each field's value and a confidence from 0 to 1. Use it to map what a person said to one of a fixed set of actions, intents, queues or labels. Below about 0.85 confidence, ask the person instead of acting.",
  "input_schema": {
    "type": "object",
    "properties": {
      "schema": {
        "type": "object",
        "description": "Field name to field. One decision per field. Each field has a question and exactly one of: options (pick one), type yes_no, or scale (ordered levels, low to high).",
        "additionalProperties": {
          "type": "object",
          "properties": {
            "question": {
              "type": "string",
              "description": "The question the model answers about the text."
            },
            "options": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Pick one of these. The answer is the option text, verbatim. Include a way out like \"Nothing yet\" or \"Not sure\"."
            },
            "type": {
              "type": "string",
              "enum": [
                "yes_no"
              ],
              "description": "yes_no: the answer is true or false."
            },
            "scale": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Ordered levels, low to high. The answer is a level, plus its 0-based index."
            }
          }
        }
      },
      "text": {
        "type": "string",
        "description": "What the person said or wrote: an utterance, a transcript, a ticket."
      }
    },
    "required": [
      "schema",
      "text"
    ]
  }
}
```

OpenAI (Chat Completions `tools`; the Responses API takes the same `name`, `description` and `parameters` without the `function` wrapper):

```json
{
  "type": "function",
  "function": {
    "name": "megachad_decide",
    "description": "Make fast, calibrated decisions about a piece of text with megachad (the model decides in ~17 ms). Give a schema of fields; each field is one question answered by picking one of its options, yes/no, or a level on a scale. Returns each field's value and a confidence from 0 to 1. Use it to map what a person said to one of a fixed set of actions, intents, queues or labels. Below about 0.85 confidence, ask the person instead of acting.",
    "parameters": {
      "type": "object",
      "properties": {
        "schema": {
          "type": "object",
          "description": "Field name to field. One decision per field. Each field has a question and exactly one of: options (pick one), type yes_no, or scale (ordered levels, low to high).",
          "additionalProperties": {
            "type": "object",
            "properties": {
              "question": {
                "type": "string",
                "description": "The question the model answers about the text."
              },
              "options": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Pick one of these. The answer is the option text, verbatim. Include a way out like \"Nothing yet\" or \"Not sure\"."
              },
              "type": {
                "type": "string",
                "enum": [
                  "yes_no"
                ],
                "description": "yes_no: the answer is true or false."
              },
              "scale": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Ordered levels, low to high. The answer is a level, plus its 0-based index."
              }
            }
          }
        },
        "text": {
          "type": "string",
          "description": "What the person said or wrote: an utterance, a transcript, a ticket."
        }
      },
      "required": [
        "schema",
        "text"
      ]
    }
  }
}
```

Example tool input, which is also a valid `/v1/decide` body:

```json
{
  "schema": {
    "team": {
      "question": "Which team should handle this ticket?",
      "options": [
        "Billing",
        "Bug",
        "Account",
        "Other"
      ]
    },
    "urgent": {
      "question": "Does the customer need an answer today?",
      "type": "yes_no"
    }
  },
  "text": "I was charged twice this month and need the refund before rent is due on Friday"
}
```

Handler:

```python
import os
import requests

def run_megachad_decide(tool_input):
    r = requests.post(os.environ.get("MEGACHAD_BASE_URL", "https://api.megachadcua.com") + "/v1/decide",
                      headers={"Authorization": f"Bearer {os.environ['MEGACHAD_API_KEY']}"},
                      json=tool_input, timeout=20)
    body = r.json()
    if r.status_code != 200:
        return {"error": body["error"]}  # the model reads code and message; 400 bad_schema means fix the schema
    return body["fields"]
```
