Keeping an agent on the plan
Keep your next agent session grounded in the project. Connect an MCP agent, give it a task to claim, and carry decisions and handoffs forward with Project Memory. This guide explains how to see progress, choose enforcement settings and prepare the next session.
This guide is for the person running the agent. It takes about five minutes to set up. For the tool-by-tool reference, see the connector docs.
On this page
1 · Connect your agent
Get a token
In the app, open the profile menu → Agent tokens → New token. Give it the name you want to see on the board — "Claude Code", "Codex on the laptop" — because that name is what appears beside every task it touches. Copy the token; it is shown once.
Point the client at LatticeRun
Any MCP-compatible client. If yours only offers a "connector" or "custom integration"
box — claude.ai, Claude Desktop, mobile — skip the token and use the sign-in flow
instead: give it just https://mcp.latticerun.com/mcp and approve it. The
connector docs cover that path. For Claude
Code, Kimi, Hermes and anything else that lets you set a header:
{
"mcpServers": {
"latticerun": {
"url": "https://mcp.latticerun.com/mcp",
"headers": { "Authorization": "Bearer latticerun_your_token_here" }
}
}
}
Check it took
Ask your agent to list your LatticeRun projects. If it comes back with names and progress, you are connected. From a terminal:
curl -sS -X POST https://mcp.latticerun.com/mcp \
-H "Authorization: Bearer latticerun_your_token_here" \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
2 · Tell it the house rules
The connector explains the protocol to an agent the moment it connects — but an agent that has not connected yet cannot be told anything, and something has to make it connect. So put the rules in whatever instructions file your client reads, in your own repository. The name depends on the client:
| Client | File it reads |
|---|---|
| Codex, Cursor, Kimi and most others | AGENTS.md — the cross-provider convention, and the one to use if you run more than one agent |
| Claude Code | CLAUDE.md |
| Gemini CLI | GEMINI.md |
| GitHub Copilot | .github/copilot-instructions.md |
This is not the same thing as agent.md. LatticeRun's
agent.md is not a file at all — it is the per-project brief stored in LatticeRun,
which you edit in the app and which is handed to an agent on every claim. The house rules
below are a snippet for a file in your repository, and they are optional: they only
cover the moment before an agent has connected. Copy them from
Agent → Project Context in the app, or from here:
## LatticeRun holds the plan You are connected to LatticeRun over MCP. The tree is the plan of record — not this file, and not your own notes. 1. Do not write code before claiming the work: `latticerun_start_task`. It hands you the project brief, bounded current Project Memory and Project Plan context. Read them and follow them. 2. If the user asks for planning, keep the Project Plan or optional task breakdown current while it can still be corrected. Planning is not required before code. 3. Finish each piece with `latticerun_complete_task` and one honest sentence on what actually changed — its successful checkout writes a proposed Project Memory checkpoint. 4. Stuck or blocked? `latticerun_release_task` with the reason — a plain hand-back by default; pass `blocked: true` when a human must unblock it. Never go quiet while holding a claim. 5. Before intentional retirement or stopping, call `latticerun_create_handoff` with status, next actions, blockers and verification, then rewrite the brief with `latticerun_write_context`. A hard crash cannot guarantee a handoff. 6. When you settle a durable choice, call `latticerun_record_decision`; it is mirrored into Project Memory. You may only change the branch you have claimed.
Keep it this short. Long instruction files get skipped in favour of whatever you actually typed in the prompt — this one works because it is a constitution, not a roadmap. The roadmap belongs on the tree.
3 · What the protocol actually is
Claim, work and report are checked by the server. Planning is an optional visual workflow you choose when it is useful.
| Step | What happens |
|---|---|
Claimlatticerun_start_task |
The agent takes a branch and says in one sentence how it means to tackle it. In return it gets your agent.md, the task's place in the tree, the whole branch with its ids, the active sprint, bounded current Project Memory and Project Plan context, and the decisions already taken. There is no separate "remember to read the context" step — claiming is reading it. |
Planlatticerun_plan_task |
Draw the Project Plan flowchart yourself, put an agent in planning mode to draw it, or shape it together while you steer the work. Plan Mode is optional; approval and release create or link executable tasks, whose progress rolls back up through the plan. LatticeRun does not block coding until this happens. |
| Work | While it holds a claim, that task and everything under it are its to change. Nothing else is. One claim at a time, so an agent cannot wander off into a branch you were not watching. |
Reportlatticerun_complete_task |
Each piece is finished with a sentence on what was actually built. The task and project history save it, and a successful checkout writes a proposed Project Memory checkpoint. |
Or give uplatticerun_release_task |
Stopping, blocked or out of road: the branch goes back with the reason attached — a plain hand-back, unless you pass blocked: true, which writes a proposed Project Memory blocker handoff. For intentional retirement, call `latticerun_create_handoff`; a hard crash cannot guarantee one. |
Context debt
Every completed task adds to a debt against the project's agent.md, and the
debt is cleared when the brief is rewritten. Agents are told how much they owe as they
work; on a strict project, an agent that owes too much cannot claim anything new until it
writes one. This is what turns "please update the notes" into something that actually
happens — the brief stays current because work is what makes it stale.
4 · Choose how strict to be
Set this per project from the Agent menu → Agent protocol, which shows the current level and changes it in one click, or in the Project Context dialog beside the brief it governs. New projects start on strict; projects created earlier keep their current level. Agents can read the setting; no tool changes it — a guardrail an agent can lower is decoration.
| Level | What happens | Use it when |
|---|---|---|
| Off | Nothing is checked. Agents change what they like, in any order. | A scratch project, or a workflow you already trust and do not want interrupted. |
| Guided | Nothing is ever refused. A call made out of sequence still succeeds, but the result comes back with the correction attached — and agents generally read that and fall into line. | When you want an agent taught without risking a session — watch the corrections, then decide. |
| Strict | A write outside the claimed branch is refused outright, and an agent that owes the brief a rewrite cannot claim new work. | Where new projects start. Long sessions, more than one agent, or anything you cannot afford to have quietly reshaped. |
If a refusal surprises you, drop the project to guided and watch one session — the corrections show you exactly which habit the gate caught. Move it back to strict when you have seen enough.
5 · Reading the board while it works
Everything below updates live. You do not need to refresh, and you do not need the terminal open.
- A green pill on a task — an agent is holding this branch right now. Hover it for the sentence the agent wrote about what it is doing and how long it has been at it.
- An amber "Blocked" pill — an agent gave up here. Hover for why. This is your queue: it is the list of things only you can unstick.
- New sub-tasks appearing under a task — that is the plan being laid out while you can still steer it. If it is wrong, now is the cheap moment to say so.
- Rings filling — work completing. Open any completed task to read the summary of what was actually built.
- The Activity feed — the full history: who did what, in order, with agents labelled and the model they claim to be running.
In Agent → Project Context you also get the live list of what is held and by whom, with a Release button for each — the escape hatch for an agent whose process died while holding a branch.
6 · Approving what it produces
Deliverables that need your sign-off — a blog draft, a spec, a plan, a comment it wants to post — arrive as artefacts, not as chat messages. One thread per task: if the agent files five drafts for one task in a single run, they are five sections of one thread rather than five separate items, and each section is decided on its own — approve it, reject it, or ask for a revision, with your reason in the section's comment box so it is posted with the decision.
Comments let you say what you are thinking without issuing a verdict — the thread has its own box, and every section has one too, for notes that belong to that paragraph. The agent reads them, with the decision note, on its next pass — a revision request and the comment count both arrive on its next claim. An approved thread is done by the agent and marked executed; a rejected one is closed for good. The Artefacts tab keeps every thread in view, list beside thread, with a dot when a decision is waiting.
Deliverables that are files attach to their task and appear in Files, readable there in place — images, PDFs and text open in a preview without leaving the app.
7 · Waking the agent when a decision lands
The Artefacts tab tells you a decision is waiting; nothing tells the agent until it next claims work. Agent notifications close that gap: when you approve, decline, request a revision or comment on an artefact, LatticeRun can email the agent that wrote it — so whatever starts your agent can start it. The email is a doorbell, not a report: it names the agent and the artefact, states the decision and your note, and links back. The claim bundle still carries every decision, so a missed email is late, never lost.
Give the agent an inbox
An agent needs an address of its own before anything can be delivered. The easiest is AgentMail, a mail provider built for agents: inboxes are created from an API, messages are readable over HTTP and WebSockets, and webhooks are first-class. Any mailbox works — LatticeRun only sends email.
| Setup | What it costs (AgentMail, at the time of writing) |
|---|---|
| One shared inbox, one reader | $0 at any fleet size |
| One inbox per agent | ≈$0 up to 3 · ≈$30/month for 15 · ≈$100/month for 50 — annual is less (≈$0 / ≈$24 / ≈$80) |
| Extra inboxes on the developer tier | about $2/month each |
| The flat ≈$200/month tier | only cheaper above about 100 inboxes — not the answer for a 15-agent team |
Define the address
Profile menu → Agent tokens → Notification addresses → add the address agent mail should go to. Label it ("Research bots") if the agents it manages need a name.
Assign agents to it
Each agent row has a Notify: line — pick an address there. One address can manage many agents; each agent has at most one. With none assigned, nothing is sent, exactly as before. If a decision arrives while an agent has no address, it is recorded and shown on the row rather than dropped silently.
One address, several agents — the dispatcher pattern
Sharing one address is supported, with a single dispatcher: one process reads the inbox, looks at the Agent: line the email carries, and routes the work on. LatticeRun delivers the email and stops there — how it reaches the individual agent is your side of the line, and no relaying mechanism is assumed.
One inbox has one reader. AgentMail has no mark-as-read endpoint — read state is a single label on the message, shared by every reader, with no atomic claim. Two independent readers consume each other's mail and can both act on the same message, which is silent data loss rather than an error you will see. For agents that read independently, give each its own inbox; use pods to keep different vendors' mail apart.
Receiving the mail
- A webhook receiver hosted anywhere public — a small server, a serverless function or a container. Instant, as long as the host is up.
- A tunnel to a local machine — Cloudflare Tunnel, Tailscale Funnel or ngrok. Nothing to deploy; the tunnel must stay up.
- Long-polling the provider's API — nothing exposed publicly at all; you get the mail when you next poll.
No public endpoint means no instant push, and a machine that is asleep receives nothing until it wakes, whichever shape you pick. The mail simply waits.
The last mile: from email to a running agent
"The agent gets notified" really means "the thing that starts the agent gets notified" — an exited process cannot be woken by a message. The piece you write is the wake trigger: a webhook receiver accepts the event and the wake trigger turns it into a run. In industry terms this is event-driven agent invocation, and there is no single settled standard for the last part — treat it as a pattern.
| Host | Startable from outside? | Confidence |
|---|---|---|
| Hermes CLI | Yes | Verified |
Claude Code CLI (claude -p, Agent SDK) | Yes | Verified |
OpenAI API (POST /responses) | Yes | Verified |
| Grok Bot | Partial — schedules and Slack/GitHub event triggers are first-party; email/webhook wake is community-documented | Mixed |
| Claude Desktop app | No — scripting and the Agent SDK are CLI-only | Verified |
| ChatGPT app | No documented way to start a turn from outside | Inferred |
Where there is no external entry point there is no last mile to build — the honest fallbacks are notifying the human, or letting the agent pick the work up on its next claim. Do not wire a wake trigger to a host that cannot be started; it will look like it works and quietly do nothing.
A worked example
A reference build of the whole path uses an AgentMail inbox
(sequelai@agentmail.to): a named tunnel exposes a local receiver that verifies
the webhook signature and rejects unsigned calls with a 400, storing valid
events once in a local database keyed by event id; a WebSocket subscription gives a second
path when the tunnel is down; and a small always-on process polls that store, coalesces a
burst of messages into one job, records the event as handled before starting the
agent, and caps how often it may fire. The agent replies once, when the work is done.
When it does not work: a 400 on your test call is the signature check doing its
job; a 204 with nothing stored means the handler answered before persisting; if
the agent never starts, the wake trigger — not the mail — is the usual culprit; duplicates
should be absorbed by the event key; and a sleeping machine has lost nothing.
What this cannot do
- It cannot wake a machine that is off or asleep, and it cannot start an agent by itself — LatticeRun sends an email to the address you configured and stops there.
- It never fetches a URL you supply, and it cannot run anything on your machine.
- It is an optimisation, not the source of truth: the agent still learns every decision on its next claim.
8 · Where project context lives
Project context stays with the project instead of in a scratch file or a second tool. Each surface has a distinct job:
| Where | What belongs in it |
|---|---|
| agent.md the brief | What you would tell someone over coffee before they started: the stack, the constraints, the conventions, where things live. Agents read it on every claim and rewrite it when they finish. Keep it compact — it is re-sent on every request. |
| Project Memory checkpoints, handoffs, decisions | Durable project state for successors. Successful completion and blocked-release checkouts write proposed records; `latticerun_record_decision` mirrors decisions here. Use `latticerun_create_handoff` for intentional retirement. |
| Task notes work-specific context | Details that belong to one task: acceptance criteria, references and implementation notes. They remain attached to that work rather than becoming project-wide guidance. |
| Activity feed | What happened, in order, permanently. Nobody writes to it deliberately; it is the record. |
9 · When something goes wrong
"A task is stuck showing an agent on it"
The agent's process probably died mid-task. Open Agent → Project Context and press Release next to the claim. Another agent can also take over a claim that has been quiet for 45 minutes, but you should never have to wait for that.
"My agent says it was refused"
On a strict project that is the gate doing its job — read the message, it says exactly what the agent should have done. If it is refusing something legitimate, drop the project to guided, finish the session, and tell us what it caught wrongly.
"It keeps working without claiming anything"
Check the house rules are actually in the repo the agent is working in, and that it is the file that client reads. Some agents also need a nudge in the first prompt: "use LatticeRun, claim the task before you start." After that the corrections in each tool result usually take over.
"Another agent took my connection"
Each plan sets how many agents can be connected at once, and every token gets one session:
reconnecting takes that token's own slot back, telling the incumbent it was superseded. A
different token never displaces another — when the account is at its cap, a new connection
is refused with a 409 naming who holds the sessions. Note this is separate
from claims: the connection is how many agents may talk to LatticeRun, a claim is
which branch one of them owns.
The connector and everything on this page are included with Solo Pro, Founder Lifetime and Team Block. See pricing →