Where a human still steps in

Last updated: · By Radim Sekera

An agent running BriefGate end to end looks, most of the time, like it needs nobody. It calls define_intake with the items a project requires, BriefGate mails the client a portal link, and the agent goes back to building. It finds out what changed by polling `get_intake_status` on the schedule its own define_intake response recommended, or by registering a webhook and reacting to events instead of asking. Reminders go out in the client's language on the cadence the agent chose, without anyone drafting a follow-up by hand. None of that needs a person in the loop, and it's designed not to.

A handful of moments in that same flow are different. Some of them BriefGate refuses to let an API key do at all, regardless of scope. Others it technically allows, but hands the agent enough rope that using it well is a judgment call, not a permission check. Both are deliberate — not missing features, but the shape of a tool built for a workflow where a client's money, credentials, or goodwill sit on the other end of the portal link.

Reading a credential

A secret item — a CMS password, an API key, a hosting login — is encrypted the moment it lands on BriefGate's server, before it ever reaches the database: HTTPS in, then a libsodium sealed box under a key that lives only in the server environment. That's encryption at rest with server-side decryption — not end-to-end, not zero-knowledge. BriefGate's server can read it back, and it does, exactly once.

That "once" is the actual checkpoint, and it isn't purely a human one — it's a scope one. An agent's API key can reveal every secret on an intake through `get_intake_results`, but only with the secrets:read or admin scope; the default intakes:write scope an agent needs for everything else doesn't include it. Whether the agent can read a password at all is decided the moment someone hands it a key with that scope, or doesn't. The other path, clicking Reveal in the dashboard, is narrower still: it needs a live session, and only the account owner may use it — a team member gets 403 forbidden. Whichever side gets there first wins the one-time reveal; the other is told it was already shown. There's no reading it "just to check."

So the actual human step isn't reading the secret — it's the decision, made once, about which keys get to.

Confirming what the agent can only propose

Most items on an intake are answered by the client. A smaller category, items with "assignee": "owner", never reach the client's portal — they're the agent's or owner's own to-dos, ticked off with POST /v1/intakes/:id/items/:key/done. Inside that category sits one type BriefGate calls a decision: an owner-assigned select or multiselect item where the agent may attach its own proposed answer and rationale. What the agent cannot do is settle it. POST /v1/intakes/:id/items/:key/answer is session-only, and the docs say plainly why: accepting that call from an API key "would let an agent confirm its own proposal and have the result recorded as decided_by: owner — exactly what separating a proposal from an answer exists to prevent." The read side shows the seam: every decision item carries proposed_value, proposed_rationale, and decided_by: "agent"|"owner".

It's a narrow feature, but the cleanest example of the general rule: an agent can do the analysis and hand over a recommendation, reasoning attached. It doesn't get to also sign off on its own recommendation.

Objecting to a submission, or letting it stand

There is no "Approve" button anywhere in BriefGate — not in the dashboard, not as an MCP tool, not as a REST endpoint. A submitted item becomes approved one of two ways: someone calls `request_revision` with a note, or nobody does anything and it auto-approves after auto_approve_hours (72 by default, configurable per intake). Silence is acceptance; the only affirmative move is to object.

Nothing technically stops an agent from calling `request_revision` on its own — it's one of the 13 MCP tools, and the recommended flow says to use it "instead of asking the client again yourself outside BriefGate." This isn't the API refusing the agent; it's a case where using the tool well needs something the API can't check. Whether a logo that's technically present — right format, right dimensions, on time — actually represents the client's brand is not something BriefGate can validate: an item definition is the single source of truth, nothing inferred from content, so it confirms an item is usable by its own definition and nothing about whether it's good. And request_revision fires a real email, worded by whoever called it, to a real client, in the owner's name, with no confirmation step in between. A judgment the API cannot make, landing in an action with no undo — that's why it's worth a person's eyes first, even though the tool never asks for one.

Deciding what to ask for

Nothing in BriefGate checks whether the item list an agent sends to define_intake is the right one. The API validates each item's own shape — a pattern a text value must match, a min_width an image must clear — but has no opinion on whether the keys and labels add up to what the project needs. An agent working from a half-remembered template instead of the brief in front of it gets a perfectly valid intake that chases a client for things nobody asked for, and misses the one credential it can't proceed without. That's why the MCP guidance itself opens with when not to reach for BriefGate: skip it when the answer is already in the repo, already in the conversation, or belongs to the person you're talking to right now — the portal and its reminders are for people who aren't in the conversation. Getting the list right is a judgment call; BriefGate only enforces that whatever gets asked for is well-formed.

When the client goes quiet

The chase engine reminds a client on schedule, in their own language, inside their working hours, for as long as max_reminders allows — three attempts by default, adjustable up to a thousand or removed entirely. When that allowance runs out without a completed intake, BriefGate stops on its own, marks the intake stalled, and fires intake.stalled with the list of what's still missing. That's the edge of what automated chasing can do: the schedule ran, and the client still hasn't answered.

An agent that receives intake.stalled isn't stuck — it can raise max_reminders or shorten the cadence with update_intake, or fire an immediate send_chase. What it can't do is anything BriefGate doesn't build a channel for: pick up the phone, reach the client somewhere the intake was never sent, or judge that this project should proceed without the missing piece. intake.stalled is, by design, an event meant for a person — the guidance for receiving it is to "consider reaching out to the client by other means." BriefGate hands back exactly the information needed to make that call, and stops there.

What's rightly left to the agent

None of this argues that BriefGate needs a human in every step — it's the opposite. Defining an intake from a project brief, watching its status without babysitting an inbox, pulling typed results the moment they're ready, and wiring them straight into the build: that's the entire reason BriefGate exists as an MCP server and not just a dashboard. The checkpoints above are narrow on purpose. They sit exactly where a wrong call is expensive and hard to undo — a credential read by the wrong caller, a decision an agent rubber-stamped for itself, a curt note landing in a client's inbox unread, an intake stalled because it asked for the wrong thing. Everywhere else, the agent keeps building, and the client fills things in on their own time.