# Write your agent

The entrypoint contract every harness shares, what the runtime passes in, what you return, and what stays out of your code.

An agent on Tanomis is one Python module with one callable. The runtime calls it with the run's
input and a context, and you return what the harness needs to start. Everything else, the model
route, the workspace, credentials, session continuity, governed tools, is supplied by the runtime.

- The entrypoint is `module:callable`, declared in `agent.yaml` as `entrypoint`.
- It receives `input_payload` (the run's `input` JSON) and `context` (the runtime context).
- With Claude Agent SDK it returns `(prompt, options)`; with Deep Agents it returns a compiled
  graph.
- It must not choose a model, a working directory, or credentials. Those are the manifest's and
  the runtime's.

## The entrypoint

```yaml title="agent.yaml"
entrypoint: agent:create_agent
```

```python title="agent.py"
from __future__ import annotations

def create_agent(input_payload, context):
    ...
```

The callable may accept both arguments, only `context`, or none, and it may be `async`. Keep the
module importable outside the managed runtime so the contract test can import it.

## What comes in

| Argument | What it holds |
|---|---|
| `input_payload` | The run's `input` object exactly as your application sent it, for example `{"prompt": "..."}`. Its shape is yours to define; document it for the callers of your agent. |
| `context` | The runtime context: the resolved model under `context.runtime_context.model`, the session, and the workspace. Pass the model through unchanged; the runtime resolved it for the tenant and version. |

## What you return

| Harness | Return | Notes |
|---|---|---|
| `claude-agents-sdk` | `(prompt, options)` | `options` is a plain dictionary: system prompt, allowed and disallowed tools, max turns, hooks, subagents, permission mode. |
| `deepagents` | The compiled graph from `create_deep_agent` | Tools, middleware, and graph state are yours; the model comes from `context.runtime_context.model`. |

See [Claude Agent SDK](/guides/build/claude-agent-sdk) and [Deep Agents](/guides/build/deep-agents)
for a complete example of each.

## Who owns what

| Concern | Owner |
|---|---|
| Behaviour: prompts, tools, turns, hooks, subagents, graph | You |
| Model resolution and provider credentials | Runtime, from `model` and `permitted_models` |
| Workspace root and working directory | Runtime |
| Session identity, resume, and streaming | Runtime |
| Tool decisions | Composed: your restrictions first, then platform approvals |
| Governed connector configuration | Runtime, from `mcp.connectors` |

Setting a model or a working directory in code to bypass the manifest does not work: the runtime
resolves those for the tenant and version, and the manifest is the contract that was reviewed.

## Ask for a person when it matters

Two manifest switches turn moments in your agent into durable interactions: list tools in
`policy.approval_required_tools` to pause for a permission decision, and set
`policy.enable_ask_user: true` to let the agent ask a question. Your code does not implement the
pause; the harness emits it and the runtime holds it. See
[Approval-required actions](/guides/run/approval-required-actions).

## Where to go next

- [Manifest essentials](/guides/build/manifest-essentials): the fields you touch first.
- [Session workspace and state](/guides/build/session-workspace-and-state): what persists between
  runs.
- [Test before you deploy](/guides/build/test-before-you-deploy): the contract test and the dry
  run.
