The Model

Sensitivity tiers

17 scopes split by sensitivity. Reads are cheap. Writes are gated. Two are high-sensitivity.

17 scopes split by sensitivity. Reads are cheap. Writes are gated by family scope. Two scopes (gems_adjust, screentime_approve) are high-sensitivity: explicit consent + rate limits.

Three tiers of sensitivity

Most calls are family-scoped writes, safe with consent at handshake. Two carry an extra confirmation step and per-partner rate caps.

TierScopesNotes
Readsfamily:read, task:read, skill:read, canvas:read, reward:read, routine:read, screentime:read, gems:read, project:readCheap. No mutation. Family-scoped.
Writestask:write, skill:write, canvas:write, reward:write, routine:write, project:writeMutate. Family-scoped. Idempotency varies by tool.
High-sensitivitygems:adjust, screentime:approveExplicit consent at OAuth. Rate-limited. Audited.

High-sensitivity

Two scopes carry an extra confirmation step at OAuth time (the parent explicitly opts in by name, not just bulk-approve) and are rate-limited at runtime:

Both surface a typed error if you trip rate limits. Surface it to the parent, do not silently retry.

Family scoping

Every read or write is bound to the OAuth token's family. Cross-family ids return PERMISSION_DENIED, indistinguishable from "not found" so partners cannot enumerate. You cannot accidentally read or mutate another family.

Idempotency: three mechanisms

It is not a single header across the surface. Three mechanisms cover three families of writes:

Dry-run

canvas_create, canvas_update, skill_write, skill_update all support dryRun: true + the specHash round-trip. routine_describe exists as a dedicated preview tool. task_create does not have a dry-run (asymmetric; file an issue if it bites).

Composite safety

A skill is exactly as sensitive as the most sensitive artifact it touches and the most exposed tool it triggers. A morning brief that calls post_message only is low-stakes; the same skill the moment it also calls gems_adjust inherits that scope's full sensitivity profile. Review skills at the bound of their reach, not the bound of their prompt text.

infoDeclared-tool enforcement (the rule that a skill can only invoke tools it declared at authoring time) is intended but not yet shipped. Today hands_referenced on a skill documents intent; dangerous tools self-gate at the handler regardless of which skill called them. Your agent should respect the declaration anyway; the platform will enforce it later.

Errors point at the fix

Tool responses and BAD_INPUT errors carry directional nextStep copy: literally the next call to make. Read it, follow it. Do not guess.

What this means for your agent

Build your authoring + delivery pipeline as dry-run, preview, confirm, commit. Use the Idempotency-Key on every commit. Surface rate-limit and consent errors to the parent. The Sprout interaction discipline ("checkpoint, do not barrel") is baked into both the docs and the error copy.

Try it

Shell
# Verify your scopes before any work
mcp_whoami
{
"user_id": "...",
"app_id": "...",
"sprout_scopes": [...]
}
# High-sensitivity call with Idempotency-Key
gems_adjust({
childId: "019c5229-...",
delta: 5,
reason: "for helping Shane with breakfast"
}, headers={"Idempotency-Key": "sha256(...)"})
# If rate-limited:
{ "error": "RATE_LIMITED", "retryAfter": 12 }

Further reading

Was this page helpful?
OAuth & scopes chevron_right