All articles
Product

Your agent's filesystem is now an API

The Maritime Files API: eight endpoints and both SDKs to browse, upload, download, and edit an agent's disk over HTTP, even while the agent sleeps.

Maritime Team·August 17, 2026·5 min read

Every Maritime agent runs on its own computer: an isolated container or microVM with a persistent volume that survives restarts, redeploys, and sleep. Until now, two things could touch that disk: the agent itself, and you, clicking through the dashboard file browser. Everything else that might want to (your product, your CI, your scripts, your other agents) had to go through chat and hope.

As of today, that disk is a public surface: the Maritime Files API. Eight endpoints, shipped in both SDKs, documented at /docs/api#files. Anything that can send an HTTP request can browse an agent's files, push work in, pull results out, edit config in place, or run a one-shot command next to the data.

The eight endpoints

EndpointWhat it does
GET /files/listList a directory: name, size, mtime
GET /files/downloadDownload a file, any absolute path
POST /files/uploadPush a file in: exact directory, or the agent's inbox
PUT /files/writeCreate or overwrite a UTF-8 text file
POST /files/mkdirCreate a directory, parents included
POST /files/moveMove or rename, 409 if the destination exists
DELETE /files/deleteDelete a file or directory
POST /execRun one shell command, get exit code and output

Everything lives under /api/agents/{agent_id} and authenticates with the same scoped mk_ keys as the rest of the API:

curl -H "Authorization: Bearer mk_xxxxxxxxxxxx" \
  "https://api.maritime.sh/api/agents/AGENT_ID/files/list"

Hand your agent a file

Upload has two modes, and the difference is the point. With a dest_dir, the file lands at that exact path and nothing else happens. That is manager mode: push a config, stage a dataset, update a prompt, silently.

Without a dest_dir, the upload is a delivery. The file lands in the agent's inbox, and the agent gets a notice in its conversation along with whatever message you attached:

from maritime import Maritime
m = Maritime(api_key="mk_xxxxxxxxxxxx")
m.agents.files.upload(
    "AGENT_ID",
    open("q3-leads.csv", "rb").read(),
    "q3-leads.csv",
    message="Dedupe this against /data/crm and write the clean list to /data/out/q3-clean.csv",
)

That call is a complete work handoff: the data and the instruction arrive together, and the agent starts working. Later, collect the result:

clean = m.agents.files.download("AGENT_ID", "/data/out/q3-clean.csv")

No polling a chat endpoint, no parsing an answer out of prose. Files in, files out.

It works while the agent sleeps

On our serverless hosts, an idle agent is a snapshot on disk: no process, no memory, no CPU. Its volume is still there. Any files call wakes the agent first (median restore is 674 ms) and then runs. Your CI job or cron script does not need to know or care whether the agent was awake; it calls the endpoint, and the platform handles the resurrection.

This is the detail that makes the API composable. A pipeline that drops a report request at 6 a.m. and picks up the PDF at 7 does not need an agent running in between.

Run a command in the agent's sandbox

POST /exec runs one shell command inside the agent's sandbox and returns the exit code and output:

curl -X POST https://api.maritime.sh/api/agents/AGENT_ID/exec \
  -H "Authorization: Bearer mk_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"command": "du -sh /data"}'

This is the glue endpoint: check disk usage before a big upload, tail a log after a deploy, kick a script the agent left behind. It is for one-shots, not sessions; if you want a terminal, the dashboard has one.

The boring parts that matter

  • Uploads never execute. A file pushed through this API is written to disk, full stop. (The provisioning API's custom build files are the opposite by design: those are build inputs, and shell scripts among them run at the next deploy. The two surfaces are deliberately separate.)
  • Mutation is scoped to the volume. Browse, write, move, and delete validate every path against the agent's volume root before anything runs. Download deliberately reaches wider, because agents drop artifacts in /tmp and workspace directories; that makes it equivalent in power to exec, which the same key already grants, not an escalation.
  • Errors are honest. Moving onto an existing destination is a 409. Moving or deleting something that is not there is a 404. Deleting the volume root is refused. Earlier internal versions of these endpoints silently no-opped some of those cases; the public surface tells you the truth.
  • Downloads are sanitized. Filenames with control characters cannot corrupt response headers, and non-ASCII names survive intact via RFC 5987.

Limits, stated plainly

  • 100 MB per file, both directions. Transfers are buffered, not streamed end to end. Ship archives, not disk images.
  • `exec` caps at 120 seconds (default 60) and 256 KB of output.
  • Every call wakes a sleeping agent. A monitor that polls files/list every 30 seconds keeps that agent awake around the clock. Poll rarely, or flip the direction and have the agent tell you when the work is done.

Getting started

The SDKs (maritime-sdk on npm, maritime on PyPI, both 0.8.0) expose the whole surface as agents.files plus agents.exec:

import { Maritime } from 'maritime-sdk'
const m = new Maritime({ apiKey: process.env.MARITIME_API_KEY })
const dir = await m.agents.files.list('AGENT_ID')
console.log(dir.entries.map((e) => e.name))

The full reference, including the curl for every endpoint, is at /docs/api#files, with SDK details at /docs/sdk/agents.

Agents earned their reputation by talking. The useful ones also produce things: reports, datasets, builds, cleaned-up spreadsheets. Your agent always had a computer to make them on. Now the rest of your stack can reach it.