Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail

repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"

staged_paths="$(git diff --cached --name-only --diff-filter=ACMRD | sort -u)"
unstaged_paths="$(git diff --name-only --diff-filter=ACMRD | sort -u)"
partial_paths="$(comm -12 <(printf '%s\n' "$staged_paths") <(printf '%s\n' "$unstaged_paths"))"
if [ -n "$partial_paths" ]; then
echo "pre-commit: these files have staged and unstaged edits:" >&2
while IFS= read -r path; do
printf ' - %s\n' "$path" >&2
done <<< "$partial_paths"
echo "Stage each whole file before committing." >&2
exit 1
fi

make test

while IFS= read -r path; do
case "$path" in
docs.json|api-reference/endpoint/*.mdx|Makefile|.githooks/pre-commit)
make _lint-openapi-drift
break ;;
esac
done <<< "$staged_paths"
25 changes: 18 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,34 +1,45 @@
SHELL := /bin/bash

.PHONY: dev lint test _lint-openapi-drift
.PHONY: dev install-hooks lint test _lint-openapi-drift

OPENAPI_URL ?= https://raw.githubusercontent.com/agentsfleet/agentsfleet/main/public/openapi.json

dev:
npx mintlify dev

install-hooks:
@git config core.hooksPath .githooks
@echo "Git hooks enabled from .githooks"

test:
@bash scripts/test-spec.sh
@python3 scripts/test-documentation.py
@python3 scripts/check-documentation.py .

lint: _lint-openapi-drift
lint: test _lint-openapi-drift
npx mintlify validate
npx mintlify broken-links
find . -name "*.mdx" | xargs -I{} npx markdown-link-check --config .mlc-config.json {}

_lint-openapi-drift:
@command -v jq >/dev/null 2>&1 || { echo "jq not installed — skipping openapi drift check"; exit 0; }
@command -v jq >/dev/null 2>&1 || { echo "jq is required for the OpenAPI drift check"; exit 1; }
@tmp=$$(mktemp); \
if ! curl -sSfL --connect-timeout 5 "$(OPENAPI_URL)" -o "$$tmp"; then \
echo "warn: could not fetch $(OPENAPI_URL) — skipping openapi drift check"; \
rm -f "$$tmp"; exit 0; \
if ! curl -sSfL --connect-timeout 5 --max-time 10 "$(OPENAPI_URL)" -o "$$tmp"; then \
echo "could not fetch $(OPENAPI_URL) for the OpenAPI drift check"; \
rm -f "$$tmp"; exit 1; \
fi; \
upstream=$$(jq -r '.paths | to_entries[] | . as $$p | $$p.value | keys[] | (ascii_upcase + " " + $$p.key)' "$$tmp" | sort -u); \
referenced=$$(grep -hoE '"(GET|POST|PUT|DELETE|PATCH) /[^"]+"' docs.json api-reference/endpoint/*.mdx 2>/dev/null | tr -d '"' | sort -u); \
missing=$$(comm -23 <(echo "$$referenced") <(echo "$$upstream")); \
unlisted=$$(comm -13 <(echo "$$referenced") <(echo "$$upstream")); \
rm -f "$$tmp"; \
if [ -n "$$missing" ]; then \
echo "❌ openapi drift: paths referenced by docs but missing from $(OPENAPI_URL):"; \
echo "$$missing" | sed 's/^/ - /'; \
exit 1; \
fi; \
if [ -n "$$unlisted" ]; then \
echo "❌ openapi drift: operations missing from docs.json:"; \
echo "$$unlisted" | sed 's/^/ - /'; \
exit 1; \
fi; \
echo "✓ openapi drift check clean"
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,38 @@ Each one wakes on an event — a pull request, an incident, a deploy — investi

## Development

Install the [Mintlify CLI](https://www.npmjs.com/package/mint) to preview documentation changes locally:
Before editing a page or API text, read `~/Projects/dotfiles/docs/DOCUMENTATION_RULES.md`.

1. Install the [Mintlify CLI](https://www.npmjs.com/package/mint).

```bash
npm i -g mint
```

```text
added <varies> packages in <varies>
```

2. Enable the repository's pre-commit checks.

```bash
make install-hooks
```

```text
Git hooks enabled from .githooks
```

3. Start the local preview.

```bash
mint dev
```

```text
Local: http://localhost:3000
```

View your local preview at `http://localhost:3000`.

## Publishing
Expand Down
548 changes: 286 additions & 262 deletions api-reference/error-codes.mdx

Large diffs are not rendered by default.

76 changes: 36 additions & 40 deletions api-reference/introduction.mdx
Original file line number Diff line number Diff line change
@@ -1,59 +1,55 @@
---
title: 'API Reference'
description: 'agentsfleet Control Plane API — deploy, observe, and control fleets programmatically.'
title: API introduction
description: Base URL, authentication, errors, and common response formats.
type: explanation
audience: user
verified: 2026-07-12
product_version: 0.17.0
executable: false
---

## Base URL
# API introduction

```
https://api.agentsfleet.net
```
## What it is

## Authentication
The `agentsfleet` API lets your software create, inspect, and control fleets. Send requests to `https://api.agentsfleet.net`.

All API endpoints require a Bearer token in the `Authorization` header, except health checks and the initial auth session creation.
The linked OpenAPI file describes every path, request body, response, and status code.

```bash
curl https://api.agentsfleet.net/v1/workspaces/0198a7b0-3c2d-7f14-9a08-1b6e4d2f8c50/fleets \
-H "Authorization: Bearer $AGENTSFLEET_API_KEY"
```
## Why it exists

Use the API when a script or service needs direct access. Use the command-line client for interactive terminal work.

Two kinds of bearer token are accepted:
## How it behaves

- **Tenant API key (`agt_t…`)** — long-lived, for programmatic and service-to-service callers (CI, cron, integrations, scripts). Create one in the dashboard from the **API Keys** page (in the sidebar); the raw value is shown once. This is the right token for calling the API directly.
- **User JWT** — short-lived, for an interactive human. Mint one with `agentsfleet login`, a browser device flow with terminal-side verification. It can't be obtained by a bare API client — the flow needs the dashboard's browser leg — so for unattended access use a tenant API key.
Most paths accept a bearer token in the `Authorization` header. Tenant API keys start with `agt_t` and are shown once when created.

## Errors
Interactive users can sign in with `agentsfleet login`. The login flow saves a short-lived JSON Web Token (JWT).

All errors use RFC 7807 problem detail (`Content-Type: application/problem+json`):
Webhook and connector paths use provider signatures instead of bearer tokens. The OpenAPI security section on each operation states the required method.

```json
{
"docs_uri": "https://docs.agentsfleet.net/api-reference/error-codes#UZ-AGT-009",
"title": "Fleet not found",
"detail": "No fleet with the given ID exists in this workspace.",
"error_code": "UZ-AGT-009",
"request_id": "0198a7b6-1f2a-7d53-8c94-2b7e5a1f9d40"
}
`<WORKSPACE_ID>` comes from `agentsfleet workspace list`. Use an obviously fake key in copied examples.

```bash
curl https://api.agentsfleet.net/v1/workspaces/<WORKSPACE_ID>/fleets -H "Authorization: Bearer af_test_00000000"
```

Error codes follow the `UZ-<DOMAIN>-NNN` scheme in the `error_code` field. Every response includes a `request_id` for tracing. On `409 Conflict` responses the body may carry an extra `current_state` field naming the resource's blocking state (e.g. `paused`). See [Error codes](/api-reference/error-codes) for the full registry.
```text
{"items":<varies>,"total":<varies>,"cursor":<varies>}
```

Errors use the HTTP problem details format. Each product error includes an `error_code`, a `request_id`, and a documentation URL.

Identifiers use version 7 Universally Unique Identifiers (UUIDs). Timestamps use Unix milliseconds unless an operation states another unit.

## Conventions
## Limits

- **IDs** are UUIDv7.
- **Timestamps** are Unix milliseconds.
- **State transitions** are partial updates on the parent resource (e.g., `PATCH /v1/workspaces/{workspace_id}/fleets/{fleet_id}` with body `{status: "stopped"}`). Sub-resources (e.g., `/messages`, `/events`, `/events/stream`) handle data-flow operations.
- **Streaming endpoints** (activity stream) return Server-Sent Events.
Rate limits apply per workspace. A limited request includes `Retry-After`; wait for that delay before retrying.

## Rate limits
Streaming activity uses Server-Sent Events (SSE). A stream can return `UZ-API-002` when the service cannot accept another subscriber.

API rate limits are per-workspace. If you hit a rate limit, the response includes a `Retry-After` header.
## Related pages

<Card
title="OpenAPI Spec"
icon="code"
href="https://raw.githubusercontent.com/agentsfleet/agentsfleet/main/public/openapi.json"
>
View the full OpenAPI 3.1 specification
</Card>
- [OpenAPI 3.1 file](https://raw.githubusercontent.com/agentsfleet/agentsfleet/main/public/openapi.json)
- [Authentication scopes](/api-reference/scopes)
- [Error registry](/api-reference/error-codes)
83 changes: 55 additions & 28 deletions api-reference/scopes.mdx
Original file line number Diff line number Diff line change
@@ -1,42 +1,69 @@
---
title: 'Scopes'
description: 'The capability vocabulary every agentsfleet token (dashboard session or API key) carries as its `scopes` claim — what each scope grants, and what to do when a request is rejected for lacking one.'
title: API scopes
description: Permissions that an agentsfleet access token can carry.
type: reference
audience: user
verified: 2026-07-12
product_version: 0.17.0
executable: false
---

## How scopes work
# API scopes

Every request is authorized against an explicit `scopes` claim on the caller's token — not a role name. A scope like `fleet:write` grants exactly what it says; there is no hidden bundle of extra capabilities behind it.
## Synopsis

Related scopes ladder: holding the higher one satisfies a check for the lower one. `fleet:admin` holder passes a `fleet:read` gate; `apikey:write` passes an `apikey:read` gate. Discrete-verb scopes (`billing:read`, `workspace:admin`, `library:write`, `approval:read`/`approval:resolve`) don't ladder — each is its own, separately grantable capability.
Each access token carries named scopes. An API request fails when the token lacks the required scope.

<Note>
If a request returns [`UZ-AUTH-022`](/api-reference/error-codes#authentication--authorization) (Insufficient scope), the response's `detail` field names the exact scope your token is missing. Ask a workspace admin to grant it — see [API keys](/api-reference/introduction) for how a tenant API key's scopes are set.
</Note>
Some scope groups use `read`, `write`, and `admin` levels. A higher level includes every lower level in the same group.

## Fleets & workspace resources
## Example with output

Laddered `read < write < admin`:
This request uses an obviously fake token. Replace the token with a tenant API key from **Settings → API Keys**.

| Scope | Grants |
|---|---|
| `fleet:read` / `fleet:write` / `fleet:admin` | view fleets, their events, and memories / create, update, and message fleets / delete a fleet |
| `secret:read` / `secret:write` | list workspace secrets / store, rotate, or delete them, including your tenant LLM provider config |
| `apikey:read` / `apikey:write` / `apikey:admin` | list tenant API keys / create and rotate them / delete (revoke) one |
| `fleetkey:read` / `fleetkey:write` | list fleet-scoped keys / create and delete them |
| `grant:read` / `grant:write` | list integration grants / revoke them |
| `connector:read` / `connector:write` | read a connector's status / start a connector connect flow |
```bash
curl -s https://api.agentsfleet.net/v1/fleets -H 'Authorization: Bearer af_test_00000000'
```

## Discrete capabilities
```text
{"title":"Insufficient scope","error_code":"UZ-AUTH-022","detail":"Missing required scope: fleet:read"}
```

Each of these is its own capability — no ladder:
## Options

| Scope | Grants |
|---|---|
| `billing:read` | read your tenant's billing snapshot, charges, and metering periods |
| `workspace:admin` | create workspaces; list your tenant's workspaces |
| `library:write` | onboard an entry into your workspace's Fleet library |
| `approval:read` / `approval:resolve` | view the approval inbox / approve or deny a gate |
| Scope | Effect | Included by |
|---|---|---|
| `fleet:read` | Reads fleets, events, and memory. | `fleet:write`, `fleet:admin` |
| `fleet:write` | Creates, updates, and messages fleets. | `fleet:admin` |
| `fleet:admin` | Deletes fleets. | None |
| `secret:read` | Lists secret names and metadata. | `secret:write` |
| `secret:write` | Creates, rotates, and deletes secrets. | None |
| `apikey:read` | Lists tenant API keys. | `apikey:write`, `apikey:admin` |
| `apikey:write` | Creates and rotates tenant API keys. | `apikey:admin` |
| `apikey:admin` | Revokes tenant API keys. | None |
| `fleetkey:read` | Lists fleet keys. | `fleetkey:write` |
| `fleetkey:write` | Creates and deletes fleet keys. | None |
| `grant:read` | Lists integration grants. | `grant:write` |
| `grant:write` | Revokes integration grants. | None |
| `connector:read` | Reads connector state. | `connector:write` |
| `connector:write` | Starts a connector setup flow. | None |
| `billing:read` | Reads the tenant balance and charges. | None |
| `workspace:admin` | Creates and lists workspaces. | None |
| `library:write` | Adds an entry to a workspace library. | None |
| `approval:read` | Reads pending approvals. | None |
| `approval:resolve` | Approves or denies a request. | None |

## Platform-operator scopes
Operator tokens may carry `runner:*`, `platform-key:*`, `model:*`, or `workspace:any`. Tenant integrations do not need these scopes.

A smaller set of scopes (`runner:*`, `platform-key:*`, `model:*`, `workspace:any`) gates platform-administration surfaces — enrolling runners, setting the platform-default model, and cross-tenant operator tooling. These aren't relevant to a typical tenant API integration; they're documented for platform operators alongside the deployment's own admin runbook, not here.
## Errors

### UZ-AUTH-022: Insufficient scope

The token lacks the scope named in `detail`. Create a new key with that scope, then retry the request.

Do not add unrelated scopes. A narrower key limits the effect of a leaked key.

## Related pages

- [API introduction](/api-reference/introduction)
- [Error codes](/api-reference/error-codes)
- [Client configuration](/cli/configuration)
58 changes: 30 additions & 28 deletions billing/budgets.mdx
Original file line number Diff line number Diff line change
@@ -1,53 +1,55 @@
---
title: "Budgets and cost control"
description: "Per-fleet dollar ceilings, tenant-wide spend caps, and how debits work."
title: Fleet budgets
description: Daily and monthly spending limits for one fleet.
type: explanation
audience: user
verified: 2026-07-12
product_version: 0.17.0
executable: false
---

agentsfleet enforces budgets at two levels: per-fleet ceilings declared in `TRIGGER.md`, and a tenant-wide balance that every run debits against.
# Fleet budgets

<Note>
**Free until July 31, 2026.** During the launch trial, hosted execution is free — the tenant-wallet mechanics below apply **after** the trial. See [pricing](https://agentsfleet.net/pricing).
</Note>
## What it is

## Per-fleet ceilings (`daily_dollars` / `monthly_dollars`)

Every fleet declares its own dollar ceilings in `TRIGGER.md`:
A fleet budget limits how much one fleet can spend. The fleet author sets the budget in `TRIGGER.md`.

```yaml
budget:
daily_dollars: 5.0
monthly_dollars: 29.0
```

- `daily_dollars` caps spend over a rolling 24-hour window.
- `monthly_dollars` caps spend over the calendar month.
`daily_dollars` is required. `monthly_dollars` is optional.

When either ceiling is reached the fleet stops processing new events and a budget breach is recorded in the activity stream. This is the first line of defence — one bad prompt never becomes an infinite burn on a single fleet.
## Why it exists

Per-event token and wall-clock caps are internal runtime controls. They are not user-configurable in `TRIGGER.md` today.
Every workspace under one tenant shares the same credit balance. A fleet budget stops one fleet from draining that shared balance.

## Tenant wallet
The fleet owns its budget. Updating the fleet replaces the limits, and deleting the fleet removes them.

Separately, your tenant has a single wallet (the $5 free credit at signup, topped up via Stripe). Every completed run debits this wallet.
## How it behaves

- The wallet is **tenant-scoped**, not workspace-scoped. All workspaces under your tenant share the same pool.
- When the wallet hits **zero**, runs across all workspaces stop until the tenant tops up.
- The wallet balance is visible in the dashboard header and via `agentsfleet billing show`.
The daily limit covers a rolling 24-hour window. The monthly limit covers one Coordinated Universal Time (UTC) calendar month.

Set a monthly spend cap on your tenant from the billing page at [app.agentsfleet.net/billing](https://app.agentsfleet.net/billing).
`agentsfleet` checks the limits before a run and while the run continues. A reached limit blocks new work and stops an active run at its next billing check.

<Note>A `agentsfleet billing budget set` CLI command is planned for a future release.</Note>
A blocked event does not retry. Raise the limit, update the fleet, and send a new event.

## Run cancellation
The fleet, memory, and activity stream survive a budget stop. A stopped run has no final result.

Cancel an in-flight run at any time via CLI or API:
## Limits

```bash
agentsfleet kill <fleet_id>
```
| Field | Default | Unit | Valid range |
|---|---|---|---|
| `daily_dollars` | None; required | Dollars per rolling 24 hours | More than `$0` and at most `$1,000` |
| `monthly_dollars` | None | Dollars per UTC month | More than `$0` and at most `$10,000` |

An invalid budget blocks fleet installation. A stored budget that cannot be read blocks the next run.

Cancelling stops the run at the next lease renewal. The run time already elapsed is metered and debited — cancelling doesn't refund the work done so far. See [Credit deduction timing](#credit-deduction-timing) below for the full rule.
`UZ-RUN-015` marks a budget stop during a run. `UZ-EXEC-015` records the final failure class.

## Credit deduction timing
## Related pages

Credit is metered continuously while a run executes: each background lease renewal debits the elapsed time slice from your tenant balance, and a final settle covers the last partial slice when the run ends. Because billing accumulates as the run proceeds, a run that is cancelled or fails partway through is still charged for the time it actually ran — only a run that never starts, or fails before its first metered slice, costs nothing. The same single tenant wallet is debited for every run, across all workspaces.
- [Author a fleet](/fleets/authoring)
- [Error codes](/api-reference/error-codes)
Loading
Loading