Build a platform
Networks
Every agent and computer has three network settings: what it may reach on the internet, where its traffic exits, and which of your private systems it may use. The defaults reach everything from a shared address and nothing private. Change one setting and the platform enforces it on the host, outside the workload, so the workload cannot talk its way around it.
The three settings
| Setting | Values |
|---|---|
| internet | all reaches everything (the default). list reaches only the entries of a preset plus the workload's own allow list. none reaches nothing on the internet. A deny list of addresses or CIDRs wins over every allow. |
| exit | shared leaves from the account's shared address (the default). fixed gives the workload its own address that stays the same, for allowlists on the other side. country leaves from a chosen country. through leaves through one of your private networks, so the other side sees your office or your server. |
| access | The private resources the workload may reach, by id. A resource is a host and port you published from your own machine or server with maritime connect --allow host:port. Inside the workload the resource answers to its name, such as db.office.private. |
Allow entries are domains (api.example.com), wildcards (*.example.com, subdomains at any depth, not the apex), IPv4 addresses, or IPv4 CIDRs. Deny entries are IPv4 addresses or CIDRs. The Maritime platform itself stays reachable in every mode. list with no entries and no preset equals none. A fourth switch, cutOff, stops all traffic at once and restores it when turned off.
Presets
A preset is a named allow and deny list shared by every agent and computer in the account. Two are built in. coding allows package registries (PyPI, npm, crates, Go, Maven, RubyGems, NuGet, pub.dev), source hosting (GitHub), container registries (Docker Hub, GHCR), Linux package mirrors, Nix, and Hugging Face. llm-apis allows the hosted model APIs (OpenAI, Anthropic, Google, OpenRouter, Mistral, Groq, Together, xAI, DeepSeek, Cohere, Fireworks). Your own presets live in Company settings, Policies, the CLI, and the API. Deleting a preset that workloads use is refused and the refusal counts them.
Dashboard
Open an agent, then Settings. The Network card shows the three settings as three rows, each one a click to change. The Exit row shows the address the internet sees today. The Test box tries one connection from inside the agent and names what stopped it. View activity lists what the workload connected to, with the outcome. Computers show the same card on their page.
CLI
The same six flags set the network on maritime agents create, maritime agents update, and maritime computers create. Flags not given keep their current value; none clears a list.
| Flag | Meaning |
|---|---|
| --internet all|none|list | The internet mode. --allow-out implies list. |
| --allow-out <entry> | One allow entry, repeatable: domain, *.domain, IPv4 address, or CIDR. |
| --deny-out <cidr> | One deny entry, repeatable. Deny wins over allow. |
| --network-policy <preset> | A preset by name or id, such as coding or llm-apis. |
| --egress shared|fixed|country:<CC>|through:<network> | Where the traffic exits. |
| --access <resource> | One private resource by address or id, repeatable. |
# Only package registries, source hosting, and one API of your own
maritime agents create --name worker --template-id codex \
--internet list --network-policy coding --allow-out api.example.com
# Change a running agent: its own fixed address, and a database on your machine
maritime agents update <agent_id> --egress fixed --access db.office.private
# What is in force, and the address the internet sees
maritime agents network <agent_id>
# Try one connection from inside the agent
maritime agents network test <agent_id> api.example.com:443
# Presets shared by every agent and computer in the account
maritime network presets list
maritime network presets create --name partners --allow api.partner.com --allow '*.partner.com'
maritime network presets delete <preset_id>maritime agents network test exits non-zero when the destination is not reached, so it works in scripts. A create that asks for a setting the account cannot have is refused with 422 and creates nothing.
API
One object, the same everywhere. Read and change it per workload, send it as network at creation, and manage presets at /api/v1/network/presets. The workload kind is agent or computer. Every field in an update is optional and replaces what it names; presetId: null clears the preset.
| Operation | Route |
|---|---|
| read | GET /api/v1/network/workloads/{kind}/{id} |
| change | PUT /api/v1/network/workloads/{kind}/{id} {internet?, exit?, access?, cutOff?} |
| test | POST /api/v1/network/workloads/{kind}/{id}/test {destination} |
| at creation | POST /api/agents and POST /api/v1/computers with network: {internet?, exit?, access?} |
| presets | GET /api/v1/network/presets, POST /api/v1/network/presets {name, allow, deny}, DELETE /api/v1/network/presets/{id} |
PUT /api/v1/network/workloads/agent/{agent_id}
{
"internet": { "mode": "list", "presetId": "coding", "allow": ["api.example.com"], "deny": [] },
"exit": { "mode": "fixed" },
"access": ["<resource_id>"]
}The read returns the settings, exitIp (the address the internet sees today, null for country and through), enforcement (pending until the host confirms, then active), metadataUrl, and options: the presets, and for each exit mode whether the account may pick it and the sentence to show when it may not. A 422 carries that same sentence.
SDK
// At creation. A 422 names the reason and creates nothing.
const agent = await maritime.agents.create({
name: 'worker',
templateId: 'codex',
network: { internet: { mode: 'list', presetId: 'coding', allow: ['api.example.com'] } },
})
// Later. Every field given replaces what it names.
await maritime.agents.updateNetwork(agent.id, { exit: { mode: 'fixed' } })
const net = await maritime.agents.network(agent.id)
net.exitIp // the address the internet sees today
net.enforcement // 'active' once the host confirms
const probe = await maritime.agents.testNetwork(agent.id, 'api.example.com:443')
probe.reached // false
probe.reason // 'Refused by the internet policy.'
// Presets
const presets = await maritime.network.presets.list()
await maritime.network.presets.create({ name: 'partners', allow: ['api.partner.com'] })
// Computers take the same object
await maritime.computers.create({ externalUserId: 'u_123', network: { internet: { mode: 'none' } } })Inside the workload
A program inside the workload reads its own settings at http://100.127.254.1/network. It is the live view: it changes the moment you change a setting. The access entries name what to connect to.
$ curl -s http://100.127.254.1/network
{
"kind": "agent",
"workloadId": "...",
"enforcement": "active",
"cutOff": false,
"internet": { "mode": "list", "allow": ["github.com", "api.example.com", "..."], "deny": [] },
"exit": { "mode": "fixed", "ip": "203.0.113.7", "countryCode": null, "networkName": null },
"access": [
{ "name": "db.office.private", "address": "100.127.0.3", "port": 5432,
"target": "localhost:5432", "networkName": "Office" }
]
}Agents also get a snapshot in their environment at boot:
| Variable | Value |
|---|---|
| MARITIME_NETWORK_URL | http://100.127.254.1/network |
| MARITIME_INTERNET | The internet mode: all, none, or list. |
| MARITIME_EXIT_IP | The exit address, when known at boot. |
| MARITIME_ACCESS_<NAME> | One per private resource: the name in upper case with other characters replaced by _. The value is the address to connect to. |
Limits
- At most 100 allow entries and 50 deny entries per workload or preset. Deny wins over allow.
- Under
listandnone, a connection to a destination not on the list is reset at once. Name lookups still work, so a program sees a refused connection, not a hanging one. Activity records the destination with outcomeblocked. fixedandcountryneed a verified email and a paid plan.countryis off for accounts that declared patient data.throughneeds one of your networks that allows internet. The read tells you which, before you try.- A fixed address is requested when the first workload in a region asks for it and shows as
requestedfor a short while. It is released when the last workload in that region leavesfixed.