Skip to content

bot-marshal

Let your AI agents use the services they need. Control each HTTP request, inject credentials without giving them to the agent, and explain every refusal.
Single binary · Local or CI · Deny unless allowed

Give agents useful access with clear boundaries

Section titled “Give agents useful access with clear boundaries”

Your coding agent needs GitHub, package registries and model APIs. Allowing an entire host also allows requests you may never have intended: a repository write, an unsafe tool call, or a request carrying a leaked credential.

bot-marshal is an HTTP proxy you run between your agents and those services. It inspects requests, applies your rules, adds the credentials an allowed request needs, and records the result. You can permit GitHub reads while refusing writes, restrict a tool to selected repositories, or choose which model provider an agent uses.

Run marshal on your developer machine, in CI, or as a dedicated service. Configure clients to use its HTTP or SOCKS5 proxy and trust its generated certificate authority (CA), so it can inspect HTTPS requests. On Linux, marshal run can launch an agent in an isolated network namespace with no direct route around the proxy. Other deployments need external network controls for enforced containment; proxy settings alone route cooperative clients.

Installation and platform support → · Client and container routing →

Permit reads, refuse unwanted writes

Decide by destination, HTTP method and path, rather than trusting every request to an allowed host. With an enforcing deny-by-default profile, each request needs explicit permission. Refusals include a structured reason the agent can act on.

How policy works → · Configure request rules →

Use API keys without handing them to the agent

Keep real credentials in marshal’s protected environment or files. Marshal adds them to allowed requests for the destinations you choose and redacts learned secrets from its logs. Keep those sources outside the agent’s environment and filesystem access.

Configure secret injection → · Provider examples →

Manage OAuth login and token renewal

Enrol a credential once and let marshal refresh access tokens as needed. For a vendor CLI, supervised login capture can discover its OAuth configuration; capture mode decides whether the tool also receives a working credential.

Choose a login workflow → · Login capture walkthrough →

Choose models without changing every client

Give agents stable model names such as fast and smart, then map them to providers or your own compatible server. Translate between OpenAI Chat Completions and Anthropic Messages, including streaming responses and tool calls.

Model routing and complete configuration →

Control individual MCP tools

Model Context Protocol (MCP) calls share an endpoint, but need different permissions. Permit selected tools and constrain their arguments—for example, issue creation only in approved repositories. Filter tool listings so agents see the tools they may use.

MCP controls and configuration →

Detect credentials leaving in requests

Scan headers and query strings for known credential patterns, and optionally inspect request bodies with an explicit size cap. Refuse matches before forwarding. This is pattern detection; response scanning is not implemented.

Leak detection and its limits →

Give each agent its own permissions

A release bot and a research assistant need different access. Select a named policy profile using connection identity, and launch Linux agents with marshal run to enforce proxy routing. Choose an identity resolver appropriate to your deployment.

Configure agent identity → · Linux containment →

Add an AI judge where static rules fall short

Put hard rules first, then ask an LLM to judge requests that need additional context. The judge receives method, host, path and header names; it receives neither bodies nor header values. Its verdict remains subject to the ordering you configure.

Native decision APIs are also available for bounded verdicts and agent decision routing.

Jev and DecisionsApi → · Judge configuration and failure behavior →

Keep streamed responses responsive

Bodies stream by default, including server-sent events (SSE), WebSockets and large uploads. Features that inspect a whole body require explicit, bounded buffering, so you can choose inspection costs deliberately.

Streaming and buffering → · Response size limits →

See what happened and why

Follow each request’s agent identity, policy decision and accumulated evidence. Use structured audit records and metrics to investigate refusals, and warn mode to discover an existing agent’s needs before enforcing a new policy.

Audit records → · Roll out with warn mode →

Headers and response sizes are configurable too: set or filter request headers and cap response bodies. For service operation, use the management API and reload guide to inspect health, change policies and identify settings that require a restart.

Once a client is routed through marshal, its connection identity selects a policy profile. An allowed request gets its configured rewrites and credentials before being forwarded or answered locally, as in OAuth capture. A refused request gets a reason; every outcome leaves an audit record.

agent request→identify agent→check policy→add credentials→service·refusal + reason

The full request lifecycle →

Terminal window
brew install gregbacchus/tap/bot-marshal
mkdir -p ~/.config/bot-marshal
cat > ~/.config/bot-marshal/config.yaml <<'CFG'
tls:
ca_cert: "~/.config/bot-marshal/ca.crt"
ca_key: "~/.config/bot-marshal/ca.key"
profile:
default_action: deny
policy:
- layer: allowlist
allow: { domains: ["api.github.com"] }
on_match: allow
on_miss: pass
CFG
marshal --config ~/.config/bot-marshal/config.yaml config check
marshal --config ~/.config/bot-marshal/config.yaml ca init
marshal --config ~/.config/bot-marshal/config.yaml serve --listen 127.0.0.1:8080

In another terminal, send a request while trusting the generated CA:

Terminal window
curl --cacert ~/.config/bot-marshal/ca.crt -x http://127.0.0.1:8080 https://api.github.com/zen

This allowlisted request should succeed. Follow the walkthrough for denied requests and Linux namespace isolation; proxy variables alone do not enforce containment.

Full walkthrough → · Documentation index →