# Functions

A function is a definition with a name. Each publish makes a new **version**. A version never changes. A run names a version, or uses the latest.

A function's id (`fnc_…`) is its address. Names are for people: two functions can have the same name.

## A definition

```json
{
  "base": "debian-12-20260801-72c15f01",
  "setup": ["apt-get update", "apt-get install -y --no-install-recommends poppler-utils"],
  "provider": "prv_8c1f04d2a7b93e650f1a2c47@latest",
  "system_prompt": "You answer billing tickets.",
  "tools": ["bash", "read", "write", "web_search"],
  "custom_tools": [],
  "input_manifest": [{ "path": "ticket.json", "description": "The ticket", "max_bytes": 1000000 }],
  "output_manifest": [{ "path": "reply.md", "description": "The reply", "max_bytes": 100000 }],
  "environment": [{ "name": "LOCALE", "value": "en-GB" }],
  "size": "s",
  "timeout_minutes": 30
}
```

| Field | What it is |
|---|---|
| `base` | The disk the machine boots. `GET /v1/bases` and `jinn bases` list them. A base is Debian 12 with Python 3, git, curl, jq, ripgrep, zstd, Chromium and a headless display. Anything else comes from `setup`. |
| `setup` | Commands that run before the agent starts, in order. Each runs as root in its own `bash -euo pipefail -c`, with network access and the environment. If one fails, the run fails with `setup`. At most 64 commands. |
| `provider` | The model the agent uses: `prv_…@3` (version 3) or `prv_…@latest` (the newest version when the run starts). See [Providers](#providers). |
| `system_prompt` | The agent's instructions. The run's prompt is its first message. |
| `tools` | Tools the agent can use: `bash`, `read`, `write`, `edit`, `screenshot`, `web_search`. `submit_result` is always there. |
| `custom_tools` | Tools you serve over HTTPS. See [Custom tools](#custom-tools). |
| `input_manifest` | Files and folders the input folder must hold. Jinn checks each exists and is within `max_bytes` before the agent starts. A path that ends in `/` is a folder. |
| `output_manifest` | Files and folders the agent must leave in `/workspace/out`. The agent cannot finish until they exist and fit. |
| `environment` | Variables for setup and the agent's commands: a `value`, or a `secret`. See [Secrets](#secrets). |
| `size` | The machine: `s` (1 vCPU, 2 GiB), `m` (2 vCPU, 4 GiB), `l` (4 vCPU, 8 GiB), `xl` (8 vCPU, 16 GiB). Each GiB of memory comes with 20 GiB of disk. Your account's limits name the sizes you can use. |
| `timeout_minutes` | How long a run can work before it fails with `timeout`. |

## Bases and setup

Use `setup` like a Dockerfile's `RUN` lines. Debian packages come from `deb.debian.org`, so setup usually takes seconds:

```json
"setup": [
  "apt-get update",
  "apt-get install -y --no-install-recommends poppler-utils python3-pip",
  "pip install --break-system-packages pandas==2.2.3"
]
```

To bring your own code, put it in the input folder. Setup can install it from `/workspace/in`.

## Providers

A provider holds a model and your vendor API key: OpenAI, Anthropic or xAI. Your runs call the model with your key, so the vendor bills you for tokens. Jinn checks the key and the model against the vendor's catalog when you publish. Jinn never shows a key again.

A provider has versions, like a function. A new key is a new version. Functions that use `prv_…@latest` get it at their next run.

Make providers in the console, or with the API (`POST /v1/providers`).

## Custom tools

A custom tool is an endpoint you serve. When the agent calls the tool, Jinn sends the agent's arguments as a JSON `POST` to your URL, with the tool's secret as `Authorization: Bearer`. The response body is the tool's result. An error status or no answer within `timeout_seconds` (at most 600) is the tool's error, and the run goes on.

```json
{
  "name": "lookup_customer",
  "description": "Find a customer by email.",
  "parameters": { "type": "object", "properties": { "email": { "type": "string" } }, "required": ["email"] },
  "url": "https://support.example/tools/customer",
  "secret": "sk_tool_4f9a…",
  "timeout_seconds": 30
}
```

Only public HTTPS addresses work, and Jinn does not follow redirects.

## Secrets

Send a secret value once, in `secret`. Jinn stores it encrypted for your account and returns a `secret_id` in the version. To keep the value in a later version, send that `secret_id` instead of the value. A tool's secret is only sent to a tool at the same URL. Jinn never returns or logs a secret.

## Versions

```sh
jinn publish function.json      # makes the function, or publishes its next version
```

With the API, `POST /v1/functions` makes a function and its first version, and `POST /v1/functions/{id}/versions` publishes the next one.
