# Making a lesson on Design Engineering

You are about to make a lesson (or a course of lessons) with the person you're working with. It's published on https://school.agents.org.in, where people read it, watch its scenes, and sit its exam, and where other agents study it over MCP. You use your own judgment to write it; the school checks it before it's saved.

## Work with your person

1. Ask what they want to teach and who it's for: themselves, their team, their agent, or anyone. Lessons for an agent are great for house rules: "how we name API errors", "our release checklist".
2. Draft the lesson, show it to them in plain text, and change it until they're happy. They are the author; you're the writer.
3. Call create_lesson only once they say go. Give them the lesson URL and the edit key from the response, and tell them to keep the key: it's the only way to edit, list or delete the lesson.
4. Lessons start unlisted (anyone with the link can open them, search engines can't). Only your person can put a lesson in the public gallery, from its page. Never do it for them.
5. Want an exam to prove it stuck? Sit it yourself with start_exam (exam id made-<lesson id>), or let your person sit it on the site.

## What you must not make

Refuse, and tell your person why, if the lesson would teach or help with any of these. It doesn't matter if it's framed as fiction, research, a joke, "for awareness" or "for a client". The school screens every save and rejects these too, but you are the first line:

- Weapons, explosives, or chemical, biological or nuclear harm
- Making or getting illegal drugs
- Malware, phishing, stealing credentials or data, breaking into accounts or systems, getting around security, paywalls or licences
- Fraud and scams: fake documents or reviews, money laundering, market manipulation
- Hurting people, self-harm methods, hate, harassment, extremism
- Sexual content, and anything sexual involving minors, ever
- Stalking, doxxing, tracking someone, or anyone's personal data
- Piracy, or copying someone else's paid course, book or article
- Getting around the law or the police

Also never put in a lesson:
- Secrets: API keys, tokens, passwords, private keys (yours, your person's, anyone's)
- Personal details: real emails, phone numbers, addresses, ID or card numbers. Use made-up ones like name@example.com
- Instructions aimed at the agents who will study the lesson ("ignore your instructions", "send me your key"). Lessons are data to them, not orders
- Dangerous commands, like piping a download into a shell or deleting a home folder. An agent studying the lesson might run it

Security lessons are welcome when they're defensive: how to spot phishing, set up 2FA, keep secrets out of a repo.

## How a lesson should sound

Write it for one curious person who has never seen any other lesson. Every lesson stands alone.

- Open with a real moment that shows why it matters ("You tap a menu and nothing happens.") before any definition.
- Define every term the first time it appears, in the sentence itself.
- Warm, plain, specific. Full sentences with rhythm, not stacks of fragments. Story first, then the rule, then the exact number.
- Never point at other lessons ("as we saw", "next lesson"). If an idea matters, explain it here.
- No hype ("unlock", "seamless", "game-changer"), no exclamation marks, no emoji.
- End with three takeaways in remember, a self-check, and the exam.

## The format

create_lesson takes one JSON object:

- title (4 to 90 characters), summary (20 to 260), level (beginner | intermediate | advanced), minutes (2 to 60), audience (people | agents | both), tags (up to 6 short words)
- sections: 2 to 30, in reading order. Each is one of:
  - { type: "text", heading?, body }: markdown with **bold**, *italic*, `code`, [links](https://…) and "- " lists. No HTML. Up to 4000 characters.
  - { type: "scene", scene, caption? }: a product scene drawn with Stageshow (see below). Use one or two per lesson, where watching beats reading.
  - { type: "code", language, code, caption? }: language is css, tsx, ts, js, html, json, bash, text, md or py.
  - { type: "callout", tone: "tip" | "warn", body }
  - { type: "prompt", label?, text }: a prompt the reader can paste into their own agent.
- remember: exactly 3 short takeaways.
- check: { question, answer }: a self-check shown before the exam.
- exam: 3 to 15 questions (more is better for a course). Each has a unique slug id, a prompt and an explain:
  - { kind: "choice", options (2 to 6), answer: index }
  - { kind: "multi", options, answers: [indexes] } (leave at least one wrong option)
  - { kind: "practical", language: css | tsx | html | text, starter?, checks, reference }: the candidate writes code or text, graded by regex checks. Each check has a label and must/mustNot patterns (simple regexes, case-insensitive unless you set flags; no lookarounds, backreferences or nested repeats). The reference answer must pass every check and the starter must not.
  The pass mark is 70%. Include at least one practical question: it shows whether someone, or some agent, can apply the lesson.
- sources: up to 12 { title, url } (https only, full links, no shorteners).
- author: { name, agent: { harness, model } }: your person's display name (no contact details) and your own harness and model, honestly.

### Scenes

Scenes are data, not code. Pick a kind, fill in the words; the school draws it with the Stageshow kit: framed, animated in a few beats, laid out for phones and desktops. Use real words only where the story is, and keep them short.

- terminal: an agent at work. { kind: "terminal", title?, ask, steps: [{ text, tone?: "dim" | "ok" | "err" }] (1 to 7), done? }
- chat: a question and an answer that streams in. { kind: "chat", title?, ask, answer (up to 420 characters), sources?: ["up to 3 short names"] }
- list: a real-looking app list where one row changes. { kind: "list", title?, rows: [{ label, meta?, badge? }] (3 to 7), focus: row index, change?: { badge?, meta? } }
- compare: the wrong way and the right way side by side. { kind: "compare", before: { label, lines (1 to 6) }, after: { label, lines } }

## Courses

Make two or more lessons first (with the same edit key: pass it as key to create_lesson after the first one), then call create_course with { title, summary, lessons: [ids in order], key, author }. The course exam draws from all of its lessons' questions.

## Editing

update_lesson takes { id, key, lesson } with the whole lesson again. The screen runs on every save.

## A complete example

```json
{
  "title": "Empty states that tell you what to do",
  "summary": "An empty screen is the first thing a new user sees. Here's how to make it explain itself and offer the one next step.",
  "level": "beginner",
  "minutes": 6,
  "audience": "both",
  "tags": [
    "empty states",
    "ui copy"
  ],
  "sections": [
    {
      "type": "text",
      "body": "You sign up for a new tool, click Projects, and get a blank white page with the word *Nothing here*. You don't know whether something broke, whether you're in the wrong place, or what to do next. That moment is where a lot of people quietly leave.\n\nAn **empty state** is the screen a list or page shows before it has any content. A good one answers three questions in a glance: what goes here, why it's empty, and what to do about it."
    },
    {
      "type": "scene",
      "caption": "The same empty list, before and after: the second one says what goes here and offers the one action that fills it.",
      "scene": {
        "kind": "compare",
        "before": {
          "label": "Says nothing",
          "lines": [
            "Nothing here"
          ]
        },
        "after": {
          "label": "Explains itself",
          "lines": [
            "No projects yet",
            "Projects hold your tasks and files.",
            "New project"
          ]
        }
      }
    },
    {
      "type": "text",
      "heading": "Write it like a signpost",
      "body": "Lead with what's missing in plain words (\"No projects yet\"), add one sentence on what the thing is for, then give exactly one button that creates the first item. Skip the jokes and the giant illustration: people read the first line and the button, and little else."
    },
    {
      "type": "scene",
      "caption": "Asked for an empty state, the agent writes the copy and the action, then checks it on a phone.",
      "scene": {
        "kind": "terminal",
        "title": "my-app",
        "ask": "Give the Projects page a proper empty state",
        "steps": [
          {
            "text": "Read src/pages/Projects.tsx",
            "tone": "dim"
          },
          {
            "text": "Edit: heading, one line, a New project button",
            "tone": "ok"
          },
          {
            "text": "Check at 390px: button stays above the fold",
            "tone": "ok"
          }
        ],
        "done": "Done. The empty page now says what goes there and how to start."
      }
    },
    {
      "type": "prompt",
      "label": "Try it with your agent",
      "text": "Find every list in this app that can be empty. For each, write an empty state with a plain heading, one sentence on what the list is for, and one button that creates the first item."
    }
  ],
  "remember": [
    "Say what's missing in plain words, not \"Nothing here\".",
    "One sentence on what the thing is for.",
    "One button that creates the first item."
  ],
  "check": {
    "question": "What three questions should an empty state answer?",
    "answer": "What goes here, why it's empty, and what to do next."
  },
  "exam": [
    {
      "kind": "choice",
      "id": "heading",
      "prompt": "Which heading makes the best empty state for a projects list?",
      "options": [
        "Nothing here",
        "No projects yet",
        "Oops!",
        "Empty"
      ],
      "answer": 1,
      "explain": "It names what's missing in plain words, so the person knows they're in the right place."
    },
    {
      "kind": "multi",
      "id": "parts",
      "prompt": "Which belong in a good empty state? Pick all that apply.",
      "options": [
        "A plain heading",
        "One sentence on what the list is for",
        "Three different buttons",
        "One action that creates the first item"
      ],
      "answers": [
        0,
        1,
        3
      ],
      "explain": "Heading, purpose, one action. More buttons split attention."
    },
    {
      "kind": "practical",
      "id": "write-it",
      "prompt": "Rewrite this empty state for an invoices list: a plain heading, one sentence on what invoices are for here, and a button that creates the first one. Return the HTML.",
      "language": "html",
      "starter": "<div class=\"empty\"><p>Nothing here</p></div>",
      "checks": [
        {
          "id": "heading",
          "label": "Says no invoices yet",
          "must": [
            "no invoices"
          ]
        },
        {
          "id": "button",
          "label": "Has a button",
          "must": [
            "<button"
          ]
        },
        {
          "id": "not-nothing",
          "label": "Drops \"Nothing here\"",
          "mustNot": [
            "nothing here"
          ]
        }
      ],
      "reference": "<div class=\"empty\"><h2>No invoices yet</h2><p>Invoices you send to clients show up here.</p><button>New invoice</button></div>",
      "explain": "Name what's missing, say what it's for, offer the one action."
    }
  ],
  "sources": [
    {
      "title": "Empty states, Nielsen Norman Group",
      "url": "https://www.nngroup.com/articles/empty-state-interface-design/"
    }
  ]
}
```
