Vibe coding with AI course Β· Module 15: Claude Code CLI
Hooks, Headless Mode, and the Complete Vibecoding Workflow
In this lesson6
The last treasure chest! In this lesson you meet hooks, the headless mode built for automation, and then tie everything together into one complete vibecoding workflow with Claude Code. After this exercise you are a fully fledged AI captain.
Hooks - automatic actions
So far every action started with you: you typed a prompt, Claude answered, you looked at the diff. Hooks turn that around. Hooks are shell commands that run automatically on specific events in Claude Code - for example right after a file edit. Picture a crew so well drilled that one whistle sends every sailor to their station: Claude changes something, and the hook does its job without being told twice.
It is worth saying what a hook is not, because the name is overloaded. It is not a special command for logging in - signing in is /login, and OAuth has nothing to do with hooks. It is not a binary file holding the Claude model weights either, since the model never lives inside your repository. And despite sharing a name with React hooks, it is not a user-interface component: a hook renders nothing at all, it only runs a shell command in your terminal.
The events hooks react to
When Claude uses a tool in a new session, the events fire in this order (PreToolUse and PostToolUse repeat for every tool use, and Stop comes after every response):
SessionStart- at the very beginning of the sessionPreToolUse- before Claude uses a toolPostToolUse- after a tool has been used (for example after a file edit)Stop- when Claude finishes its response
Keep that sequence in your head: the session opens, a tool is about to run, the tool has run, and only then does Claude stop talking. Every hook you ever write hangs off one of those four moments.
Where do you configure them?
Hooks usually live in your project's .claude/settings.json (they can also go in ~/.claude/settings.json or .claude/settings.local.json). There is no .claude/hooks.yaml, that file simply does not exist, and you never touch package-lock.json, which npm generates for you and which knows nothing about Claude Code. Here is a hook that runs prettier every time a file is created or edited, so your code is always formatted. This is what goes into .claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write ."
}
]
}
]
}
}Read it from the outside in: PostToolUse is the moment, matcher decides which tools it applies to (here Edit|Write, where | means "or"), and command is the shell line that actually runs. Swap the matcher and the very same shape works for any other tool - nothing else about the file changes.
A hook can just as easily block edits to protected paths or fire your test suite after every change. That is your automatic first mate, keeping the deck in order while you steer.
Headless mode and CI/CD
Headless mode is Claude Code running without an interactive session - exactly what you want inside scripts and pipelines. Its heart is the -p flag, which means "one prompt, one answer, then exit", paired with --output-format json so the reply comes back as structured data instead of prose:
# Headless: the answer comes back as structured JSON
claude -p "List functions from @src/utils.ts" \
--output-format jsonThe prompt and --output-format json may swap places; here the prompt follows -p and --output-format json comes last. A result shaped like that is trivial to parse in a script, and combined with the ready-made GitHub Actions integration it lets you build fully automatic processes - pull request reviews, generated changes, nightly reports.
Editor integrations
Claude Code does not only live in the terminal:
- VS Code - official extension
- JetBrains - official extension
- Desktop and web - claude.ai/code
So you can use the power of the agentic CLI without ever leaving your favourite environment.
The complete vibecoding workflow with Claude Code
Let us now join everything you have learned in this module into one smooth process.
Step 1: Prepare the project
Every voyage starts with a chart. Open a claude session in your project and run the built-in command that reads the codebase and writes its memory file for you:
# In a claude session, generate the project memory
/initOut of this comes CLAUDE.md - the ship's logbook that Claude loads at the start of every later session. Write your conventions down once, and you never explain them again.
Step 2: Describe the feature (plan mode for big changes)
For a small fix you can prompt straight away, but a larger feature deserves a plan first. Launch Claude in plan mode so it is allowed to explore and think, but not yet to edit:
claude --permission-mode plan "Add a comment system to posts"Claude explores the project, reads the files that matter and comes back with a plan instead of a diff. You read it, correct whatever looks wrong, and accept it - not a single file is touched before you do.
Step 3: Claude implements
Now the crew goes to work. Claude reads and edits the files on its own and runs the tests after each change. Your job is to watch the deck, answer the questions it asks and steer it back on course when it drifts - which is precisely what vibecoding means.
Step 4: Review and iterate
Never commit blind. Before the changes go into history, hand the whole diff to Claude in headless mode and ask for a review:
# Review the changes before committing
git diff | claude -p "Review these changes before I commit"The pipe feeds your entire diff in as context, and -p keeps it to a single question with a single answer - no session, no ceremony. Fix whatever the review flags, then run the cycle again until the diff is clean.
Step 5: Level up with advanced features
- Hooks - add automatic formatting (prettier after every edit)
- Subagents - delegate the review to
code-reviewer(.claude/agents/) - MCP - connect your own tools, such as GitHub or Sentry (
/mcp) - Skills - package repeatable workflows into
/<skill-name>
The whole Claude Code map - cheat sheet
| Element | How to use it |
|---|---|
| Install | curl -fsSL https://claude.ai/install.sh | bash or npm install -g @anthropic-ai/claude-code |
| Start | claude (interactive) or claude -p "..." (script) |
| Files | @file in the prompt, or cat file | claude -p "..." |
| Model | /model or --model sonnet |
| Memory | CLAUDE.md (generate it with /init) |
| Planning | Shift+Tab, /plan or --permission-mode plan |
| Subagents | .claude/agents/<name>.md |
| Skills | /<skill-name> |
| MCP | claude mcp add, the /mcp command |
| Hooks | .claude/settings.json |
| Context | /clear, /compact, /context, /usage |
Pin that table above your desk - every row is one thing you can do today.
Final summary
Congratulations! You have completed the whole Vibecoding course and mastered Claude Code!
In this module you learned the REAL Claude Code:
Fundamentals - install, /login, interactive mode versus -p, models
Files and pipes - references with @, chaining commands (git diff | claude -p)
Slash commands - /help, /clear, /compact, /init, /code-review, /usage
CLAUDE.md - the project memory generated by /init
Plan Mode - planning before editing (Shift+Tab, /plan, --permission-mode plan)
Subagents - delegating work (.claude/agents/)
Skills and MCP - repeatable workflows and connected tools (/mcp)
Hooks - automatic actions on events (.claude/settings.json)
Headless/CI - claude -p --output-format json plus GitHub Actions
You are ready now to build professional applications with agentic AI right in your terminal!
Fair winds - sail on and discover new lands of code!
Code for this lesson: .mcp.json
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": {
"Authorization": "Bearer ${GITHUB_PAT}"
}
},
"sentry": {
"type": "http",
"url": "https://mcp.sentry.dev/mcp"
}
}
}Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What are hooks in Claude Code?
2. In which file do you define Claude Code hooks?
Hands-on tasks in the game
- Horizontal ordering
Arrange the headless-mode command that returns the answer as JSON:
- Vertical ordering
Put the hook events in the order they occur while using a tool in a session: