> For the complete documentation index, see [llms.txt](https://docs.drizz.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.drizz.dev/twins/using-twins/run-your-agent.md).

# Run your agent

Run any agent in a world with twin world run, control the world's clock, make mail arrive mid-run, and inject faults.

`twin world run` starts your agent inside a world, with the world's address, token and clock in its environment.

|                     |                                                                               |
| ------------------- | ----------------------------------------------------------------------------- |
| **Twins**           | Google Calendar · Gmail                                                       |
| **You need**        | a world folder from `twin world create`                                       |
| **Your agent gets** | `TWIN_MCP`, `TWIN_TOKEN`, `TWIN_GMAIL_MCP`, `TWIN_GMAIL_TOKEN` and `TWIN_NOW` |
| **Watch out**       | a second run in the same world starts from what the first run left            |

## Prerequisites

* A world folder. See [Describe a world](/twins/using-twins/describe-a-world.md).
* The command that starts your agent. Any command works.

## Copy this

Give `twin world run` the world's folder, then `--`, then the command that starts your agent:

```bash
twin world create seed.md --folder world
twin world run world -- python my_agent.py "What's on my calendar this week?"
twin world calls world --writes
twin world delete world
```

Your agent starts with the world's MCP address and token in its environment (`TWIN_MCP`, `TWIN_TOKEN`, and `TWIN_GMAIL_MCP`, `TWIN_GMAIL_TOKEN` for a mailbox), plus the world's clock in `TWIN_NOW`. So it reaches the twin and not the real app. `twin world run` ends with your agent's own exit status.

Any command works:

```bash
twin world run world -- python3 my_agent.py "Book Priya's call and reply to her."
twin world run world -- sh claude_agent.sh "Book Priya's call and reply to her."   # Claude Code, one run
twin world run world -- twin-agent "Move my Dentist to Thursday 2pm"              # the example agent
```

The Claude Code script is on [Connect your agent](/twins/using-twins/connect-your-agent.md#connect-a-client).

## Steps

{% stepper %}
{% step %}

### Make the world

```bash
twin world create seed.md --folder world
```

The folder `world/` keeps the world's address and tokens. Every other `twin world` command takes it.
{% endstep %}

{% step %}

### Run your agent

```bash
twin world run world -- python my_agent.py "Priya asked for a call on Thursday 2-4pm. Book it and reply to her."
```

{% endstep %}

{% step %}

### Look at what it did

```bash
twin world calls world --writes
```

See [See what your agent did](/twins/using-twins/see-what-your-agent-did.md).
{% endstep %}

{% step %}

### Change the world, and run again

The world keeps its state between runs. Make new mail arrive, then run your agent again in the same world:

```bash
twin world trigger world new-mail.md
twin world run world -- python my_agent.py "Anything new from Priya?"
```

{% endstep %}

{% step %}

### Delete it

```bash
twin world delete world
```

A world you forget deletes itself when its lease ends (6 hours by default).
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Start every run from a known state.** A second run in the same world starts from what the first run left. To run again from the start, make a fresh world from the same seed file, or keep a snapshot and make the world again from it (see [Keep a world](/twins/using-twins/see-what-your-agent-did.md#keep-a-world)).
{% endhint %}

## Several worlds at once

Each `twin world create` makes a new, separate world. Run different agents side by side, or the same agent twice. A `--label` groups the worlds, so you can list and delete them together:

```bash
twin world create seed.md --folder a1 --label demo
twin world create seed.md --folder a2 --label demo
twin world run a1 -- python agent_v1.py "Book Priya's call."
twin world run a2 -- python agent_v2.py "Book Priya's call."
twin world list --label demo
twin world cleanup --label demo
```

A label is up to 12 letters, digits or hyphens. Your organization holds 25 worlds at a time unless an admin raised it; `twin world list` shows how many are in use. See [Keys and limits](/twins/reference/keys-and-limits.md#limits).

## The world's clock

A seed file's `now:` line pins the world's clock, such as `now: Mon 09:00`. Every day in the seed file is read against it, so "Thursday" means the same day whenever you make the world. See [Describe a world](/twins/using-twins/describe-a-world.md#the-worlds-clock).

Your agent gets that moment in `TWIN_NOW`, for example `2026-09-28T09:00:00Z`. Pass it to your agent's model, so its "today" is the world's today and not the real one:

```bash
task=${TWIN_NOW:+"(Today is $TWIN_NOW.) "}$1
```

In the [web console](/twins/using-twins/web-console.md#twin-controls), a twin's controls show what its clock reads, and can wind it forward by an hour, a day or a week.

## Make things happen mid-run

`twin world trigger` adds mail and events to a world as it stands now. It never resets the world. Write a trigger file in the seed file's own syntax:

```markdown
## World: gmail
now  Priya Shah <priya@acme.test> -> me  "Re: Offsite dates"  #offsite // Thursday is out, sorry.
today 09:12  Ops <ops@acme.test> -> me  "Outage report"  // The API was down from 08:50.

## World
Thu 15:00-16:00  Incident review  (ops@acme.test)
```

```bash
twin world trigger world new-mail.md
```

* **Mail** arrives as new mail does: in `INBOX` and `UNREAD` unless the line gives labels, and the mailbox's filters run over it.
* **Dates.** A day on the line is read against the world's clock. `now` in place of the day and time dates the mail by the twin's own clock.
* **Threads.** An email whose `#thread` (or subject, less its "Re:") matches mail already in the world joins that thread, as a reply does.
* **Events** go on the primary calendar.
* **The record.** What a trigger adds is the world, not your agent. Its calls are left out of `twin world calls`, as the seed's own are.

`--json` prints what landed. You can trigger while your agent is running, from another terminal.

For mail that arrives on a cue instead, put an `after message.send#1:` line in the seed file: it lands when your agent sends its first email. See [Mail that arrives mid-task](/twins/using-twins/describe-a-world.md#mail-that-arrives-mid-task).

## Inject faults

A clean run shows what your agent does when nothing goes wrong. Faults show what it does when a call fails. A fault makes one attempt of one calendar operation fail, with a status you choose.

Add a `## Faults` section to your seed file, one fault per line: `<operation> <attempt> <status>`.

```markdown
## Faults
events.create 1 503
events.list 2 503
```

Here the first `events.create` and the second `events.list` fail. Faults are armed after the world is seeded, so seeding never trips one. Each fires on a fixed attempt, so a run with faults repeats like a clean one.

Or set `TWIN_FAULTS` when you create the world, to a preset or to fault lines, comma-separated:

```bash
TWIN_FAULTS=light twin world create seed.md --folder world
TWIN_FAULTS="medium, events.update 2 503" twin world create seed.md --folder world
```

| `TWIN_FAULTS` | What your agent meets                                                                                               |
| ------------- | ------------------------------------------------------------------------------------------------------------------- |
| `light`       | the first `events.list` fails with a server error                                                                   |
| `medium`      | that, and the first write of each kind fails too (`events.create`, `events.update`, `events.remove`, `events.move`) |
| `nonatomic`   | the first `events.create` is made, and still answered with 504                                                      |
| `quiet`       | the first `events.list` answers 200 with one event left out                                                         |

Two more kinds go at the end of a fault line:

| Line                          | What your agent meets                                                                                                        |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `events.create 1 504 applied` | the event is made, and the call still answers with an error. An agent that retries without reading back first books it twice |
| `events.list 1 drop_item`     | 200, with one event left out of the list. No error to react to                                                               |

{% hint style="warning" %}
**Use the twin's own operation names**: `events.create`, not Google's `events.insert`; `events.update`, not `events.patch`; `events.remove`, not `events.delete`. A fault on a name the twin does not serve would never fire, so it is refused. Two faults on the same attempt of one operation are refused too: only the first could fire.
{% endhint %}

If the twin does not offer a fault kind yet (such as `drop_item`), that fault is skipped with a warning, and the world still opens.

In the [web console](/twins/using-twins/web-console.md#twin-controls), "Make a call fail" arms a fault on a twin that is already running.

## Settings that matter

Set these in front of the command, or in your shell. `twin help environment` lists every variable.

| Variable                  | What it does                                                                                                               |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `TWIN_FAULTS`             | faults injected into your agent's calendar calls: `light`, `medium`, `nonatomic`, `quiet`, or fault lines, comma-separated |
| `TWIN_SERVER`             | the twin server `twin login` signs in to (default: Drizz's hosted twins)                                                   |
| `TWINS_API_KEY`           | a key minted elsewhere, used instead of a kept sign-in. For CI                                                             |
| `TWIN_WORLD_SHARED`       | `1`: worlds your organization shares (a teammate's key reads them; only an admin's deletes them), instead of private ones  |
| `TWIN_DEBUG`              | `1`: an error comes with its traceback                                                                                     |
| `TWIN_LOG_LEVEL`          | the log messages shown on stderr: `WARNING` (default), `INFO`, `ERROR`                                                     |
| `TWIN_SKIP_HEALTH`        | `1`: skip asking the twin's `/health` before a command starts                                                              |
| `TWIN_NO_UPDATE_NOTIFIER` | `1`: never check for a newer release                                                                                       |

And the options on the commands themselves:

| Option                                | What it does                                                                                                                                             |
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `twin world create --lease <seconds>` | how long the world lives if never deleted (default 6 hours)                                                                                              |
| `twin world create --label <name>`    | a group name, to list and clean up worlds together                                                                                                       |
| `twin world create --person <name>`   | whose calendar and mailbox (default: your first identity)                                                                                                |
| `twin start --lease <seconds>`        | how long a `twin start` world lives when you are signed in (default 1 hour). A trial world, made without a sign-in, lives as long as the server gives it |

See the [command reference](/twins/reference/cli.md) for every option.

## Common mistakes

| What you write                                          | What happens                                                                                                    |
| ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `events.insert 1 503` in `## Faults`                    | Refused. The twin's name is `events.create`; a fault on a name the twin does not serve would never fire         |
| `events.patch` or `events.delete` in a fault            | Refused the same way. Use `events.update` and `events.remove`                                                   |
| Two faults on the same attempt of one operation         | Refused: only the first could fire                                                                              |
| A second run in the same world, expecting a fresh start | It starts from what the first run left. Make a fresh world from the seed file, or make it again from a snapshot |

## Next

* [See what your agent did](/twins/using-twins/see-what-your-agent-did.md): read every call it made.
* [Several twins as one unit](/twins/using-twins/several-twins.md): calendar and mailbox as one environment.
* [CLI reference](/twins/reference/cli.md): every option.

***

*Last updated: 27 October 2026*
