Architecture

How the course-authoring pipeline coordinates specialist agents, enforces correctness, and produces verified course material.

The Stay Learning pipeline generates complete, pedagogically sound courses by orchestrating specialist AI agents through a strict sequence of stages. Each agent reads and writes structured files on disk, and a mechanical validator enforces correctness after every edit.

This page explains the architecture: how stages connect, why state lives in files, and what keeps the output consistent even when agents are non-deterministic.

The Big Picture

flowchart TD
    U[User Request] --> O[Orchestrator]
    O --> A[Audience Analysis]
    A --> C[Curriculum Design]
    C --> L[Learning Outcomes]
    L --> AS[Assessment Design]
    AS --> LP[Lesson Planning]
    LP --> W{All plans current?}
    W -->|yes| LC[Lesson Content]
    W -->|yes| EX[Exercises]
    W -->|yes| QZ[Quizzes]
    W -->|yes| CP[Capstone Project]
    LC --> V[Validator]
    EX --> V
    QZ --> V
    CP --> V
    V --> WEB[Web Viewer]

    subgraph "Exclusive Stages (sequential)"
        A
        C
        L
        AS
        LP
    end

    subgraph "Wave Stage (parallel)"
        LC
        EX
        QZ
        CP
    end

The orchestrator is the only user-invocable agent. It determines which stage to run next, invokes the responsible subagent, and gates progression on artefact status.

Pipeline Stages

Exclusive stages (sequential)

These five stages run one at a time, in order. Each produces a YAML artefact that the next stage depends on.

#StageOutputKey decisions
1Audience Analysisaudience.yamlLearner profile: experience level, motivation, prerequisites, anticipated misconceptions
2Curriculum Designcurriculum.yamlModule/lesson structure, sequencing rationale, dependency graph, cognitive load estimates, pacing
3Learning Outcomesoutcomes.yaml3–5 measurable outcomes per lesson, each tagged with a Bloom taxonomy level
4Assessment Designassessment.yamlDiagnostics, formatives, checkpoints, summatives — each mapped back to specific outcomes
5Lesson Planning*.plan.yamlSection-by-section structure for each lesson (introduction, motivation, theory, worked example, guided practice, summary)

No stage can begin until its upstream artefact has status current. If you change the audience profile, everything downstream becomes stale and must be regenerated from that point forward.

Wave stage (parallel)

Once every lesson plan reaches current, four agents run simultaneously:

  • Lesson Content — Full Markdown prose following the plan’s section structure. Each lesson produces a standalone .md file.
  • Exercises — One standalone practice task per outcome at Bloom level apply or above. Exercises live beside the lesson they belong to.
  • Quizzes — One knowledge-check item per outcome. Multiple-choice or short-answer, verifiable against the outcome’s verb.
  • Capstone Project — A project brief, milestones, and rubric mapped to module-level skills. One per course.

Wave agents share no mutable state with each other. They all read the same plans and outcomes, and they each write to non-overlapping file paths. This is what makes parallelism safe.

State as Files on Disk

Every piece of course state is a file under courses/<slug>/:

courses/intro-to-containers/
├── course.yaml          # manifest + status map
├── audience.yaml
├── curriculum.yaml
├── outcomes.yaml
├── assessment.yaml
├── project.yaml
├── glossary.yaml
└── modules/
    └── m01-container-foundations/
        ├── m01-l01.plan.yaml
        ├── m01-l01.md
        ├── m01-l01.exercises.yaml
        └── m01-l01.quiz.yaml

This gives you:

  • Diffability — Every artefact change shows up in git diff. You can review what the assessment agent wrote, revert it, or compare runs.
  • Versionability — Branch per course, or branch per experimental run. Standard Git workflows apply.
  • Regenerability — Any file can be deleted and regenerated from its upstream artefacts. There is no hidden state in a database or API.

The single state contract

A shared course-state skill defines the YAML schema, the ID format (m01, m01-l01, m01-l01-o1), and the write procedure. Every agent loads this skill before reading or writing any course file. This prevents schema drift between agents that were authored months apart.

Key Architectural Decisions

Idempotency

Every agent writes whole files, never appends. If you re-run the curriculum designer, it overwrites curriculum.yaml completely. This means:

  • No accumulation of partial state from interrupted runs
  • The output is always a function of the inputs, not of the run history
  • You can safely retry any failed stage

Stage gates and status propagation

Each artefact carries a status: missing, stale, or current. The rules are simple:

  1. An agent refuses to run if its upstream artefact is missing.
  2. An agent warns if its upstream artefact is stale (but the orchestrator won’t normally invoke it in that state).
  3. Writing any artefact marks every downstream artefact stale.

This creates a directed acyclic graph of dependencies. Change one thing at the top, and the system knows exactly what must be regenerated.

Provider-agnostic design

No agent file contains a model: field. The pipeline works with whatever LLM backend your VS Code Copilot configuration points at — GPT-4o, Claude, Gemini, or a local model. Pinning a vendor string in one agent would break portability for every user with a different subscription.

That is a portability decision, not a claim that every model performs equally. In practice we recommend running with Claude Opus 5. Each stage agent has to absorb a detailed contract — a schema, a set of instruction files, the artefacts written by earlier stages — and then emit a complete, valid artefact in a single pass. Weaker models trip the validator more often, and a blocked write costs a retry. The recommendation lives in the documentation, where a user can override it, rather than in the agent files, where they could not.

No shell access for agents

Agents cannot execute arbitrary commands. The Python validator reaches the shell through a PostToolUse hook that triggers automatically after file edits — not through a tool the agent can invoke. This means an agent cannot bypass validation, and a prompt injection in course content cannot escalate to code execution.

Mechanical Verification

A Python script (validate.py) runs automatically after every file edit via the PostToolUse hook. It checks:

CategoryWhat it verifies
StructuralID uniqueness, cross-reference integrity, required fields present
PedagogicalOutcome-to-plan coverage (every outcome appears in a plan section), Bloom verb correctness
Cognitive loadTerm introduction counts per section, concept density heuristics
AssessmentLevel ceilings (a formative can’t test above its lesson’s highest outcome), rubric vagueness detection
Prose qualityBanned patterns (marketing speak, unresolved TODOs), diagram node limits

Results have two severities:

  • FAIL — Blocks the run. The agent must fix the issue before proceeding.
  • WARN — Marks a transient state that is valid mid-write (e.g., a plan referencing an outcome that hasn’t been written yet in the current turn) but would be invalid once the run stops.

Running with --strict promotes all warnings to failures. Use this in CI or after a run you believe is complete.

The Web Viewer

A separate Astro application in web/ reads the courses/ directory and renders it as a browsable learning experience. It provides:

  • Course listing and progress tracking (client-side storage)
  • Lesson content rendering with syntax highlighting
  • Interactive quizzes with immediate feedback
  • Exercise presentation with Bloom-level badges

The viewer is read-only — it never writes to course files. If something renders incorrectly, the fix belongs in the course artefact or the viewer’s TypeScript, never in a manual edit to course content (which would be silently overwritten on the next agent run).

How It Fits Together

The architecture optimises for three properties:

  1. Correctness — Mechanical validation catches errors that LLMs reliably make (wrong Bloom verbs, dangling references, vague rubric criteria). The validator doesn’t trust the agent; it verifies.

  2. Reproducibility — File-based state, whole-file writes, and no hidden dependencies mean you can delete any artefact and regenerate it deterministically from its inputs.

  3. Composability — Each agent is a single Markdown file (.agent.md) with a role description and tool restrictions. Adding a new stage means writing one file and updating the orchestrator’s stage list.

The pipeline is not a monolithic application. It is a coordination protocol — a set of contracts about file layout, status propagation, and validation — that turns a collection of independent agents into a reliable production system.