--- name: crush-config description: Use when the user needs help configuring Crush — working with crush.json, setting up providers, configuring LSPs, adding MCP servers, managing skills or permissions, or changing Crush behavior. --- # Crush Configuration Crush uses JSON configuration files with the following priority (highest to lowest): 1. `.crush.json` (project-local, hidden) 2. `crush.json` (project-local) 3. `$XDG_CONFIG_HOME/crush/crush.json` or `$HOME/.config/crush/crush.json` (global) ## Basic Structure ```json { "$schema": "https://charm.land/crush.json", "models": {}, "providers": {}, "mcp": {}, "lsp": {}, "hooks": {}, "options": {}, "permissions": {}, "tools": {} } ``` The `$schema` property enables IDE autocomplete but is optional. ## Common Tasks - Add a custom provider: add an entry under `providers` with `type`, `base_url`, `api_key`, and `models`. - Disable a builtin or local skill: add the skill name to `options.disabled_skills`. - Add an MCP server: add an entry under `mcp` with `type` and either `command` (stdio) or `url` (http/sse). ## Model Selection ```json { "models": { "large": { "model": "claude-sonnet-4-20250514", "provider": "anthropic", "max_tokens": 16384 }, "small": { "model": "claude-haiku-4-20250514", "provider": "anthropic" } } } ``` - `large` is the primary coding model; `small` is for summarization. - Only `model` and `provider` are required. - Optional tuning: `reasoning_effort`, `think`, `max_tokens`, `temperature`, `top_p`, `top_k`, `frequency_penalty`, `presence_penalty`, `provider_options`. ## Custom Providers ```json { "providers": { "deepseek": { "type": "openai-compat", "base_url": "https://api.deepseek.com/v1", "api_key": "$DEEPSEEK_API_KEY", "models": [ { "id": "deepseek-chat", "name": "Deepseek V3", "context_window": 64000 } ] } } } ``` - `type` (required): `openai`, `openai-compat`, or `anthropic` - `api_key` supports `$ENV_VAR` syntax. - Additional fields: `disable`, `system_prompt_prefix`, `extra_headers`, `extra_body`, `provider_options`. ## LSP Configuration ```json { "lsp": { "go": { "command": "gopls", "env": { "GOTOOLCHAIN": "go1.24.5" } }, "typescript": { "command": "typescript-language-server", "args": ["--stdio"] } } } ``` - `command` (required), `args`, `env` cover most setups. - Additional fields: `disabled`, `filetypes`, `root_markers`, `init_options`, `options`, `timeout`. ## MCP Servers ```json { "mcp": { "filesystem": { "type": "stdio", "command": "node", "args": ["/path/to/mcp-server.js"] }, "github": { "type": "http", "url": "https://api.githubcopilot.com/mcp/", "headers": { "Authorization": "Bearer $GH_PAT" } } } } ``` - `type` (required): `stdio`, `sse`, or `http` - Additional fields: `env`, `disabled`, `disabled_tools`, `timeout`. ## Options ```json { "options": { "skills_paths": ["./skills"], "disabled_tools": ["bash", "sourcegraph"], "disabled_skills": ["crush-config"], "tui": { "compact_mode": false, "diff_mode": "unified", "transparent": false }, "auto_lsp": true, "debug": false, "debug_lsp": false, "attribution": { "trailer_style": "assisted-by", "generated_with": true } } } ``` > [!IMPORTANT] > The following skill paths are loaded by default and DO NOT NEED to be added to `skills_paths`: > `.agents/skills`, `.crush/skills`, `.claude/skills`, `.cursor/skills` Other options: `context_paths`, `progress`, `disable_notifications`, `disable_auto_summarize`, `disable_metrics`, `disable_provider_auto_update`, `disable_default_providers`, `data_directory`, `initialize_as`. ## Hooks Hooks are user-defined shell commands that fire on agent events. Currently only `PreToolUse` is supported, which runs before a tool is executed. ```json { "hooks": { "PreToolUse": [ { "matcher": "^(edit|write|multiedit)$", "command": ".crush/hooks/protect-files.sh" }, { "matcher": "^bash$", "command": ".crush/hooks/no-haskell.sh" } ] } } ``` ### Hook Properties - `command` (required): Shell command to execute. Runs via `sh -c`. - `matcher` (optional): Regex pattern tested against the tool name. Empty or absent means match all tools. - `timeout` (optional): Timeout in seconds. Defaults to 30. ### Event Name Normalization Event names are case-insensitive and accept snake_case variants: `PreToolUse`, `pretooluse`, `pre_tool_use`, and `PRE_TOOL_USE` all work. ### How Hooks Work 1. When a tool is about to be called, all `PreToolUse` hooks with a matching `matcher` (or no matcher) run in parallel. 2. Duplicate commands are deduplicated — each unique command runs at most once. 3. The hook receives JSON on **stdin** and hook-specific **environment variables**. ### Hook Input (stdin) A JSON payload is piped to the hook command: ```json { "event": "PreToolUse", "session_id": "abc-123", "cwd": "/path/to/project", "tool_name": "bash", "tool_input": {"command": "ls -la"} } ``` ### Hook Environment Variables | Variable | Description | |---|---| | `CRUSH_EVENT` | Event name (e.g. `PreToolUse`) | | `CRUSH_TOOL_NAME` | Name of the tool being called | | `CRUSH_SESSION_ID` | Current session ID | | `CRUSH_CWD` | Current working directory | | `CRUSH_PROJECT_DIR` | Project root directory | | `CRUSH_TOOL_INPUT_COMMAND` | Value of `command` from tool input (if present) | | `CRUSH_TOOL_INPUT_FILE_PATH` | Value of `file_path` from tool input (if present) | ### Hook Output **Exit code 0** — the hook succeeded. Stdout is parsed as JSON: ```json {"decision": "allow", "context": "optional context appended to tool result"} ``` - `decision`: `allow` to explicitly allow, `deny` to block, `none` (or omit) for no opinion. - `reason`: Explanation text (used when denying). - `context`: Extra context appended to the tool result. - `updated_input`: Replacement JSON for the tool input. Last non-empty value wins. **Exit code 2** — the tool call is blocked. Stderr is used as the deny reason. ```bash echo "No Haskell allowed" >&2 exit 2 ``` **Any other exit code** — non-blocking error. The tool call proceeds as normal. ### Claude Code Compatibility Crush also supports the Claude Code hook output format: ```json { "hookSpecificOutput": { "permissionDecision": "allow", "permissionDecisionReason": "Auto-approved", "updatedInput": {"command": "echo rewritten"} } } ``` Existing Claude Code hooks should work without modification. ### Decision Aggregation When multiple hooks match, their decisions are aggregated: - **Deny wins over allow** — if any hook denies, the tool call is blocked. - **Allow wins over none** — if no hook denies but at least one allows, the call proceeds. - All deny reasons are concatenated (newline-separated). - All context strings are concatenated (newline-separated). - For `updated_input`, the last non-empty value wins. ## Tool Permissions ```json { "permissions": { "allowed_tools": ["view", "ls", "grep", "edit"] } } ``` ## Environment Variables - `CRUSH_GLOBAL_CONFIG` - Override global config location - `CRUSH_GLOBAL_DATA` - Override data directory location - `CRUSH_SKILLS_DIR` - Override default skills directory