> ## 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.

# Your agent’s own actions: risk, approvals and levels

> 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.

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

## Goal

Make your agent’s own tools, such as refunding an order, ask for approval by the same rules StackShift applies to its own actions.

## Prerequisites

* An agent with the agents SDK (`@stackshift-cloud/agent` or `stackshift-agent`) in its code.
* Each action declared under `actions:` in `stackshift.yaml` with a risk.

## Workflow

**Step 1**

Declare the action in `stackshift.yaml` with a summary, a risk and an input schema. Add `money` or `reachesPeople` where they apply.

**Step 2**

Wrap your function with `agent.action(key, fn)`. Call the wrapped function wherever the agent would have called the function itself.

**Step 3**

Deploy. The action appears on the agent’s page, read-only, with its risk in plain words, such as “always asks you”.

**Step 4**

When the agent calls it, StackShift checks the arguments against the schema, the stop switch, the level, the money limit and the untrusted-text check, then answers allowed, waiting or refused.

**Step 5**

When it waits, decide on the approval card. The agent runs the action with exactly the arguments shown on the card.

## Risk words

Two flags add to the risk. `money` says the action spends or moves money: it counts as a cost under levels, and its `limit` is a hard ceiling per action, with today’s total checked too. `reachesPeople` says it contacts people.

`safe` lets an action run on its own at “Safe changes on its own”, but only if it names an undo action and it has no `money` and no `reachesPeople`.

* `read`: runs at once and never changes anything.
* `change`: waits unless the agent’s level allows it.
* `tell_me`: the same as `change`, and you are told when it runs.
* `ask`: always waits for you.
* `owner_only`: always waits for the owner, signed in.

## Levels

The same levels govern what the agent may do on StackShift itself, through its connection. A level is the ceiling; a new version, a lower level or a stop only ever makes the agent stricter.

* Ask me every time (default): anything above `read` waits for you.
* Safe changes on its own: actions marked `safe`, and `change` actions that are not costly, run on their own; the rest wait.
* Whole tasks, then tell me: the agent works through the whole task and you are told afterwards. Actions that are `ask` or `owner_only` still wait.

## Declare and wrap an action

The wrapper asks StackShift first, with the arguments and the run. If the answer is allowed, your function runs and the result is recorded. If it is refused, the call throws with the reason. If it is waiting, the SDK by default saves the call in the agent’s state and ends the run. When you decide, an `approval.decided` event wakes the agent and the SDK runs the saved call with the approved arguments. Pass `wait: true` to hold the run for up to 55 seconds instead.

An approval covers exactly the arguments on its card. If the model asks again with a different amount, that is a new request and a new card.

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

const refund = agent.action('refund_order', async ({ order_id, amount, currency }) => {
  return payments.refund(order_id, amount, currency)
})

agent.on('inbox.message', async ({ data }) => {
  await refund({ order_id: 'A-1043', amount: '1250000', currency: 'NGN' })
})

await agent.start()
```

## Untrusted text

StackShift keeps a record of text that came from outside during each run: inbox messages, agreement messages, webhook bodies, messages from other agents, and the output of actions you mark `output: untrusted`. Mark text your code fetched itself with `agent.untrusted(text, source)`.

When the arguments of an action match that text, StackShift asks you before it runs: always for a direct match on an action above `read`, and for an indirect one on actions with `money` or `reachesPeople`. The card quotes the text and where it came from. This is the same rule Stackie and connected agents follow.

## What this does and does not enforce

You own the code, so you can call your function without the wrapper. The check governs your agent’s model, which is what goes wrong in practice; it is not a guard against the developer. What StackShift enforces whatever the code does: model calls (they go through StackShift), actions on StackShift (they go through the agent’s connection), email and agreements, and internet access (the allowed addresses).

## Expected result

> [!TIP]
>
> Every call to a declared action is decided by StackShift, recorded in the action log as `custom.<agent>.<key>`, and shows who decided: the level, a limit, or you.

## Common failures

> [!WARNING]
>
> * action\_unknown: the action is not declared in the version that is running. Declare it and deploy.
> * The call is refused with a reason in plain words, such as “That is over your limit of ₦50,000.” Raise the limit in `stackshift.yaml` and deploy, or change what the agent asks for.
> * agent\_stopped (423): the agent, its connection or your account is stopped. Start the agent from its page.
> * Five refused or failed actions in a row stop the agent. Read its last runs, fix the cause and start it again.

## Related guides

> [card] [The agent block in stackshift.yaml](https://docs.stackshift.cloud/ai-features/hosted-agents-manifest.md)
>
> Reference for the `type: agent` service: what wakes the agent, how it pays, what it may reach and which actions it has.

> [card] [The agents SDK for TypeScript and Python](https://docs.stackshift.cloud/ai-features/hosted-agents-sdk.md)
>
> 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.

> [card] [Budgets, stopping and runaway protection](https://docs.stackshift.cloud/ai-features/hosted-agents-budgets.md)
>
> Three budgets, a Stop button that halts everything at once, and layers that stop an agent that loops or fails.


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