---
name: ergoda-setup
description: Add Ergoda to an AI agent codebase, request one-time full site authority, and operate discovery, routing and ongoing review. Use when asked to set up Ergoda or let an agent manage its lifecycle.
---

# Set up Ergoda in this codebase

Ergoda sits around the model call an agent already makes. Once added, it
measures that call; routes start disabled. A person can delegate ongoing
operation once with a full-scope site key, or keep route changes manual. Your
job is to add it so that **every call behaves exactly as before** until the
customer's evidence supports a route change.

You can set up and operate Ergoda. A person is needed to approve the agent's
site access once, from an account and site they already chose to open:

1. **Approving your login**, in their browser, after you run `ergoda login`.
   When asked to operate Ergoda over time, request `--scope full`. The approval
   page names the access being granted.

## Rules

- Never create an account, sign up, or enter anyone's email address
  anywhere. Do not prompt for signup as part of setup. If the person has not
  already chosen to create an account and site, stop here; that is a separate
  decision they must make themselves.
- Never print, paste or repeat a key in the chat, and never commit
  `ergoda.env`. Keys start with `hk_`. Refer to them by variable name.
- Do not change any call site's arguments, model name or response handling.
- `ergoda init` writes a policy that routes nothing. Keep traffic there while
  collecting evidence. With a full-scope grant, you may publish justified
  routes and operate their ongoing review; policy checks still enforce the
  site's risk limits.
- Do not put keys in source. Environment variables only.
- If anything below does not match this codebase, stop and ask rather than
  guess.

## 1. Find the step and the frontier model

Search for the provider client's create call:

- Anthropic: `messages.create` (Python and TypeScript)
- OpenAI: `chat.completions.create` (Python and TypeScript)

Pick the call the agent makes on every step, usually the one inside its loop.
If there are several, pick the one called most often and mention the others
in your report; do not wrap them all. Give it a short step name in snake_case
that says what the step does, such as `resolve_ticket` or `plan_reply`.

The **frontier model** is the model that call uses in production. Read it off
the `model` argument. If it comes from a variable, an environment variable or
a config file, find the production value. Write it as `provider/model`, for
example `anthropic/claude-opus-5` or `openai/gpt-5.6-sol`. If you cannot tell
which model production uses, ask.

If the call goes through another library (LangChain, LiteLLM, a gateway, a
provider not listed above), stop and ask the person how they want to proceed,
and point them to https://ergoda.com/docs/python-sdk/.

## 2. Install

Python 3.11 or newer, in the project's own environment (its venv, Poetry or
uv project):

```sh
pip install ergoda          # or: uv add ergoda / poetry add ergoda
```

Add `ergoda` to the project's dependency list too (`requirements.txt`,
`pyproject.toml`), the way the project lists its others; `uv add` and
`poetry add` do this themselves.

TypeScript (Node.js 22.18 or newer):

```sh
npm install @ergoda/sdk
```

The npm package provides its own `ergoda` command. It does not need Python.

## 3. Log in (the person approves)

Run this from the project's root directory:

```sh
npx --package=@ergoda/sdk ergoda login --scope full --no-wait
```

The first run exits 3 ("waiting"): that is expected, and its output holds the
link and the code:

```text
Approve this login in your browser:
  https://app.ergoda.com/cli/BCDF-GHJK
Check that the page shows the code BCDF-GHJK.
```

Then tell the person, in your own words but with the real link and code:

> Please open https://app.ergoda.com/cli/BCDF-GHJK, check that it shows the
> code BCDF-GHJK and requests full site access, then grant it. You can revoke
> the key later under API keys. Tell me when you've approved it.

Wait for their reply. Then run the same command again:

```sh
npx --package=@ergoda/sdk ergoda login --scope full --no-wait
```

| Exit code | Meaning | What you do |
|---|---|---|
| 0 | Approved. `ergoda.env` is written | Go on to step 4 |
| 3 | Still waiting for approval | Ask the person again; do not loop on it |
| 1 | Denied in the browser, or the link expired (ten minutes) | Tell the person what it printed. Run it again for a new link only if they want to continue |
| 2 | Wrong flags | Read the message; check `ergoda login --help` |

If the person says the link expired or they lost it, run the same command
again: once the ten minutes are up it prints a new link and code. Before
then it prints the same one, which still works.

Running it again while a login is pending reuses the same link and code, so
the person's open browser tab stays valid. If your tool can wait up to ten
minutes, you may instead run `ergoda login --no-browser`, which returns by
itself once they approve.

On success it prints `Logged in to <organization> (<site id>).` and writes
`ergoda.env` (mode 0600) with `ERGODA_URL`, `ERGODA_KEY` and `ERGODA_SITE`. If
the project is a git repository that does not ignore `ergoda.env`, it adds it
to `.gitignore` and says so; keep that change. With `--scope full`,
`ERGODA_KEY` can read reports, publish/revert/revoke site policies, run
autopilot, adjust evidence sampling, use the site's discovered commands, and
create or revoke site API keys. Without it, the key is ingest-only.
Both are scoped to this site. The approving member can revoke the keys, and
removing that member also revokes keys they granted, including child keys.
Full scope does not manage account ownership, membership, payment methods, or
plan changes; those remain owner/admin controls. The login issues no other
key: do not pass `--read`, which asks for a read key to every report of the
site and is for a person's own machine. Do not open or
print `ergoda.env`; you do not need its contents.

**Interactive login.** To wait for a person to approve in their browser,
`npx --package=@ergoda/sdk ergoda login --scope full` can run without `--no-wait`. It writes
`ergoda.env` after approval. The person must sign in to an existing account;
the agent cannot create the account or approve its own grant. If there is no
account yet, stop setup and let the person decide separately whether to create
one.

## 4. Write the starting policy (Python)

```sh
ergoda init --frontier <provider/model from step 1> --step <step name>
```

`init` writes `routes.yaml`, which routes nothing: every call keeps going to
the model the code names. It adds `ERGODA_POLICY` and `ERGODA_DEFAULT_MODEL`
to `ergoda.env` and prints the lines to add to the code. Commit `routes.yaml`
with your change; it holds no secret.

`init` never opens `ergoda.env` for you to read; trust its output.

TypeScript skips `init`: the client below states the frontier model itself.

## 5. Wrap the call

**Python.** At module scope, next to where the provider client is built. If
the project builds a stand-in client for tests or offline runs, wrap whatever
it built; the wrapper only needs the same call shape:

```python
from ergoda.sdk import Client

ergoda = Client.from_env()
create = ergoda.wrap({"anthropic": client.messages.create}, step="<step name>")
```

For OpenAI the key is `"openai"` and the function is
`client.chat.completions.create`. An async client (`AsyncAnthropic`,
`AsyncOpenAI`) works the same way and is awaited as before. Then replace the
original call with `create(...)`, passing exactly the same arguments. In a
serverless handler (Lambda, Cloud Run), wrap the handler body in
`with ergoda.request():`.

**TypeScript.** At module scope:

```ts
import { Client } from "@ergoda/sdk"

const ergoda = new Client({
  controlPlaneUrl: process.env.ERGODA_URL!,
  siteKey: process.env.ERGODA_KEY,
  siteId: process.env.ERGODA_SITE!,
  defaultModel: "<provider/model from step 1>",
})
const create = ergoda.wrap(
  { anthropic: anthropic.messages.create.bind(anthropic.messages) },
  { step: "<step name>" },
)
```

For OpenAI, use `{ openai: openai.chat.completions.create.bind(openai.chat.completions) }`.
Replace the original call with `await create(...)`, same arguments. On a
platform with `waitUntil` (Vercel, Cloudflare), call
`waitUntil(ergoda.flush())` after responding; on AWS Lambda wrap the handler
body in `ergoda.request(() => ...)`.

The variables must reach the process that makes the model call. Locally,
run `set -a; . ./ergoda.env; set +a` before starting it. Both CLIs write
`export` lines, but a file from the Node CLI 0.1.7 or earlier has none for
`ERGODA_KEY`, and `set -a` exports it anyway. For a
deployed service, tell the person which variables to set in the platform's
environment settings, by name; do not copy values out of `ergoda.env`.

## 6. Verify

1. Run the project's own tests. They must pass unchanged. Missing Ergoda
   configuration never raises; it prints one line on stderr and the call runs
   as before.
2. Confirm the diff touches only the dependency list, the import, the client
   setup, the call site's function name, `routes.yaml` and `.gitignore`.
   `ergoda.env` is untracked and ignored; leave it out of any commit.
3. If the project has a way to run the agent once locally, ask the person
   before you run it, because it makes real model calls on their key. A
   project with an offline or fake-model mode can be run that way without
   asking; its calls still reach Ergoda. Run it with `ergoda.env` loaded:
   `set -a; . ./ergoda.env; set +a` works in any POSIX shell.
4. Run `ergoda status` (Python, or `uvx ergoda status`). It checks the policy,
   the environment and the key, counts the requests that reached Ergoda, and
   prints the one command to run next. A count above zero means setup works.
   A count of zero right after a run can take a few seconds; run it again.
   Note the count before your run so you can tell that your run moved it.
   After a working setup `status` suggests recording traces (`[ ] traces`).
   Record traces locally, then use `ergoda onboard` and `ergoda analyse` to
   find candidates. For live operation, use the site API at
   https://ergoda.com/docs/api/: discover actions with `/commands`, review
   `/steps` and `/autopilot`, publish routes supported by evidence, and run
   `/autopilot/run` as evidence accumulates. The hosted service runs
   regression checks and monthly reviews; inspect reports and act on problems.
   Do not add `record(...)` on top of the wrap.

"Routes nothing" is the expected result during measurement: every call still
goes to the frontier model. With a full-scope grant, the agent can use the
customer's evidence to publish routes and manage their lifecycle without
repeated approval. Report each change and its evidence.

## 7. Report back

Tell the person, in a few lines:

- the step name and the call it wraps, and any other model calls you saw but
  left alone;
- the files you changed;
- the variables the agent's runtime needs (`ERGODA_URL`, `ERGODA_KEY`,
  `ERGODA_SITE`, and for Python `ERGODA_POLICY` and `ERGODA_DEFAULT_MODEL`),
  where they are set now, and where they still need to be set for
  deployment;
- what `ergoda status` said;
- the granted scope, the evidence behind any policy changes, and how the owner
  can revoke the agent key at https://app.ergoda.com/.

## If something goes wrong

- `accounts are opened on the web`: you, or an old instruction, passed
  `--email`. Do not retry with an address. Ask the person to open an account
  at https://app.ergoda.com/onboarding, then run `ergoda login`.
- `ergoda: command not found`: the package is installed in another
  environment. Use the project's runner (`uv run ergoda`, `poetry run ergoda`)
  or activate its venv.
- `ergoda status` says "key accepted" but shows no count: that is the agent
  key working as intended; it cannot read counts. The person sees them on the
  dashboard, or with `ergoda login --read` on their own machine. Do not ask
  for a read key yourself.
- A viewer cannot approve a login. The person needs to be a member who can make
  changes in that organization.
- Anything else: https://ergoda.com/docs/troubleshooting/.
