Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .claude/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Claude Code Configuration — Heady Context

This directory configures Claude Code for **maximum usable context** and
**Heady-optimal operation** when working in this repository. Settings are
team-wide (committed); personal overrides belong in `.claude/settings.local.json`
(gitignored).

## Maximum context

| Setting | Value | Effect |
|---------|-------|--------|
| `autoCompactWindow` | `1000000` | Compaction defers until the **1M-token** boundary — the full window is used before any summarization. |
| `env.ANTHROPIC_BETAS` | `context-1m-2025-08-07` | Opts into the 1M-token context beta. Pair with a 1M-capable model (e.g. `claude-opus-4-8[1m]`). |
| `autoCompactEnabled` | `true` | Long sessions never hard-stop; context is summarized at the boundary instead of failing. |
| `env.CLAUDE_CODE_MAX_OUTPUT_TOKENS` | `64000` | Large single-turn outputs (full files, long reports). |
| `env.MAX_THINKING_TOKENS` | `32000` | Deep extended-thinking budget (stays below the output cap). |
| `env.MAX_MCP_OUTPUT_TOKENS` | `50000` | Heady runs many MCP servers; raises the per-call output cap so tool results aren't truncated. |
| `effortLevel` | `xhigh` | Maximum reasoning effort on supported models. |
| `alwaysThinkingEnabled` / `showThinkingSummaries` | `true` | Thinking always on and visible in the transcript. |

> **Model note:** the 1M window requires a 1M-capable model. Select it per
> session (`/model claude-opus-4-8[1m]`) or pin it in your personal
> `.claude/settings.local.json`. It is intentionally **not** pinned in
> committed settings so the team isn't forced onto one model/tier.

## Heady-optimal operation

- **`enableAllProjectMcpServers: true`** — auto-approves the project's MCP
servers (`.mcp.json`) so the Heady toolchain is available without per-server
prompts.
- **`fileCheckpointingEnabled` / `todoFeatureEnabled`** — safe `/rewind` and
task tracking for multi-stage pipeline work.
- **`cleanupPeriodDays: 90`** — long transcript retention for long-running
orchestration sessions.
- **Permissions** — read/search/agent and the common Heady dev commands
(git, npm/pnpm, node, python, gitleaks) are allowed; secrets
(`.env`, `.heady/**`, keys) are **deny-read**; catastrophic and
destructive-infra commands are blocked or gated (see hooks).

## Hooks

| Hook | Script | Purpose |
|------|--------|---------|
| `SessionStart` | `hooks/session-context.sh` | Injects live repo context (branch, HEAD, present canonical configs, Stop Rule) so each session starts grounded in current state, not a stale snapshot. |
| `PreToolUse(Bash)` | `hooks/guard-bash.sh` | Hard-**denies** catastrophic commands (`rm -rf /`, force-push, `mkfs`, fork-bombs) and **asks** before destructive-but-legitimate ones (`DROP TABLE`, `gcloud … delete`, `wrangler … delete`). Enforces the governance rule that irreversible actions need human confirmation. |

Both scripts are pure `bash` + `jq` (both required at runtime) and emit the
documented hook JSON contracts. Test them directly:

```bash
echo '{}' | bash .claude/hooks/session-context.sh | jq .
echo '{"tool_input":{"command":"rm -rf /"}}' | bash .claude/hooks/guard-bash.sh | jq .
```

Review or disable any hook live via the `/hooks` menu.
61 changes: 61 additions & 0 deletions .claude/hooks/guard-bash.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env bash
# PreToolUse(Bash) hook — last-line guard against catastrophic, irreversible
# commands that pattern-match past the permission allowlist. Aligns with the
# Heady governance rule: destructive actions require explicit human confirmation.
#
# Exit contract: emits a PreToolUse permissionDecision. "deny" hard-blocks the
# call; "ask" forces a confirmation prompt; absence of either lets normal
# permission rules decide. Never blocks on benign commands.
set -uo pipefail

payload="$(cat)"
if command -v jq >/dev/null 2>&1; then
cmd="$(printf '%s' "$payload" | jq -r '.tool_input.command // empty' 2>/dev/null)"
else
cmd="$payload"
fi

emit() {
# $1 = allow|deny|ask, $2 = reason
jq -n --arg d "$1" --arg r "$2" \
'{hookSpecificOutput: {hookEventName: "PreToolUse", permissionDecision: $d, permissionDecisionReason: $r}}'
}

# Catastrophic / irreversible — hard deny.
deny_patterns=(
'rm[[:space:]]+-rf[[:space:]]+/'
'rm[[:space:]]+-rf[[:space:]]+~'
':\(\)\{.*\|.*&.*\}'
'git[[:space:]]+push[[:space:]].*(--force|-f)([[:space:]]|$)'
'git[[:space:]]+reset[[:space:]]+--hard[[:space:]]+origin'
'mkfs\.'
'dd[[:space:]]+if=.*of=/dev/'
'>[[:space:]]*/dev/sd'
)

# Destructive but legitimate in context — require confirmation.
ask_patterns=(
'DROP[[:space:]]+(TABLE|DATABASE|SCHEMA)'
'TRUNCATE[[:space:]]+TABLE'
'gcloud[[:space:]]+.*delete'
'gh[[:space:]]+repo[[:space:]]+delete'
'wrangler[[:space:]]+.*delete'
'kubectl[[:space:]]+delete'
)

for p in "${deny_patterns[@]}"; do
if printf '%s' "$cmd" | grep -qiE "$p"; then
emit deny "Blocked by Heady guard: matches catastrophic pattern /$p/. Irreversible data/infra loss — run by hand after confirming."
exit 0
fi
done

for p in "${ask_patterns[@]}"; do
if printf '%s' "$cmd" | grep -qiE "$p"; then
emit ask "Heady guard: destructive operation (/$p/). Confirm before proceeding."
exit 0
fi
done

# No match: stay silent so normal permission rules apply.
exit 0
39 changes: 39 additions & 0 deletions .claude/hooks/session-context.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# SessionStart hook — injects live Heady ecosystem context into the model at
# the start of every session so it operates against current repo state, not a
# stale snapshot. Emits the SessionStart additionalContext contract as JSON.
set -euo pipefail

repo_root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
cd "$repo_root"

branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'detached')"
head_sha="$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')"
head_subject="$(git log -1 --pretty=%s 2>/dev/null || echo 'n/a')"

# Surface which canonical config files are present (source of truth per CLAUDE.md).
configs=""
for f in configs/hcfullpipeline.yaml configs/resource-policies.yaml \
configs/governance-policies.yaml configs/service-catalog.yaml \
heady-registry.json; do
[ -f "$f" ] && configs="${configs}${f} "
done
[ -z "$configs" ] && configs="(none found in this repo)"

context=$(cat <<EOF
HEADY SESSION CONTEXT (auto-loaded $(date -u +%Y-%m-%dT%H:%M:%SZ)):
- Repo root: ${repo_root}
- Branch: ${branch} @ ${head_sha} — "${head_subject}"
- Canonical configs present: ${configs}
- Context budget: 1M window, auto-compact at boundary, xhigh effort. Use the
full window: read whole configs and source files rather than fragments.
- Source of truth: configs/*.yaml and heady-registry.json. Treat outdated docs
as a defect (CLAUDE.md Standing Rule).
- Stop Rule: build aggressively when healthy; repair first when core infra,
data integrity, or security errors exist.
EOF
)

# jq builds valid JSON regardless of special characters in the context body.
jq -n --arg ctx "$context" \
'{hookSpecificOutput: {hookEventName: "SessionStart", additionalContext: $ctx}}'
124 changes: 124 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",

"autoCompactEnabled": true,
"autoCompactWindow": 1000000,

"effortLevel": "xhigh",
"alwaysThinkingEnabled": true,
"showThinkingSummaries": true,

"fileCheckpointingEnabled": true,
"todoFeatureEnabled": true,
"cleanupPeriodDays": 90,
"skillListingBudgetFraction": 0.02,

"env": {
"ANTHROPIC_BETAS": "context-1m-2025-08-07",
"CLAUDE_CODE_MAX_OUTPUT_TOKENS": "64000",
"MAX_THINKING_TOKENS": "32000",
"MAX_MCP_OUTPUT_TOKENS": "50000",
"BASH_MAX_OUTPUT_LENGTH": "120000",
"BASH_MAX_TIMEOUT_MS": "600000",
"BASH_DEFAULT_TIMEOUT_MS": "120000"
},

"enableAllProjectMcpServers": true,

"permissions": {
"defaultMode": "default",
"allow": [
"Read",
"Glob",
"Grep",
"Agent",
"Edit",
"Write",
"Bash(git status*)",
"Bash(git diff*)",
"Bash(git log*)",
"Bash(git show*)",
"Bash(git branch*)",
"Bash(git checkout*)",
"Bash(git switch*)",
"Bash(git add*)",
"Bash(git restore*)",
"Bash(git stash*)",
"Bash(git fetch*)",
"Bash(git pull*)",
"Bash(git commit*)",
"Bash(git rev-parse*)",
"Bash(git grep*)",
"Bash(git remote -v)",
"Bash(npm run*)",
"Bash(npm test*)",
"Bash(npm ci*)",
"Bash(npm install*)",
"Bash(npm audit*)",
"Bash(pnpm *)",
"Bash(npx *)",
"Bash(node *)",
"Bash(python3 *)",
"Bash(pytest*)",
"Bash(jq *)",
"Bash(rg *)",
"Bash(ls *)",
"Bash(cat *)",
"Bash(gitleaks *)"
],
"deny": [
"Bash(rm -rf /*)",
"Bash(rm -rf ~*)",
"Bash(rm -rf .*)",
"Bash(git push --force*)",
"Bash(git push -f*)",
"Bash(git reset --hard origin*)",
"Bash(git clean -fdx*)",
"Read(./.env)",
"Read(./.env.*)",
"Read(**/.env)",
"Read(**/.env.*)",
"Read(**/.heady/**)",
"Read(**/*.pem)",
"Read(**/id_rsa*)",
"Read(**/*.key)",
"Edit(**/.env)",
"Edit(**/.env.*)"
],
"ask": [
"Bash(gcloud *delete*)",
"Bash(*DROP TABLE*)",
"Bash(*DROP DATABASE*)",
"Bash(gh repo delete*)",
"Bash(wrangler * delete*)"
]
},

"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/session-context.sh",
"timeout": 20,
"statusMessage": "Loading Heady ecosystem context"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/guard-bash.sh",
"timeout": 10,
"statusMessage": "Screening for destructive commands"
}
]
}
]
}
}