Give your agents their own small worlds.

Connect them to your customers' apps, data, and APIs through one governed terminal. Credentials, policy, and approvals included.

Twenty-six tool calls. One Bash command.

Structured tools repeat the workflow page by page. smallworld lets the agent compose the whole job in Bash.

Product agent

Structured tools

calls
26
tokens
54.7k
elapsed
40.0s

Set the Status of every page in Content calendar to Published.

The Product agent uses 26 structured tool calls, 54.7 thousand model tokens, and 40 seconds to update 25 Notion pages. With smallworld, the same agent composes one Bash command and finishes with one tool call, 1.4 thousand model tokens, and 11 seconds.

You ship the agent.smallworld gives it a world.

Your backend owns the model loop and customer experience. Add one execute tool; smallworld runs the durable terminal behind it, connecting each end user’s accounts through the policy you set for that agent.

Product agent

Merge the pull request linked to “Retry failed imports” and move the backlog item to Done.

Found PR #482 in acme/webComplete
Merged PR #482 in acme/webComplete
Marked backlog item DoneComplete

Done. I merged PR #482 and moved “Retry failed imports” to Done in Notion.

Backend

Your stack
  1. import { Agent, run, tool } from "@openai/agents";
  2. import { z } from "zod";
  3. const sessionId = await sessionFor(endUser.id);
  4. const apiKey = process.env.SMALLWORLD_API_KEY;
  5. const execUrl = `${SMALLWORLD_URL}/v1/worlds/` +
  6. `${WORLD_ID}/sessions/${sessionId}/exec`;
  7. const execute = tool({ name: "execute",
  8. parameters: z.object({ command: z.string() }),
  9. async execute({ command }) {
  10. const job = await fetch(execUrl, {
  11. method: "POST", headers: {
  12. Authorization: `Bearer ${apiKey}`,
  13. "Idempotency-Key": crypto.randomUUID(),
  14. }, body: JSON.stringify({
  15. command, mode: "sync" }),
  16. }).then((res) => res.json());
  17. if (job.status === "awaiting_approval")
  18. await publishApproval(job);
  19. return await waitForCompletion(job);
  20. },
  21. });
  22. const agent = new Agent({
  23. instructions: worldPrompt,
  24. model: process.env.OPENAI_MODEL,
  25. tools: [execute],
  26. });
  27. await run(agent, message);

smallworld

Complete
  1. notion database item get \  --database "Product backlog" \  --name "Retry failed imports"
    Found linked pull request · acme/web#482
  2. github pull-request merge \  --repo acme/web \  --number 482 \  --method squash
    Merged PR #482 with squash
  3. notion page update \  --page "Retry failed imports" \  --status Done
    Set Status to Done
A product agent sends one execute call through its company-owned backend into a governed smallworld World. Inside that durable invocation, smallworld finds the linked pull request in Notion, pauses the GitHub merge for end-user approval in the product, resumes the exact terminal continuation, and updates the original Notion item.

A gateway in your loop

Keep your model, agent loop, UI, and existing tools. Add one execute tool as the gateway to everything smallworld exposes.

A durable workspace

Use pipes, files, and saved session state. The model doesn’t need to handle every step.

Governance made easy

Keep credentials outside the model. Allow, ask, or deny every operation on user or world level.

Turn raw tool output into the next command's input.

When joins and business rules outgrow a shell pipeline, use JavaScript or Python. Customer records and SLA rules turn 86 orders into a 14-order review queue, with 4 exceptions kept for follow-up.

Shell tools
included
JavaScript
QuickJS
Python
CPython-WASM
build_queue.pyPython
01import json02from datetime import datetime, timedelta, timezone03from pathlib import Path0405def load(name):06    path = Path("input") / f"{name}.json"07    return json.loads(path.read_text())0809def save(name, rows):10    path = Path("output") / f"{name}.json"11    path.write_text(json.dumps(rows, indent=2))1213orders = load("orders")14customers = {c["id"]: c for c in load("customers")}15rules = load("sla-rules")16now = datetime.now(timezone.utc)17queue, exceptions = [], []1819for order in orders:20    customer = customers.get(order.get("customer_id"))21    rule = rules.get(customer.get("tier")) if customer else None22    if not rule:23        exceptions.append({24            "order_id": order["id"],25            "reason": "missing_customer_or_sla",26        })27        continue28    opened = datetime.fromisoformat(order["opened_at"].replace("Z", "+00:00"))29    due = opened + timedelta(hours=rule["response_hours"])30    high_value = order["amount_cents"] >= rule["review_over_cents"]31    if due <= now + timedelta(hours=4) or high_value:32        queue.append({33            "order_id": order["id"],34            "owner": customer["owner"],35            "due_at": due.isoformat(),36        })3738queue.sort(key=lambda item: item["due_at"])39save("priority", queue)40save("exceptions", exceptions)
Wrote 14 priority orders and 4 exceptions
Python joins customer and SLA data with order records, then writes a priority queue and an exception file inside the World's virtual filesystem.
Example session

/workspace

  • input/
    • orders.json86 records
    • customers.json61 records
    • sla-rules.json3 tiers
  • scripts/
    • build_queue.py1.4 KB
  • output/
    • priority.json14 records
    • exceptions.json4 records
  • reports/
    • priority-page.json1.8 KB

Command log

  1. notion database query

    --id orders-db > input/orders.json · 86 pages

  2. hubspot company list

    --properties tier,owner > input/customers.json · 61 records

  3. python scripts/build_queue.py

    exit 0 · 14 priority orders · 4 exceptions

  4. fs.write

    reports/priority-page.json · 1.8 KB

  5. notion page create

    --file reports/priority-page.json · allowed

  6. fs.commit

    snapshot v12 · 7 files · 18.4 KB

Oversized stdout is materialized as a virtual file.

The next command starts where the last one finished.

After every execution, smallworld saves a versioned virtual-filesystem snapshot. Return to the same World and represented user, and the session resumes with the same files.

The accounts change. Your agent's interface doesn't.

Give each World the providers and operations its workflows need. End users connect accounts once in the Workspace; your agent keeps the same execute tool across the entire catalog.

All integrations. One command surface.

  • Notion
  • Gmail
  • Google Drive
  • Calendar
  • Figma
  • Asana
  • Airtable
  • Linear
  • GitHub
  • GitLab
  • Jira
  • Vercel
  • Cloudflare
  • Sentry
  • PagerDuty
  • Datadog
  • HubSpot
  • Stripe
  • Shopify
  • Intercom
  • Zendesk
  • Mailchimp
  • Calendly
  • Typeform
  • Snowflake
  • PostgreSQL
  • BigQuery
  • Supabase
  • Many more integrations

Access for the World

Select the providers and operations this World may use.

End users connect accounts

Reuse one user connection wherever that provider is enabled.

One unchanged interface. Your agent sees only the commands available to that World and user through the same execute tool.

The policy decides what runs, asks, or stops.

Set a default for the World, then override individual operations. Each call is allowed, sent for approval, or denied before credentials attach.

The catalog defines each approval. It applies only to the paused operation.

Standard preset
Example operation risk classes and governance verdicts
OperationClassResult
Read customer recordReadAllow
Update campaignReversible writeAllow
Merge pull requestDestructiveAsk
Change organization settingsAdminAsk
Unclassified operationUnknownDeny

Your agent can request an action. It never receives a token.

smallworld checks policy first, then its credential broker authenticates only the permitted provider call. The credential never enters the World.

  1. Inside the World

    01

    Agent requests

    A named operation and its arguments.

  2. 02

    Policy evaluates

    The World allows, asks, or denies.

  3. Outside the World

    03

    Broker authenticates

    Only the permitted provider call.

    Credential attaches here

  4. 04

    Provider receives

    The brokered request.

Tokens never enter the model, terminal, virtual files, or output.

Give your agent a governed place to work.

Create a World, run its first command, and connect customer accounts only when a workflow needs them.