Agents
Everything an agent needs works without the console: the mountable CLI, the
skill that teaches this workflow, and the MCP server.
Who holds which credential
| Who | How | Used for |
|---|---|---|
| A person | mountable login | everything |
| A backend or agent | MOUNTABLE_API_KEY=mtbl_… in the environment | managing filesystems and tickets |
| A sandbox | a one-time ticket on stdin | mounting only |
An owner or admin creates the API key in the console. A key belongs to one organisation and is never broader than its creator: it sees only filesystems it has a grant on (a filesystem it creates gets a read-write grant), and it cannot delete filesystems or change grants, members or keys. See Permissions.
The workflow
Backend: create (or pick) a filesystem, then a one-time ticket, with an idempotency key you choose for this mount, such as the job ID:
export MOUNTABLE_API_KEY=mtbl_…
FS_ID=$(mountable fs create agent-workspace)
mountable ticket create "$FS_ID" --idempotency-key job-42 --json
# → {"id": SESSION_ID, "state": "requested", "ticket": "mtbltk_…", "ticket_expires_at": …}Add --ro for a read-only mount. The ticket works once and expires within
minutes, so hand it to the sandbox right away.
Sandbox: mount onto an existing, writable directory, with the ticket on
stdin, and wait for the mounted event:
mkdir -p /mnt/work
printf '%s\n' "$MOUNTABLE_TICKET" | mountable mount --ticket-stdin --json /mnt/work &mount keeps running while the filesystem is mounted and writes JSON lines:
{"event":"mounted","path":"/mnt/work","filesystem_id":"…","mode":"rw"}
{"event":"unmounted","reason":"signal|unmount|revoked|expired|error","detail":"…"}Use the directory only after mounted. If the command exits first, its last
line is {"error": …}. When done, run mountable unmount /mnt/work (or send
SIGTERM to the mount process) so pending writes are committed.
Backend, optionally: end access early with mountable sessions list FS_ID
and mountable sessions revoke SESSION_ID. A revoked mount stops within
seconds.
The sandbox needs the CLI and FUSE (/dev/fuse); see
Mount from a sandbox. Never put an API key or a ticket in a
command-line argument or a log.
JSON output and exit codes
--jsonon every command writes one JSON document to stdout, with the API's field names. Diagnostics go to stderr, and nothing ever prompts.mountable mcpis the exception: its stdout is the MCP protocol.- Exit codes:
0success;1an error from the API, network, mount or credentials;2wrong usage. - Errors carry a stable code and a next step: on stderr, or with
--jsonas
{"error": {"code": "not_found", "message": "…", "hint": "check the ID with `mountable fs list`"}}Error codes
| Code | What to do |
|---|---|
unauthenticated | Run mountable login or set MOUNTABLE_API_KEY. |
org_required | Pass --org ORG_ID (see mountable orgs list). |
not_found | Check the ID with mountable fs list; an API key sees only filesystems it has a grant on. |
no_grant | Ask an owner or admin for a grant, or use --ro. |
api_key_forbidden | A person must do this, in the console or with mountable login. |
payment_required | The hint is the console's billing link; give it to a person. |
rate_limited | Wait retry_after seconds, then retry. |
ticket_already_used | Use a new --idempotency-key for another mount. |
ticket_invalid | The ticket was used or expired; create a new one. |
idempotency_conflict | An identical request is in progress; retry shortly with the same key. |
network_error, outcome_unknown | Retry reads; for ticket create, retry with the error's idempotency_key. |
Retries
- Reads (
orgs list,fs list,fs usage,sessions list) are safe to retry. ticket createsends an idempotency key: the one given with--idempotency-key, or a random one it prints to stderr before sending. When the outcome is unknown (network_errororoutcome_unknown), the error'sidempotency_keyis the key that request was sent with: retry with exactly that key. A replay returns the existing session without a ticket, and the CLI handles it by the session's state:- still
requested: its ticket was lost. The CLI revokes that session, creates a new one with a fresh key, and returns it withreplaced_session_idnaming the old one. activeor later: the ticket was used. Nothing is revoked and the command fails withticket_already_used. Keep the working mount, and use a new key for another mount.
- still
fs createhas no idempotency key, and names need not be unique. After an unknown outcome, runfs listand look for the name before creating again. Never retry blindly.sessions revokeis idempotent.- HTTP 429 (
rate_limited): waitretry_afterseconds.