Sachin Koli

HooCodeStart here

Settings

HooCode uses JSON settings files with project settings overriding global settings.

Location Scope
~/.hoocode/settings.json Global (all projects)
.hoocode/settings.json Project (current directory)

Edit directly or use /settings for common options.

All Settings

Model & Thinking

Setting Type Default Description
defaultProvider string - Default provider (e.g., "anthropic", "openai")
defaultModel string - Default model ID
defaultThinkingLevel string - "off", "minimal", "low", "medium", "high", "xhigh"
hideThinkingBlock boolean false Hide thinking blocks in output
thinkingBudgets object - Custom token budgets per thinking level
thinkingDisplay string - "summarized" or "omitted". Controls how adaptive-thinking models return thinking content. Opus 4.8 defaults to "omitted" (faster tool-use turns, reasoning effort unchanged); set "summarized" to surface thinking text.

thinkingDisplay

"omitted" keeps full reasoning effort but skips streaming the thinking summary, lowering time-to-first-token (faster tool use) at the cost of not showing thinking text. "summarized" returns visible thinking. When unset, Opus 4.8 defaults to "omitted"; other models default to "summarized".

{
  "thinkingDisplay": "summarized"
}

thinkingBudgets

{
  "thinkingBudgets": {
    "minimal": 1024,
    "low": 4096,
    "medium": 10240,
    "high": 32768
  }
}

UI & Display

Setting Type Default Description
theme string "dark" Theme name ("dark", "light", or custom)
quietStartup boolean false Hide startup header
collapseChangelog boolean false Show condensed changelog after updates
enableInstallTelemetry boolean true Send an anonymous install/update version ping after first install or changelog-detected updates. This does not control update checks
doubleEscapeAction string "tree" Action for double-escape: "tree", "fork", or "none"
treeFilterMode string "default" Default filter for /tree: "default", "no-tools", "user-only", "labeled-only", "all"
editorBorder string "box" Input editor border: "box" (side borders and corners) or "rule" (horizontal lines only)
editorPaddingX number 1 Horizontal padding for input editor (0-3)
autocompleteMaxVisible number 5 Max visible items in autocomplete dropdown (3-20)
showHardwareCursor boolean false Show terminal cursor

Tips

An occasional one-line tip on the band above the prompt, shown when the session has been idle for a while or when a turn has been running long enough that you are watching a spinner. A tip never interrupts: it is only ever posted when the band is empty, so it cannot delay or replace a notification you caused. It never repeats until it has run out of things to say, and it remembers across sessions.

Setting Type Default Description
tips.enabled boolean true Show tips. Also in /settings → Advanced → Tips
tips.seen string[] [] Ids of tips already shown. Bookkeeping; clear it to see them all again
tips.starNudges number 0 How many times the “star the repo” nudge has been shown (lifetime cap: 3)

The tips themselves live in one file, src/modes/interactive/tips.ts. Know a trick that is not in there? Send a PR — it is one row in an array, and it is genuinely one of the easiest useful first contributions to the project.

Telemetry and update checks

enableInstallTelemetry is inert: HooCode sends no install or update telemetry anywhere, and the setting is kept only so an existing settings.json does not fail to parse. Update checks are separate and do still run – they read the published version straight from the npm registry (https://registry.npmjs.org/@kolisachint/hoocode-agent/latest) and send nothing but a User-Agent. Set HOOCODE_OFFLINE=1 or HOOCODE_SKIP_VERSION_CHECK=1 to turn that off too.

Set HOOCODE_SKIP_VERSION_CHECK=1 to disable the HooCode version update check. Use --offline or HOOCODE_OFFLINE=1 to disable all startup network operations described here, including update checks, package update checks, and install/update telemetry.

Warnings

Setting Type Default Description
warnings.anthropicExtraUsage boolean true Show a warning when Anthropic subscription auth may use paid extra usage
warnings.websearchApiKey boolean true Show a warning when websearch is enabled with no search API key, so it falls back to keyless DuckDuckGo
{
  "warnings": {
    "anthropicExtraUsage": false,
    "websearchApiKey": false
  }
}

Both warnings are shown once per session in the TUI and can also be toggled from /settings → Warnings.

Compaction

Setting Type Default Description
compaction.enabled boolean true Enable auto-compaction
compaction.reserveTokens number 16384 Tokens reserved for LLM response
compaction.keepRecentTokens number 20000 Recent tokens to keep (not summarized)
{
  "compaction": {
    "enabled": true,
    "reserveTokens": 16384,
    "keepRecentTokens": 20000
  }
}

Context budget

Everything in the system prompt and in an active tool’s schema is re-sent on every request. These three settings decide how large that is, and /settings groups them under Context with the live per-turn cost printed under the list.

Setting Type Default Description
light boolean false Low-token preset: read/write/edit/bash only with stripped schemas, a terse system prompt, and no subagents/TodoWrite/skills/context files
contextGc boolean true Stub superseded read results out of the outgoing context

light is read at startup to pick the tool set and the system prompt, so toggling it in /settings applies on the next session. --light turns it on for a single run. Auto-compaction lives in the same category and is documented under Compaction.

/settings also prices each tool by what its schema costs per turn, on the switch itself, so it is clear which one is worth turning off. hoocode --print-token-surface prints the same measurement as text.

Branch Summary

Setting Type Default Description
branchSummary.reserveTokens number 16384 Tokens reserved for branch summarization
branchSummary.skipPrompt boolean false Skip “Summarize branch?” prompt on /tree navigation (defaults to no summary)

Retry

Setting Type Default Description
retry.enabled boolean true Enable automatic agent-level retry on transient errors
retry.maxRetries number 3 Maximum agent-level retry attempts
retry.baseDelayMs number 2000 Base delay for agent-level exponential backoff (2s, 4s, 8s)
retry.provider.timeoutMs number SDK default Provider/SDK request timeout in milliseconds
retry.provider.maxRetries number SDK default Provider/SDK retry attempts
retry.provider.maxRetryDelayMs number 60000 Max server-requested delay before failing (60s)

When a provider requests a retry delay longer than retry.provider.maxRetryDelayMs (e.g., Google’s “quota will reset after 5h”), the request fails immediately with an informative error instead of waiting silently. Set to 0 to disable the cap.

{
  "retry": {
    "enabled": true,
    "maxRetries": 3,
    "baseDelayMs": 2000,
    "provider": {
      "timeoutMs": 3600000,
      "maxRetries": 0,
      "maxRetryDelayMs": 60000
    }
  }
}

Message Delivery

Setting Type Default Description
steeringMode string "one-at-a-time" How steering messages are sent: "all" or "one-at-a-time"
followUpMode string "one-at-a-time" How follow-up messages are sent: "all" or "one-at-a-time"
transport string "sse" Preferred transport for providers that support multiple transports: "sse", "websocket", or "auto"

Terminal & Images

Setting Type Default Description
terminal.showImages boolean true Show images in terminal (if supported)
terminal.imageWidthCells number 60 Preferred inline image width in terminal cells
terminal.clearOnShrink boolean false Clear empty rows when content shrinks (can cause flicker)
images.autoResize boolean true Resize images to 2000x2000 max
images.blockImages boolean false Block all images from being sent to LLM

Shell

Setting Type Default Description
shellPath string - Custom shell path (e.g., for Cygwin on Windows)
shellCommandPrefix string - Prefix for every bash command (e.g., "shopt -s expand_aliases")
npmCommand string[] - Command argv used for npm package lookup/install operations (e.g., ["mise", "exec", "node@20", "--", "npm"])
{
  "npmCommand": ["mise", "exec", "node@20", "--", "npm"]
}

npmCommand is used for all npm package-manager operations, including installs, uninstalls, and dependency installs inside git packages. Use argv-style entries exactly as the process should be launched. When npmCommand is configured, git package dependency installs use plain install to avoid npm-specific flags in wrappers or alternate package managers.

Normally the package manager’s global modules location is queried using root -g. As a special case, if the first element of npmCommand is "bun", the modules location will instead be queried with pm bin -g.

Sessions

Setting Type Default Description
sessionDir string - Directory where session files are stored. Accepts absolute or relative paths, plus ~.
{ "sessionDir": ".hoocode/sessions" }

When multiple sources specify a session directory, precedence is --session-dir, HOOCODE_CODING_AGENT_SESSION_DIR, then sessionDir in settings.json.

Learning from sessions

The window /learn mines when looking for repeated directives, fixes, and workflows.

All five are editable from /settings under Learning. /learn settings prints the same values as text, alongside the paths of both settings files and the session directory being read.

Setting Type Default Description
learnMaxSessions number 20 Recent sessions in this directory to scan
learnMaxAgeDays number 30 Ignore sessions older than this
learnMinRepeats number 2 Separate sessions a directive must recur in before it is proposed
learnMinRequestRepeats number 3 Separate sessions a piece of work must be asked for before it is proposed as a slash command
learnMaxProposals number 8 Cap on each list in the digest
{ "learnMaxSessions": 50, "learnMaxAgeDays": 90, "learnMinRepeats": 3 }

Widen the window on a repo you touch rarely, so a habit spread over months still reaches the repeat threshold. Narrow it on one you work in daily, where the last few weeks are the only relevant history. learnMinRepeats is the signal/noise dial: raise it for fewer, better-evidenced proposals.

Both thresholds count distinct sessions, not occurrences: saying a thing twice in one sitting usually means it was ignored the first time, which is evidence about that afternoon rather than about how you work. learnMinRequestRepeats is higher than learnMinRepeats on purpose — a rule stated twice is a rule, but a job asked for twice may just be a job that came up twice. learnMaxProposals bounds what a single run can ask you to review; every proposal costs the model context.

Non-numeric or non-positive values fall back to the default rather than narrowing the window to nothing. As with all settings, a project .hoocode/settings.json overrides the global one, so a repo can carry its own window.

Plugins and artifacts

Where hoocode writes what it authors. Both are editable from /settings under Plugins, which writes the global settings file — the layout a machine targets is an environment-level choice, so it is set once rather than passed on every run.

Setting Type Default Description
enablePluginTools boolean false Master switch for the autonomous plugin system: the lifecycle tools, ProposePlugin, and the plugin-reuse nudge
platform string | string[] - Vendor layout(s) to write artifacts in: claude, github (aliases copilot, gh), agents (alias native)
pluginInstallScope string "user" Where an autonomous plugin install lands: user (~/.agents/plugins) or project (<cwd>/.agents/plugins, shared once committed)
{ "enablePluginTools": true, "platform": ["claude", "github"], "pluginInstallScope": "user" }

/settings writes the global file. If a project .hoocode/settings.json sets one of these keys it is merged over that on the next session, so the pane marks the row as overridden rather than letting the change look permanent.

enablePluginTools is off by default and is the one gate for the whole autonomous system — see Plugins. Toggling it in /settings attaches the tools on the next session, since they are wired up when the session is built; the reuse nudge re-reads the setting and follows immediately. The --enable-plugintools flag turns it on for a single run. Slash-command plugin management (/plugin) is unaffected either way.

platform governs the two things hoocode writes: authored plugins, and the /new-skill, /new-agent and /new-command scaffolds. Reading is unaffected — every vendor convention is read regardless of this setting.

It takes a list because emitting for two platforms at once is a supported shape; in /settings the three tokens are independent toggles for that reason. Unsetting it (all toggles off) is not the same as targeting nothing: the defaults come back, which are claude for an authored plugin and .hoocode/ for a scaffold. agents is a scaffold-only target — a plugin is a distribution unit and the native layout belongs to no marketplace — so plugin authoring filters it out rather than failing.

The --platform CLI flag sets the same targets for a single run and overrides this setting.

Model Cycling

Setting Type Default Description
enabledModels string[] - Model patterns for Ctrl+P cycling (same format as --models CLI flag)
{
  "enabledModels": ["claude-*", "gpt-4o", "gemini-2*"]
}

Markdown

Setting Type Default Description
markdown.codeBlockIndent string " " Indentation for code blocks

External tools

hoocode is self-sufficient without any of these. Five optional Rust binaries expand what it can do: two make an existing tool faster, three add a capability hoocode otherwise does not have. Each resolves from HOOCODE_<TOOL>_BINARY → hoocode’s bin directory → PATH → a published release download.

Because hoocode degrades quietly without them, they are easy to miss. /settings → External tools lists all five with live status and what each one adds; rows below that are inert without their binary are marked needs <binary> there.

Binary Adds Without it
rg Fast path for the lexical half of SearchCodebase. Fetched at startup. A pure-JS scanner with identical output, slower on large trees.
fd Fast path for find. Fetched at startup. A JS directory walker, slower, with approximated glob/ignore handling.
embsearch Semantic hits fused into SearchCodebase, and meaning-ranked capability/MCP lookup. Fetched on first use. Must be the ONNX build. SearchCodebase runs lexical-only. Nothing errors; intent-phrased queries rank worse.
webtools The webfetch and websearch tools. Fetched on first use. Both tools error when called.
voicetools Push-to-talk voice input in the TUI. Fetched on first use. Voice capture reports an error and never starts.
Setting Type Default Description
enableWebTools boolean false Enable webfetch + websearch (network access). Needs the webtools binary.
webtools.timeoutSecs number 15 Per-request timeout in seconds, clamped 1–120. Wins over HOOCODE_WEBTOOLS_TIMEOUT.
webtools.search object — Search backend and credentials, read by the webtools binary itself. See Web search providers.
enableSemanticIndex boolean true Build and fuse the semantic index into SearchCodebase. Set false to run it lexical-only.
embsearchBinaryPath string — Explicit path to the embsearch binary. Default: resolve from PATH.
embsearchThresholdBytes number 0 Minimum indexable source bytes before a repo is embedded. 0 indexes every repo.
voice.silenceMs number 800 Trailing silence before voice capture auto-stops, clamped 300–10000. VOICETOOLS_SILENCE_MS overrides this.

Environment variables:

Variable Effect
HOOCODE_<TOOL>_BINARY Point at a local build; authoritative when the path exists. <TOOL> is RG, FD, EMBSEARCH, WEBTOOLS, or VOICETOOLS.
VOICETOOLS_BIN Same, checked before the generic override for voice.
HOOCODE_OFFLINE=1 Never download a missing binary.
HOOCODE_NATIVE_SEARCH=1 Force the JS search paths even when rg/fd are installed.

On Android/Termux the published Linux builds do not run; install with pkg install <name> instead.

Mapping a long page

webfetch(url, outline: true) returns the page’s headings instead of its body — each with the offset that reads its section and what that section costs:

  Installation — offset 0, ~143 tokens
  Configuration — offset 557, ~145 tokens
Read a section by fetching it at the offset shown.

A page maps for a few dozen tokens whatever its length, and the one section worth reading is then fetched at its own offset. Outline offsets are the same offsets paging uses, so a row feeds straight back into offset.

Needs a webtools binary that supports --outline (v0.5.0 or newer). An older one rejects the flag, and hoocode reports that the binary needs updating rather than passing the parser message through.

Finding a mention on a long page

An outline helps when the page has headings and one names what you are after. webfetch(url, grep: "pattern") covers the rest — where does this page mention a thing, on a document whose headings do not say, or that has none:

offset 512 in "Configuration" (+2 nearby) — …the rate limit defaults to sixty…
Read a match by fetching it at the offset shown.

Match offsets are the offsets offset reads, like outline offsets, so a hit is read by fetching at it. The pattern is a regular expression, case-insensitive unless it carries an uppercase letter. Occurrences close together collapse into one hit carrying a count, so a term repeated through a paragraph is one result rather than eight near-identical ones.

outline and grep are alternatives, not a pair: asking for both is rejected before a subprocess is spawned. Needs webtools v0.6.0 or newer.

Reading a long page

webfetch budgets its output in tokens (maxTokens, default 4000, hard cap 25000). When a page runs past that, the result says so — the budget it stopped at, and the ways past it — so a long document reads as a first page rather than a dead end. The TUI marks the same fetch ~4000 tokens (truncated at 4000).

When the webtools binary reports paging offsets, the note names the offset to continue at; pass it back as offset to read the next window. Windows tile the document exactly, so a long page costs one budget per window rather than one copy of the page per attempt. Against an older binary the note falls back to advising a larger maxTokens.

Prefer a more specific URL or #anchor over paging a whole document: extraction has already dropped nav and boilerplate, so the first few thousand tokens are usually the article itself.

Web search providers

websearch needs no configuration: it defaults to keyless DuckDuckGo Lite. That backend is scraped HTML, though — rate-limited hard, and it can fail outright — so when search reliability matters, point it at a backend with an actual API contract. With none configured, the TUI says so once per session (see warnings.websearchApiKey).

The webtools binary reads its own webtools key out of the user-level ~/.hoocode/settings.json, using its own (snake_case) key names. HooCode never writes this block; it only reads it to tell whether a keyed backend exists. Put it in the user-level file — a project .hoocode/settings.json is not read by the binary, and a file holding credentials is worth keeping out of a working tree.

{
  "webtools": {
    "search": {
      "provider": "brave",
      "fallback": "duckduckgo",
      "providers": {
        "brave": { "api_key": "..." },
        "tavily": { "api_key": "..." },
        "searxng": { "base_url": "https://searx.internal" }
      }
    }
  }
}

Environment variables win over the file, so a key can stay out of it entirely:

Variable Effect
WEBTOOLS_SEARCH_PROVIDER Backend to use: duckduckgo (default), brave, tavily, searxng. Pin duckduckgo to accept the keyless backend and silence the warning.
WEBTOOLS_SEARCH_FALLBACK Backend tried when the primary fails; none disables the fallback.
WEBTOOLS_BRAVE_API_KEY, BRAVE_API_KEY Brave Search key.
WEBTOOLS_TAVILY_API_KEY, TAVILY_API_KEY Tavily key. Returns cleaned page content, so a search often answers without a follow-up webfetch.
WEBTOOLS_SEARXNG_URL, WEBTOOLS_SEARXNG_API_KEY Self-hosted SearXNG endpoint (and optional key), for networks where the public APIs are unreachable.

Every result records the backend that answered it, so a fallback to the scraped backend is never silent.

Resources

These settings define where to load extensions, skills, prompts, and themes from.

Paths in ~/.hoocode/settings.json resolve relative to ~/.hoocode. Paths in .hoocode/settings.json resolve relative to .hoocode. Absolute paths and ~ are supported.

Setting Type Default Description
packages array [] npm/git packages to load resources from
extensions string[] [] Local extension file paths or directories
skills string[] [] Local skill file paths or directories
prompts string[] [] Local prompt template paths or directories
themes string[] [] Local theme file paths or directories
enableSkillCommands boolean true Register skills as /skill:name commands

Arrays support glob patterns and exclusions. Use !pattern to exclude. Use +path to force-include an exact path and -path to force-exclude an exact path.

packages

String form loads all resources from a package:

{
  "packages": ["hoocode-skills", "@org/my-extension"]
}

Object form filters which resources to load:

{
  "packages": [
    {
      "source": "hoocode-skills",
      "skills": ["brave-search", "transcribe"],
      "extensions": []
    }
  ]
}

See packages.md for package management details.

Example

{
  "defaultProvider": "anthropic",
  "defaultModel": "claude-sonnet-4-20250514",
  "defaultThinkingLevel": "medium",
  "theme": "dark",
  "compaction": {
    "enabled": true,
    "reserveTokens": 16384,
    "keepRecentTokens": 20000
  },
  "retry": {
    "enabled": true,
    "maxRetries": 3
  },
  "enabledModels": ["claude-*", "gpt-4o"],
  "warnings": {
    "anthropicExtraUsage": true,
    "websearchApiKey": true
  },
  "packages": ["hoocode-skills"]
}

Project Overrides

Project settings (.hoocode/settings.json) override global settings. Nested objects are merged:

// ~/.hoocode/settings.json (global)
{
  "theme": "dark",
  "compaction": { "enabled": true, "reserveTokens": 16384 }
}

// .hoocode/settings.json (project)
{
  "compaction": { "reserveTokens": 8192 }
}

// Result
{
  "theme": "dark",
  "compaction": { "enabled": true, "reserveTokens": 8192 }
}