Hooks and Context Injection
SCM uses hooks to automatically inject context into your AI coding sessions. This guide explains how the hook system works and how to configure it.
How Context Injection Works
When you start a Claude Code session, SCM automatically injects your configured context (fragments, profiles) into the conversation. This happens through a SessionStart hook that runs before each session.
The Flow
- You run
scm runor start Claude Code in a project with SCM configured - SCM assembles context from your default profile, bundles, and tags
- Context is written to a temporary file in
.scm/context/ - The SessionStart hook injects this context into the AI session
- The context file is deleted after injection (one-time use)
Automatic Hook Setup
When you run scm init or scm mcp serve, SCM automatically configures hooks in your AI tool's settings:
Claude Code
SCM adds a hook to .claude/settings.json:
{
"hooks": {
"SessionStart": {
"hooks": [
{
"type": "command",
"command": "scm hook inject-context <hash>",
"timeout": 60
}
]
}
}
}
Gemini
Similar configuration in .gemini/settings.json.
Manual Hook Management
Apply Hooks
Regenerate and apply hooks to your backend configuration:
# Apply to all backends
scm hooks apply
# Apply to specific backend
scm hooks apply --backend claude-code
# Apply without regenerating context
scm hooks apply --no-regenerate
Via MCP
{
"tool": "apply_hooks",
"arguments": {
"backend": "claude-code",
"regenerate_context": true
}
}
Context Assembly
What Gets Included
Context is assembled from:
- Default Profile - Your configured default profile
- Profile Parents - Any parent profiles inherited
- Bundles - All bundles referenced by the profile
- Tagged Fragments - Fragments matching profile tags
Assembly Order
Fragments are assembled in a deterministic order:
- Parent profiles (in order specified)
- Direct bundles (alphabetically)
- Tag-matched fragments (alphabetically)
Deduplication
SCM automatically deduplicates content:
- Same fragment from multiple sources appears once
- Content-hash based deduplication catches identical content even from different bundles
Context Size Management
Size Warning
SCM warns when assembled context exceeds 16KB:
SCM: warning: assembled context is 24KB (recommended max: 16KB)
SCM: warning: large context may reduce LLM effectiveness; consider using fewer/smaller fragments
Research shows that LLM performance degrades with larger context, particularly for middle-positioned content. See the Distillation Guide for details.
Reducing Context Size
If you see size warnings:
- Use distillation - Distill verbose fragments to compressed versions
- Be selective - Only include fragments relevant to current work
- Split profiles - Create task-specific profiles instead of one large profile
- Review bundles - Remove unused bundles from profiles
Hook Commands
inject-context
The primary hook command that injects context:
scm hook inject-context <hash>
<hash>- Content hash identifying the context file- Reads from
.scm/context/<hash>.md - Outputs context to stdout for the AI to consume
- Deletes the context file after reading
Environment Variables
The hook system uses:
| Variable | Description |
|---|---|
SCM_CONTEXT_FILE | Path to the context file to inject |
SCM_VERBOSE | Enable verbose output for debugging |
Debugging Hooks
Check Hook Configuration
# View Claude Code settings
cat .claude/settings.json | jq '.hooks'
# View current context file
ls -la .scm/context/
Test Context Assembly
# Preview what would be injected
scm run --dry-run --print
# Assemble and show context
scm run --print
Verbose Mode
Enable verbose output to see hook execution:
SCM_VERBOSE=1 scm run
Custom Hooks
While SCM manages its own hooks, you can add custom hooks alongside SCM's:
{
"hooks": {
"SessionStart": {
"hooks": [
{
"type": "command",
"command": "scm hook inject-context abc123"
},
{
"type": "command",
"command": "my-custom-hook.sh"
}
]
}
}
}
Note: SCM identifies its hooks by an internal marker (_scm field) and only updates its own hooks, leaving your custom hooks intact.
Troubleshooting
Context Not Injected
- Check hooks are applied:
cat .claude/settings.json - Verify context file exists:
ls .scm/context/ - Run with verbose:
SCM_VERBOSE=1 scm run
Stale Context
If context seems outdated:
# Regenerate and reapply hooks
scm hooks apply --regenerate
Hook Timeout
If hooks timeout, increase the timeout in settings or optimize your context assembly (reduce fragments, use distillation).
Integration with Profiles
Hooks work seamlessly with profiles:
# .scm/profiles/default.yaml
description: My default development context
bundles:
- go-development
- testing-patterns
tags:
- best-practices
When this is your default profile, every session automatically gets these bundles and tagged fragments injected.
Best Practices
- Keep context focused - Include only what's relevant to your current work
- Use profiles - Create different profiles for different tasks
- Monitor size - Watch for size warnings and optimize as needed
- Test changes - Use
--dry-runto preview context changes - Version control - Commit your
.scm/configuration