Product

Every call your agents make, under one set of rules

MCP, HTTP and SSH through one broker. Your agent asks for an action. Sallyport decides what class it is and brings a person in when the class calls for one. Then it writes the record, puts the key on the request and sends it. The same rules apply whether the call arrives over MCP, over HTTP or over SSH.

The unit you configure

A binding is one key, one service, one set of rules

Everything else hangs off it. A binding names the credential, the channel, the host, the path prefix and the methods your agents may use. It also names the approval mode that goes with them. Give an agent a binding and it gets a tool with a description in plain words. Take it away and the tool is gone from the list.

Your agents see it all up front
A new agent lists every binding in its workspace on the first call. Each one names the service, the key, and what runs at once against what waits. Nobody discovers their access by failing.
No access comes back as a link you can grant
A call to a host with no binding comes back with an access request and a URL. A person grants it on one screen, the agent repeats the call, and the work continues.
Per-agent rules only tighten
An override on an agent can narrow what its binding allows and can never widen it. The check lives in the database, not in a code path somebody can forget.

The ladder

Read runs. Write asks. Destructive is refused until you say otherwise

Three classes, and the catalogue decides them for you. A GET on a list endpoint reads. A POST that moves money writes. A delete, a key rotation and a path that hands out somebody else's secret are destructive.

Profiles instead of policy files
Observer, workhorse and prod ship as profiles you apply to many bindings at once, with a preview of what changes before you commit.
Watch first, enforce after
Observe mode runs a binding for a week, then shows you the report. Every call it saw, the ones the profile would have stopped, and the reason on each. Turn it on when you agree with it.
Grants with an edge
Approve a class for the next hour with a call budget. The grant is a row, it is checked at the boundary of every call, and revoking it stops the next one.

The card

The screen that decides the product

A person opens the card on a phone, gives it three seconds, and has no memory of what the agent was doing. It carries enough to tell a normal call from a hostile one and nothing beyond that.

Rendered from the request we are about to send
The target line comes from the canonical request the gateway built. Class, method, host, path, the arguments in full, the credential by name, the rule that fired and what triggered it.
Untrusted text is marked as untrusted
Anything the agent wrote sits in its own block, escaped, with control and direction-flipping characters stripped, and the buttons live above it. Telegram cards carry no markup at all.
One question per burst
Fifty writes in a loop become one grouped card with all, first five or one at a time. A destructive call adds a step-up and a written reason.

We watch for stamping. When a workspace's answers get fast and identical, the cards group harder, and a destructive call asks for a written reason before it moves.

The catalogue

Recipes carry the facts about somebody else's API

A recipe knows the hosts a service answers on, how its credential is presented, which paths write and which paths destroy. It ships as JSON with a schema and classification tests, in a public repository. A wrong class is a data fix, and you can send it yourself.

Paths that hand out secrets are named
GitHub installation tokens, GitLab CI variables, Vercel env with decrypt, Vault kv. Marked in the recipe, classed destructive, refused by default, and listed in your console for your own tenant.
Drift is an event
When an upstream adds an endpoint the catalogue does not know, you hear about it before an agent uses it.
Anything not in the catalogue still works
A host with no recipe gets a conservative default and an access request. An unknown API is a question for a person, never a dead end for the agent.

Friction rules

A refusal caused by configuration is a bug in this product

Minimum friction is a requirement here, and tests enforce it. Five of them are worth stating in public.

Waiting always carries an id
Every stop answer has a call id, an approval URL, an expiry, a poll interval and an expected wait. Repeat with the id and you continue the same operation on all four transports.
Data is never lost
The agent gets as much of the body as its context can take, and the whole thing stays available by reference. A 100 MiB answer keeps its head inline and the rest a fetch away.
Errors say what to do next
Every stopping code carries an instruction and a link in the text the model reads, as well as in the structured field.
Limits never wake you up
A rate limit answers with a retry time. Going over a plan starts a trial and sends a note. Neither one raises a card and neither one blocks production.

For agencies

One workspace per client, with their approver and their journal

Run agents on your clients' infrastructure and each client gets their own vault and their own approvers. Their journal exports on its own, and the card carries your brand. Clone a workspace when you sign the next one. No vendor with a published price has this shape.

A guest approver needs no account
Send a magic link. The client's own person answers the card that concerns their key, and the record shows who it was.
The report is theirs
Every workspace exports its own journal segment and its own digest, so the client can read what your agents did on their systems.

Put one key behind it and watch

Start with the noisiest agent you have and the key you least want it to hold.

Connect my first agent

Free for 10,000 calls a month. Observe mode shows you what a policy would have stopped before you turn it on.