Build

Agent definitions

An agent definition is the set of fields that decide how an agent behaves on a turn: its instructions, model, reasoning effort, per-turn timeout, toolkits, and skills. By default those fields live in Mobius, on the agent row. You can also send a definition with a request, or have Mobius fetch one from your own backend. Whichever source produces it, the runtime runs the same flat definition the same way.

Pluggable definitions exist for one job: when you embed Mobius as the agentic backend for a product, your app already owns how the agent should behave and ships changes on its own cadence. Copying those definitions into per-tenant Mobius rows means every behavior change fans out across tenants and drifts. Keeping the definition in your system means a behavior change is just different bytes on the next call.

The agent row still exists as the durable anchor for identity and state: its principal, memory, sessions, and run history. Only its behavior becomes source-pluggable.

Where a definition comes from

There are three sources. They converge on one definition; the executor never knows which one produced it.

SourceWho supplies itUse when
mobius_storedMobius, from the agent rowYou author and edit agents in Mobius. This is the default.
Inline configYou, on the invoke requestYou initiate the run and want to send the definition with it.
Client resolverYour endpoint, called by MobiusMobius initiates the run (a schedule or a trigger) and must fetch your current definition at run start.

The split follows the two ways a run starts. A run you initiate carries a request that can hold the definition, so inline config fits. A run Mobius initiates has no such request, so Mobius calls your resolver instead. Both land on the same definition shape below.

What's in a definition

Every field is optional. When a field is present it replaces the agent's stored value; when it is absent the agent's stored value stands.

FieldMeaning
instructionsSystem-prompt instructions for the agent. An empty value falls back to the generated default.
modelModel identifier. Resolves through the same model routing and allow rules as a stored agent's model.
effortReasoning effort for the turn: low, medium, high, xhigh, max, or inherit.
timeout_secondsPer-turn execution timeout. Zero uses the platform default. A loop step's own timeout still overrides this.
toolkitsToolkit selections that replace the agent's toolkit assignments. Each names actions from this project's catalog.
skillsSkills that replace the agent's skill assignments. Each carries its own instruction body, loaded on demand.

toolkits and skills are lists, and a supplied list replaces the agent's list whole. Mobius does not merge lists item by item, because a partial merge would make the resulting tool surface depend on state you can't see in the request.

Two rules keep a supplied definition from widening access:

  • toolkits select from your project's catalog, they do not create tools. A toolkit can name only actions the project already has (built-ins and connected integrations). Names outside the catalog are ignored, so a definition can scope tools down, never fabricate them. See toolkits and skills for how the final tool manifest resolves.
  • The org ceiling clamps, it does not grant. If your organization caps a field (today, the per-turn timeout), a definition from any source is clamped to the allowed maximum. A source can narrow behavior but never widen it past org policy.

Send a definition with the invoke request

For runs you initiate, add a config block to the compound invoke call. This is the path most embedding products use, and it works the same way system and tools travel with a Messages API request.

{
  "agent_ref": { "id": "agt_scout" },
  "session": {
    "mode": "continue_or_create",
    "session_key": "app:acct_123:user_456:support"
  },
  "config": {
    "instructions": "You are Acme's support agent. Be concise and cite ticket numbers.",
    "model": "claude-sonnet-4-6",
    "effort": "medium",
    "timeout_seconds": 120,
    "toolkits": [
      { "name": "tickets", "actions": ["tickets.search", "tickets.get"] }
    ],
    "skills": [
      { "name": "refunds", "description": "How to issue a refund", "body": "..." }
    ]
  },
  "input": {
    "content": [{ "type": "text", "text": "Summarize my open tickets." }],
    "idempotency_key": "msg_01J8..."
  }
}

Mobius stores config on the resolved session, so you send it once and later turns reuse it:

  • Send it on the call that creates the session and it becomes the session's definition.
  • Send it again on a later turn to replace it. A session holds one config at a time, and the last one Mobius saves wins.
  • Leave it out on a later turn and the session keeps the definition it has.
  • Send an empty {} to clear it and revert the session to the agent's own definition.

A stateless client can simply send the full document on every invoke. To run two different definitions at the same time, give each its own session_key, or send session.mode: "new" so each call gets its own session.

Precedence on each turn is inline config, then the agent's stored overrides, then the resolved source, all clamped by the org ceiling. The serialized config is capped at 256 KB, large enough for real instruction sets and small enough to keep the request cheap to validate.

Note: config is for one-off invocations. Loops and schedules must point to a stored agent, so creating or updating a loop with config is rejected. Loops reference a definition; they never freeze a snapshot of one. For Mobius-initiated runs, use a client resolver instead.

See agent invocation for the full invoke mechanics: streaming modes, idempotency, and reconnect rules.

Definitions for Mobius-initiated runs

A loop run started by a schedule or a trigger has no request to carry config. If your definitions live in your own system, point your organization at an HTTPS endpoint Mobius calls at run start. This is an embedding-platform capability; an org admin (Admin or Owner) sets it up with Mobius rather than through a self-serve API.

At run start Mobius POSTs your endpoint with Authorization: Bearer <token> and a batch-of-one request:

{
  "protocol_version": 1,
  "org_id": "org_123",
  "project": { "id": "prj_456", "external_ref": "workspace_789" },
  "trigger": { "kind": "schedule" },
  "refs": [{ "selector": "agent/scout", "known_digest": "sha256:abc..." }]
}

Your endpoint reads the tenant from project.external_ref, then returns the flat definition, or unchanged when your digest still matches what Mobius cached:

{
  "resolved": {
    "agent/scout": {
      "digest": "sha256:def...",
      "value": {
        "agent": {
          "instructions": "...",
          "model": "claude-opus-4-8",
          "effort": "high",
          "timeout_seconds": 600
        },
        "toolkits": [{ "name": "crm", "actions": ["crm.lookup"] }],
        "skills": [{ "name": "triage", "body": "..." }]
      }
    }
  }
}

Return { "unchanged": true } for a ref whose known_digest is current, and Mobius serves its cached copy. Return { "error": { "code": "unknown_agent" } } to fail the run with a reason rather than run an empty definition.

  • Tenant identity is external_ref, not the token. Set an immutable external_ref (your own tenant or workspace id) on each project. Mobius sends it on every resolve so you map it to your own definition. The bearer token only proves the caller is Mobius.
  • Canary and rollback are yours. Vary the returned digest per cohort in your resolver. Mobius stores no pins, so a rollout is a branch in your code, not a migration in ours.

When your endpoint is unavailable

If your endpoint is briefly down, the run does not have to fail. The resolver config sets a degradation policy:

  • last_known_good (the default) serves the last successful definition, which Mobius keeps durably in Postgres, up to a staleness bound you set.
  • fail fails the run to start with a clear reason.

Either way, Mobius never silently runs an empty definition. A fresh cache also skips the network entirely, so a short revalidation window keeps run-start fast without a fetch on every fire.

Warning: Resolver URLs must be https. Mobius refuses loopback, link-local (including cloud metadata), private, and reserved targets, pins the connection to the validated address so a rebind can't redirect it, and never follows redirects. The bearer token is sealed at rest and redacted on read.

Guarantees

  • Definitions come from you; execution binds to the project. A gmail action in a supplied definition resolves this project's Gmail connection at run time, exactly as a built-in tool does. No per-user credential crosses the resolver boundary.
  • A source can narrow, never widen. Both the org ceiling and the catalog-only toolkit rule hold for every source, so a mistake or a compromise in your definition can only reduce scope, not escalate it.
  • The agent row is the constant. Identity, memory, sessions, and run history stay on the agent regardless of where a turn's behavior came from.

FAQ

Does sending config change the stored agent?

No. Inline config lives on the session, not the agent row. The agent's stored definition is unchanged, and other sessions on the same agent are unaffected.

Can I define brand-new actions or MCP servers in a definition?

Not yet. A definition can select existing catalog actions through toolkits and carry skills bodies. Bundle actions and mcp_servers fields are carried for provenance but are not executable, and per-reference ($ref) resolution is a later addition. For now, connect the integration in the project and select its actions.

What happens to model if my org restricts models?

The model you send resolves through the same routing and allow rules as a stored agent's model. If your organization restricts models, a restricted value is rejected the same way it would be on a stored agent.

Next

  • Agent invocation covers the invoke endpoint that carries inline config: streaming, idempotency, and reconnect.
  • Agents are the durable identity behind every definition.
  • Agent sessions hold the inline config and the transcript it runs against.
  • Toolkits and skills explain how a definition's tool surface resolves.