# Sprout for Builders: full docs corpus Generated from the docs build. Plain text for LLM consumption. ──────────────────────────────────────────────────────────── # Overview ──────────────────────────────────────────────────────────── # Introduction Plug your agent in over MCP and ship something your kid will see in five minutes. ## What is Sprout? Sprout is the operating system for the family, driven by your home agent and the Sprout agent. You connect your agent once over OAuth. From then on it reads and writes family state through the Sprout MCP: pull the roster, ship a task to your kid, save a skill, schedule a recurring check-in. The kid does the thing, earns gems, spends them on rewards or screen-time. Sprout runs the surface and the economy. You run everything else. Sprout is an MCP-guided service, not an API you wire by hand. Your agent reads the live tool catalog and the authoring guide at runtime, so these pages are the map, not the spec. They tell you what the pieces are, where the seams sit, and what bites. The exact call signatures live in the MCP. **Your agent is the bridge to your home systems. The Sprout agent works the inside.** ## The cast Two agents drive. The Sprout apps surface it. Sprout Systems orchestrates. - **Your agent.** Makes decisions with data outside Sprout. Lives in your home systems. Talks to Sprout over MCP. - **The Sprout agent.** Powers in-app moments for your kids. An assistant inside the Sprout apps for parents. - **Parent app.** Parents' window into the family. Setup, oversight, the human-in-the-loop moments. - **Kid app.** Where your kids experience Sprout. They explore, build habits, and earn what's next. - **Sprout Systems.** The platform and the data underneath it all. Routes between the agents and the apps, and guides the agents with the live tool catalog and authoring resources. For where the lines are drawn and the failure modes you will hit, see [The cast](/docs/concepts/three-parties). ## Start here Three pages, in order. By the end you have a skill in your library and a working task on a kid's iPad. [ Plug your agent in Add the Sprout MCP to your client and complete the OAuth handshake. Works with Claude Code, Codex, OpenClaw, ChatGPT, anything MCP. `claude mcp add --transport http sprout https://api.sproutgoodhabits.com/mcp` ](/docs/start/plug-your-agent) [ Your first task Read the family, create a conversation task. Two MCP calls; no skill, no canvas. Lands on the kid's iPad. ](/docs/start/first-task) [ Save it as a skill Wrap the procedure into a reusable skill so your agent can update today's chat with real context each morning. ](/docs/start/save-as-skill) ## The nouns The pieces your agent works with. Eight that round out a family's day. [See the full map →](/docs/concepts/objects) [ Task The kid-facing moment. A check-in chat, a chore, an interactive challenge. Every kid touchpoint is a task. ](/docs/concepts/task) [ Skill Your agent's family skill book. Save a procedure, parameterize it, invoke it tomorrow with new context. ](/docs/concepts/skill) [ Canvas Interactive moments inside a task. Mini-games, drills, custom widgets, anything you can render. When text isn't enough. ](/docs/concepts/canvas) [ Heartbeat How Sprout keeps a rhythm. Cron-driven today; event-driven soon. The trigger that wakes the Sprout agent to refresh, post, or act. ](/docs/concepts/heartbeat) [ Reward What kids work for. Gems earned per task, spent on parent-defined rewards. The loop that makes habits stick. ](/docs/concepts/reward) [ Screen-time The screen-time bouncer. Kids request time; your agent reviews, approves, or steers them somewhere else. ](/docs/concepts/screen-time) [ Activity The family feed for parents. Tasks completed, skills run, gems earned, screen-time requests. Every kid update in one place. Soon streamed live to your home agent so it can react in real time. ](/docs/concepts/activity) [ SoonProgram A way to group tasks so kids see a coherent path, not the whole list at once. Useful for habit ladders, learning paths, and project-based work. ](/docs/concepts/program) ## On our roadmap The next moves that widen what your agent can do for your family. If a docs page hints at one of these, you're seeing it land in real time. - **Camera as a first-class task type.** `runMode: "camera"` for ask-for-a-clip moments and on-device challenges. - **Storage-backed canvas experiences.** Canvases that remember. Persistent kid-scoped state, save progress across sessions, build on what came before. - **Asset-backed canvases.** `sprout.uploadAsset` for photos, clips, and other artifacts captured inside an activity; the upload becomes part of the task's completion proof. - **A cross-family skill library.** Great skills travel. Subscribe to the ones other families' agents use; share your own. - **Live agent ↔ kid moments.** Realtime threads, voice, and live coaching between your home agent and the kid surface. - **Village apps.** Coach, tutor, grandparent agents joining the family with scoped access. ──────────────────────────────────────────────────────────── # Start ──────────────────────────────────────────────────────────── Start # What Sprout is Sprout is the operating system for the family, driven by your home agent and the Sprout agent. ## How it works **Your agent is the bridge to your home systems. The Sprout agent works the inside.** You connect your agent once over OAuth. From then on it reads and writes family state through the Sprout MCP: pull the roster, ship a task to your kid, save a skill, schedule a recurring check-in. The kid does the thing, earns gems, spends them on rewards or screen-time. Sprout runs the surface and the economy. You run everything else. Sprout is an MCP-guided service, not an API you wire by hand. Your agent reads the live tool catalog and the authoring guide at runtime, so these pages are the map, not the spec. They tell you what the pieces are, where the seams sit, and what bites. The exact call signatures live in the MCP. ## The cast Two agents drive. The Sprout apps surface it. Sprout Systems orchestrates. - **Your agent.** Owns intent. Lives in your home systems. Talks to Sprout Systems over MCP. - **The Sprout agent.** Powers the in-app agentic moments, especially for your kids. An accessible assistant within the Sprout apps for parents. - **Parent app.** Onboarding and setup; a surface to quickly view, respond to, and add things to Sprout Systems, with help from the Sprout agent. - **Kid app.** Where your kids experience Sprout. *(More apps to come: villager, coach…)* - **Sprout Systems.** The platform and the data underneath it all. Family state, the gem economy, the skill lifecycle, the screen-time gates. Routes between the agents and the apps. The full breakdown, including where the lines are drawn and the failure modes you will hit, is in [The cast](/docs/concepts/three-parties). ## Start here Three more pages, in order. By the end you have a skill in your library and a working task on a kid's iPad. - [**Plug your agent in**](/docs/start/plug-your-agent). One OAuth handshake. Common pitfall: the default scope set may miss `canvas:*` or `skill:*`; reconnect to pick up the full set. - [**Your first task**](/docs/start/first-task). Read the family, create the task. Two MCP calls; no skill, no canvas. Lands on the kid's iPad. - [**Save it as a skill**](/docs/start/save-as-skill). Wrap that task into a `home_agent` skill so your agent can fire it again tomorrow with one call. ## Further reading - [The nouns](/docs/concepts/objects) - [Skill lifecycle](/docs/concepts/skill) - [The cast](/docs/concepts/three-parties) [Plug your agent in chevron_right](/docs/start/plug-your-agent) Start # Plug your agent in Point your MCP client at the Sprout endpoint and authenticate once. From here your agent can read and write family state. Claude, ChatGPT, Codex, Cursor. Any agent with MCP works. warningFinish Sprout onboarding first. Authentication binds to a parent account with a set-up family, so the parent must have completed onboarding in the Sprout app (a family with at least one kid) before you connect. Connect before that and there is no family for your agent to act on. ## What you point at | **Endpoint** | `https://api.sproutgoodhabits.com/mcp` | **Transport** | HTTP (streamable) | **Auth** | OAuth. Approve in your client after adding. ## Add it to your client Sprout works with any MCP client. A few common ones are below. For anything else, follow that client's own MCP integration guide and point it at the endpoint above. Claude Code Codex OpenClaw ChatGPT Shellcontent_copy ``` claude mcp add --transport http sprout https://api.sproutgoodhabits.com/mcp ``` Then run `/mcp`, select **sprout**, and complete the OAuth prompt in your browser. Shellcontent_copy ``` codex mcp add sprout --url https://api.sproutgoodhabits.com/mcp codex mcp login sprout ``` The first command registers the server (stored in `~/.codex/config.toml` under `[mcp_servers.sprout]`; you can also add it by hand). The second opens the OAuth prompt in your browser. Once you authorize, start Codex and run `/mcp` to confirm the Sprout tools are listed. infoIf your Codex build does not complete the OAuth prompt for a URL server, bridge it with `mcp-remote`: set `command = "npx"`, `args = ["-y", "mcp-remote", "https://api.sproutgoodhabits.com/mcp"]`. Add Sprout under `mcpServers` in `~/.openclaw/openclaw.json`, then restart the gateway: JSONcontent_copy ``` { "mcpServers": { "sprout": { "url": "https://api.sproutgoodhabits.com/mcp" } } } ``` Or use the built-in `mcporter` skill to add and authenticate it from chat. Complete the OAuth prompt when it appears. In ChatGPT, go to **Settings > Apps > Advanced Settings > Developer Mode** and turn it on. Then **Create App**, add Sprout's details (name `sprout`, the endpoint above), and complete the OAuth flow. infoDeveloper Mode is what exposes custom MCP apps and their write tools; it requires a paid ChatGPT plan. ## Scopes Sprout uses OAuth 2.0. Each scope maps to a family of MCP tools. Connection is all-or-nothing today: the parent sees the full list and approves it as one set at consent time. Approve everything you might want to use; adding a scope later requires a full reconnect, which interrupts the parent. | Scope | Tier | Tools unlocked | `family:read` | Read | `family.query_overview` | `task:read` | Read | `task.list`, `task.review` | `task:write` | Write | `task.create`, `task.update`, `task.complete`, `task.delete` | `skill:read` | Read | `skill.list`, `skill.get` | `skill:write` | Write | `skill.write`, `skill.update`, `skill.invoke`, `skill.post_result` | `canvas:read` | Read | `canvas.list`, `canvas.get` | `canvas:write` | Write | `canvas.create`, `canvas.update` | `reward:read` | Read | `reward.list` | `reward:write` | Write | `reward.create`, `reward.update` | `heartbeat:read` | Read | `heartbeat.list`, `heartbeat.describe` | `heartbeat:write` | Write | `heartbeat.create`, `heartbeat.update` | `screentime:read` | Read | `screentime.list_requests`, `screentime.query_state` | `gems:read` | Read | `gems.query_balance`, `gems.list_transactions` | `project:read` | Read | `project.list`, `project.get` | `gems:adjust` | High | `gems.adjust` | `screentime:approve` | High | `screentime.review_request` ## Verify it worked Shellcontent_copy ``` mcp.whoami # Look at the sprout_scopes array. If you're missing canvas:write or skill:write, # disconnect and reconnect to pick up the full set. ``` **Now you can:** your agent reads and writes family state through Sprout. Next, ship something a kid can see. [Your first task chevron_right](/docs/start/first-task) Start # Your first task A daily check-in your kid sees on their iPad. Your agent reads the family, then creates the task. No skill, no canvas: the simplest thing that lands on your kid's screen. A **task** is the kid-facing unit in Sprout. It's the thing that shows up on the iPad and that your kid taps into. You can author one directly from your agent; no skill wrapper required. We'll save it as a skill in the next page. ## Read the family Every meaningful call starts with knowing who's in the family. `family.query_overview` returns the roster: parents, kids, ids, names, ages. Resolve a kid's name to an id yourself; never hardcode UUIDs. Shellcontent_copy ``` family.query_overview() # Returns: # { # parents: [{ userId, name, ... }], # kids: [{ childId, name, birthDate, age, ... }] # } # # Pick the kid you want; remember their childId for the next call. ``` ## Create the task One call creates the task and assigns it to your kid. We use `runMode: "conversation"` so Sprout's in-app agent runs a guided chat. The `conversationSpec.guidance` is the prompt Sprout follows. Weekday cadence at 5pm, three gems on completion. Shellcontent_copy ``` task.create({ name: "Daily check-in", assignChildIds: [""], runMode: "conversation", conversationSpec: { goalType: "share", guidance: "Ask about one highlight from today, one lowlight, and one thing they're looking forward to tomorrow. Listen well; reflect back. Keep it warm, short. Under 3 minutes." }, scheduleSpec: { taskType: "schedule", days: ["mon","tue","wed","thu","fri"], startMinutes: 1020 }, rewardSpec: { gems: 3 } }) # Returns: { taskId: "" } # The task is now live on the kid's iPad, weekdays at 5pm. ``` ## What the kid sees .kid-demo{margin:16px 0 24px;width:100%;display:flex;flex-direction:column;align-items:flex-start} .kid-demo .scaler{transform:scale(.7);transform-origin:top left;width:300px;height:632px} .kid-demo .scaler > .device-wrapper{width:max-content} .kid-demo .device-wrapper{background:#fff;border:1px solid rgba(0,0,0,.08);border-radius:32px;padding:4px;box-shadow:0 12px 16px -4px rgba(10,13,18,.08),0 4px 6px -2px rgba(10,13,18,.03),0 2px 2px -1px rgba(10,13,18,.04)} .kid-demo .device-inner-shadow{background:#fff;border-radius:28px;padding:4px;overflow:hidden;position:relative} .kid-demo .device-inner-shadow::after{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;box-shadow:inset 0 0 6px 2px rgba(10,13,18,.08),inset 0 0 4px 2px rgba(10,13,18,.03);z-index:6} .kid-demo .device-mockup{background:#fafafa;border:2px solid #e9eaeb;border-radius:24px;clip-path:inset(0 round 24px);position:relative} .kid-demo .device-screen{width:402px;height:874px;position:relative;overflow:hidden;background:#e0f2fe;user-select:none} .kid-demo .status-bar{position:absolute;top:0;left:0;right:0;height:62px;display:flex;align-items:flex-end;justify-content:space-between;padding:0 24px 8px;z-index:10;pointer-events:none} .kid-demo .status-bar-time{font-size:17px;font-weight:600;color:#181d27;letter-spacing:-.01em;font-family:'Inter',sans-serif} .kid-demo .status-bar-icons{display:flex;align-items:center;gap:6px} .kid-demo .chat-toolbar{position:absolute;top:62px;left:0;right:0;height:56px;display:flex;align-items:flex-start;justify-content:space-between;padding:0 16px 8px;z-index:10;background:#e0f2fe;box-shadow:0 3px 0 0 #e9eaeb} .kid-demo .chat-toolbar-title{position:absolute;left:50%;top:13px;transform:translateX(-50%);font-family:'Inter',sans-serif;font-size:18px;line-height:28px;font-weight:600;color:#181d27;white-space:nowrap} .kid-demo .chat-toolbar-btn{width:48px;height:48px;display:flex;align-items:center;justify-content:center;background:#fff;border:2px solid #e9eaeb;border-radius:9999px;box-shadow:0 3px 0 0 #e9eaeb;flex-shrink:0} .kid-demo .chat-toolbar-btn svg{width:24px;height:24px;color:#181d27} .kid-demo .chat-thread{position:absolute;top:118px;left:0;right:0;bottom:330px;padding:16px;display:flex;flex-direction:column;gap:8px;z-index:5;font-family:'Inter',sans-serif} .kid-demo .bg-bottom{position:absolute;bottom:0;left:0;right:0;z-index:1;pointer-events:none} .kid-demo .bg-grass-edge{width:100%;height:24px;border-radius:24px 24px 0 0;background:#86cb3c} .kid-demo .bg-grass-fill{width:100%;height:89px;background:#86cb3c} .kid-demo .rive-wrap{position:absolute;bottom:-196px;left:50%;transform:translateX(-50%);width:690px;height:690px;z-index:2;pointer-events:none} .kid-demo .rive-canvas{width:690px;height:690px} .kid-demo .home-indicator{position:absolute;bottom:8px;left:50%;transform:translateX(-50%);width:134px;height:5px;border-radius:100px;background:#181d27;z-index:20} .kid-demo .composer-bar{position:absolute;bottom:45px;left:0;right:0;z-index:10;display:flex;align-items:flex-end;justify-content:space-between;padding:0 16px} .kid-demo .btn-util{width:48px;height:48px;flex-shrink:0;display:flex;align-items:center;justify-content:center;background:#fff;border:2px solid #e9eaeb;border-radius:9999px;box-shadow:0 3px 0 0 #e9eaeb;padding:0} .kid-demo .btn-util svg{width:24px;height:24px;color:#181d27} .kid-demo .mic-btn{width:72px;height:72px;flex-shrink:0;display:flex;align-items:center;justify-content:center;border-radius:9999px;padding:0;position:relative;border:2px solid #0086c9;box-shadow:0 4px 0 0 #0086c9} .kid-demo .mic-btn::before{content:'';position:absolute;inset:0;border-radius:inherit;background:#0ba5ec;mix-blend-mode:multiply} .kid-demo .mic-btn svg{position:relative;z-index:1;width:40px;height:40px} .kid-demo figcaption{margin-top:8px;font-size:13px;color:var(--docs-fg-secondary);max-width:289px} 9:41 Sprout Hey there! Tell me about your day. The kid taps the Daily check-in card; Sprout opens the chat. (function(){ function init(){ if(!window.rive)return; var c=document.getElementById('docs-rive-character');if(!c)return; var r=new rive.Rive({src:'/kid-design-system/sprout.riv',canvas:c,autoplay:true,stateMachines:'State Machine 1',fit:rive.Fit.Contain,alignment:rive.Alignment.BottomCenter,onLoad:function(){r.resizeDrawingSurfaceToCanvas();try{var inputs=r.stateMachineInputs('State Machine 1');if(inputs)inputs.forEach(function(i){if(i.name==='hairID')i.value=1});}catch(e){}}}); } if(window.rive)init();else{var s=document.createElement('script');s.src='https://unpkg.com/@rive-app/canvas@2.35.2';s.onload=init;document.head.appendChild(s);} })(); Every weekday at 5pm, the Daily check-in card lands on the kid's iPad. They tap in, Sprout opens the chat with the guidance you wrote, and listens. They get 3 gems on completion, and the chat posts to the family inbox automatically. **Now you can:** your agent ships a real, recurring thing to your kid in two MCP calls. Next, save the procedure as a skill so your agent can update today's chat with real context each morning. [Save it as a skill chevron_right](/docs/start/save-as-skill) Start # Save it as a skill The Daily check-in works. Now you want today's chat to fit today's actual day. That's where a skill earns its keep: save the procedure once, your agent invokes it every morning to update the task with new context. If the prompt is the same every weekday, you don't need a skill. `task.create` with a weekday schedule already handles that. Skills earn their keep when the content has to change between runs: today's chat reflects today's school day, this week's evening question reflects last week's themes, tomorrow's debrief mentions the test your kid mentioned today. Save the procedure as a skill once. Your agent invokes it on a cadence, pulls fresh context, and updates the task accordingly. ## Two shapes a skill can take Skills are tagged by **where they make sense to run**, not who runs them. - **`generic`.** The default. The skill only touches Sprout (read the family, list tasks, update a task, adjust gems, post a result). Either your home agent or Sprout's agent can run it. Most skills you save will be this shape. - **`home_agent`.** Tag a skill this way when the procedure reaches outside Sprout: read your school portal, your calendar, your email, a folder on your machine, another skill that's specific to your home agent. Skills with home-context reads can't run inside Sprout's agent and the server refuses to invoke or heartbeat them; they only make sense when your home agent is the one driving. For the example below, we tag `home_agent` because we read the school day before updating the task. ## Write the skill This skill refreshes today's Daily check-in to reflect what actually happened at school. Each morning your agent pulls today's school events from your home connector, finds the open check-in task, and rewrites `conversationSpec.guidance` so the kid is asked about the day they actually had. The `prompt` is the procedure your agent reads when it invokes the skill. `handsReferenced` declares the MCP tools the procedure uses. `inputVariables` are the values you pass on each invocation. Shellcontent_copy ``` skill.write({ name: "Refresh today's check-in", description: "Pull today's school events and rewrite today's Daily check-in chat to match the actual day.", category: "home_agent", prompt: `For {{input.child_name}} ({{input.child_id}}) on {{input.today}}: 1. Read today's events for this kid from the school portal connector. 2. task.list({ assignedChildIds:[{{input.child_id}}], status:'open' }); find the open task named 'Daily check-in'. 3. Rewrite conversationSpec.guidance to fit today specifically. If PE today, ask how PE went and what they tried. If a test, ask how it felt and what was hardest. If a field trip, ask the highlight and one thing they noticed. Otherwise, keep the highlight / lowlight / tomorrow shape. Warm, short, two or three questions. 4. task.update(taskId, { conversationSpec: { goalType:'share', guidance: } }).`, handsReferenced: ["task_list", "task_update"], inputVariables: [ { name: "child_name" }, { name: "child_id" }, { name: "today" } ] }) # Returns: { skillId: "" } # The skill is in your library now. Visible to your agent on every reconnect. ``` ## Invoke the skill Each morning, your agent reads the skill, fills in the inputs, and runs the procedure. One call. Shellcontent_copy ``` skill.invoke({ skillId: "", input: { child_name: "Jay", child_id: "", today: "2026-05-23" } }) # Your agent reads the rendered prompt, pulls today's school day from the # home connector, finds today's open check-in, and updates the guidance. # By 5pm, Jay's chat asks about today, not the generic three questions. ``` You can drive this on your own cadence (a morning cron in your agent) or hand the cadence to Sprout via a heartbeat. Either way, the procedure lives in one place: the skill. ## What you have now - Your agent is connected to Sprout. - A daily task on your kid's iPad, on a weekday cadence. - A saved skill in your family library that refreshes the task each morning with real context. **Now you can:** read the family, ship a task, save a skill that changes the task each day. From here, get to know the other Sprout nouns that round out your family's day. [Build: Author a canvas chevron_right](/docs/how-to) ──────────────────────────────────────────────────────────── # Build ──────────────────────────────────────────────────────────── Build # Overview A catalog of patterns plus walkthroughs that chain them. Use it as a lookup or read for the full hero arc. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } Build is a catalog of patterns, plus walkthroughs that chain them into real family use cases. Use it as a lookup when you're trying to do a thing, or read top-to-bottom for the full hero arc. ## Patterns Stable shapes you compose. Each page leads with the outcome, then walks the full build. [Interactive canvasKid-facing HTML in a sandboxed iframe with avatar reactions via the Sprout SDK.](/docs/how-to/canvas) [Conversational taskA coached chat tuned by the engagement levers in conversationSpec.](/docs/how-to/journal) [Reports and briefsStructured cards in the family inbox. Detailed analyses and scannable digests.](/docs/how-to/reports) [Autonomous loopA skill on a heartbeat fires the cycle daily. Parent intervenes through Sprout's in-app agent.](/docs/how-to/automate) [Reactive loopHome agent reacts to Sprout-pushed events. Rule-based decisions; defer ambiguous ones to the parent.](/docs/how-to/reactive) [Context bridgeYour home agent reads outside data and carries the summary into Sprout. Mostly home-agent-side.](/docs/how-to/context) [SoonProgramStructured set of work assigned per kid. Recursive units, slot substitution.](/docs/how-to/program) [SoonPhoto and video proofKid captures real-world evidence as completion proof. Camera task or canvas upload.](/docs/how-to/proof) ## Walkthroughs Concrete scenarios that chain patterns into things you'd actually ship. Each walks pattern recipes with specific inputs. [Solar system learning loopA 3rd-grade worksheet becomes a daily learning loop that adapts to the kid.](/docs/how-to/walkthrough/solar-system) [Chore + photo proofDaily room-cleaning task with photo evidence. Optional home-agent print pipeline.](/docs/how-to/walkthrough/chore-photo-proof) [Weekly family briefA Sunday-night digest card. Reports and briefs + Autonomous loop in 30 lines.](/docs/how-to/walkthrough/weekly-brief) [Music LabA four-unit music program complementing piano lessons. Program-led; chains canvas + conversational + autonomous loop + reports.](/docs/how-to/walkthrough/music-lab) ## Before you start - Your home agent is plugged into Sprout (see [Plug your agent in](/docs/start/plug-your-agent)). - You've shipped at least one task to a kid (see [Your first task](/docs/start/first-task)). - You've saved at least one `home_agent` skill (see [Save it as a skill](/docs/start/save-as-skill)). **Two ways to enter.** Looking for a specific shape: open a Pattern. Want a real scenario walked end-to-end: open a Walkthrough. Build # Interactive canvas Kid-facing HTML in a sandboxed iframe. Avatar reactions via the Sprout SDK. Single completion call. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## What you'll build Your kid plays an interactive moment on the iPad: a mini-game, a math drill, a drawing, a quiz, a narrated story. Sprout's avatar reacts in real time to what they're doing, celebrating right answers, encouraging on misses, noticing when they're stuck. Completion gets scored, timed, or marked done. The artifact is a one-off or recurring task in the kid app, with custom interactive HTML rendered inside it. ## Pieces you'll combine - **[Canvas](/docs/concepts/canvas)**: the kid-facing HTML rendered in a sandboxed iframe. - **[Skill](/docs/concepts/skill)**: wraps the canvas for governance and reuse. - **[Task](/docs/concepts/task)** with `runMode: "canvas"`: delivers the canvas as a kid-visible activity. - **The `sprout.*` SDK**: the only host bridge from inside the iframe. Drives avatar reactions and the completion call. ## Build it Five movements: **1. Author the canvas (dry-run).** Two-step commit so the parent sees a preview before anything ships. Shellcontent_copy ``` canvas.create({ name: "", emoji: "🌟", html: `
`, completionSchema: { kind: "score", maxScore: 5 }, dimensions: { age: "8-9" }, dryRun: true }) # Returns { previewHtml, analyzerIssues, specHash } ``` **2. Show the preview, get the OK, commit.** Shellcontent_copy ``` canvas.create({ ...same input..., dryRun: false, specHash: "" }) # Returns { canvasId } ``` **3. Wrap in a skill** so the canvas has a governed home in your library. Shellcontent_copy ``` skill.write({ name: " canvas skill", description: "Deliver the linked canvas to a kid as a one-off task.", category: "home_agent", prompt: "Create a task for {{input.child_id}} with the linked canvas, due {{input.date}}, with a {{input.gems}}-gem reward.", handsReferenced: ["task_create"], inputVariables: [{ name: "child_id" }, { name: "date" }, { name: "gems" }], canvasIds: [""] }) # Returns { skillId } ``` **4. Invoke the skill** to deliver the task. Shellcontent_copy ``` skill.invoke({ skillId: "", input: { child_id: "", date: "2026-05-24", gems: 5 } }) # Your agent renders the prompt, calls task.create with runMode "canvas". ``` **5. Hook up avatar reactions** inside the canvas HTML using the SDK. The signals fire mid-activity; the completion call fires once at the end. JavaScript (inside the canvas)content_copy ``` // Mid-activity signals sprout.signal("celebration"); sprout.signal("attempt-failed"); sprout.signal("user-stuck"); // Mandatory single completion call sprout.score({ value: 4, max: 5 }); // Or: sprout.complete({ summary: "..." }) // Or: sprout.timed({ durationSeconds: 287 }) ``` Full SDK contract: `resources/read sprout://canvas/sdk`. ## When to use it - The kid is doing something interactive: game, drill, drawing, quiz. - You want visual structure beyond a chat message. - Completion depends on a structured artifact (score, timing, captured photo). - Anti-pattern: the kid is sharing or reflecting. Use [Conversational task](/docs/how-to/journal) instead. ## Tools touched - [`canvas.create`](/docs/reference/canvas#canvas-create), [`canvas.update`](/docs/reference/canvas#canvas-update): author and edit the canvas HTML. - [`skill.write`](/docs/reference/skill#skill-write): wrap the canvas in a governed skill. - [`task.create`](/docs/reference/task#task-create) with `runMode: "canvas"`: deliver to the kid. ## Recommended skills Drop these into your library to compose with this pattern. [Screen readerin prod](/docs/skills/screen-reader)[Quiz templatetemplate](/docs/skills/quiz-template) ## Roadmap - Soon **Storage-backed canvases.** Persistent kid-scoped state across sessions. Save progress, build on what came before. - Soon **Asset upload.** `sprout.uploadAsset()` lets the canvas capture a photo or short video as completion evidence. See the [Photo and video proof](/docs/how-to/proof) pattern for the full shape. ## Seen in walkthroughs [Solar system learning loop](/docs/how-to/walkthrough/solar-system) [Chore + photo proof](/docs/how-to/walkthrough/chore-photo-proof) ## Related patterns - [Conversational task](/docs/how-to/journal): when the kid should talk, not click. - [Autonomous loop](/docs/how-to/automate): pair to schedule the canvas on a cadence. Build # Conversational task A coached chat tuned by the engagement levers in conversationSpec. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## What you'll build A kid sits down with the Sprout app and gets into a coached chat: a daily journal, an explain-it-back, a quick debate, a language practice session. Sprout asks, listens, reflects, doesn't push past what the kid wants to share. The transcript becomes input for downstream analysis if you want it. The artifact is a task in the kid app with `runMode: "conversation"`, tuned by the engagement levers in `conversationSpec`. ## Pieces you'll combine - **[Task](/docs/concepts/task)** with `runMode: "conversation"`: the kid-facing chat. - **`conversationSpec`**: the lever cluster that shapes the conversation. ## Build it One call, but every field matters. The `conversationSpec` object is where the personality of the conversation lives. Shellcontent_copy ``` task.create({ name: "", assignChildIds: [""], runMode: "conversation", conversationSpec: { goalType: "share", // share | explain | debate | practice guidance: ``, minResponses: 3, // anti-bounce floor effort: "balanced", // lenient | balanced | strict grading: "engagement", // engagement | correctness dailyTarget: 1 // submissions per day toward completion }, scheduleSpec: { taskType: "onetime", oneTimeDate: "2026-05-24", startMinutes: 480 // minutes from midnight (480 = 8am) }, rewardSpec: { gems: 3 } }) # Returns { taskId } ``` **The levers in `conversationSpec`:** - `goalType`: `share` = reflective journal, `explain` = Feynman-style teach-back, `debate` = argue a side, `practice` = language/social practice. - `guidance`: the load-bearing field. Specific topics plus how Sprout should run the chat. Be concrete; vague guidance produces vague conversations. - `minResponses`: floor on kid responses before the task can complete. Anti-bounce. - `effort`: how hard Sprout pushes for more depth. `lenient` accepts brief answers; `strict` probes. - `grading`: `engagement` grades on participation; `correctness` grades on accuracy (for teach-back). - `dailyTarget`: how many submissions count toward completion when run on a cadence. ## When to use it - The kid is reflecting, teaching back, debating, practicing. Anything where they talk and Sprout listens. - The transcript will feed downstream analysis (Reports and briefs). - Anti-pattern: a fixed-shape activity. Use [Interactive canvas](/docs/how-to/canvas). - Anti-pattern: a parent-facing brief. Use [Reports and briefs](/docs/how-to/reports). ## Tools touched - [`task.create`](/docs/reference/task#task-create), [`task.update`](/docs/reference/task#task-update): author and adjust the task. - [`task.describe`](/docs/reference/task#task-describe): read the transcript back after completion. ## Recommended skills Drop these into your library to compose with this pattern. [Daily check-in openertemplate](/docs/skills/daily-checkin)[Screen readerin prod](/docs/skills/screen-reader) ## Seen in walkthroughs [Solar system learning loop](/docs/how-to/walkthrough/solar-system) [Chore + photo proof](/docs/how-to/walkthrough/chore-photo-proof) ## Related patterns - [Interactive canvas](/docs/how-to/canvas): when the kid should click, not talk. - [Reports and briefs](/docs/how-to/reports): pair to analyze the transcript and post a card. Build # Reports and briefs Structured cards in the family inbox. Reports (detailed analyses) and briefs (scannable digests). .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## What you'll build A structured card lands in the family inbox. Two flavors with the same plumbing: - **Report**: detailed analysis of something that happened. Themes, gaps, next move. Usually event-triggered. - **Brief**: scannable summary at a cadence. Morning brief, weekly digest, end-of-day recap. The artifact is an auditable, scrollable card the parent can return to. Posted via `skill.post_result`. ## Pieces you'll combine - **[Skill](/docs/concepts/skill)** (`home_agent` category) that does the analysis or digest. - **`skill.post_result`** publishes the structured payload. - **Read tools**: `task.list`, `task.describe` today; `resources/subscribe sprout://family/activity` Soon. ## Build it Three movements: **1. Author the analyzer or digest skill.** Reusable: same skill runs tomorrow's data, next week's, on a different kid. Shellcontent_copy ``` skill.write({ name: "", description: "Read X, produce Y as a structured card.", category: "home_agent", prompt: `For {{input.child_name}} ({{input.child_id}}): 1. Read the relevant tasks via task.list / task.describe. 2. Extract: . 3. Phrase in parent-readable language. 4. skill.post_result with the structured payload below.`, handsReferenced: ["task_list", "task_describe", "skill_post_result"], inputVariables: [ { name: "child_name" }, { name: "child_id" }, { name: "scope" } ] }) # Returns { skillId } ``` **2. Invoke it.** Your agent renders the prompt and does the work in conversation. Shellcontent_copy ``` skill.invoke({ skillId: "", input: { child_name: "", child_id: "", scope: "last 7 days" } }) ``` **3. Publish the result.** Shellcontent_copy ``` skill.post_result({ skillId: "", result: { summary: "", themes: [...], gaps: [...], next_topic: "" } }) # Returns { resultId, threadId, postedAt } ``` **Trigger options.** Run ad-hoc with `skill.invoke` for one-offs ("summarize this week"). Pair with [Autonomous loop](/docs/how-to/automate) for cadenced output (daily brief at 6am, weekly digest Sunday night). ## When to use it - Output worth saving next to the raw activity that produced it. - Daily/weekly summaries, end-of-session recaps, threshold alerts. - Anti-pattern: chatty side commentary that doesn't merit an inbox card. Keep the bar high. ## Tools touched - [`skill.write`](/docs/reference/skill#skill-write), [`skill.invoke`](/docs/reference/skill#skill-invoke), [`skill.post_result`](/docs/reference/skill#skill-post_result). - [`task.list`](/docs/reference/task#task-list), [`task.describe`](/docs/reference/task#task-describe) for reading what happened. - [Subscriptions](/docs/reference/subscriptions) for push-based reads (Soon). ## Recommended skills Drop these into your library to compose with this pattern. [Journal analyzertemplate](/docs/skills/journal-analyzer)[Morning brieftemplate](/docs/skills/morning-brief) ## Seen in walkthroughs [Solar system learning loop](/docs/how-to/walkthrough/solar-system) [Weekly family brief](/docs/how-to/walkthrough/weekly-brief) ## Related patterns - [Autonomous loop](/docs/how-to/automate): pair to run on cadence. - [Context bridge](/docs/how-to/context): inverse direction (outside → in vs. in → parent). Build # Autonomous loop A skill on a heartbeat fires the cycle daily. You intervene through Sprout's in-app agent when you want a different call. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## What you'll build A skill that fires on its own clock and does real work without you. It reads state, decides, and acts. Two common shapes: - **Ship more work to the kid**: a planner skill authors tomorrow's tasks based on yesterday's analysis. - **Publish a report or brief on cadence**: pair with [Reports and briefs](/docs/how-to/reports) to fire the analyzer every morning, every Sunday, every end-of-session. When you want a different call, you tell Sprout's in-app agent and it makes the change for you. ## Pieces you'll combine - **[Heartbeat](/docs/concepts/heartbeat)**: the cron-driven trigger. - **A run skill**: a `home_agent` skill that does one full cycle. - **Sprout's in-app agent**: how you intervene (cancel, modify, pause). ## Build it Three movements: **1. Author the run skill** that does one cycle (read, decide, act). Shellcontent_copy ``` skill.write({ name: "", description: "What one fire of the loop does.", category: "home_agent", prompt: `For {{input.child_name}} ({{input.child_id}}): 1. Read state (task.list, the latest analysis card, etc). 2. Decide what to do next. 3. Act: task.create, skill.invoke, skill.post_result.`, handsReferenced: ["task_list", "skill_invoke"], inputVariables: [{ name: "child_name" }, { name: "child_id" }] }) # Returns { skillId: "" } ``` **2. Schedule it** with `heartbeat.create`. Shellcontent_copy ``` heartbeat.create({ name: "", cron: "0 9 * * *", // daily at 9am tz: "America/New_York", runSkillId: "", skillInput: { child_name: "", child_id: "" } }) # Returns { heartbeatId, chatId, nextFireAt } # Cadence cap: 4 fires per 24h enforced server-side. ``` **3. Intervene through Sprout's agent** when you want a different call. Parent app · Sprout agent You: Cancel tomorrow morning's planned task. Move the journal to Saturday. Sprout: Got it. Canceling the task and moving the journal to Saturday at 8am. Sprout's in-app agent calls `task.update` or `task.delete` on your behalf based on your natural-language request. ## When to use it - The procedure needs to run on its own clock. - The output isn't the same every time (otherwise a recurring [task](/docs/concepts/task) with `scheduleSpec.days` would suffice). - Anti-pattern: fixed-content recurrence (same prompt every weekday at 5pm). Use a recurring task instead. ## Tools touched - [`heartbeat.create`](/docs/reference/heartbeat#heartbeat-create), [`heartbeat.update`](/docs/reference/heartbeat#heartbeat-update), [`heartbeat.describe`](/docs/reference/heartbeat#heartbeat-describe). - [`skill.invoke`](/docs/reference/skill#skill-invoke) (inside the run skill). - [`task.update`](/docs/reference/task#task-update), [`task.delete`](/docs/reference/task#task-delete) (via Sprout's agent on parent intervention). ## Recommended skills Drop these into your library to compose with this pattern. [Morning brieftemplate](/docs/skills/morning-brief)[Next-session plannertemplate](/docs/skills/next-session-planner) ## Seen in walkthroughs [Solar system learning loop](/docs/how-to/walkthrough/solar-system) [Weekly family brief](/docs/how-to/walkthrough/weekly-brief) [Chore + photo proof](/docs/how-to/walkthrough/chore-photo-proof) ## Related patterns - [Reports and briefs](/docs/how-to/reports): the artifact pattern most commonly cadenced by this loop. - [Reactive loop](/docs/how-to/reactive): the push twin. Sprout events trigger the cycle instead of a cron. Build # Reactive loop Your home agent reacts to Sprout-pushed events: approve a screen-time request by rule, defer the ambiguous ones to the parent through a skill. Push twin of Autonomous loop. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## What you'll build Sprout pushes an event to your home agent. Your agent decides what to do based on rules you set, then acts: approve a screen-time request that fits the kid's plan, reject one that doesn't, defer to the parent through a skill when the call isn't clear-cut. This is the push twin of [Autonomous loop](/docs/how-to/automate). Autonomous fires on your agent's clock; Reactive fires on Sprout's events. Same shape (read, decide, act), different trigger. ## Pieces you'll combine - **[Subscriptions](/docs/reference/subscriptions)** over SSE: the push channel from Sprout. `resources/subscribe` on a specific resource URI. - **Your home agent's rules engine**: lives on your side. The "approve a screentime request under N minutes if today's screen budget isn't blown" logic. - **The matching action tool**: `screentime.review_request`, `task.review`, `gems.adjust`, etc. Whichever one closes the loop on the event you received. - **A deferral skill**: when the rule says "ask the parent", invoke a `home_agent` skill that posts the question to the family inbox via `skill.post_result`. The parent decides in-app. ## Build it Four movements: **1. Subscribe to a channel.** Pick the resource URI that matches the event you want to react to. Shellcontent_copy ``` resources/subscribe sprout://child/{kidId}/screentime/requests # Open SSE stream; events arrive whenever the kid requests screen time. # See /docs/reference/subscriptions for the full channel list. ``` **2. On each event, evaluate.** Your agent's rules: kid's earned gems, today's plan, time of day, what's still on the schedule. Make the decision local; don't round-trip a model call for every event if you don't have to. **3a. Act directly if the call is clear.** Shellcontent_copy ``` // Auto-approve a 15-min request when the kid still has budget. screentime.review_request({ requestId: "", approve: true, note: "auto-approved: within today's budget" }) ``` **3b. Defer to the parent if it's ambiguous.** Wrap the question in a skill so the parent sees it in the family inbox and decides in-app. Shellcontent_copy ``` skill.invoke({ skillId: "", input: { question: "Alex is asking for 30 more minutes after dinner. Budget is at 80%. Approve?", options: ["Approve", "Approve 15min only", "Reject"], callbackTool: "screentime.review_request", callbackArgs: { requestId: "" } } }) # The skill posts a card via skill.post_result; the parent taps in-app. # Sprout's in-app agent calls the callback tool with the parent's choice. ``` **4. Keep the loop open.** SSE streams stay open; your agent stays subscribed. Reconnect on drop. Idempotency keys on action calls protect against duplicate events. ## When to use it - Sprout is the source of truth for state changes you want to react to (screentime requests, gem milestones, task completions, parent-review pending). - The decision can usually be made by rule, with a fallback to the parent for the edge cases. - Anti-pattern: polling on a heartbeat for things that have a push channel. Use the subscription. - Anti-pattern: deciding everything by hand-typed parent input. Encode your common rules; reserve deferral for the ambiguous N%. ## Tools touched - [`resources/subscribe`](/docs/reference/subscriptions): the SSE channels. `child/screentime/requests` and `child/gems` shipped; `child/today` and `family/activity` Soon. - Whatever action tool closes the loop: `screentime.review_request`, `task.review`, `gems.adjust`, etc. - [`skill.invoke`](/docs/reference/skill#skill-invoke) + [`skill.post_result`](/docs/reference/skill#skill-post_result) for the parent-deferral path. ## Recommended skills No skills in the catalog pair with this pattern yet. [Browse the catalog](/docs/skills). ## Roadmap - Soon **More channels.** `child/today` (full day state, push on change) and `family/activity` (the family feed as a stream) ship next. - Soon **Deferral pattern as a first-class tool.** A platform-level "ask the parent" tool so you don't have to build the skill yourself. ## Seen in walkthroughs Not yet. A "screentime auto-approver" walkthrough is on the list. ## Related patterns - [Autonomous loop](/docs/how-to/automate): the pull twin. Your agent on its own clock. - [Context bridge](/docs/how-to/context): also home-agent-side, but flowing the other direction (outside → Sprout). - [Reports and briefs](/docs/how-to/reports): pair with this pattern to post the post-decision summary to the family inbox. Build # Context bridge Your home agent reads outside data and carries the summary into Sprout. Mostly home-agent-side; Sprout never reaches outside its own surface. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## What you'll build Sprout's planning calls land in the right context: your agent walks in already knowing what's happening outside Sprout's surface. A worksheet from school. An upcoming family event. A photo of a drawing. Whatever data lives outside, your home agent reads it, summarizes it, and carries the gist into the Sprout conversation. The artifact is a working summary your agent uses immediately when calling Sprout. The data flow is: outside source → your home agent → Sprout context. ## Pieces you'll combine - **Your home agent**: does most of the work. Reads the source, summarizes, holds the summary in conversation. - **[Family overview](/docs/concepts/task)** via `family.query_overview`: the one Sprout call this pattern needs, to pin which kid the work is for. ## Build it Three movements: - Your agent reads the source (file, page, photo, transcript). - Your agent extracts what matters and summarizes. - Your agent calls `family.query_overview` to resolve the kid context. From here, downstream pattern calls have everything they need. Conversationcontent_copy ``` You: [drops a PDF or pastes a page] Read this and let's plan something for tonight. Your agent: [reads] Got it. Summary: . Want a 5-minute review activity for tonight? You: Yes. Reading level matters: she handles common words but struggles with multi-syllable. Keep it light. Your agent: Logged. Pulling kid context from Sprout... ``` Shellcontent_copy ``` family.query_overview() # Returns: { parents: [...], kids: [{ childId, name, age, ... }] } # Your agent picks the right kid, holds the childId for downstream calls. ``` ## When to use it - The next Sprout action depends on data Sprout can't see. - You want planning to ground in what's actually happening (school, weather, family schedule). - Anti-pattern: the source is already inside Sprout (a previous task's transcript, an Activity event). Just read it directly. ## Tools touched - [`family.query_overview`](/docs/reference/utilities#family-query_overview): pulls the family roster. Used to resolve kid ids. The rest of this pattern lives on your home agent's side. Sprout exposes no specific "context loading" tool; the agent is the bridge. ## Recommended skills Drop these into your library to compose with this pattern. [School connectortemplate](/docs/skills/school-connector) ## Roadmap - Soon **Direct upload to Sprout Systems.** Hand a file (PDF, photo, audio) straight to Sprout via an asset endpoint instead of stashing it on your agent's side. Sprout holds the canonical copy; the summary is just a reference. - Soon **Use uploaded context in canvases and tasks.** Reference an uploaded asset from a canvas (worksheet image rendered inside a review canvas) or from a conversational task's `guidance` (Sprout reads the asset to ground the chat). Closes the loop: context that came in via this pattern flows back out to the kid surfaces. ## Seen in walkthroughs [Solar system learning loop](/docs/how-to/walkthrough/solar-system) [Chore + photo proof](/docs/how-to/walkthrough/chore-photo-proof) ## Related patterns - [Reports and briefs](/docs/how-to/reports): the inverse direction. Outside → in (Context bridge) vs. in → parent (Reports and briefs). - [Reactive loop](/docs/how-to/reactive): also home-agent-side, but pushed by Sprout events instead of pulled in. Build # Program A multi-week structured arc assigned per kid. Recursive units, slot substitution. Soon. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## What you'll build A multi-week structured arc assigned per kid. Units that can nest. A reading ladder. A 3rd-grade science curriculum. A summer art project broken into weeks. The kid sees a coherent path; the parent sees the whole arc. Programs are Soon end-to-end. MCP tools exist; the kid-facing surface and the home-agent authoring path land in stages. ## Pieces you'll combine - **[Program](/docs/concepts/program)**: recursive unit tree. - **Templates and assignments**: same template, different kid; slot substitution fills the per-kid bits. - Existing **[skills](/docs/concepts/skill)** as leaf actions inside units. ## Build it (planned shape) Two calls: Shell (planned)content_copy ``` program.create({ name: "", type: "template", units: [ { name: "Unit 1", children: [ { name: "Topic A", taskRef: { skillId: "" }}, { name: "Topic B" }, { name: "Topic C" } ] }, { name: "Unit 2", children: [...] } ], inputVariables: [ { name: "kid_name" }, { name: "reading_level" }, { name: "weekly_cadence" } ] }) # Returns { programId: "" } program.assign({ templateId: "", childId: "", slots: { kid_name: "", reading_level: "8-9", weekly_cadence: "Mon/Wed/Fri" } }) # Tasks for the first unit get authored automatically. ``` ## When to use it - The work has structure beyond "do this, then that". Curriculum, habit ladder, multi-week project. - You want to share the template with other families (cross-family library, also Soon). - Anti-pattern: a single skill or a one-off loop. Programs are heavier than they need to be for those. ## Tools touched - [`program.create`](/docs/reference/program#program-create), [`program.update`](/docs/reference/program#program-update), [`program.delete`](/docs/reference/program#program-delete). - [`program.assign`](/docs/reference/program#program-assign): copy template to kid with slot substitution. ## Recommended skills No skills in the catalog pair with this pattern yet. [Browse the catalog](/docs/skills). ## Seen in walkthroughs [Music Lab](/docs/how-to/walkthrough/music-lab) [Solar system learning loop](/docs/how-to/walkthrough/solar-system) (final step) ## Related patterns - [Autonomous loop](/docs/how-to/automate): programs often replace ad-hoc loops once the arc is clear. Build # Photo and video proof Kid captures real-world evidence as completion proof: either as a camera task (runMode: camera) or inside a canvas via sprout.uploadAsset(). Both Soon. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## What you'll build The kid finishes a real-world thing (cleaned room, finished art piece, practiced an instrument, did the chore) and captures evidence on the iPad: a photo, a short video. The artifact attaches to the task as completion proof. The parent sees the picture, not just a checkmark. Both shapes below are Soon. The platform-level decisions are locked; the surfaces are landing in stages. We're publishing the pattern early so you can plan against it. ## Pieces you'll combine Two routes, pick the one that fits the activity: - **Camera task** (`runMode: "camera"` with `cameraTaskSpec`): native iPad camera surface managed by Sprout. No canvas authoring. Best when the entire task *is* the capture moment. - **Canvas with upload** (`sprout.uploadAsset()`): a regular interactive canvas with a capture step inside it. Best when the capture is one step inside a richer activity (a drawing tool that saves the final piece, a quiz where the last question is "show me your work"). ## Build it (planned shape) ### Route A: Camera task (`runMode: "camera"`) A new task `runMode` alongside `self-check`, `conversation`, and `canvas`. Sprout owns the camera surface end-to-end: opens the iPad camera, captures photo or short video, lets the kid retry, hands the asset to Sprout as completion proof. Your home agent never touches the file. Shell (planned)content_copy ``` task.create({ name: "", assignChildIds: [""], runMode: "camera", cameraTaskSpec: { captureKind: "photo", // "photo" | "video" prompt: "", maxDurationSeconds: 15, // video only retryAllowed: true, requireParentReview: true // pause completion in review state }, scheduleSpec: { taskType: "schedule", days: ["Mon","Tue","Wed","Thu","Fri"], startMinutes: 1020 }, rewardSpec: { gems: 3 } }) # Returns { taskId } # Asset stored in Sprout. Read via task.describe: returns asset id + signed URL. ``` ### Route B: Canvas with `sprout.uploadAsset()` The existing [Interactive canvas](/docs/how-to/canvas) pattern, plus a new SDK call. The canvas opens the camera (or photo picker) when the kid taps a capture button; the captured asset flows back to Sprout via `sprout.uploadAsset()`. The completion call (`sprout.score` / `sprout.complete`) fires after the upload resolves. JavaScript inside the canvas (planned)content_copy ``` // In the canvas body: captureButton.onclick = async () => { const result = await sprout.uploadAsset({ kind: "photo", // or "video" purpose: "completion-proof", maxBytes: 8_000_000 }); // result: { assetId, signedUrl, mime, sizeBytes } showThumbnail(result.signedUrl); }; submitButton.onclick = () => { sprout.complete({ summary: "Submitted with photo proof", assetIds: [latestAssetId] }); }; ``` An authoring helper skill (analogous to [Screen reader](/docs/skills/screen-reader)) ships alongside `uploadAsset`: it teaches your agent the canvas constraints around capture buttons, retry handling, thumbnail rendering, and the upload-then-complete sequence. Slug: `photo-capture`. Status: Soon, lands when `uploadAsset` lands. ## When to use it - **Camera task**: the activity is "capture this moment". Daily chore proof, "show me your finished homework", a quick practice clip. The camera *is* the task. - **Canvas with upload**: capture is one step inside a richer activity. A drawing app that saves the finished piece. A reading reflection where the kid photographs their journal page. A multi-stage quiz with a final "show your work" step. - Anti-pattern: kid privacy moments (bath, bedroom changing, anything sensitive). Sprout will not author or accept these tasks; design for non-sensitive proof only. - Anti-pattern: storage-hungry video archives. Cap durations short; the platform enforces a ceiling regardless. ## Tools touched (planned) - [`task.create`](/docs/reference/task#task-create) with `runMode: "camera"` + `cameraTaskSpec` (Soon). - [`canvas.create`](/docs/reference/canvas) + `sprout.uploadAsset()` SDK method (Soon). - [`task.describe`](/docs/reference/task#task-describe): returns asset ids + signed URLs for read-back. ## Recommended skills No skills in the catalog pair with this pattern yet. [Browse the catalog](/docs/skills). ## Roadmap - Soon **Camera task mode.** `runMode: "camera"` with `cameraTaskSpec`. Sprout-owned capture surface. - Soon **Canvas asset upload.** `sprout.uploadAsset()` SDK method. Capture inside a richer activity. - Soon **Photo capture authoring skill.** Authoring helper that teaches your agent the capture-then-complete pattern (analogous to [Screen reader](/docs/skills/screen-reader)). - Soon **Parent-review gate.** Optional `requireParentReview: true` holds completion until a parent thumbs the photo through. ## Seen in walkthroughs [Chore + photo proof](/docs/how-to/walkthrough/chore-photo-proof) ## Related patterns - [Interactive canvas](/docs/how-to/canvas): the host for Route B. - [Reports and briefs](/docs/how-to/reports): digest a week of captured photos into a single card. - [Autonomous loop](/docs/how-to/automate): cadence the capture task daily; cadence the digest weekly. Build # Solar system learning loop From a 3rd-grade worksheet to a self-improving daily learning loop. Chains all six patterns. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## The setup Your kid (we'll call them **Alex**) came home with a 3rd-grade worksheet on the solar system. The vocabulary list said: *orbit, planet, moon, gravity, rocky planet, gas giant*. The teacher's note said: *"Tell someone in your family three new things you learned!"* You want to keep the curiosity going without turning it into homework. By the end of this walkthrough, your home agent and Sprout will be running a self-improving daily learning loop on this topic, kicked off by one piece of paper. ## Patterns we'll chain - [Context bridge](/docs/how-to/context): read the worksheet, summarize into Sprout context. - [Interactive canvas](/docs/how-to/canvas): build tonight's 5-min review. - [Conversational task](/docs/how-to/journal): tomorrow morning's journal. - [Reports and briefs](/docs/how-to/reports): analyze the journal, post a card. - [Autonomous loop](/docs/how-to/automate): cadence the analyzer + planner daily. - [Program](/docs/how-to/program) (Soon): promote the loop to a full 3rd-grade science curriculum. ## The arc ### 1. Bring the context home You hand the worksheet to your home agent. It reads, summarizes, calls `family.query_overview` to pin Alex's id. Now Sprout knows: solar system unit, 3rd grade, vocabulary capped at "gravity," skipping "asteroid". Follows the [Context bridge](/docs/how-to/context) pattern. ### 2. Build the review canvas Your agent authors a 5-minute solar-system review canvas: narrator paragraph + 5-question quiz + avatar reactions. Pairs with the [Screen reader](/docs/skills/screen-reader) skill from your library (synth voice with word highlighting) for the narration section. Full recipe lives on the [Interactive canvas](/docs/how-to/canvas) pattern page. Shell · this walkthrough's inputscontent_copy ``` canvas.create({ name: "Solar system review", emoji: "🌍", dimensions: { age: "8-9" }, // ... narrator + 5 questions on planets/orbits ... }) # Wrap + invoke per the Interactive canvas recipe. ``` ### 3. Add the journal Tomorrow morning at 8am, Alex gets a 3-question journal: highlight, lowlight, what they want to know next. Follows the [Conversational task](/docs/how-to/journal) pattern with these specific levers: Shell · this walkthrough's inputscontent_copy ``` conversationSpec: { goalType: "share", guidance: "Alex finished a solar system review last night. Ask, in order: highlight, lowlight, what to know next. Keep vocabulary to grade level; skip 'asteroid' unless Alex uses it.", minResponses: 3, effort: "balanced", grading: "engagement", dailyTarget: 1 } ``` ### 4. Analyze and post a report After the journal, your agent invokes the [Journal analyzer](/docs/skills/journal-analyzer) skill. Reads the transcript, extracts themes/gaps/next-topic, posts via `skill.post_result`. Card lands in the family inbox. Full pattern at [Reports and briefs](/docs/how-to/reports). ### 5. Automate the next session Your agent schedules a daily heartbeat at 9am. The run skill (built from the [Next-session planner](/docs/skills/next-session-planner) template) reads yesterday's analysis card, picks the next topic ("asteroids"), and authors tonight's canvas + tomorrow's journal, replaying steps 2 and 3 with new inputs. Full pattern at [Autonomous loop](/docs/how-to/automate). ### 6. Promote to a program (Soon) Once the daily loop is solid, your agent can promote it to a 3rd-grade science [program](/docs/how-to/program): explicit units (solar system, weather, animals), each unit containing topics. Alex sees a coherent path across weeks; you see progress against the whole curriculum. ## The result A self-improving daily learning loop, kicked off by one worksheet: - Each evening Alex does a topic-specific canvas review. - Each morning Alex journals about it. - Each morning at 9, your agent reads the analysis and plans the next topic. - Each day, you get an inbox card summarizing what Alex did and what they're curious about next. - You step in (through Sprout's app) only when you want a different call. ## Variations - **Different subject.** Swap "solar system" for "fractions" or "American history". Same patterns, different content. - **Older kid.** Bump `dimensions.age` and `conversationSpec.effort` to `strict`; switch `goalType` to `explain` for teach-back grading. - **Multiple kids.** Re-invoke the canvas + journal skills per kid; the planner skill can branch on `family.query_overview`. - **Weekly cadence.** Run the loop Mon/Wed/Fri instead of daily; just change the heartbeat cron. Build # Chore + photo proof Daily room-cleaning chore with photo evidence. Optional home-agent print pipeline. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## The setup You want your kid to clean their room every weekday after school, with a photo as proof. The follow-up: photos collect in a family album, and (optionally) the home agent prints them out at the end of each week to put on the fridge. Visual reinforcement of follow-through. Most of this is buildable today. The photo-capture inside a canvas is Soon (waiting on `sprout.uploadAsset`); the print pipeline is on your home agent's side. We'll note where each piece sits. ## Patterns we'll chain - [Photo and video proof](/docs/how-to/proof): the new pattern (Soon, both shapes). Either as a camera task or a canvas with `sprout.uploadAsset()`. - [Conversational task](/docs/how-to/journal): fallback ask-and-confirm for today, until proof ships. - [Reports and briefs](/docs/how-to/reports): weekly digest of chore completion + thumbnail strip. - [Autonomous loop](/docs/how-to/automate): heartbeat-fired weekly digest; home-agent-side print pipeline. ## The arc ### 1. Author the chore prompt A short conversational task fires each weekday at 5pm. Sprout asks: "Did you tidy your room? Show me what it looks like." If the kid says yes, Sprout asks for a photo. Follows the [Conversational task](/docs/how-to/journal) pattern with `goalType: "share"` + `minResponses: 2`. ### 2. Photo capture (Soon) When the [Photo and video proof](/docs/how-to/proof) pattern lands, you have two shapes to pick from. For a chore-and-snap flow, **Route A (camera task)** is the natural fit: `task.create` with `runMode: "camera"` + `cameraTaskSpec.captureKind: "photo"`. Sprout owns the capture surface, no canvas needed. If you want the kid to do a quick reflection alongside the photo, **Route B (canvas with `uploadAsset`)** lets you bundle both into one activity. Until either ships, the kid uploads via the parent app or sends it to you for forwarding. ### 3. Weekly digest Every Sunday night, the [Morning brief](/docs/skills/morning-brief)-style skill (adapted) runs on the past week's chore data. Card in inbox: completion streak, photo thumbnails, any skipped days. Follows the [Reports and briefs](/docs/how-to/reports) pattern. ### 4. Home-agent print pipeline This step lives entirely on your home agent's side. Sprout doesn't reach into your printer. Your agent reads the week's photos via `task.describe`, runs them through your favorite photo-print integration (Polaroid printer, AirPrint to a home photo printer, Shutterfly API, whatever), and posts to the inbox: "5 photos sent to the printer." Follows the [Autonomous loop](/docs/how-to/automate) pattern with a heartbeat firing Sunday at 9pm. ## The result Every weekday, your kid does the chore and snaps a photo. Every Sunday, you get a digest card AND a stack of printed photos to put on the fridge. The kid sees their week of follow-through made physical. ## Variations - **Different chore**: swap "tidy room" for "feed the dog" / "put dishes away" / "make bed". Same pattern. - **No printer**: drop the print pipeline; just keep the weekly digest. Still useful. - **Multiple chores**: one conversational task per chore, weekly digest covers all of them. - **Gem-rewarded**: bump `rewardSpec.gems` on the daily task; pair with a [Reward](/docs/concepts/reward) for streak milestones. Build # Weekly family brief A Sunday-night digest card. Reports and briefs + Autonomous loop in 30 lines of glue. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## The setup You want a Sunday-night digest of your family's week. What everyone did, gems earned, screen-time used, anything that needs your attention going into Monday. One card; scrollable, scannable, ready for a 60-second review with coffee. This is the shortest walkthrough in Build: two patterns, ~30 lines of glue. Reliable and high-leverage. ## Patterns we'll chain - [Reports and briefs](/docs/how-to/reports): the digest skill that reads the week and posts a card. - [Autonomous loop](/docs/how-to/automate): heartbeat firing the digest every Sunday at 8pm. ## The arc ### 1. Author the digest skill A `home_agent` skill that reads the past week and structures it. Per kid: tasks completed, gems earned, screen-time consumed, anything pending review. Pair with the [Morning brief](/docs/skills/morning-brief) skill as a starting template; tune for weekly cadence. Shell · this walkthrough's inputscontent_copy ``` skill.write({ name: "Weekly family brief", category: "home_agent", prompt: `Read the past 7 days: - task.list per kid, status: completed - gems.list_transactions per kid - screentime.query_state per kid, period: week - any pending parent reviews Format as a compact card, one section per kid. skill.post_result with the structured payload.`, handsReferenced: ["task_list", "gems_list_transactions", "screentime_query_state", "skill_post_result"], inputVariables: [{ name: "family_id" }] }) ``` ### 2. Schedule it Heartbeat fires every Sunday at 8pm in your timezone. Cron is the only thing you tune. Shellcontent_copy ``` heartbeat.create({ name: "Weekly family brief", cron: "0 20 * * 0", // Sunday 8pm tz: "America/New_York", runSkillId: "", skillInput: { family_id: "" } }) ``` ## The result Every Sunday at 8pm, a card lands in your family inbox. One scroll: each kid's week summarized. If there's anything pending, a screen-time request, a task you haven't reviewed, it's at the top. You catch up with coffee Monday morning. The loop runs itself. ## Variations - **Daily morning brief**: drop cron to `0 7 * * *`; reduce scope to today's plan. - **End-of-day brief**: cron to `0 21 * * *`; focus on what landed since this morning. - **Per-kid digest**: one heartbeat per kid; tighter focus, more frequent cadence. - **Trend layer**: add a "themes this week" section (asks your agent to spot patterns across the journal transcripts) for deeper insight. Build # Music Lab A four-unit music program: note reading drills, ear training, composition prompts, listening reflection. Program-led walkthrough. .build-mockup { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 20px 22px; margin: 16px 0 28px; } .build-mockup-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 8px; } .build-mockup-title { font-size: 16px; font-weight: 600; color: var(--docs-fg-primary); margin-bottom: 4px; } .build-mockup-meta { font-size: 12px; color: var(--docs-fg-secondary); margin-bottom: 12px; } .build-mockup hr { border: 0; border-top: 1px solid var(--docs-border-secondary); margin: 12px 0; } .build-mockup-section { margin: 10px 0; } .build-mockup-bullets { font-size: 14px; color: var(--docs-fg-primary); margin: 8px 0; padding-left: 18px; } .build-mockup-bullets li { margin: 4px 0; } .build-mockup-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--docs-brand-emph); background: rgba(11, 165, 236, 0.10); padding: 3px 7px; border-radius: 4px; margin-right: 6px; } .build-mockup-quote { border-left: 3px solid var(--docs-brand); padding-left: 14px; font-style: italic; color: var(--docs-fg-secondary); font-size: 14px; margin: 10px 0; } .docs-skill-chip { display: inline-block; padding: 4px 10px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 999px; font-size: 12px; color: var(--docs-fg-primary); text-decoration: none; margin: 4px 6px 4px 0; } .docs-skill-chip:hover { border-color: var(--docs-brand); color: var(--docs-brand); } .docs-skill-chip-status { display: inline-block; margin-left: 6px; padding: 1px 5px; font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 3px; } .docs-skill-chip-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .docs-skill-chip-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } ## The setup Your kid takes piano lessons once a week. The teacher gives them a piece to practice. You want the in-between days to do more than rote practice: note reading drills, ear training prompts, little composition sparks, listening reflection. You want a coherent *lab* structure, not a pile of one-off tasks. By the end of this walkthrough, you'll have a four-unit Music Lab program assigned to your kid, with each unit pulling from a different Build pattern (canvas, conversational, listen-and-tell). The program is the spine; the patterns are the limbs. This walkthrough leans on the [Program](/docs/how-to/program) pattern, which is Soon on the kid surface. The MCP tools exist; we'll use them and call out what's still landing. ## Patterns we'll chain - [Program](/docs/how-to/program): the four-unit Music Lab template, assigned per kid. - [Interactive canvas](/docs/how-to/canvas): tap-the-key drills for note reading. - [Conversational task](/docs/how-to/journal): composition prompts and listening reflection. - [Reports and briefs](/docs/how-to/reports): weekly digest of which units moved forward. - [Autonomous loop](/docs/how-to/automate): a nudge that picks one unit per session. ## The arc ### 1. Define the template The Music Lab has four units, each with one or two leaf tasks. Each leaf task points to a skill that knows how to deliver it (the canvas to render, or the conversation to run). Tasks without a `taskRef` are placeholders the parent fills in later. Shellcontent_copy ``` program.create({ name: "Music Lab", description: "Pick-and-choose music adventure that complements piano lessons. Note reading, ear training, composition, and listening.", type: "template", units: [ { name: "Note Reading", emoji: "🎼", description: "Read notes on the staff.", children: [ { name: "Treble Clef Notes", emoji: "🎵", description: "See a note, hear it, tap C/D/E.", taskRef: { skillId: "" } } ] }, { name: "Pitch Ear", emoji: "👂", description: "Hear pitch and identify it. Needs a grown-up and piano.", children: [ { name: "High or Low?", emoji: "🎶", description: "Grown-up plays two notes. You say which is higher.", taskRef: { skillId: "" } } ] }, { name: "Compose & Create", emoji: "✨", description: "Make up songs at the real piano; reflect with Sprout.", children: [ { name: "Make Up a Song", emoji: "🎼", description: "Make up a little song. Then tell me about it.", taskRef: { skillId: "" } }, { name: "Song with a Feeling", emoji: "💖", description: "Make a happy song and a sleepy song. What changed?", taskRef: { skillId: "" } } ] }, { name: "Listen", emoji: "🎧", description: "Build the music brain by listening and reflecting.", children: [ { name: "What Did You Hear?", emoji: "👂", description: "Tell me about music you heard or played today.", taskRef: { skillId: "" } } ] } ], inputVariables: [ { name: "kid_name", description: "First name, used in prompts." }, { name: "weekly_cadence", description: "e.g. 'Mon/Wed/Fri after dinner'." } ] }) # Returns { programId: "" } ``` The skills referenced under each `taskRef` are skills you've already built using the other Build patterns. Treble Clef Notes wraps an [Interactive canvas](/docs/how-to/canvas) with a staff renderer and tap targets. The composition and listening prompts wrap [Conversational tasks](/docs/how-to/journal) with the right `guidance` for each goal. ### 2. Assign to your kid Shellcontent_copy ``` program.assign({ templateId: "", childId: "", slots: { kid_name: "Alex", weekly_cadence: "Mon/Wed/Fri after dinner" } }) # Tasks for the first unit get authored automatically as the kid progresses. ``` ### 3. Cadence with an Autonomous loop The program is pick-and-choose by design, but kids do better with a nudge. A daily heartbeat at 5pm checks the program state and queues one unit task for the kid to choose from. Follows the [Autonomous loop](/docs/how-to/automate) pattern. Shell · this walkthrough's inputscontent_copy ``` heartbeat.create({ name: "Music Lab nudge", cron: "0 17 * * 1,3,5", // Mon/Wed/Fri 5pm tz: "America/New_York", runSkillId: "", skillInput: { kid_id: "", program_id: "" } }) ``` The nudge skill: read program progress, pick the unit that hasn't moved in the longest, surface that unit's leaf task as the suggestion. ### 4. Weekly digest Sunday night, a [Reports and briefs](/docs/how-to/reports) skill summarizes the week per unit: how many sessions, which leaf tasks moved, what the kid said about their songs. Card in the family inbox. Pairs nicely with a [heartbeat](/docs/how-to/automate) firing `0 20 * * 0`. ## The result Your kid opens Sprout and sees a Music Lab section with four units. They can pick where to go. The nudge points them gently when they haven't been on the piano in a few days. Each session, Sprout asks about what they played, listens to their reflection, scores a tap drill if they want one. Sunday night you get the digest. The piano teacher sees more engaged practice without you turning into a drill sergeant. ## Variations - **Different instrument.** Swap "piano" for "guitar" / "violin" / "drums". The unit shapes (read, ear, compose, listen) translate; the task content changes. - **Different domain.** The same four-unit shape works for sports drills (technique, conditioning, scrimmage reflection, watching tape), language practice (vocab, listening, speaking, reading), or art (sketching, color theory, composition, art history). - **No nudge.** Skip the heartbeat; let the kid drive entirely. Programs work either way. - **Two kids, same template.** Call `program.assign` twice with different `slots`. The template is shared; the assigned instances are independent. ## Notes on current state The MCP program tools (`program.create`, `program.assign`, `program.update`) are live and the schema accepts the shape above. The kid-facing Music Lab section in the app is Soon: today the assigned tasks land as regular tasks in the kid's task list; the explicit "program with units" surface is coming. The walkthrough is fully buildable as MCP plumbing now; the visual structure lands with the kid surface. ──────────────────────────────────────────────────────────── # Skills ──────────────────────────────────────────────────────────── Skills # Skills catalog Reusable .md skills you can drop into your home agent's library. Compose with patterns from Build. .skills-banner { background: rgba(11, 165, 236, 0.06); border-left: 3px solid var(--docs-brand); border-radius: 0 8px 8px 0; padding: 16px 20px; margin: 8px 0 28px; font-size: 14px; color: var(--docs-fg-secondary); } .skills-banner strong { color: var(--docs-fg-primary); } .skill-status { display: inline-block; padding: 2px 8px; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; border-radius: 4px; vertical-align: middle; margin-left: 10px; } .skill-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .skill-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } .skill-download { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--docs-brand); color: white; border-radius: 8px; font-size: 14px; font-weight: 600; text-decoration: none; margin: 8px 0 28px; } .skill-download:hover { filter: brightness(0.95); color: white; } .skill-meta-row { display: flex; flex-wrap: wrap; gap: 18px; margin: 16px 0 24px; padding: 14px 18px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 10px; font-size: 13px; } .skill-meta-row dt { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 4px; } .skill-meta-row dd { margin: 0; color: var(--docs-fg-primary); } .skill-meta-cell { min-width: 140px; } .skill-spec { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 18px 22px; } .skill-spec pre { margin: 0; font-size: 12px; line-height: 1.5; white-space: pre-wrap; } **Heads up.** We're actively working on a share-within-platform feature so families can publish and discover each other's skills directly inside Sprout. Until then, this catalog is a curated set of starting points: one is in-production at Sprout (Screen reader); the rest are templates we use internally and recommend as scaffolds. Each skill is a small `.md` artifact: YAML frontmatter declaring inputs + tools, a prompt body your home agent renders, and an example invocation. Download the file, drop it into your agent's skill library, tune the inputs to your family. Organized by the pattern they pair with. Skills that pair with multiple patterns appear under their primary category. ## Interactive canvas [Screen reader In prodRead text aloud word-by-word with synced highlighting, for kid-facing canvases with narrated passages.](/docs/skills/screen-reader)[Quiz template TemplateMultiple-choice quiz scaffold with avatar reactions on right/wrong and a single sprout.score completion call.](/docs/skills/quiz-template) ## Conversational task [Daily check-in opener TemplateReflective journal opener tuned for grade-school kids. Highlight, lowlight, what's next.](/docs/skills/daily-checkin) ## Context bridge [School connector TemplateRead a school worksheet/email/PDF, summarize the topic and vocab cap, hand into Sprout context.](/docs/skills/school-connector) ## Reports and briefs [Journal analyzer TemplateRead a conversational task transcript and post a structured themes/gaps/next-topic card.](/docs/skills/journal-analyzer)[Morning brief TemplateA daily 7am card summarizing yesterday's activity per kid and today's plan.](/docs/skills/morning-brief) ## Autonomous loop [Next-session planner TemplateRead yesterday's analyzer card, pick tomorrow's topic, author the next canvas + journal.](/docs/skills/next-session-planner) ## Contribute Got a skill you'd add? When the share-within-platform feature ships, you'll publish from inside Sprout. For now, email [hello@sproutgoodhabits.com](mailto:hello@sproutgoodhabits.com) with the .md and a 1-line description. Skills # Screen reader Read text aloud word-by-word with synced highlighting, for kid-facing canvases with narrated passages. .skills-banner { background: rgba(11, 165, 236, 0.06); border-left: 3px solid var(--docs-brand); border-radius: 0 8px 8px 0; padding: 16px 20px; margin: 8px 0 28px; font-size: 14px; color: var(--docs-fg-secondary); } .skills-banner strong { color: var(--docs-fg-primary); } .skill-status { display: inline-block; padding: 2px 8px; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; border-radius: 4px; vertical-align: middle; margin-left: 10px; } .skill-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .skill-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } .skill-download { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--docs-brand); color: white; border-radius: 8px; font-size: 14px; font-weight: 600; text-decoration: none; margin: 8px 0 28px; } .skill-download:hover { filter: brightness(0.95); color: white; } .skill-meta-row { display: flex; flex-wrap: wrap; gap: 18px; margin: 16px 0 24px; padding: 14px 18px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 10px; font-size: 13px; } .skill-meta-row dt { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 4px; } .skill-meta-row dd { margin: 0; color: var(--docs-fg-primary); } .skill-meta-cell { min-width: 140px; } .skill-spec { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 18px 22px; } .skill-spec pre { margin: 0; font-size: 12px; line-height: 1.5; white-space: pre-wrap; } [file_download Download screen-reader.md](/docs/skills/screen-reader.md) StatusIn prod Pairs with[Interactive canvas](/docs/how-to/canvas) [Conversational task](/docs/how-to/journal) NounsCanvas, Skill ## What it does An authoring helper for building Sprout canvases with read-aloud narration synced to browser speech boundary events. Renders each word as a span; `SpeechSynthesisUtterance.onboundary` drives the active-word highlight using the real `charIndex`, not guessed timers. This is the actual skill the Sprout team uses in-production. The prompt and input variables below are the verbatim body shipped on the platform. ## How to use it Invoke this skill before authoring (or updating) any canvas that reads text aloud. Your agent receives the implementation pattern and the canvas constraints, then calls `canvas.create` or `canvas.update` with narration wired up correctly. Pass `canvas_goal` and `narration_text`. ## The spec This is the raw `.md` content. [Download as file](/docs/skills/screen-reader.md) or copy below. ``` name: Screen reader slug: screen-reader description: Authoring helper for building Sprout canvases with read-aloud narration and word highlighting synced to browser speech boundary events. category: home_agent trustTier: experimental kidCallable: false status: published pairs_with_patterns: - canvas - journal pairs_with_nouns: - Canvas - Skill handsReferenced: - canvas_create - canvas_update inputVariables: - name: canvas_goal display_name: Canvas goal description: What the canvas is trying to teach or do. json_schema: { type: string } - name: narration_text display_name: Narration text description: The sentence or lesson text to read aloud and highlight. json_schema: { type: string } # Skill prompt When building or updating a Sprout canvas that reads text aloud, use this procedure. Use browser SpeechSynthesisUtterance.onboundary with charIndex to highlight the actual word being spoken. Do not rely on guessed timers for word highlighting unless the selected browser voice does not emit boundary events. Implementation pattern: 1. Tokenize the sentence with a regex that records each word's start and end character offsets. 2. Render each word as a span with data-start and data-end attributes. 3. On SpeechSynthesisUtterance.onboundary, read event.charIndex and mark the span whose character range contains that index. 4. Clear the active word on onend or onerror. 5. If no boundary events arrive, surface that limitation or use a conservative fallback; do not present the fallback as exact sync. For lesson screens, make narration unskippable when requested: disable Next, Replay, and Play while narration is speaking, then unlock them only in the onend/onerror completion path. Replay should lock the page again until the replay narration completes. Keep Sprout canvas constraints in mind: no external scripts, no fetch, no localStorage, and exactly one final sprout.score, sprout.complete, or sprout.timed completion call at the end of the activity. The reader helper itself must not call completion. ``` ## Related [Interactive canvas](/docs/how-to/canvas) [Conversational task](/docs/how-to/journal) Skills # Quiz template Multiple-choice quiz scaffold with avatar reactions on right/wrong and a single sprout.score completion call. .skills-banner { background: rgba(11, 165, 236, 0.06); border-left: 3px solid var(--docs-brand); border-radius: 0 8px 8px 0; padding: 16px 20px; margin: 8px 0 28px; font-size: 14px; color: var(--docs-fg-secondary); } .skills-banner strong { color: var(--docs-fg-primary); } .skill-status { display: inline-block; padding: 2px 8px; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; border-radius: 4px; vertical-align: middle; margin-left: 10px; } .skill-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .skill-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } .skill-download { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--docs-brand); color: white; border-radius: 8px; font-size: 14px; font-weight: 600; text-decoration: none; margin: 8px 0 28px; } .skill-download:hover { filter: brightness(0.95); color: white; } .skill-meta-row { display: flex; flex-wrap: wrap; gap: 18px; margin: 16px 0 24px; padding: 14px 18px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 10px; font-size: 13px; } .skill-meta-row dt { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 4px; } .skill-meta-row dd { margin: 0; color: var(--docs-fg-primary); } .skill-meta-cell { min-width: 140px; } .skill-spec { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 18px 22px; } .skill-spec pre { margin: 0; font-size: 12px; line-height: 1.5; white-space: pre-wrap; } [file_download Download quiz-template.md](/docs/skills/quiz-template.md) StatusTemplate Pairs with[Interactive canvas](/docs/how-to/canvas) NounsCanvas ## What it does A canvas template: title, question array, multiple-choice answer buttons, immediate visual feedback per answer, mid-activity avatar signals on right/wrong/stuck, and a single `sprout.score` call at the end. Drop your questions in, hand the rest to Sprout. Tunable by age via `dimensions.age`. ## How to use it Open the .md spec. Copy the canvas HTML, fill in the `questions` array. The skill prompt tells your agent how to `canvas.create` + wrap + deliver. Two-step dry-run/commit included. ## The spec This is the raw `.md` content. [Download as file](/docs/skills/quiz-template.md) or copy below. ``` name: quiz-template slug: quiz-template description: Multiple-choice quiz canvas with avatar reactions and one sprout.score completion call. category: home_agent status: template pairs_with_patterns: - canvas pairs_with_nouns: - Canvas - Task handsReferenced: - canvas_create - skill_write - task_create inputVariables: - name: title - name: questions description: "Array of { prompt, choices[], correctIndex }." - name: age description: Reading-level dimension. "6-7" | "8-9" | "10+". # Canvas shape

# Skill prompt For {{input.title}} on age {{input.age}}: 1. canvas.create with dryRun: true, embedding the questions array. 2. Echo the previewHtml + specHash to the parent. Pause. 3. On approval: canvas.create dryRun: false, specHash: . 4. skill.write wrapping the canvas. 5. task.create when invoked. ``` ## Related [Interactive canvas](/docs/how-to/canvas) Skills # Daily check-in opener Reflective journal opener tuned for grade-school kids. Highlight, lowlight, what's next. .skills-banner { background: rgba(11, 165, 236, 0.06); border-left: 3px solid var(--docs-brand); border-radius: 0 8px 8px 0; padding: 16px 20px; margin: 8px 0 28px; font-size: 14px; color: var(--docs-fg-secondary); } .skills-banner strong { color: var(--docs-fg-primary); } .skill-status { display: inline-block; padding: 2px 8px; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; border-radius: 4px; vertical-align: middle; margin-left: 10px; } .skill-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .skill-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } .skill-download { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--docs-brand); color: white; border-radius: 8px; font-size: 14px; font-weight: 600; text-decoration: none; margin: 8px 0 28px; } .skill-download:hover { filter: brightness(0.95); color: white; } .skill-meta-row { display: flex; flex-wrap: wrap; gap: 18px; margin: 16px 0 24px; padding: 14px 18px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 10px; font-size: 13px; } .skill-meta-row dt { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 4px; } .skill-meta-row dd { margin: 0; color: var(--docs-fg-primary); } .skill-meta-cell { min-width: 140px; } .skill-spec { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 18px 22px; } .skill-spec pre { margin: 0; font-size: 12px; line-height: 1.5; white-space: pre-wrap; } [file_download Download daily-checkin.md](/docs/skills/daily-checkin.md) StatusTemplate Pairs with[Conversational task](/docs/how-to/journal) NounsTask ## What it does A canonical 3-question morning check-in: highlight from yesterday, lowlight from yesterday, what they want today to be about. `conversationSpec.goalType: "share"`, `minResponses: 3`, `effort: "balanced"`. ## How to use it Copy the spec, drop your kid's age in. Invoke daily via heartbeat (see [Autonomous loop](/docs/how-to/automate)) or one-off via `task.create`. ## The spec This is the raw `.md` content. [Download as file](/docs/skills/daily-checkin.md) or copy below. ``` name: daily-checkin slug: daily-checkin description: Three-question reflective journal opener: highlight, lowlight, today's intention. category: home_agent status: template pairs_with_patterns: - journal pairs_with_nouns: - Task handsReferenced: - task_create inputVariables: - name: child_id - name: child_name - name: age - name: date # Skill prompt task.create({ name: "Morning check-in", assignChildIds: ["{{input.child_id}}"], runMode: "conversation", conversationSpec: { goalType: "share", guidance: `Ask {{input.child_name}} ({{input.age}}) three questions, in order: 1. What's one good thing from yesterday? 2. What's one thing that didn't go well? 3. What do you want today to be about? Keep follow-ups brief; don't push past what they want to share.`, minResponses: 3, effort: "balanced", grading: "engagement", dailyTarget: 1 }, scheduleSpec: { taskType: "onetime", oneTimeDate: "{{input.date}}", startMinutes: 480 }, rewardSpec: { gems: 2 } }) ``` ## Related [Conversational task](/docs/how-to/journal) Skills # School connector Read a school worksheet/email/PDF, summarize the topic and vocab cap, hand into Sprout context. .skills-banner { background: rgba(11, 165, 236, 0.06); border-left: 3px solid var(--docs-brand); border-radius: 0 8px 8px 0; padding: 16px 20px; margin: 8px 0 28px; font-size: 14px; color: var(--docs-fg-secondary); } .skills-banner strong { color: var(--docs-fg-primary); } .skill-status { display: inline-block; padding: 2px 8px; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; border-radius: 4px; vertical-align: middle; margin-left: 10px; } .skill-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .skill-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } .skill-download { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--docs-brand); color: white; border-radius: 8px; font-size: 14px; font-weight: 600; text-decoration: none; margin: 8px 0 28px; } .skill-download:hover { filter: brightness(0.95); color: white; } .skill-meta-row { display: flex; flex-wrap: wrap; gap: 18px; margin: 16px 0 24px; padding: 14px 18px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 10px; font-size: 13px; } .skill-meta-row dt { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 4px; } .skill-meta-row dd { margin: 0; color: var(--docs-fg-primary); } .skill-meta-cell { min-width: 140px; } .skill-spec { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 18px 22px; } .skill-spec pre { margin: 0; font-size: 12px; line-height: 1.5; white-space: pre-wrap; } [file_download Download school-connector.md](/docs/skills/school-connector.md) StatusTemplate Pairs with[Context bridge](/docs/how-to/context) NounsSkill ## What it does A home-agent-side skill that takes a school document (paper, photo, PDF, email forward) and produces a working summary: subject, topic, vocabulary list, reading level. Calls `family.query_overview` to pin which kid it's for. ## How to use it The skill lives on your agent's side; it doesn't call any Sprout tools beyond `family.query_overview`. Use it as a pre-step before authoring a review canvas or journal. ## The spec This is the raw `.md` content. [Download as file](/docs/skills/school-connector.md) or copy below. ``` name: school-connector slug: school-connector description: Summarize a school document and resolve which kid it's for, ready for downstream Sprout calls. category: home_agent status: template pairs_with_patterns: - context pairs_with_nouns: - Skill handsReferenced: - family_query_overview inputVariables: - name: source description: "File path, URL, photo description, or pasted text." - name: hint description: "Optional: which kid this is for, if your agent can guess." # Skill prompt 1. Read {{input.source}}. 2. Extract: subject, specific topic, vocabulary list (cap at the highest term the kid is expected to know), reading level if signaled. 3. Call family.query_overview() to get the roster. 4. Pick the right kid. If unsure between two, ask the parent. 5. Hold a summary in conversation: { childId, subject, topic, vocab_cap, vocab_skip[], reading_level } 6. Return it to the caller. Don't call task.create / canvas.create yourself; that's the next step in the parent's plan. ``` ## Related [Context bridge](/docs/how-to/context) Skills # Journal analyzer Read a conversational task transcript and post a structured themes/gaps/next-topic card. .skills-banner { background: rgba(11, 165, 236, 0.06); border-left: 3px solid var(--docs-brand); border-radius: 0 8px 8px 0; padding: 16px 20px; margin: 8px 0 28px; font-size: 14px; color: var(--docs-fg-secondary); } .skills-banner strong { color: var(--docs-fg-primary); } .skill-status { display: inline-block; padding: 2px 8px; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; border-radius: 4px; vertical-align: middle; margin-left: 10px; } .skill-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .skill-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } .skill-download { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--docs-brand); color: white; border-radius: 8px; font-size: 14px; font-weight: 600; text-decoration: none; margin: 8px 0 28px; } .skill-download:hover { filter: brightness(0.95); color: white; } .skill-meta-row { display: flex; flex-wrap: wrap; gap: 18px; margin: 16px 0 24px; padding: 14px 18px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 10px; font-size: 13px; } .skill-meta-row dt { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 4px; } .skill-meta-row dd { margin: 0; color: var(--docs-fg-primary); } .skill-meta-cell { min-width: 140px; } .skill-spec { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 18px 22px; } .skill-spec pre { margin: 0; font-size: 12px; line-height: 1.5; white-space: pre-wrap; } [file_download Download journal-analyzer.md](/docs/skills/journal-analyzer.md) StatusTemplate Pairs with[Reports and briefs](/docs/how-to/reports) [Conversational task](/docs/how-to/journal) NounsSkill, Task ## What it does A `home_agent` analyzer skill. Reads the transcript of a completed conversational task via `task.describe`, extracts themes, gaps, and a next-topic recommendation, posts via `skill.post_result`. ## How to use it Invoke right after a journal task completes, or on a heartbeat (morning analyzer of yesterday's chat). ## The spec This is the raw `.md` content. [Download as file](/docs/skills/journal-analyzer.md) or copy below. ``` name: journal-analyzer slug: journal-analyzer description: Analyze a conversational task transcript and post a themes/gaps/next-topic card. category: home_agent status: template pairs_with_patterns: - reports - journal pairs_with_nouns: - Skill - Task handsReferenced: - task_describe - skill_post_result inputVariables: - name: task_id - name: child_name - name: child_id # Skill prompt For task {{input.task_id}} ({{input.child_name}}): 1. task.describe({ taskId: "{{input.task_id}}" }) to read the transcript. 2. Extract: - themes: 2-4 phrases the kid kept returning to. - gaps: vocab they fumbled, concepts they couldn't articulate. - next_topic: one specific topic that would naturally follow. 3. Phrase in plain language a parent reads in 30 seconds. 4. skill.post_result({ skillId: "", result: { summary, themes, gaps, next_topic } }) ``` ## Related [Reports and briefs](/docs/how-to/reports) [Conversational task](/docs/how-to/journal) Skills # Morning brief A daily 7am card summarizing yesterday's activity per kid and today's plan. .skills-banner { background: rgba(11, 165, 236, 0.06); border-left: 3px solid var(--docs-brand); border-radius: 0 8px 8px 0; padding: 16px 20px; margin: 8px 0 28px; font-size: 14px; color: var(--docs-fg-secondary); } .skills-banner strong { color: var(--docs-fg-primary); } .skill-status { display: inline-block; padding: 2px 8px; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; border-radius: 4px; vertical-align: middle; margin-left: 10px; } .skill-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .skill-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } .skill-download { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--docs-brand); color: white; border-radius: 8px; font-size: 14px; font-weight: 600; text-decoration: none; margin: 8px 0 28px; } .skill-download:hover { filter: brightness(0.95); color: white; } .skill-meta-row { display: flex; flex-wrap: wrap; gap: 18px; margin: 16px 0 24px; padding: 14px 18px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 10px; font-size: 13px; } .skill-meta-row dt { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 4px; } .skill-meta-row dd { margin: 0; color: var(--docs-fg-primary); } .skill-meta-cell { min-width: 140px; } .skill-spec { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 18px 22px; } .skill-spec pre { margin: 0; font-size: 12px; line-height: 1.5; white-space: pre-wrap; } [file_download Download morning-brief.md](/docs/skills/morning-brief.md) StatusTemplate Pairs with[Reports and briefs](/docs/how-to/reports) [Autonomous loop](/docs/how-to/automate) NounsSkill ## What it does A digest skill paired with a heartbeat. Each morning at 7am, reads yesterday's completed tasks, gems earned, screen-time used, anything pending review, and posts a per-kid summary card. ## How to use it Author the skill, then schedule it via `heartbeat.create` with `cron: "0 7 * * *"`. The first run is also the test. ## The spec This is the raw `.md` content. [Download as file](/docs/skills/morning-brief.md) or copy below. ``` name: morning-brief slug: morning-brief description: Daily 7am card summarizing yesterday's activity per kid and today's plan. category: home_agent status: template pairs_with_patterns: - reports - automate pairs_with_nouns: - Skill - Heartbeat handsReferenced: - task_list - gems_list_transactions - screentime_query_state - skill_post_result inputVariables: - name: family_id # Skill prompt For each kid in family {{input.family_id}}: 1. task.list({ status: "completed", since: "yesterday" }) 2. gems.list_transactions({ since: "yesterday" }) 3. screentime.query_state({ period: "yesterday" }) 4. task.list({ status: "scheduled", on: "today" }) Compose a compact card: one block per kid. skill.post_result({ skillId: "", result: { kids: [...] } }) # Heartbeat heartbeat.create({ cron: "0 7 * * *", tz: "America/New_York", runSkillId: "", skillInput: { family_id: "" } }) ``` ## Related [Reports and briefs](/docs/how-to/reports) [Autonomous loop](/docs/how-to/automate) Skills # Next-session planner Read yesterday's analyzer card, pick tomorrow's topic, author the next canvas + journal. .skills-banner { background: rgba(11, 165, 236, 0.06); border-left: 3px solid var(--docs-brand); border-radius: 0 8px 8px 0; padding: 16px 20px; margin: 8px 0 28px; font-size: 14px; color: var(--docs-fg-secondary); } .skills-banner strong { color: var(--docs-fg-primary); } .skill-status { display: inline-block; padding: 2px 8px; font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; border-radius: 4px; vertical-align: middle; margin-left: 10px; } .skill-status.in-prod { background: rgba(134, 203, 60, 0.15); color: #5a8a26; } .skill-status.template { background: rgba(141, 138, 138, 0.15); color: var(--docs-fg-tertiary); } .skill-download { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--docs-brand); color: white; border-radius: 8px; font-size: 14px; font-weight: 600; text-decoration: none; margin: 8px 0 28px; } .skill-download:hover { filter: brightness(0.95); color: white; } .skill-meta-row { display: flex; flex-wrap: wrap; gap: 18px; margin: 16px 0 24px; padding: 14px 18px; background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 10px; font-size: 13px; } .skill-meta-row dt { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--docs-fg-tertiary); margin-bottom: 4px; } .skill-meta-row dd { margin: 0; color: var(--docs-fg-primary); } .skill-meta-cell { min-width: 140px; } .skill-spec { background: var(--docs-bg-secondary); border: 1px solid var(--docs-border-primary); border-radius: 12px; padding: 18px 22px; } .skill-spec pre { margin: 0; font-size: 12px; line-height: 1.5; white-space: pre-wrap; } [file_download Download next-session-planner.md](/docs/skills/next-session-planner.md) StatusTemplate Pairs with[Autonomous loop](/docs/how-to/automate) NounsSkill ## What it does The planner half of a self-improving loop. Each morning, reads the most recent analyzer card, picks the next topic, invokes the canvas skill + journal skill with those inputs. Ships tomorrow's work without your involvement. ## How to use it Author the skill. Schedule via `heartbeat.create`. Pair with [Journal analyzer](/docs/skills/journal-analyzer) running the evening before. ## The spec This is the raw `.md` content. [Download as file](/docs/skills/next-session-planner.md) or copy below. ``` name: next-session-planner slug: next-session-planner description: Read yesterday's analyzer card and author tomorrow's canvas + journal. category: home_agent status: template pairs_with_patterns: - automate pairs_with_nouns: - Skill - Heartbeat handsReferenced: - skill_invoke - task_list inputVariables: - name: child_id - name: child_name - name: canvas_skill_id description: "The Interactive canvas skill in your library." - name: journal_skill_id description: "The Conversational task skill in your library." # Skill prompt For {{input.child_name}}: 1. Read the most recent journal-analyzer result for this kid. 2. Pull next_topic. If none, fall back to the kid's curriculum cursor. 3. skill.invoke({ skillId: "{{input.canvas_skill_id}}", input: { topic: next_topic, age: "...", date: "tonight" } }) 4. skill.invoke({ skillId: "{{input.journal_skill_id}}", input: { topic: next_topic, date: "tomorrow morning" } }) # Heartbeat heartbeat.create({ cron: "0 9 * * *", tz: "America/New_York", runSkillId: "", skillInput: { child_id, child_name, canvas_skill_id, journal_skill_id } }) ``` ## Related [Autonomous loop](/docs/how-to/automate) ──────────────────────────────────────────────────────────── # Model ──────────────────────────────────────────────────────────── Model # The cast Two agents drive. The Sprout apps surface it. Sprout Systems orchestrates. Sprout is the operating system for the family. Two agents drive it: yours, over MCP, and Sprout's own. Sprout makes the day safe, scheduled, and kid-ready. **Your agent is the bridge to your home systems. The Sprout agent works the inside.** ## The cast Five entities, grouped as two agents that drive, the Sprout apps that surface, and one platform that orchestrates. | Layer | Entity | What it does | **Agents** | **Your agent** | Owns intent. Lives in your home systems. Talks to Sprout Systems over MCP. | **The Sprout agent** | Powers the in-app agentic moments, especially for your kids. An accessible assistant within the Sprout apps for parents. | **Sprout apps** | **Parent app** | Onboarding and setup; a surface to quickly view, respond to, and add things to Sprout Systems, with help from the Sprout agent. | **Kid app** | Where your kids experience Sprout. *(More apps to come: villager, coach…)* | **Orchestrator** | **Sprout Systems** | The platform and the data underneath it all. Family state, the gem economy, the skill lifecycle, the screen-time gates. Routes between the agents and the apps. ## Where the lines are drawn The clean dividing line between the two agents is what they can reach. **Anything touching your home systems is exclusively your agent.** Your integrations, your data, your external models. School portals, the family calendar, photos, your LMS, the day's plan, vision models, anything you bring from the outside. Sprout's agent doesn't reach out there. **The Sprout agent works inside Sprout Systems.** Family state, the gem economy, the skill lifecycle, the screen-time gates, the inbox. It can read and write the platform on your behalf, but it doesn't have your credentials or your connections. Two named worlds, two agents that bridge them: *your home systems*, and *Sprout Systems*. ## Three failure modes you will hit ### No scope First-handshake OAuth typically misses `canvas:*` and `skill:*`. Your agent will try the canonical sequence the docs describe and get "tool not in catalog" or "requires scope(s) not granted." Fix: `/mcp` disconnect + reconnect, approve the new scopes. ### Wrong family Cross-family ids return `PERMISSION_DENIED`, deliberately indistinguishable from "not found" so partners cannot enumerate. Never hardcode UUIDs. Start every workflow with `family.query_overview` and resolve ids on the fly. ### Authored but never delivered You created a canvas and wrote a skill. The kid sees nothing. Authoring is not delivery. You also need a `task.create` (one-off) or `heartbeat.create` (recurring). ## What to do next Read [Connect your agent](/docs/start/plug-your-agent) to confirm your token has what it needs. Then [Hello, family](/docs/start/first-task) for the smallest useful first call. Then [the lifecycle](/docs/concepts/lifecycle) for the model you will use for everything else. ## Try it Shellcontent_copy ``` # Confirm your token, see your scopes mcp.whoami { "user_id": "2f1bba9f-...", "app_id": "7408ecc5-...", "sprout_scopes": ["family:read", "task:write", "skill:write", "canvas:write", ...] } # If skill:* or canvas:* is missing, reconnect: # /mcp -> sprout -> disconnect -> connect ``` ## Further reading - [Connect your agent](/docs/start/plug-your-agent) - [Hello, family](/docs/start/first-task) - [The skill lifecycle](/docs/concepts/lifecycle) - [The object model](/docs/concepts/objects) Was this page helpful? thumb_up Yes thumb_down No [The eight nouns chevron_right](/docs/concepts/objects) Model # 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 `instructions` to 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. Your home agent - initialize 1 The map instructions field, returned once on initialize ~800 tokens injected into your agent's system prompt for the session "before authoring X, read sprout://X/guide" 2 The pointers resources/read sprout://*/authoring-guide deep model loaded on demand, only for the operation about to run tools/call X 3 The next step every tool response carries directional guidance error.code names the fix • response.nextStep names the next call your agent doesn't memorize the protocol; the protocol reminds it next operation, same pattern **The map.** On `initialize`, the `instructions` field 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/read` the 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 carry `nextStep`. 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. Shellcontent_copy ``` # 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`: before `skill.write` or before reading a foreign skill. - `sprout://canvas/sdk`: before `canvas.create` or `canvas.update`. - `sprout://heartbeat/authoring-guide`: before `heartbeat.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 a `specHash` over the canonical input. - Show the preview to the parent. Confirm. - Call again with `dryRun: false` and the echoed `specHash`. The server re-hashes the input (excluding `dryRun` and `specHash`) and rejects mismatches with `SPEC_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`, `activity` reads, `heartbeat.list`: to discover what changed since last check. **Push (shipping now, leaf-by-leaf):** - **Subscriptions over SSE.** Your agent calls `resources/subscribe `; the MCP response upgrades to SSE; the server pushes `notifications/resources/updated` on every change. foundation is live. - **More resources coming.** `sprout://child/{childId}/screentime/requests` and `sprout://child/{childId}/gems`. Next: `sprout://child/{childId}/today`, then `sprout://family/activity` (which makes *event-driven heartbeats* real). - Full catalog, code example, delivery semantics: [Reference: Subscriptions](/docs/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 `:read` implicitly. Write implies read. - **High** , `gems:adjust`, `screentime:approve`. Single-call effects with direct economic / behavioral impact. Confirm with the parent before invoking (the server's `instructions` field also nudges this). See [the scope table on Plug your agent in](/docs/start/plug-your-agent#scopes) for the per-tool mapping. ## Further reading - [The cast](/docs/concepts/three-parties): who acts on which side of the protocol. - [The nouns](/docs/concepts/objects): what the calls operate on. - [Plug your agent in](/docs/start/plug-your-agent): the connect tutorial. - [How safety works](/docs/help/safety): how the protocol enforces safety. Model # The nouns The full directory of Sprout's nouns. The Overview shows the canonical eight; this is the comprehensive list. The full directory. The [Overview](/docs) shows the canonical eight that ground a builder's first week; this page is the comprehensive list, including the less-frequently-used and the planned ones. Every noun has its own page. [ Task The kid-facing moment. A check-in chat, a chore, an interactive challenge. Every kid touchpoint is a task. ](/docs/concepts/task) [ Skill Your agent's family skill book. Save a procedure, parameterize it, invoke it tomorrow with new context. ](/docs/concepts/skill) [ Canvas Interactive moments inside a task. Mini-games, drills, custom widgets, anything you can render. ](/docs/concepts/canvas) [ Heartbeat How Sprout keeps a rhythm. The trigger that wakes the Sprout agent to refresh, post, or act. ](/docs/concepts/heartbeat) [ Reward What kids work for. Gems earned per task, spent on parent-defined rewards. The loop that makes habits stick. ](/docs/concepts/reward) [ Screen-time The screen-time bouncer. Kids request time; your agent reviews, approves, or steers them somewhere else. ](/docs/concepts/screen-time) [ Activity The family feed for parents. Every kid update in one place. Soon streamed live to your home agent. ](/docs/concepts/activity) [ SoonProgram A way to group tasks so kids see a coherent path. Habit ladders, learning paths, project-based work. ](/docs/concepts/program) This list grows. As Sprout's surface widens, new nouns land here first. **Once you've explored the nouns,** head to [Build](/docs/how-to) for an example use case that wires these pieces into something your agent can ship. Model # Task The kid-facing unit. A check-in chat, a chore, an interactive challenge. Every kid touchpoint is a task. A **task** is the kid-facing unit in Sprout. It is the thing that shows up on the kid's iPad, the thing they tap into, the thing they complete. Every kid touchpoint: a chat, a chore, an interactive canvas, a camera proof: is a task or starts with one. Tasks can stand alone (your agent creates one directly) or be governed by a [skill](/docs/concepts/skill) that re-runs them or refreshes them over time. Most first-time builders ship a task before they ship a skill. ## Where you'll see this **In the wild:** [Your first task](/docs/start/first-task) ## A worked example A daily check-in conversation task. Read the family first to resolve the kid id, then ship the task. Shellcontent_copy ``` task.create({ name: "Daily check-in", assignChildIds: [""], runMode: "conversation", conversationSpec: { goalType: "share", guidance: "Ask about one highlight from today, one lowlight, and one thing they're looking forward to. Listen well; reflect back. Keep it warm and short." }, scheduleSpec: { taskType: "schedule", days: ["mon","tue","wed","thu","fri"], startMinutes: 1020 }, rewardSpec: { gems: 3 } }) ``` That's it. No skill needed for the simple recurring shape. Same idea works for `self_check` (chores) and `canvas` (interactive activities) tasks: swap the spec object. ## Shape Every task has these key fields: - `name`: what the kid sees on the card. - `assignChildIds`: which kid(s) it lands on. `assignAllChildren` covers the family. - `runMode`: discriminator. `self_check` (default), `conversation`, `canvas`. Camera is planned. - `conversationSpec` / `canvasSpec`: the spec object matching the runMode. `conversationSpec.guidance` is the load-bearing field for a chat task; `canvasSpec.canvasId` points at the rendered HTML for a canvas task. - `scheduleSpec`: when it fires. `taskType: "onetime"` with `oneTimeDate`, or `taskType: "schedule"` with `days` + `startMinutes`. - `rewardSpec`: gems on completion. Omit to award no gems. - `assignmentSkillId`: optional. Link a [skill](/docs/concepts/skill) for governance, audit, reuse. ## When to use it (and when not to) Reach for a standalone task when: - The thing is a one-off or recurs on a fixed weekly cadence. - The content is the same every time (or the variations come from a canvas you've already authored). - You don't need to re-run the authoring procedure with new context tomorrow. Wrap it in a [skill](/docs/concepts/skill) when: - Tomorrow's task should reflect tomorrow's data (school day, last week's themes, the kid's mood). - You want the skill in your library so it can re-fire across kids or contexts. - The procedure benefits from audit and parameterization. ## Common errors - `BAD_INPUT` · `conversation-needs-guidance` , `runMode:"conversation"` without a non-empty `conversationSpec.guidance`. Fix: add guidance. - `BAD_INPUT` · `canvas-needs-a-skill` , `runMode:"canvas"` without `assignmentSkillId`, or with a skill that doesn't link the canvas. Fix: wrap in a skill that links the canvas. - `BAD_INPUT` · `one-mode-only`: passing a `conversationSpec` with `runMode:"canvas"`, or vice versa. Fix: spec must match the mode. - `PERMISSION_DENIED`: the `childId` or `assignmentSkillId` doesn't belong to this family. ## Related tools - `task.create`: author a new task. - `task.update`: partial patch. Pass only the fields to change. - `task.list`: keyset-paginated; filter by child, status, type. - `task.describe`: read-back / preview shape without guessing. - `task.complete`: fuzzy-match what a kid did against open tasks. - `task.review`: approve/deny a completion. - `task.delete`: destructive; confirm with parent. ## Roadmap for this noun - Soon `runMode: "camera"`: first-class video/photo proof. Pair with `sprout.uploadAsset` on canvas. - Soon Event-driven scheduling: tasks created in response to [activity](/docs/concepts/activity) events, not just clocks. ## Related reading - [Your first task](/docs/start/first-task): the hands-on Start page. - [Skill](/docs/concepts/skill): when you outgrow a standalone task. - [Canvas](/docs/concepts/canvas): when text isn't enough. Model # Skill A saved procedure your agent invokes. Reusable, parameterized, auditable. Like Claude Skills, family-shaped. A **skill** is a saved procedure your agent invokes. Like Claude Skills or custom GPTs, family-shaped. Reusable, parameterized, auditable. A skill captures *what your agent does*: the prompt, the tool list, the inputs: so it can re-run with new context tomorrow without re-prompting. Skills are tagged by where they make sense to run, not who runs them. `generic` skills only touch Sprout and can run anywhere; `home_agent` skills reach outside Sprout (school portal, your calendar, your folders) and only make sense in your home agent's context. ## Where you'll see this **In the wild:** [Save it as a skill](/docs/start/save-as-skill) ## A worked example A skill that refreshes today's Daily check-in to reflect what actually happened at school. Tagged `home_agent` because it reads the school portal before updating the task. Shellcontent_copy ``` skill.write({ name: "Refresh today's check-in", description: "Pull today's school events and rewrite the check-in chat to match.", category: "home_agent", prompt: `For {{input.child_name}} ({{input.child_id}}) on {{input.today}}: 1. Read today's events for this kid from the school portal connector. 2. task.list({ assignedChildIds:[{{input.child_id}}], status:'open' }); find the open task named 'Daily check-in'. 3. Rewrite conversationSpec.guidance to fit today specifically. 4. task.update(taskId, { conversationSpec: { goalType:'share', guidance: } }).`, handsReferenced: ["task_list", "task_update"], inputVariables: [ { name: "child_name" }, { name: "child_id" }, { name: "today" } ] }) # Then each morning: skill.invoke({ skillId: "", input: { child_name, child_id, today } }) ``` The [Save it as a skill](/docs/start/save-as-skill) page walks this top to bottom. ## Shape - `name` · `description`: what the skill is and what it does, in the parent's language. - `category` , `generic` (default) or `home_agent`. The audience fork. - `prompt`: the procedure your agent reads on invoke. Templates use `{{input.*}}` placeholders; child names verbatim are refused with `PII_IN_PROMPT`. - `handsReferenced`: declared tools the procedure uses. Advisory, not an allowlist; biases attention. - `inputVariables`: what your agent passes on each invoke. - `kidCallable`: flag. Whether the kid app can launch this directly. Extra scrutiny if true. - `canvasIds`: optional. Canvases linked to the skill. `skill.update` uses `addCanvasIds` / `removeCanvasIds` (incremental, not full replacement). ## Lifecycle The skill lifecycle is flat: a skill exists or it's archived. There is no separate "activate" beat: invocation records its own usage event, and `skill.get` surfaces the most recent timestamp as `lastTriggeredAt`. Archived skills can't be invoked or scheduled; create a fresh one to reuse the pattern. ## When to use it (and when not to) Save as a skill when: - You'll want the same procedure tomorrow with different inputs. - The content has to change between runs (today's school day, this week's themes). - You want an audit trail and library entry, not a one-off shell command. Stick with a standalone task when: - The content is the same every time; the schedule does the work. - It's truly one-off and you don't expect a sibling pattern. ## Common errors - `BAD_INPUT` · `PII_IN_PROMPT`: a real child's name appeared verbatim in `prompt` or `description`. Use `{{input.child_name}}`. - `BAD_INPUT` · `SPEC_HASH_MISMATCH`: your commit input changed between dry-run and commit. Re-dry-run. - `BAD_INPUT` · `SCHEDULER_AS_RUN_SKILL`: passed a scheduler-shaped skill as the run skill of a heartbeat. - `PERMISSION_DENIED`: invoking or heartbeating a `home_agent` skill from Sprout-runtime. By design. ## Related tools - `skill.write`: author. Supports `dryRun` + `specHash`. - `skill.update`: partial patch. Conditional gates: name/desc-only skips safety + policy. - `skill.invoke`: your agent renders the skill into the conversation. Not kid delivery. - `skill.list` / `skill.get`: read shape; canvas metadata denormalized on `get`. - `skill.post_result`: explicit publish to the family inbox. ## Roadmap for this noun - Soon Cross-family skill library: subscribe to skills other families' agents publish. Metadata review becomes a hard gate. - Soon Granular consent: per-skill parent approval at first invoke, not just at OAuth time. ## Related reading - [Save it as a skill](/docs/start/save-as-skill): the Start hands-on. - [Task](/docs/concepts/task): what skills wrap and orchestrate. - [How safety works](/docs/help/safety): the home-agent's job in evaluating a skill before invoke. Model # Canvas Interactive HTML the kid plays inside a task. Sandboxed. The Sprout SDK is the only host bridge. A **canvas** is interactive HTML the kid plays inside a task. Mini-games, math drills, drawing tools, sticker boards, narrated stories, anything you can render. When text isn't enough, you reach for a canvas. Canvases run in a strict sandbox. The auto-injected `sprout.*` SDK is the only host bridge: no `fetch`, no external `