---
title: "Academy hook bundle, auto-recipe lookup, session-start dashboard | Recipe — StudioMeyer Academy"
description: "Two hooks for the Academy MCP itself. UserPromptSubmit points the assistant at a matching recipe when you ask 'how do I X'. SessionStart shows XP, rank and next lesson without typing a command."
canonical: "https://studiomeyer.academy/en/recipes/16.5-academy-hook-bundle"
language: en
markdown_versions: ["https://studiomeyer.academy/en/recipes/16.5-academy-hook-bundle.md"]
publisher: "StudioMeyer Academy, https://studiomeyer.academy (llms.txt: https://studiomeyer.academy/llms.txt)"
---

[← Alle Recipes](https://studiomeyer.academy/recipes)

Phase 16 · Claude Code Hooks·6 steps

# Academy hook bundle, auto-recipe lookup, session-start dashboard

Two hooks for the Academy MCP itself. UserPromptSubmit points the assistant at a matching recipe when you ask 'how do I X'. SessionStart shows XP, rank and next lesson without typing a command.

6 steps0%

Du liest ohne Account. Mit [Login](https://studiomeyer.academy/login?next=/recipes/16.5-academy-hook-bundle) speichern wir Step-Fortschritt + Notes.

# Academy hook bundle, auto-recipe lookup, session-start dashboard

The Academy MCP comes in two shapes, and which one you run decides which hooks can work at all.

**As a library**: `npx -y mcp-academy` over stdio. The whole curriculum is baked into the package: lessons, playbooks, recipes, three languages, no account, no network. You get the **10 reading tools** plus the generic `search` and `fetch`. Nothing personal, because there is nobody to be personal about.

**As a course**: the hosted connector at `https://mcp.studiomeyer.academy/mcp`. Same reading tools, plus the **account tools**: `academy_stats`, `academy_next_lesson`, `academy_progress_complete`, `academy_quiz`, `academy_quiz_submit`, `academy_review`, `academy_review_grade`, `academy_certificates`, `academy_tutor`. Those need a login, because progress has to live somewhere.

Step 1 works either way. Step 2 and Step 4 need the account tools, so they need the connector.

## The `server` field is your own config key

Every `mcp_tool` hook below has a `"server"` field. That is **the name you gave the server in your own config**, not the npm package name. If you added it with

```bash
claude mcp add academy -s user -- npx -y mcp-academy
```

then your key is `academy` and the examples below work as written. If you called it `studiomeyer-academy`, every `"server": "academy"` has to say `"studiomeyer-academy"` instead. Get this wrong and the hook fails silently. No error, just nothing happening. Check yours with `claude mcp list`.

The same rule applies to the `matcher` in Step 4: `mcp__academy__academy_progress_complete` is `mcp__<your-key>__<tool-name>`.

### Step 1: UserPromptSubmit hook → auto-recipe lookup

When you ask "how do I publish to npm" or "recipe for OAuth setup" or "wie mache ich X", the Academy probably has a recipe for it. Nudge the assistant to go look:

```json
{
  "UserPromptSubmit": [
    {
      "hooks": [
        {
          "type": "command",
          "command": "~/.claude/hooks/academy-recipe-trigger.sh",
          "timeout": 3
        }
      ]
    }
  ]
}
```

Where `academy-recipe-trigger.sh`:

```bash
#!/usr/bin/env bash
input=$(cat)
prompt=$(echo "$input" | jq -r '.prompt // .user_prompt // ""')
# Trigger phrases (DE + EN) that indicate the user wants step-by-step guidance
if echo "$prompt" | grep -qiE 'how (do|to)|recipe for|wie mache ich|wie geht|step.by.step|schritt für schritt'; then
  echo '{"hookSpecificOutput":{"additionalContext":"User asked for how-to guidance. Call academy_search({query: \"<topic>\"}) to find matching material, then academy_recipes({phase: <n>}) to list recipes in that phase, then academy_recipe({slug}) for the full text of the best match."}}'
fi
```

Why inject context instead of calling a tool directly? Because the topic has to be pulled out of a free-text prompt, and bash regex is the wrong instrument for that. The injected sentence tells the assistant which tools to call and in what order; it does the extraction.

Note the tool names: `academy_search`, `academy_recipes` (list), `academy_recipe` (one, by slug). Recipes are English-only and take no `locale`: lessons and playbooks do.

### Step 2: SessionStart hook → dashboard injection

Requires the hosted connector and a login. Every session then starts knowing where you stand:

```json
{
  "SessionStart": [
    {
      "hooks": [
        {
          "type": "mcp_tool",
          "server": "academy",
          "tool": "academy_stats",
          "input": {},
          "timeout": 10,
          "statusMessage": "Academy: loading stats..."
        },
        {
          "type": "mcp_tool",
          "server": "academy",
          "tool": "academy_next_lesson",
          "input": { "locale": "en" },
          "timeout": 10,
          "statusMessage": "Academy: finding next lesson..."
        }
      ]
    }
  ]
}
```

Two parallel hooks, both pure reads. Result: every session you start, the assistant already knows your progress and what to suggest next, without you typing a command.

If you are running the stdio library instead, these two tools do not exist and both hooks fail silently. That is the single most common reason this recipe "does not work".

### Step 3: Privacy and idempotency notes

- **Idempotent.** `academy_stats` and `academy_next_lesson` are pure reads, as is `academy_search`.
- **Deterministic.** Same state, same answer.
- **Side-effect-free without a user trigger.** Nothing in Step 1 or 2 writes anything.
- **Where your data goes.** With the library, nowhere: the curriculum is local and there is no account. With the connector, your progress lives in your own Academy account on `studiomeyer.academy` and is not shown to anyone else.

### Step 4: Optional, quiz auto-trigger on lesson completion

When you mark a lesson complete, offer the quiz for it:

```json
{
  "PostToolUse": [
    {
      "matcher": "mcp__academy__academy_progress_complete",
      "hooks": [
        {
          "type": "mcp_tool",
          "server": "academy",
          "tool": "academy_quiz",
          "input": {
            "level": "${tool_input.level}",
            "lessonSlug": "${tool_input.slug}"
          },
          "timeout": 10,
          "statusMessage": "Academy: loading quiz..."
        }
      ]
    }
  ]
}
```

Watch the parameter names. `academy_progress_complete` takes `level` and `slug` (both required, plus optional `locale`). `academy_quiz` takes `lessonSlug`, camelCase, and a different name for the same thing. Passing `lesson_slug` gets you an empty quiz and no error.

The cascade is: lesson complete → quiz fetched → assistant presents it inline → you answer → it calls `academy_quiz_submit({slug, answers})`. No "and now check the quiz" prompt needed.

### Step 5: Verify the bundle works

```bash
# Edit settings.json with the SessionStart hooks above
claude
```

You should see both status messages flash on session start. The assistant's first response should reference your progress and a recommended lesson without you asking. Nothing happening at all usually means one of two things: wrong `server` key (Step 0), or you are on the stdio library where those tools do not exist.

```bash
# In the running session:
# "wie mache ich npm publish"
```

No status message here. `UserPromptSubmit` only injects context, it does not call a tool. But the answer should now point at a concrete Academy recipe.

### Step 6: Why these hooks and not others

Hooks are for what the assistant should do on its own. Everything that needs your input stays explicit: submitting a quiz answer, grading a review, asking the tutor a question. Wiring those to lifecycle events produces noise, not help.

If you live in the Academy, two more are defensible:

- `Stop` → `academy_review` to pull up what is due for review
- `SubagentStop` → `academy_tutor` for follow-up suggestions (needs `message` and `level`)

Both are taste, not necessity. Start with Step 1 and Step 2.

## Done

Five StudioMeyer MCPs (Memory, CRM, GEO, Crew, Academy) now have working hook bundles. Your session picks up context by itself instead of waiting for you to remember a tool name.

## Next: distribute these as plugins

The bundles can be packaged as Claude Code plugins on `studiomeyer-io/studiomeyer-marketplace`: one install, all hooks at once. That is recipe 9.6.

## Sources

- [Claude Code Hooks Reference](https://code.claude.com/docs/en/hooks)
- [Academy MCP, npm package](https://www.npmjs.com/package/mcp-academy)
- [studiomeyer.academy](https://studiomeyer.academy)

[← GEO + Crew hook bundles, auto-](https://studiomeyer.academy/recipes/16.4-geo-crew-hook-bundle) [Recipes-Index →](https://studiomeyer.academy/recipes)

Phase 16

mcp\_tool hooks, Memory/CRM/GEO/Crew/Academy hook bundles

[Alle Phasen →](https://studiomeyer.academy/recipes)

Concepts

[Hooks](https://studiomeyer.academy/concepts/hooks)

## Sitemap

Public pages of this site as Markdown: [sitemap](https://studiomeyer.academy/sitemap.md). Curated entry point: [llms.txt](https://studiomeyer.academy/llms.txt), full text: [llms-full.txt](https://studiomeyer.academy/llms-full.txt).
