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

> ## Agent Instructions
> These docs describe the Ancha CLI, npm package @ancha-labs/cli, and the hosted workspace at app.ancha.io. Coding agents should start at https://docs.ancha.io/coding-agents. Run the CLI as `ancha` after `npm install -g @ancha-labs/cli`, or as `npx -y @ancha-labs/cli` without installing. Pass --json for machine-readable output, or set ANCHA_JSON=1. Every command ends with a `next:` line naming the next command. Exit codes: 0 pass, 1 a check failed or a comparison regressed, 2 usage, config or authentication error, 3 infrastructure error, 4 unimplemented endpoint with --strict.

# Tool wrappers

> Wrap your agent's own tools once with @ancha-labs/tools or the Python ancha package: in production nothing changes, and in a test made from a trace each call answers as production did.

A test made from a production trace runs your agent for real, but its tools must not reach production. The wrappers send each tool call to Ancha during a test, and call your function as before everywhere else.

| | TypeScript | Python |
| - | - | - |
| Install | `npm install @ancha-labs/tools` | `pip install ancha` |
| One function | `wrapTool(name, fn)` | `@ancha.tool` |
| Tools a framework built | `wrapTools(tools)` | `ancha.wrap_tools(tools)` |
| The command a test runs | `entry(run)` | `ancha.entry(run)` |
| A call by name | `callTool(name, args)` | `ancha.call_tool(name, args)` |
| An error production's tool raised | `AnchaToolError` | `ancha.ToolError` |

## Outside a test

A wrapper checks for `ANCHA_TOOLS_URL`. Without it, the wrapped tool is your function: the same arguments, the same result, no network call. Nothing changes in production.

## In a test

`ancha run` sets `ANCHA_TOOLS_URL` and `ANCHA_TOOLS_TOKEN` for your agent. Each call goes to Ancha, which answers it:

| Answer | When |
| - | - |
| `replayed` | Production made this call. The k-th call with the same arguments gets production's k-th answer, and a recorded error is raised. |
| `simulated` | A read production never made, or one repeated past what production recorded. A model answers in the shape production's answers had. |
| `twin` | A tool whose code called a vendor Ancha has a twin of. Your function runs, against the twin. |
| `failed` | A write production never made. It raises, unless you let that write be simulated (`tools.simulate_writes`). |

Arguments compare by value, whatever order your agent writes their keys in. Results come back in your function's types: Python restores a pydantic return type.

## TypeScript

```ts theme={null}
import { tool } from 'ai';
import { wrapTools, wrapTool, entry } from '@ancha-labs/tools';

// AI SDK tools: the wrapper replaces each execute, the schema and description stay.
const tools = wrapTools({
  lookup_order: tool({ description: 'Look up an order', inputSchema: z.object({ order_id: z.string() }), execute: lookupOrder }),
  refund_order: tool({ description: 'Refund an order', inputSchema: z.object({ order_id: z.string() }), execute: refundOrder }),
});

// A plain function, named as the trace knows it.
const notify = wrapTool('notify_slack', notifySlack);

await entry(async input => {
  // input.task, input.messages (the conversation so far), input.user (who production served)
  return runAgent(input, tools);
});
```

`wrapTools` takes an object or an array of functions and tool objects with `execute`. Pass `{ names: { lookupOrder: 'lookup_order' } }` when the trace knows a tool by another name.

## Python

```python theme={null}
import ancha
from agents import function_tool

@function_tool          # the framework's decorator, if any, outside
@ancha.tool             # innermost, on the function itself
def lookup_order(order_id: str) -> Order: ...

# Or wrap tools a framework already built: LangChain tools, OpenAI Agents SDK function tools.
tools = ancha.wrap_tools([search_accounts, update_account])

ancha.entry(lambda input: run_agent(input["user"], input["messages"]))
```

`@ancha.tool` works on sync and async functions. Parameters the model never sees, such as a framework's context, are left out of the arguments. Wrap at module level, so the wrappers exist before `ancha.entry` runs.

## entry

`entry` is the command `ancha.yaml` runs in a test. It tells Ancha which tools your agent wraps, hands your function the input production's run started with, and returns your function's answer to Ancha, which checks it.

If the trace holds a tool your agent neither wraps nor reaches over MCP, the test stops at `entry`, before your agent runs, and says which tool. The attempt is invalid, never a pass or a fail. An agent without `entry` is checked at its first tool call.

To run a test anyway with a tool that may call its real backend, a sandbox for example, pass `ancha run --allow-unwrapped <tool>`. `ancha doctor` checks the wiring before you run.

## Tools over MCP

An agent that reaches some tools over MCP needs no wrapper for them. Answer `tools.mcp` with their names when you import the trace, and point the MCP client at the test's tool server in `ancha.yaml`:

```yaml ancha.yaml theme={null}
agent:
  command: node agent.js
  env:
    OPS_MCP_URL: "{{tools.mcp_url}}"
    OPS_MCP_TOKEN: "{{tools.mcp_token}}"
```

The server lists the tools with the descriptions and schemas from the trace, and returns production's own MCP results.


## Related topics

- [From a production trace to a failing test](https://docs.ancha.io/guides/rebuild-from-traces.md)
- [ancha run](https://docs.ancha.io/cli/run.md)
- [Test file (scene.yaml)](https://docs.ancha.io/reference/test-file.md)
- [Tools](https://docs.ancha.io/tools/overview.md)
- [ancha scene](https://docs.ancha.io/cli/scene.md)


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