Features

Everything Marlo checks before
your agent does something real.

Marlo evaluates a proposed action against the chain of events that produced it. Below is what that actually means in practice, feature by feature, including the ones that are more boring than the demo suggests.

01

The request becomes a record,
not a vibe.

A raw prompt is a poor authority document. Marlo converts each user request into a structured intent object with an explicit scope: the requested action, the resources it covers, the outputs permitted, whether external writes are allowed, whether money can move, whether anything can be deleted, and when the whole thing expires.

“Draft an email to John” produces authority to create a draft and no authority to send one. The agent can call email.create_draft. It cannot call email.send. That is not a heuristic, it is the record.

Intent object
{
  "intent_id": "intent-91a2",
  "user_id": "user-104",
  "requested_action": "summarize",
  "authorized_resources": ["support_tickets"],
  "permitted_outputs": ["chat_response"],
  "external_writes_allowed": false,
  "financial_actions_allowed": false,
  "destructive_actions_allowed": false,
  "expires_at": "2026-08-04T21:00:00Z"
}
Honest note

Extraction is layered. Explicit application controls first, deterministic parsing for known commands second, model-assisted extraction only for genuine ambiguity, human confirmation for high-risk intent, and conservative defaults whenever authority is unclear. We do not let the model we are policing decide what it was authorized to do.

02

All the pieces matter.

Every source of information that reaches the agent is labeled on arrival. Authority sources can expand what the agent is allowed to do. Data sources cannot, no matter how convincingly they are written.

Source types and how Marlo treats them
SourceTreatment
Direct authenticated user requestAuthority
Organization policyTrusted policy
System instructionTrusted configuration
Approved internal database recordTrusted data, not authority
Tool resultData, not authority
Email bodyUntrusted content
Web pageUntrusted content
Support ticketUntrusted content
Another agent's messageDelegated authority, scoped
MCP tool descriptionTrusted only from approved servers

A spreadsheet can contain a customer address. That does not authorize sending data to it. An email can request a refund. That does not authorize the refund. A README can describe a shell command. That does not authorize a coding agent to run it.

03

Policies written as causes,
not as regex.

Marlo policies describe required and prohibited causal patterns. They are deterministic, which means they hold even though the agent underneath them is not.

Policy examples
SendEmail requires:
    UserIntent authorizing "send"
    AND recipient matches authorized recipient
    AND attachments within authorized data scope
    AND no expired approval
    AND no prior successful execution of the same transaction

ExternalDataTransfer prohibited when:
    sensitive data is in causal ancestry
    AND destination is not approved

PrivilegedAction prohibited when:
    sole authority ancestor is UntrustedToolResult

DeleteResource requires:
    explicit destructive intent
    AND approval bound to exact resource ID
    AND approval bound to exact action hash
    AND approval age under 10 minutes

FinancialTransaction prohibited when:
    equivalent transaction already completed
    AND current event is caused by retry or recovery
Full policy library
04

An approval for one thing,
good for one thing.

A generic “Allow?” button stops meaning anything the moment the action changes after approval, or the approval gets reused, or several operations run under one click, or the recipient changes, or the agent executes it forty minutes later in a different context.

Marlo binds approval to the exact action: tool, target, parameters, content hash, execution count, and expiry. Change any of it and the approval is void.

Bound approval
Approved action:        send_email
Approved recipient:     jane@company.com
Approved attachments:   report-q3.pdf
Approved content hash:  SHA-256: 8b91...
Approved expiration:    10 minutes
Approved executions:    1

Ten minutes, and then it is dead. That is a feature.

05

Blocking is the crudest thing
it can do.

Allow and deny is a bad interface for a production system. Most of the value sits in the decisions between them.

Decision types and their behavior
DecisionBehavior
AllowForward the call unchanged
DenyPrevent execution, return a controlled error
Require approvalShow a human the exact action and wait
NarrowStrip or restrict unauthorized parameters
SubstituteRoute to a safer read-only tool
SandboxExecute in an isolated environment
Quarantine resultKeep suspicious output out of model context
Rate limitBreak loops and runaway retries
Step upRequire stronger authentication first
EscalateNotify security or operations
Observe onlyRecord the violation, block nothing
06

Authorizing the request is
half the job.

Marlo compares what the agent proposed against what the tool actually did, wherever the downstream system exposes enough evidence to make the comparison.

Proposed vs observed
Proposed: create one Jira ticket
Observed: created three

Proposed: read /project/docs
Observed: also accessed ~/.ssh

Proposed: refund $50 to customer 1842
Observed: refunded $500

That comparison catches things no prompt-level control ever will: compromised MCP servers, schema mismatches, tool implementation bugs, silent duplicate operations, and side effects nobody documented.

07

Delegation without inheritance.

When one agent hands work to another, the second agent should not quietly acquire everything the first one could do. Marlo carries a constrained authority object across the handoff and tracks it as part of the causal chain.

manager-agent

Holds the user's authority. Can obtain quotes, can purchase, within the intent record it was given.

procurement-agent

Receives a constrained authority object: obtain quotes, from two approved vendors, maximum amount zero, expires in thirty minutes. The purchase attempt has nothing behind it.

Delegated authority
{
  "delegated_by": "manager-agent",
  "delegated_to": "procurement-agent",
  "allowed_action": "obtain_quotes",
  "purchase_allowed": false,
  "maximum_amount": 0,
  "allowed_vendors": ["approved-vendor-a", "approved-vendor-b"],
  "expires_at": "2026-08-04T21:30:00Z"
}

The procurement agent's purchase attempt traces back to a delegation that authorized collecting quotes and nothing else, so the purchase does not happen. This gets more important, fast, once no single log in your environment contains the whole decision path.

08

The Board.

Marlo's investigation view renders a session as what it actually is: a partially ordered graph of events with causal edges between them, not a list sorted by clock time. You can select any action and walk backward to whatever authorized it, or find out that nothing did.

Every link on the board carries an evidence grade, so you know which parts of the story are proven and which parts are reconstructed.

session 4f21-a9 · support-summary-agent1 blocked
UserIntentDeclaredsummarize · ticketsResourceReadticket-1842ModelResponseGeneratedplan · 3 stepsToolCallProposeddb.export_customersToolCallProposedemail.send · external
Decision detailProvabledecisiondenytoolemail.sendagentsupport-summary-agentintentsummarize support ticketsintroducing sourceJIRA/ticket-1842policyuntrusted_content_cannot_expand_authority

Blocked customer-data export. The action originated from content inside support ticket 1842, not from the user's instruction. The user authorized summarization only.

It is a case file, not a log file. That distinction is the entire point of building on a causal runtime instead of a database with timestamps in it.

09

Three grades, and we will
tell you which one you got.

“Proof” here does not mean proving what the model was thinking. Nobody can do that, and any vendor claiming otherwise is selling something. Marlo proves the observable chain around the action.

ProvableThe causal relationship was carried explicitly through the system. Identifiers propagated end to end.
MixedPart of the chain was explicit and part was reconstructed from surrounding evidence.
InferredThe relationship was estimated from timing, identity, topology, or behavior.

High-risk actions require high-grade evidence. An INFERRED chain is enough to open an investigation and not enough to authorize a production deletion. You configure that threshold. We ship conservative defaults.

10

Watch first. Enforce later.

Marlo starts in observe-only mode against real traffic. Nothing is blocked. Everything is recorded, evaluated, and reported: here is what would have been denied, here is what would have needed approval, here is the action your finance agent has been repeating on every retry since March.

Teams turn on enforcement policy by policy, usually starting with destructive and financial actions and leaving read paths in observe mode indefinitely. There is no version of this product that requires you to trust it on day one.

11

Three ways in.

Remote MCP proxy

Point your agent's MCP client at Marlo instead of at the server. Marlo handles tools/list, filters the tool inventory, intercepts tools/call, evaluates, forwards, and labels what comes back. No agent code changes.

Local stdio wrapper

For local MCP servers, launch through Marlo instead of directly:

shell
mcp-guard -- some-mcp-server

Marlo starts the real server as a child process and proxies stdin and stdout. This matters more than it sounds, because local servers often run with the same privileges as the client and reach files, credentials, and shell commands.

Native SDK

For teams that control the agent code, drop authorization directly into the tool execution loop:

go
decision, err := marlo.Authorize(ctx, ProposedAction{
    AgentID:    agent.ID,
    Tool:       "send_email",
    Parameters: params,
    IntentID:   session.IntentID,
})

switch decision.Result {
case Allow:           return tool.Execute(params)
case RequireApproval: return approval.Request(decision)
case Deny:            return decision.Explanation
}

The proxy is the fastest way to get coverage. The SDK gives Marlo better context and better evidence grades, because your application can hand over intent and identity directly instead of having them inferred at the wire.

Deployment guides

See it stop something.

Thirty minutes, a live agent, and a support ticket with something nasty in it.