Twins

Guides

Twins quickstart

Goal: a running environment with the service twins your agent touches — seeded state serving REST, MCP, and a generated CLI — in about a minute. Two equivalent paths: the blobfish CLI, or plain HTTP.

1 · Get an API key

Mint one on the portal (shown exactly once), or over HTTP:

Mint a key
$ curl -sS -X POST https://blobfish.ai/api/v1/auth/keys \
    -H "Content-Type: application/json" \
    -d '{"email":"you@company.com","name":"twin-quickstart"}'
$ export BLOBFISH_API_KEY=bf_…   # from the response — shown once

2 · Create a twin environment

With the CLI (the login step stores the key for you):

Terminal
$ uv tool install blobfish-cli
$ blobfish twin login
$ blobfish twin-runs create --twins slack,stripe --ttl 60 --wait

Or over HTTP — same request the CLI makes:

API
$ curl -sS -X POST https://blobfish.ai/api/v1/twin/environments \
    -H "X-API-Key: $BLOBFISH_API_KEY" -H "Content-Type: application/json" \
    -d '{"services":["slack","stripe"],"ttl_minutes":60}'

The response reports the environment’s observed status (service environments assemble synchronously and come back ready), the mounted services with their runtime rung, and links: the console page, the MCP endpoint, the per-service API index, and the CLI download. The ttl_minutes lease is bookkeeping — the console marks an environment expired, and delete delists it; the backing world is persistent data and is never destroyed by lease mechanics.

3 · Point your agent at it (MCP)

The create response’s routing.env keys (the CLI writes the file for you) carry one MCP endpoint for the whole environment and one per service. For an MCP-speaking agent:

MCP client config
{
  "mcpServers": {
    "blobfish-twin": {
      "url": "https://blobfish.ai/api/v1/sandbox/worlds/<world_id>/mcp",
      "headers": { "X-API-Key": "bf_…" }
    }
  }
}

tools/list returns every mounted tool (service-namespaced: slack_conversations_list, stripe_get_payment_intents, …); tools/call executes it against the seeded state.

4 · Call the REST surface

REST
# read — args as query params
$ curl -sS "https://blobfish.ai/api/v1/sandbox/worlds/<world_id>/services/slack/operations/conversations.list?token=xoxb-test" \
    -H "X-API-Key: $BLOBFISH_API_KEY"

# write — JSON body; the route 405s a write sent as GET
$ curl -sS -X POST https://blobfish.ai/api/v1/sandbox/worlds/<world_id>/services/slack/operations/chat.postMessage \
    -H "X-API-Key: $BLOBFISH_API_KEY" -H "Content-Type: application/json" \
    -d '{"token":"xoxb-test","channel":"C0000001","text":"hello twin"}'

5 · Or drive it from the generated CLI

bf-twin
$ blobfish twin-runs cli <env_id> -o bf-twin   # or curl the links.cli URL
$ ./bf-twin services
$ ./bf-twin slack ops
$ ./bf-twin slack call chat.postMessage --json '{"token":"xoxb-test","channel":"C0000001","text":"hello twin"}'
$ ./bf-twin slack state
$ ./bf-twin slack reset

For isolated parallel rollouts, ./bf-twin session new prints an export BLOBFISH_TWIN_SESSION=… line — every call carrying that session runs on a copy-on-write fork, and reset restores only that fork.

6 · Watch it

The environment’s console page (links.console) shows the live topology graph — gateway, service twins, world runtime, seed baseline, session overlays — plus per-service endpoints, state tables, and the routing.env block. Manage the lease with blobfish twin-runs extend <env_id> --ttl 60 and delist with blobfish twin-runs delete <env_id>.

Next

Local testing — point a local app at the twins · Custom scenarios — seed the exact state your test needs · Twin reference — every twin, its runtime, and its limitations.