AWS Builder Center
Weekend Agent Challenge: Piano Teacher

Weekend Agent Challenge: Piano Teacher

An always-on agent that turns a scanned piece of sheet music into a sequenced, lesson-by-lesson practice plan, triggered entirely by moving a card on a kanban board.

Learning a new piano piece from a blank score is overwhelming — you don't know how to break it into a real practice plan. That's what a good teacher does, for a student or for themselves prepping a lesson. So I built an agent that does it: drop in the sheet music, and it plans the practice, lesson by lesson.

Vision & What the Agent Does

piano-teacher is a personal agent that turns a piece of sheet music into a structured, sequenced practice plan — without me ever opening a chat window or clicking a button to kick it off.
The flow starts by adding the sheet music to a folder, then creating a card for the song on my kanban board: title, score attached, assignee set to piano-teacher. As soon as I move that card to Doing, the agent picks it up. It reads the score, decides how to break it into learnable chunks, and decomposes it into lessons — hands separately, phrase by phrase, tempo ramps, flagged tricky bars. Moments later, the lesson files show up in my folder, and the board fills in with one card per lesson, ready for me to work through.
Kanban Board
Each lesson is a bite-sized piece of the song, building up to the full piece, step by step — with embedded, playable notation so I can hear what I'm supposed to be practicing, not just read it.
The trigger is the important part: it's not a button, not a chat prompt — it's a file change on the kanban board itself. The board is the control plane. I never tell the agent to run; I just move a card, and the change to that file is what wakes it up.

How You Built It

Everything begins in a folder on my computer — it holds the music sheets, the lessons, and the board, all in markdown. The kanban board is just a markdown file rendered by Obsidian's Fancy Kanban plugin, and moving a card on screen is really just an edit to that file.
The interesting design problem was the loop guard. The agent's own output — new lesson cards — gets written back into the same board file that triggers it. A naive implementation would re-trigger itself indefinitely. The fix: the very first thing the agent does for a matched card, before any of the slow work (reading the PDF, calling the model, generating lessons), is flip that card's status to done. The re-triggered invocation from that write then scans the board, finds nothing left with status = doing AND assignee = piano-teacher, and exits immediately. It's an optimistic lock, not a true distributed lock — good enough for a single human moving cards, not airtight against a real race condition, and I'm flagging that honestly rather than over-engineering it for a weekend build.
Another decision worth calling out: the assignee field is a constrained Select, not free text, specifically because the trigger condition depends on exact string matching — a typo in a free-text field would silently break everything. The agent's logic only ever checks for its own name, piano-teacher. Any other assignee is simply ignored; there's no special-casing of other people anywhere in the code.
Lesson count is model-decided, not fixed. The prompt asks Claude to assess the piece assuming a beginner player and decompose accordingly — simpler pieces get fewer lessons, harder ones get more, each still scoped to a genuinely learnable chunk. No hardcoded lesson-count target.

Architecture Overview

Under the hood, it's a simple AWS pipeline. My Obsidian folder syncs to an S3 bucket. A change to the board file triggers an event — if there's a card assigned to piano-teacher, a Lambda wakes up and runs a Strands agent, in-process, no separate MCP server deployment. That agent calls Claude Sonnet on Amazon Bedrock (multimodal) to read the score directly — no OMR pipeline — and generate the lesson decomposition, including embedded abc notation per lesson. The agent writes everything back to the bucket: new lesson files and an updated board. I sync the bucket back down, and it's all there in Obsidian. A second plugin, ABC Music Notation, lets me visualize and play back each lesson right from my notes.
Piano Teacher Architecture
AWS services used
  • Amazon S3 (input, board, output storage, and event source),
  • AWS Lambda (event handler and agent host),
  • Amazon Bedrock — Claude (multimodal score analysis and lesson generation),
  • Strands Agents SDK (agent orchestration),
  • MCP (tool interface for S3 reads/writes),
  • IAM (least-privilege role for Lambda).

What You Learned

The board-as-trigger pattern is powerful but needs a guard rail. Using a file edit — rather than a schedule or an explicit invocation — as the trigger makes the whole system feel invisible in the best way: I just move a card, like I would with a human collaborator. But it also means the agent's own writes can re-trigger it, which is a problem you don't hit with schedule-based agents. The optimistic-lock-first pattern (flip status before doing anything slow) is a simple, cheap way to solve it for a single-user weekend build.
Multimodal score reading has real limits. Handing a PDF straight to Claude instead of building an OMR pipeline was the right call for a weekend — but it means accuracy depends on picking a clean, well-engraved demo piece rather than something handwritten or heavily ornamented.
Strands + MCP as a tool layer keeps the agent code honest. Exposing kanban read/write, PDF read, and lesson-file write as discrete MCP tools — even hosted in the same Lambda process — kept the orchestration logic (scan board, guard, read, decompose, write) legible instead of tangled with S3 SDK calls.

Source Code

Obsidian Plugins Used

  • Fancy Kanban  — renders the board.md markdown file as an interactive kanban board, and is what actually gets edited (moving a card = editing the file) to trigger the agent
  • ABC Music Notation  — renders and plays back the abc notation embedded in each generated lesson file, directly inside Obsidian
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article