Home Agent Protocol
How your home agent talks to Sprout. MCP today; the abstraction holds whatever the wire protocol becomes.
Your home agent talks to Sprout over a protocol that exposes everything you can read and write about the family. Today that protocol is MCP (Model Context Protocol). The abstraction is broader than the wire format: any future protocol that gives a home agent the same surface plugs in the same way. The shape of the conversation matters more than the bytes.
This page describes the shape: the session, the two primitives, the metadata Sprout returns alongside results, the error envelope, and the push/pull model. Read it once; from here on, the rest of the docs reference it.
The session
Connect once over OAuth. The handshake binds your agent to a parent account; from then on every call carries a token scoped to that family. The connection persists for the life of the conversation. There is no per-call auth.
On initialize the server returns three things your agent uses immediately:
- The tool catalog: what your agent can call.
- The resource catalog: what your agent can read.
- The instructions field: a system-prompt-analog Sprout asks the client to inject into the LLM's prompt for the duration of the connection. This is where Sprout names the mental model, the canonical sequences, and the checkpoints. Treat it as a contract: if your client doesn't surface
instructionsto the model, you're missing the part Sprout uses to guide your agent.
Progressive context
Sprout doesn't dump the whole SDK on your agent at connect time. The protocol gives your agent three layers of guidance, each loaded on demand, each pointing at the next.
- The map. On
initialize, theinstructionsfield lays out the mental model and the canonical sequences in around 800 tokens. Your agent injects this into its system prompt once at connect and keeps it for the session. - The pointers. When your agent is about to author something consequential (a skill, a canvas, a heartbeat), the instructions tell it to
resources/readthe matching authoring guide. The deep model loads only for the operation it's running. No upfront ceremony. - The next step. Every tool response carries directional guidance. Errors name the fix (
canvas-needs-a-skill,PII_IN_PROMPT,SPEC_HASH_MISMATCH). Success envelopes carrynextStep. Your agent doesn't have to memorize the protocol; the protocol reminds it.
The effect: your agent explores Sprout. It doesn't memorize Sprout. Context arrives just in time, in the right shape, with the next move named.
The rest of this page goes through each layer in turn.
Two primitives, tools and resources
MCP exposes two ways to interact with the server. Both matter.
Tools (tools/call) are actions. task.create, skill.write, gems.adjust, family.query_overview. Your agent picks one, fills the arguments, gets a response. Reads and writes go through the same primitive. The server enforces scopes per tool.
Resources (resources/read) are addressable documents. sprout://skill/authoring-guide, sprout://canvas/sdk, sprout://heartbeat/authoring-guide. Your agent reads them at runtime, before authoring something that needs the deep model. The same documents power these docs you're reading; there is no separate "schema" you have to learn: the resources are the spec.
# Tool: action
tools/call task.create { name, assignChildIds, runMode, ... }
# Resource: context
resources/read sprout://skill/authoring-guide
# Returns markdown your agent reads before skill.write.The instructions field
The instructions string ships on every initialize and is meant to land in your LLM's system prompt. It carries:
- The mental model summary (family, kids, skills, the two-agent split).
- Canonical sequences (the order to call things in).
- Interaction discipline (when to checkpoint, when to ask, when to barrel).
- Pointers to the deep resources (read the authoring guide before authoring).
Token budget: aim under 800 tokens, since clients pay this every request. Sprout's instructions field is treated as a public wire surface and changes go through review: your agent can rely on the shape staying consistent.
Authoring guides as resources
Three resources matter most. Your agent should resources/read them when their domain shows up:
sprout://skill/authoring-guide: beforeskill.writeor before reading a foreign skill.sprout://canvas/sdk: beforecanvas.createorcanvas.update.sprout://heartbeat/authoring-guide: beforeheartbeat.create/heartbeat.update.
These are the source of truth. The docs here are the human-readable map; the resources are what your agent reads. If a page says one thing and a resource says another, the resource wins.
Dry-run and spec-hash
Write tools with consequential effects (skill.write, canvas.create) support a two-step commit:
- Call with
dryRun: true. The server validates, runs analyzers, and returns a preview plus aspecHashover the canonical input. - Show the preview to the parent. Confirm.
- Call again with
dryRun: falseand the echoedspecHash. The server re-hashes the input (excludingdryRunandspecHash) and rejects mismatches withSPEC_HASH_MISMATCH.
The point is auditability. Two-step commit means the artifact your agent showed the parent is the artifact that ships. Blind-commit (no prior dry-run) is allowed but discouraged.
Errors and the envelope
Every tool returns either a success envelope or one of four error codes. The classification is directional: your agent reads the code and knows whether to retry, fix the input, or stop.
| Code | What it means | What to do |
|---|---|---|
BAD_INPUT | Schema or contract violation. Includes SPEC_HASH_MISMATCH, PII_IN_PROMPT, SAFETY_REJECTED, invariant violations. | Fix the input. Retry once the issue is addressed. |
PERMISSION_DENIED | The id you named doesn't belong to this family, or the scope is missing. | Stop. Don't retry with the same id. If a scope is missing, reconnect to add it. |
DOMAIN_NOT_FOUND | Read tool reports the resource is not visible (covers "missing" AND "cross-family": same code for anti-enumeration). | Treat as "not yours." Don't probe further. |
INTERNAL_ERROR | Server-side fault: downstream timeout, safety provider 5xx, DB blip. | Caller did nothing wrong. Retry with backoff. |
Misclassifying infra failure as BAD_INPUT would mask ops signal and break retry semantics, so Sprout routes every internal throw through a single re-classification site. You can trust the code.
Idempotency
Write tools accept an Idempotency-Key HTTP header. Same key on retry returns the cached envelope, not a duplicate write. Generate one stable UUID per logical operation; reuse it on retries.
This matters most for task.create, skill.write, heartbeat.create, gems.adjust. A flaky network shouldn't double-deliver a task or double-tip gems.
Cadence caps
Heartbeats are server-capped at 4 fires per 24 hours in the heartbeat's timezone. Anything tighter (e.g. "*/10 * * * *") is rejected at heartbeat.create with a directional error naming the computed fires/day. The cap protects families from runaway-fire mistakes; if you need higher frequency, that's a different surface (not heartbeats).
Pull vs push: where each lives
Today's protocol is mostly pull. Your agent asks; the server responds. Even server-driven work (heartbeats firing, activity accruing) is discovered by polling reads.
Pull (today):
- Tool calls (your agent initiates everything in this lane).
- Resource reads (your agent fetches authoring guides, canvas SDK reference, etc.).
- Polling state ,
task.list,activityreads,heartbeat.list: to discover what changed since last check.
Push (shipping now, leaf-by-leaf):
- Subscriptions over SSE. Your agent calls
resources/subscribe <uri>; the MCP response upgrades to SSE; the server pushesnotifications/resources/updatedon every change. foundation is live. - More resources coming.
sprout://child/{childId}/screentime/requestsandsprout://child/{childId}/gems. Next:sprout://child/{childId}/today, thensprout://family/activity(which makes event-driven heartbeats real). - Full catalog, code example, delivery semantics: Reference: Subscriptions.
Realtime (planned, further):
- Kid app ↔ home agent direct. A live channel where your agent participates in a moment as it's happening: coaching during a tough homework problem, narrating a chore, voicing a reflection. The kid app today talks to Sprout's agent; this channel opens a second door to your agent for the moments where presence matters.
Scopes and sensitivity tiers
Every tool requires one or more OAuth scopes. The parent approves the set at consent time; today it's all-or-nothing, per-scope re-approval is planned.
Scopes are graded by sensitivity:
- Read ,
family:read,task:read,skill:read,canvas:read, etc. Inspect state. Cheap, safe, no consequence. - Write ,
task:write,skill:write,canvas:write, etc. Mutate state. Requires the matching:readimplicitly. Write implies read. - High ,
gems:adjust,screentime:approve. Single-call effects with direct economic / behavioral impact. Confirm with the parent before invoking (the server'sinstructionsfield also nudges this).
See the scope table on Plug your agent in for the per-tool mapping.
Further reading
The cast The nouns Plug your agent in How safety works