> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackshift.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# The agents SDK for TypeScript and Python

> The packages `@stackshift-cloud/agent` and `stackshift-agent` give your code events, governed actions, StackShift calls, state, model clients and adapters for the Claude Agent SDK and the OpenAI Agents SDK.

> [!NOTE]
>
> **Not yet released.** This guide describes implemented changes awaiting rollout. Availability requires the corresponding backend and dashboard release.

## Goal

Write an agent that StackShift can run, govern and stop, in TypeScript or Python.

## Prerequisites

* Node 20 or newer for TypeScript, or Python 3.9 or newer.
* The official packages you want to use: `@anthropic-ai/sdk`, `openai`, `@anthropic-ai/claude-agent-sdk` with `zod`, or `@openai/agents` for TypeScript; `anthropic`, `openai`, `claude-agent-sdk` or `openai-agents` for Python. They are optional.

## Workflow

**Step 1**

Install `@stackshift-cloud/agent` (`npm install`) or `stackshift-agent` (`pip install`).

**Step 2**

Register handlers with `agent.on(event, …)` and wrap each declared action with `agent.action(key, …)`.

**Step 3**

End the file with `agent.start()`. It listens on `PORT`, 8080 unless you set it, and answers `POST /stackshift/events`.

**Step 4**

Declare each action and each StackShift action you use in the agent block of `stackshift.yaml`.

**Step 5**

Deploy. StackShift sets `STACKSHIFT_API_URL`, `STACKSHIFT_AGENT_ID`, `STACKSHIFT_AGENT_HANDLE`, `STACKSHIFT_EVENT_KEY` and `PORT` for the agent.

## A first agent

The handler gets the event with its `type`, `id`, `at`, `data`, `untrusted` and run id. Each event is checked against `STACKSHIFT_EVENT_KEY` before any handler runs. A repeated event id is dropped. A handler that throws ends the run `failed`, a run that saved an action for approval ends `waiting`, and anything else ends `done`.

```ts TypeScript theme={null}
import { agent } from '@stackshift-cloud/agent'

const lookupOrder = agent.action('lookup_order', async ({ order_id }: { order_id: string }) => {
  return { order_id, status: 'shipped' }
})

agent.on('inbox.message', async ({ data }) => {
  const order = await lookupOrder({ order_id: data.message.subject })
  await agent.inbox.reply(data.message, `Your order is ${order.status}.`)
})

await agent.start()
```

```python Python theme={null}
from stackshift_agent import agent


@agent.action("lookup_order")
async def lookup_order(args):
    return {"order_id": args["order_id"], "status": "shipped"}


@agent.on("inbox.message")
async def answer(event):
    order = await lookup_order({"order_id": event.data["message"]["subject"]})
    await agent.inbox.reply(event.data["message"], f"Your order is {order['status']}.")


agent.start()
```

## StackShift calls, inbox, agreements and state

`agent.platform.call(key, args)` proposes a StackShift action through the agent’s connection and waits up to 55 seconds for it to settle. `agent.platform.inspect(key, args)` runs a read. The agent can use only the actions in its `platform:` list.

`agent.inbox` has `send`, `reply`, `info` and `id`. `agent.agreements` has `list`, `inspect`, `limits`, `verify`, `wait`, `propose`, `respond`, `cancel` and `countReply` (`count_reply` in Python); it works when agreements are on for the agent’s inbox. `agent.state` keeps values and locks that survive sleep.

```ts TypeScript theme={null}
const operation = await agent.platform.call('database.inspect', { database_id }, { reason: 'Check the size' })
const inbox = await agent.platform.inspect('mail.agent_inboxes.get', { inbox_id })
await agent.state.set('last_report', { at: Date.now() }, { ttlSeconds: 86400 })
await agent.state.withLock('nightly', async () => {})
```

```python Python theme={null}
operation = await agent.platform.call("database.inspect", {"database_id": database_id}, reason="Check the size")
inbox = await agent.platform.inspect("mail.agent_inboxes.get", {"inbox_id": inbox_id})
await agent.state.set("last_report", {"at": 1}, ttl_seconds=86400)
async with agent.state.locked("nightly"):
    ...
```

## Models and the internet

`agent.anthropic()` and `agent.openai()` return the official clients, pointed at StackShift and signed in with the run token (`async_anthropic` and `async_openai` in Python). `agent.fetch` reaches the addresses you allow, adding any key you saved to send on the way out. `agent.untrusted(text, source)` marks text your code fetched itself.

## Claude Agent SDK and OpenAI Agents SDK

The adapters turn your declared actions into tools for those SDKs, with the approval step built in. A refusal or a wait comes back to the model as text, not as a crash. Call them while handling an event.

```ts TypeScript theme={null}
import { claudeTools } from '@stackshift-cloud/agent/claude'
import { openaiTools } from '@stackshift-cloud/agent/openai'

agent.on('inbox.message', async () => {
  const { mcpServers, allowedTools } = await claudeTools(agent)
  const tools = await openaiTools(agent)
})
```

```python Python theme={null}
from stackshift_agent.adapters.claude import claude_tools
from stackshift_agent.adapters.openai_agents import openai_tools


@agent.on("inbox.message")
async def on_message(event):
    claude = await claude_tools(agent)
    tools = await openai_tools(agent)
```

## Manage agents from outside

The StackShift SDKs manage agents from your own scripts: `stackshift.hostedAgents` in `@stackshift-cloud/sdk` and `stackshift.hosted_agents` in the Python `stackshift` package. They have `list`, `get`, `create`, `deploy`, `rollback`, `stop`, `start`, `delete`, `runs`, `spend` and `logs`, plus `secrets.set` and `unset` and `budget.set`.

## Expected result

> [!TIP]
>
> Your agent receives signed events once each, asks StackShift before its declared actions, and calls models and StackShift with the run token the SDK keeps for it.

## Common failures

> [!WARNING]
>
> * start fails with “STACKSHIFT\_EVENT\_KEY is not set”: the agent is not running on StackShift. Set the variable to test locally.
> * Calls to StackShift fail with “The agent has no run token yet”: the SDK gets its token from each event, so call StackShift while handling one.
> * An action fails with “Actions run while the agent handles an event”: call wrapped actions from a handler, not at start-up.
> * `agent.anthropic()` says to install the package: add `@anthropic-ai/sdk` or `anthropic`.

## Related guides

> [card] [Your agent’s own actions: risk, approvals and levels](https://docs.stackshift.cloud/ai-features/hosted-agents-actions.md)
>
> Declare the tools your agent has, give each a risk, and let StackShift apply the agent’s level, approvals and untrusted-text checks before they run.

> [card] [Events that wake your agent](https://docs.stackshift.cloud/ai-features/hosted-agents-events.md)
>
> Every email, agreement, schedule, webhook and approval reaches your agent as a signed event. The SDK checks it, drops repeats and runs your handler.

> [card] [Model access for agents](https://docs.stackshift.cloud/ai-features/hosted-agents-models.md)
>
> Your agent calls Anthropic or OpenAI through StackShift with a short-lived token. No provider key is ever in the agent.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.