My Claude Code setup: the complete guide
How I configured Claude Code to be genuinely autonomous, MCPs, hooks, subagents, GitHub PR reviews, Discord notifications, and the community resources that leveled everything up.

Why I went all-in on this
I spend a number of hours every single day inside the Claude Code CLI . That depth of usage will teach you things no blog post can. You find the edges. You figure out what default settings get wrong. You build opinions.
This isn't a "getting started" guide. There are plenty of those. This is the actual setup I run, the decisions I made, the community resources that changed how I think about it, and the things you won't find in the official docs because they only emerge from real daily use.
Stack context: I work primarily in TypeScript/Node.js and Python, run Claude Code locally on a Windows machine (not in Docker, not on a VPS), and pipe notifications to Discord. Your mileage will vary on some of the specifics, but the architecture applies everywhere.
The single most important insight: the difference between advisory and deterministic. CLAUDE.md is advisory, Claude follows it ~80% of the time. Hooks are deterministic, they fire 100% of the time. Structure your setup accordingly.
CLAUDE.md, Claude's onboarding document
CLAUDE.md is loaded into Claude's system context every session — think of it as the onboarding document for an AI engineer joining your team. The problem is that people treat it like a config dump. They throw in every rule they can think of, and wonder why Claude ignores half of them.
Claude Code's system prompt already consumes ~50 of the ~150-200 instructions frontier models can reliably follow. Every line in your CLAUDE.md competes for that budget. The constraint is real. Less is more.
The file hierarchy
| Location | Purpose |
|---|---|
| ~/.claude/CLAUDE.md | Global personal preferences |
| CLAUDE.md (project root) | Project-wide instructions |
| .claude/CLAUDE.md | User-specific project overrides |
| subdirectory/CLAUDE.md | Loaded when working in that dir |
| .claude/rules/*.md | Path-scoped modular rules |
What actually belongs in it
The highest-value content, in order: build/test/run commands (Claude must be able to verify its own work), project architecture (where things live), what to avoid (explicit no-list), and conventions (naming, patterns). Ask for every line: "Would Claude make a mistake without this?" If the answer is no, cut it.
# Project: MyApp
## Commands
- `pnpm run dev`, dev server on port 3000
- `pnpm test`, Vitest unit tests
- `pnpm run build`, production build
- `pnpm run lint`, ESLint + Prettier check
## Architecture
- `server/`, Fastify API server, WebSocket, streaming
- `web/`, React 19 + Vite + TypeScript frontend
- `shared/`, shared types and utilities
- `server/db/`, SQLite via better-sqlite3
## Conventions
- TypeScript strict mode; no `any` use `unknown` and narrow
- Named exports only, no default exports
- Use conventional commits (feat:, fix:, refactor:, etc.)
- State management via Zustand + Immer
## Avoid
- No barrel files (index.ts re-exports)
- No relative imports crossing package boundaries
- No direct DB queries outside `server/db/`Keep the root file under 80–150 lines. If it grows past that, split into .claude/rules/ with paths: frontmatter, or use subdirectory CLAUDE.md files. Don't auto-generate via /init without heavy editing, the output is bloated.
MCP servers that actually matter
MCP (Model Context Protocol) servers extend Claude with new tools, GitHub operations, web search, database access, browser automation. Every server adds tool definitions to the context window, so unused servers waste budget on every single message. Be selective.
My core stack: GitHub for repo ops, Memory for cross-session persistence, Context7 for up-to-date library docs, and Sequential Thinking for complex architectural decisions. Everything else is project-specific.
| Server | Package | My verdict |
|---|---|---|
| GitHub | @modelcontextprotocol/server-github | Essential. PRs, issues, branches, repos all in context |
| Memory | @modelcontextprotocol/server-memory | Essential. Knowledge graph that persists across sessions |
| Context7 | @upstash/context7-mcp | Essential. Current library docs without hallucinated APIs |
| Sequential Thinking | @modelcontextprotocol/server-sequential-thinking | Use for architecture decisions, not routine tasks |
| Playwright | @playwright/mcp | When you need Claude to drive a browser |
| PostgreSQL | @modelcontextprotocol/server-postgres | Project-specific. DB queries and schema inspection |
| Brave Search | @brave/brave-search-mcp-server | Good web search fallback when offline knowledge isn't enough |
| Exa | exa-mcp-server | Better than Brave for research-heavy sessions |
| Task Master | task-master-ai | PRD > structured task plans. Solid for greenfield projects |
Environment variable expansion ($${VAR}) works in .mcp.json , never hardcode tokens. Use npx -y for Node.js servers and uvx for Python ones. For Context7 and Tavily, remote MCP endpoints skip local installation entirely:
claude mcp add --transport http context7 https://mcp.context7.com/mcp
claude mcp add --transport http tavily "https://mcp.tavily.com/mcp/?tavilyApiKey=KEY"Hooks, the thing Claude can't ignore
This is the section that changes how you think about the whole system. CLAUDE.md gives Claude suggestions. Hooks run shell commands at lifecycle events, before and after tool use, on session stop, when Claude sends notifications. They don't ask permission. They always fire.
I use hooks for: auto-formatting every file Claude writes, blocking destructive commands, running tests after sessions, and sending Discord notifications when sessions complete.
This article by Anthropic (Claude) explains really well what hooks exist and how you can make implementations.
Subagents and git worktrees
Claude Code's Agent tool spawns independent Claude instances with their own fresh context windows. Each subagent starts clean, the only data channel is the prompt string. Up to 10 can run concurrently. This is the thing that makes Claude Code feel genuinely different from every other AI coding tool.
I use subagents for: research tasks (keep main context clean), test verification (separate context = independent judgment), and domain-parallel work (frontend, backend, database all running simultaneously).
---
name: code-reviewer
description: Code reviewer. Use PROACTIVELY when reviewing PRs or validating implementations.
model: sonnet
tools: Read, Grep, Glob
---
You are a code reviewer. When reviewing:
- Flag bugs, not just style issues
- Suggest specific fixes, not vague improvements
- Check for edge cases and error handling gaps
- Verify test coverage for changed code paths
- Never suggest suppressing errors with // @ts-ignore or # type: ignoreThis is a minimal example to illustrate the structure, for production-ready agents, the community has built far better ones. The shanraisshan/claude-code-best-practice repo and the anthropics/skills repository are the best places to start.
One important caveat when building your own agents and skills: be careful with persona prompting. A recent study found that instructing frontier models to behave as if they are an expert, "You are now an expert in X...", actually decreases performance compared to simply asking the question directly. The confident framing doesn't add capability; it just adds noise. Describe the task and context clearly instead of dressing Claude up in a costume.
If you do not use Claude Code with a Pro/Max subscription, this is a big cost saver. Save CLAUDE_CODE_SUBAGENT_MODEL=haiku in your settings to run subagents on the cheapest model, sufficient for exploration and test-running, around 80% cheaper than Sonnet. I personally have a Pro/Max subscription so I personally do not have this set.
# Built-in worktree support (v2.1.50+)
claude --worktree feature-auth # creates isolated branch + dir
claude --worktree bugfix-123 # another parallel session
claude -w # auto-generate worktree name
# Run three agents in parallel
git worktree add ../proj-auth -b feature/auth
git worktree add ../proj-api -b feature/api
git worktree add ../proj-db -b feature/db
# Each gets its own Claude session + branchTwo keywords worth memorizing: add ultrathink to any prompt to unlock Claude's full reasoning budget, save it for complex architectural decisions, not routine tasks. When a problem needs more compute, tell Claude to "use subagents", it offloads the work to parallel agents and keeps your main context clean.
Commands and skills
Slash commands are saved prompts stored as Markdown files. If you do something more than once a day, it should be a command. They live in .claude/commands/ (project-scoped, invoked as /project:name) or ~/.claude/commands/ (global).
Skills are the evolved form, they support autonomous invocation by Claude, bundled scripts, and work across Claude Code, Claude.ai, and Claude Desktop. Think of commands as shortcuts and skills as capabilities.
These are some examples that already exist and/or could make yourself:
| Concept | Explanation |
|---|---|
| /commit | Stage + write conventional commit message from diff |
| /pr | Create PR with auto-generated description from commits |
| /review | Self-review diff before pushing — harsh and specific |
| /test | Run only tests relevant to recently changed files |
| /fix | Fix all lint + type errors, re-verify zero remain |
| /compact | Summarize context at logical breakpoints |
Here is an example of what one of these commands might look like:
---
allowed-tools: Bash(git diff:*), Bash(git status:*), Bash(git add:*), Bash(git commit:*)
description: Stage and commit with a conventional commit message
---
## Context
!`git status --short`
!`git diff --cached`
## Task
Write a conventional commit (feat/fix/refactor/docs/chore).
Subject under 72 chars. Body only for non-trivial changes.
Run: git commit -m "<message>"
If nothing staged, run git add -u first.Automatic PR reviews with claude-code-action
Anthropic maintains anthropics/claude-code-action@v1, a GitHub Action that runs Claude on your runner to review PRs, answer questions, and respond to @claude mentions. Setup is one command:
/install-github-app
This installs the Claude GitHub App, creates a workflow PR, and prompts you to add ANTHROPIC_API_KEY as a repository secret. After merging, tag @claude in any PR comment to get a response.
Restrict tools with --allowedTools in review-only workflows, you don't want Claude writing code or accessing secrets during automated PR reviews. Use a separate "implementation" workflow for that.
Discord notifications via webhooks
Discord has native GitHub webhook support, no bot required for basic notifications. But I also wire up Claude Code's Stop hook directly to Discord so I know when a long session finishes.
GitHub to Discord (2 minutes)
- Discord > Server Settings > Integrations > Webhooks > Create Webhook > copy the URL.
- GitHub repo > Settings > Webhooks > Add webhook > paste URL with
/githubappended. Set content type toapplication/json. The/githubsuffix is critical.
The URL format that makes native GitHub embeds work:https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN/github
Claude Code session to Discord
#!/bin/bash
INPUT=$(cat)
PROJECT=$(basename "$(echo "$INPUT" | jq -r '.cwd')")
SESSION=$(echo "$INPUT" | jq -r '.session_id' | cut -c1-8)
WEBHOOK="https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN"
curl -s -H "Content-Type: application/json" -d "{
\"embeds\": [{
\"title\": \"Claude Code session complete\",
\"color\": 5763719,
\"fields\": [
{\"name\": \"Project\", \"value\": \"$PROJECT\", \"inline\": true},
{\"name\": \"Session\", \"value\": \"$SESSION\", \"inline\": true}
],
\"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"
}]
}" "$WEBHOOK" > /dev/nullMake executablechmod +x ~/.claude/hooks/discord-notify.sh
GitHub Actions CI to Discord
- name: Notify Discord
if: always()
run: |
STATUS="${{ job.status }}"
COLOR=$( [ "$STATUS" = "success" ] && echo 5763719 || echo 15548997 )
curl -H "Content-Type: application/json" -d "{
\"embeds\": [{
\"title\": \"${{ github.workflow }} — $STATUS\",
\"url\": \"https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\",
\"color\": $COLOR
}]
}" "${{ secrets.DISCORD_WEBHOOK_URL }}"New in 2026, the features changing the workflow
Claude Code has been shipping at an almost reckless pace since January 2026, v2.1.63 through v2.1.83 in a single month. Most of these features are genuinely novel and some aren't in the official docs yet. Here's what actually matters.
/btw
The most immediately useful command they've shipped in months. /btw spawns an ephemeral agent that reads your full conversation history but runs without tools and without writing anything back to the main chat. Ask a question, get an answer, close the overlay. The main session keeps running. The token cost is near-zero because it reuses the prompt cache.
# While Claude is mid-refactor, ask without derailing it:
/btw what does the calculate_metrics function return?
/btw is there a utils helper for date formatting already?
/btw which branch has the latest auth changes?
# The key distinction:
# /btw > asks about what Claude already knows from this session
# subagent goes to find out something new (has tools, fresh context)/dream
Auto Memory launched in February, Claude takes its own notes as you work (build commands, debugging patterns, architecture decisions, preferences), stored in MEMORY.md. It's genuinely useful. The problem is it degrades over time. After 20+ sessions, contradictions pile up, relative timestamps like "yesterday" lose meaning, stale debugging notes reference deleted files. The notebook becomes noise.
Auto-Dream is the fix. It runs a background subagent that does a "reflective pass" over your memory files, the system prompt literally says "You are performing a dream." The metaphor maps directly onto how REM sleep consolidates short-term memory into long-term storage, and it's not just aesthetic: the mechanism is backed by UC Berkeley's "Sleep-time Compute" paper (arXiv:2504.13171) which found pre-computing during idle time reduces test-time compute by 5x.
# Check if Auto-Dream is active on your instance:
/memory
# Look for: Auto-dream: on (or off — still staging)
# If not rolled out yet, trigger manually:
"dream" # natural language works
"consolidate my memory files" # also recognized
"auto dream"
# Disable Auto Memory if you want manual control:
# Set "autoMemoryEnabled": false in settings.json
# Then trigger /dream yourself after big refactorsThe four memory layers now are: CLAUDE.md (instructions you write) + Auto Memory (notes Claude writes) + Session Memory (conversation continuity) + Auto-Dream (periodic consolidation). Running all four is the full cognitive stack. One early report consolidated 913 sessions in under 9 minutes.
/loop
Schedule any prompt to fire on a recurring interval. Session-scoped (dies when you exit), auto-expires after 3 days as a safety valve. Think of it as in-terminal cron, perfect for polling deployments, babysitting PRs, and monitoring builds while you focus on something else.
# Syntax: /loop <interval> <prompt>
/loop 5m check if the deployment finished
/loop 1h run the test suite and summarize failures
/loop 30m check for new PR review comments on my open PRs
# Natural language works too:
/loop check the build at 3pm today # one-shot
/loop daily standup summary every 9am # recurring
# Manage running loops:
show running cron jobs # list all
cancel job c21d95a0 # cancel by ID
# Environment flag to disable entirely:
CLAUDE_CODE_DISABLE_CRON=1/voice
Push-to-talk voice input. Hold spacebar to speak, release to send. Not "always-on" listening, it's deliberate and precise. 20 languages, rebindable activation key via keybindings.json (key: voice:pushToTalk). Still rolling out to ~5% of users, so update daily and check if it's available.
/voice # activate voice mode
# Hold spacebar → speak → release → sends
# Rebind via keybindings.json:
# { "key": "meta+k", "command": "voice:pushToTalk" }Channels
Channels are the most architecturally interesting thing they've shipped. Instead of you polling Claude for status, external systems push events into a running Claude Code session, CI failures, monitoring alerts, webhook payloads, and Claude reacts while you're away. Ships as plugins: Telegram, Discord, and a localhost fakechat for development.
# Install Telegram channel plugin:
claude plugin install channels-telegram
# Or Discord channel plugin:
claude plugin install channels-discord
# Configure bot token → pair account → done
# Pair scheduled tasks + channels for full async:
/loop 15m check build status
# Results route to your Telegram DM, not your terminalOther March 2026 additions worth knowing
/effort | Set model effort level: low, medium, high. Use 'ultrathink' keyword for one-shot max effort without changing the setting. |
/color | Colorize the prompt bar of the current session. Essential when running 3+ parallel worktree sessions simultaneously. |
/simplify | Three-agent parallel code review. Replaces /review (now deprecated). Runs critic, suggester, and verifier agents concurrently. |
/batch | Run an operation across multiple files in one command. Bulk renaming, bulk formatting, bulk docstring generation. |
Auto Mode | AI-powered permission classifier replaces manual approval. Internal data: users approved 93% of prompts anyway. Shift+Tab to cycle to auto mode. |
1M context | Opus 4.6 with 1M token window on Max/Team/Enterprise. Ingest an entire large codebase without losing track. Game-changer for monorepos. |
Resources that genuinely leveled me up
The Claude Code ecosystem is moving fast, faster than the official docs. These are the resources I actually use, not just ones I've bookmarked and forgotten.
The most comprehensive community reference. 84 curated tips organized by category (planning, CLAUDE.md, agents, hooks, workflows). Direct quotes from Boris Cherny and the Claude Code team. Also tracks the best community workflow repos and compares them.
Token optimization deep dives, AgentShield security patterns, multi-language rules, and a planner agent. The token optimization docs alone are worth it, explains exactly how to reduce cost 30-40% without sacrificing quality.
TDD-first workflow with Iron Laws that Claude cannot break. The writing-plans skill is exceptional — forces planning before any implementation. Uniquely enforces whole-plan review before executing a single line.
Full SDLC with agent personas for each role (PM, architect, dev, QA). If you're building something substantial from scratch, this gives you a structured approach that prevents the classic 'started implementing before thinking' mistake.
The reference implementation for skills. Read this before building your own, the structure, frontmatter format, and progressive disclosure patterns are all defined here. Also includes /simplify and /batch built-in skills.
Fresh 200K contexts per task, wave execution pattern, and XML plan structures. The wave-based approach (plan > wave 1 > validate > wave 2) is the most reliable method I've found for large feature implementations.
How to integrate these into your workflow
Don't clone and blindly copy. The right approach: clone shanraisshan/claude-code-best-practice locally, then ask Claude to suggest which practices are relevant to your specific project. Give it the repo as context. It knows what's possible and will map it to your actual needs.
For workflow repos like superpowers or gsd: pick one methodology and internalize it fully before mixing. Mixing planning approaches creates contradictory behavior. I run the GSD wave pattern for features and the superpowers Iron Laws for code quality, they're orthogonal enough not to conflict.
Build your own extensions
The most powerful thing about Claude Code is that the extension system is just Markdown and shell scripts. No SDKs, no frameworks, no build steps. Here's how each piece works so you can build your own.
Custom command
Create any .md file in .claude/commands/. Use YAML frontmatter for allowed-tools and description. Use !`command` to inject live shell output into the prompt. Use $ARGUMENTS for dynamic input.
---
allowed-tools: Bash(git:*), Bash(npm:*), Read
description: Pre-deployment checklist — tests, types, build
---
## Current status
!`git log --oneline -5`
!`git diff --stat main...HEAD`
## Task
Run the pre-deployment checklist:
1. npm test — must pass
2. npx tsc --noEmit — must have 0 errors
3. npm run build — must succeed
4. Check for any .env.local or debug flags still in code
5. Report pass/fail for each step.
If $ARGUMENTS contains a target env, verify env-specific config too.Custom subagent
Create a .md file in .claude/agents/ with YAML frontmatter. The description field is a trigger condition, write it for the model ("use proactively when X"). Restrict tools to only what the agent needs.
---
name: security-auditor
description: Use PROACTIVELY when reviewing auth, API routes, or any code handling user input.
model: sonnet
tools: Read, Grep, Glob
---
You are a security auditor. When reviewing code:
- Check for SQL injection, XSS, CSRF vulnerabilities
- Flag hardcoded secrets or tokens
- Verify input validation on all user-facing endpoints
- Check auth middleware is applied to protected routes
- Look for exposed error messages that leak internals
Output a prioritized list: CRITICAL / HIGH / MEDIUM / LOWCustom skill
Skills are folders: .claude/skills/my-skill/SKILL.md. They're the preferred format for reusable capabilities, more powerful than commands because they support context forking, progressive disclosure, and autonomous invocation. The description field controls when Claude auto-triggers the skill.
---
name: api-design
description: Use when designing new REST API endpoints or reviewing existing ones for consistency.
tools: Read, Glob, Grep
---
## REST API design principles we follow
- Resource-based URLs (/users, /orders — not /getUser)
- HTTP verbs semantically (GET read-only, POST create, PUT replace, PATCH partial)
- Consistent error format: { error: string, code: string, details?: any }
- Pagination: { data: [], meta: { total, page, limit } }
- Version in URL: /v1/users
## Checklist when designing new endpoints
1. Does this URL represent a resource or action? (Prefer resource)
2. Is this operation idempotent? (GET, PUT, DELETE must be)
3. Does the response include a consistent envelope?
4. Are errors descriptive without leaking internals?
5. Is auth middleware applied?Custom hook
Hooks are shell commands configured in .claude/settings.json. They receive JSON on stdin. Use jq to parse. Exit 2 to block. Exit 0 to allow. Set "async": true for fire-and-forget (notifications).
#!/bin/bash
# ~/.claude/hooks/log-tool-use.sh
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
SESSION=$(echo "$INPUT" | jq -r '.session_id' | cut -c1-8)
echo "$(date -u +%FT%TZ) | $SESSION | $TOOL" >> ~/.claude/tool-usage.logSyncing sessions to an Obsidian vault
Every Claude Code session produces knowledge, architecture decisions, gotchas, patterns that work, things to avoid. Most of it evaporates. CLAUDE.md holds the critical stuff, Auto Memory holds session notes, but neither is a proper knowledge base you can navigate, search, and build on over time.
Obsidian is the answer, and the reason it works so cleanly with Claude Code is simple: it's just a folder of Markdown files. No API, no sync service, no plugin required. Claude can read and write to your vault the same way it reads and writes any file. The key is structuring when and what gets written.
The golden rule from the community: your vault should contain your authentic thinking, not AI output. Claude reads your vault for context; your learnings, decisions, and notes live there. Claude's generated content (plans, session logs, ephemeral notes) stays in ~/.claude/. The exception: distilled insights Claude surfaces from a session that you'd genuinely want to remember.
Vault structure for developers
The session skill
The session skill has two halves, start-session loads context from the vault before you begin, and end-session writes learnings back after. They're linked by a Stop hook that fires the end phase automatically.
---
name: session
description: Use at the START of any work session to load vault context and set intention. Also invoked automatically on Stop to write learnings back.
tools: Read, Write, Glob, Bash(ls:*), Bash(cat:*), Bash(date:*)
---
## Vault location
VAULT=~/vault # adjust to your vault path
## On START: load context
1. Read $VAULT/00_Inbox/ — surface any notes waiting for attention
2. Read the relevant project folder in $VAULT/01_Projects/<project>/
- architecture.md — remind yourself of decisions already made
- gotchas.md — don't repeat mistakes
- sessions/<last 3 dates>.md — what happened recently
3. Ask: "What are you working on today?" and set a one-line intention
4. Confirm: "Context loaded. Ready."
## On END: write learnings
See end-session command for the full write-back flow.---
allowed-tools: Read, Glob, Bash(ls:*), Bash(cat:*), Bash(date:*)
description: Load Obsidian vault context and set session intention
---
VAULT=~/vault
PROJECT=$(basename "$PWD")
TODAY=$(date +%Y-%m-%d)
## Inbox
!`ls -1 ~/vault/00_Inbox/ 2>/dev/null | head -20`
## Recent project sessions
!`ls -1t ~/vault/01_Projects/$PROJECT/sessions/ 2>/dev/null | head -3`
!`cat ~/vault/01_Projects/$PROJECT/architecture.md 2>/dev/null | head -60`
!`cat ~/vault/01_Projects/$PROJECT/gotchas.md 2>/dev/null | head -40`
## Task
1. Surface any Inbox items — summarize briefly
2. Remind me of the last session's outcome (from most recent session file)
3. Recall relevant architectural decisions for this project
4. Ask: "What are you working on today?"
5. Set the session intention and confirm readyThe classification logic
The most important part is deciding what goes where. The filter is brutal: if it's a convention Claude should follow in every future session on this project, it goes to CLAUDE.md. If it's a learning worth remembering but not a hard rule, it goes to the vault. Everything else is noise.
---
allowed-tools: Read, Write, Edit, Bash(date:*), Bash(mkdir:*), Bash(git log:*)
description: Write session learnings to Obsidian vault and update CLAUDE.md if critical
---
VAULT=~/vault
PROJECT=$(basename "$PWD")
TODAY=$(date +%Y-%m-%d)
SESSION_FILE="$VAULT/01_Projects/$PROJECT/sessions/$TODAY.md"
## Work done this session
!`git log --oneline --since="8 hours ago" 2>/dev/null | head -20`
## Task
Review the full conversation history and extract learnings in two passes:
### Pass 1 — CRITICAL (for CLAUDE.md)
Scan for anything that should change HOW Claude operates on this project:
- Commands that didn't work and had to be corrected
- Conventions established mid-session ("always use X pattern here")
- Things that went wrong due to missing project context
If found: append to the "## Learnings" section of ./CLAUDE.md (create if missing).
Mark each addition: "<!-- added $TODAY -->"
### Pass 2 — GENERAL (for Obsidian vault)
Write a session note to $SESSION_FILE with this format:
---
date: $TODAY
project: $PROJECT
---
## What we did
<2-3 bullet summary of work completed>
## Decisions made
<any architectural or technical decisions, with reasoning>
## Gotchas
<anything surprising, broken, or worth remembering>
## Next session
<what to pick up from and any open questions>
---
Create $VAULT/01_Projects/$PROJECT/sessions/ if it doesn't exist.
Write the file. Confirm: "Session logged to vault."The Stop hook that fires it automatically
You don't want to remember to run /project:end-session manually, I certainly don't. Wire it to the Stop hook so it fires at end of every session. Keep it async so it doesn't block Claude from stopping.
#!/bin/bash
INPUT=$(cat)
# Only fire if this is the top-level session (not a subagent stop)
IS_SUBAGENT=$(echo "$INPUT" | jq -r '.is_subagent // false')
[ "$IS_SUBAGENT" = "true" ] && exit 0
CWD=$(echo "$INPUT" | jq -r '.cwd')
cd "$CWD" || exit 0
VAULT="$HOME/vault"
PROJECT=$(basename "$CWD")
TODAY=$(date +%Y-%m-%d)
SESSION_DIR="$VAULT/01_Projects/$PROJECT/sessions"
mkdir -p "$SESSION_DIR"
# Fire the end-session command via Claude headless
claude -p "Run /project:end-session to log this session to the vault." \
--allowedTools "Read,Write,Edit,Bash(date:*),Bash(mkdir:*),Bash(git log:*)" \
--continue \
--output-format text >> "$HOME/.claude/obsidian-sync.log" 2>&1{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/discord-notify.sh",
"async": true
},
{
"type": "command",
"command": "~/.claude/hooks/obsidian-session-end.sh",
"async": true
}
]
}
],
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "ls ~/vault/00_Inbox/ 2>/dev/null | wc -l | xargs -I{} echo 'Vault Inbox: {} items waiting'",
"async": false
}
]
}
]
}
}The SessionStart hook — loading context at boot
The SessionStart hook fires before the first prompt. Use it to surface the vault state passively — a count of Inbox items, last session date — without blocking. The full context load happens when you explicitly run /project:start-session.
Optional: MCP for richer vault access
The file-based approach covers 90% of use cases. For search across the entire vault (semantic search, backlinks, queries across hundreds of notes), the community has built MCP bridges:
# obsidian-claude-code-mcp — WebSocket bridge, auto-discovers vaults
# Runs inside Obsidian, exposes vault via port 22360
# Install from Obsidian community plugins: "Claude Code MCP"
# Add to .mcp.json:
{
"mcpServers": {
"obsidian": {
"command": "node",
"args": ["/path/to/obsidian-mcp-bridge/index.js"],
"env": { "VAULT_PATH": "/Users/you/vault" }
}
}
}The reason this setup gets more valuable over time: every session adds to the gotchas and decisions files. Six months from now, when you come back to a project, Claude loads that context on /project:start-session and knows exactly what you decided, why, and what burned you. It's genuine institutional memory that accumulates across the life of a project, not just within a single session.
If you made it this far, thank you. This post started as personal notes and turned into something I genuinely hope is useful. The Claude Code ecosystem moves fast, and a lot of what's here I only figured out because others shared their setups openly. Consider this my contribution back to that cycle.