gohome is a lightweight, single-binary coding agent and terminal UI written in Go. The entire stack compiles to a single small binary with no external runtime dependencies.
For fun, mostly. Since I made a dumb choice of buying an annual subscription, I might as well use it. I mainly wanted a terminal tool for custom, local LLM endpoints — for both Anthropic and OpenAI-compatible formats. Other alternatives out there are either massive projects or not exactly what I wanted: a simple and lightweight TUI based coding agent with tool-call guardrails with human approval (plus a skip/"yolo" mode) and built-in sequential subagents you can focus into and approve independently.
Pre-built binaries are attached to each GitHub release. Pick the one matching your platform:
| Platform | Binary name |
|---|---|
| Linux x64 | gohome-linux-amd64 |
| macOS Apple Silicon | gohome-darwin-arm64 |
| macOS Intel | gohome-darwin-amd64 |
| Windows x64 | gohome-windows-amd64.exe |
# Download (replace the URL with the latest release and your platform)
curl -L -o gohome https://github.com/jhyoong/GoHome/releases/download/v0.4.3/gohome-darwin-arm64
# Make it executable
chmod +x gohome
# Move it somewhere on your PATH
sudo mv gohome /usr/local/bin/
# Verify
gohome --version- Download
gohome-windows-amd64.exefrom the latest release. - Rename it to
gohome.exe(optional, for convenience). - Move it to a directory on your
PATH, or run it directly.
The source tree lives under gohome/ at the repo root. Because the module layout places source in a subdirectory named gohome/, the binary must be built with an explicit -o flag; a bare go build ./gohome/cmd/gohome would collide with that directory name.
git clone https://github.com/jhyoong/GoHome
cd GoHome
go build -ldflags "-X main.version=v0.4.3" -o bin/gohome ./gohome/cmd/gohomeWindows note: Do not use
-ldflags "-s -w"(strip flags) when building for Windows. Stripped binaries score higher on antivirus heuristics.
./bin/gohome --model <name>| Flag | Description |
|---|---|
--model <name> |
Select a configured model config by name |
--yolo |
Start with all approval prompts disabled |
--resume |
Resume the most recent session for the current working directory |
--prompt <text> |
Run a single prompt headlessly and exit (requires --yolo). Use --prompt - for interactive JSONL-over-stdin/stdout mode (requires --yolo and --verbose) |
--verbose |
Emit all agent events as JSON lines to stdout (for programmatic use with --prompt -) |
--config |
Print merged configuration and exit |
--version |
Print version and exit |
Auto-compaction automatically summarizes your conversation history when the context window gets full, preventing the agent from hitting token limits during long sessions.
How it works:
- The agent monitors token usage during its run loop
- When usage exceeds a configured threshold, it sends the full conversation history to the LLM for summarization
- The history is replaced with a concise summary (prefixed with
[Auto-compact summary]) that preserves:- Your current goal and sub-tasks
- Key decisions and reasoning
- File paths and code changes
- Pending work and unresolved issues
- Relevant tool results
- A
Compactionevent is persisted to the session file, allowing resumption with the summarized context - The TUI displays a notice when compaction occurs
Configuration (in ~/.gohome/settings.json or .gohome/settings.json):
{
"autoCompact": false,
"autoCompactMode": "percentage",
"autoCompactPct": 0.80,
"autoCompactLeftover": 32000,
"autoCompactPrompt": ""
}| Field | Type | Default | Description |
|---|---|---|---|
autoCompact |
bool |
false |
Enable automatic compaction |
autoCompactMode |
string |
"percentage" |
Trigger mode: "percentage" or "leftover" |
autoCompactPct |
float64 |
0.80 |
For percentage mode: compaction triggers when used tokens ≥ contextWindow × autoCompactPct |
autoCompactLeftover |
int |
32000 |
For leftover mode: compaction triggers when remaining tokens < autoCompactLeftover |
autoCompactPrompt |
string |
(built-in) | Custom prompt for the summarization LLM call. Empty uses the default prompt. |
Modes:
- percentage (default): Compaction triggers when used tokens reach
autoCompactPctof the context window (e.g., 80% of 128K = 102K tokens used) - leftover: Compaction triggers when remaining tokens fall below
autoCompactLeftover(e.g., when less than 32K tokens remain)
Example: For a 128K context window with percentage mode at 0.80:
- Compaction triggers at ~102K tokens used
- The LLM summarizes the conversation into a much smaller context
- The agent continues with the summarized history
{
"modelConfig": {
"local-anthropic": {
"wire": "anthropic",
"baseURL": "http://localhost:8080",
"apiKeyEnv": "GOHOME_API_KEY",
"modelName": "claude-opus-4-7",
"contextWindow": 200000,
"maxTokens": 16384,
"thinkingBudget": 10240,
"headers": {
"X-Custom-Header": "value"
}
},
"local-openai": {
"wire": "openai",
"baseURL": "http://localhost:8081/v1",
"apiKeyEnv": "GOHOME_API_KEY",
"modelName": "gpt-4o",
"contextWindow": 128000,
"maxTokens": 16384,
"reasoningEffort": "high"
}
},
"defaultModel": "local-anthropic",
"systemPrompt": "You are a helpful coding assistant.",
"shellTimeoutMs": 120000,
"maxShellTimeoutMs": 600000,
"contextWarnPct": 0.80,
"contextCritPct": 0.95,
"retryBackoffMs": [250, 1000, 2000],
"renderThrottleMs": 0,
"autoCompact": false,
"autoCompactMode": "percentage",
"autoCompactPct": 0.80,
"autoCompactLeftover": 32000,
"autoCompactPrompt": "",
"cacheSudoPassword": false
}Both "anthropic" and "openai" wires are supported. Set apiKey for a literal key or apiKeyEnv to read from an environment variable.
Model config fields:
| Field | Default | Description |
|---|---|---|
wire |
— | Wire protocol: "anthropic" or "openai" |
baseURL |
— | Base URL of the LLM endpoint |
apiKey |
— | Literal API key (use apiKeyEnv instead to avoid storing secrets) |
apiKeyEnv |
— | Environment variable name whose value is used as the API key |
modelName |
— | Model name sent to the LLM provider |
contextWindow |
128000 |
Context window size in tokens. Used for the usage display and to decide when auto-compaction runs |
maxTokens |
16384 |
Max output tokens per LLM turn |
thinking |
— | Thinking mode (Anthropic wire only): "off" sends no thinking parameter, "adaptive" sends {"type":"adaptive","display":"summarized"}, "budget" sends {"type":"enabled","budget_tokens":N}. When unset: "budget" if thinkingBudget > 0, otherwise "adaptive" |
thinkingBudget |
10240 |
Thinking token budget, used only in "budget" mode. Must be at least 1024 and below maxTokens; gohome refuses the config at startup or on /model otherwise |
reasoningEffort |
— | Reasoning effort level, passed through as-is: reasoning_effort on the OpenAI wire, output_config.effort on the Anthropic wire (e.g. "low", "medium", "high"). Omitted when unset |
headers |
— | Custom HTTP headers added to every request to this endpoint. Map of header name to value |
Top-level fields:
| Field | Default | Description |
|---|---|---|
defaultModel |
— | Name of the model config used when --model is not passed |
systemPrompt |
— | Custom system prompt sent to the LLM. Overrides the built-in default when set |
shellTimeoutMs |
120000 |
Default shell command timeout in milliseconds |
maxShellTimeoutMs |
600000 |
Maximum shell command timeout in milliseconds |
contextWarnPct |
0.80 |
Context window usage ratio at which a warning is shown (must be < contextCritPct) |
contextCritPct |
0.95 |
Context window usage ratio at which a critical warning is shown (must be > contextWarnPct and <= 1.0) |
renderThrottleMs |
16 |
Minimum interval in milliseconds between TUI redraws during token streaming. 0 uses the default (16 ms); a negative value redraws on every token. Higher values reduce CPU use and terminal flicker |
retryBackoffMs |
[250, 1000, 2000] |
Retry backoff schedule in milliseconds. The list length sets the number of retries (attempts = length + 1). A Retry-After header (capped at 60 s) replaces the listed delay |
cacheSudoPassword |
false |
Keep the sudo password in memory after the first entry and reuse it until gohome exits. See Sudo commands |
export GOHOME_API_KEY=<your-key>
./bin/gohome --model local-anthropicProject-level settings live in ./.gohome/settings.json and are merged on top of global settings at startup.
If contextWarnPct >= contextCritPct, or either value is outside the (0, 1] range, both are silently reset to their defaults (0.80 and 0.95).
| Key | Action |
|---|---|
Enter |
Submit input (or toggle expand/collapse on the selected entry when input is empty) |
Up / Down |
Move the cursor through timeline entries when input is empty |
Alt+Enter |
Insert newline |
Esc Esc |
Cancel the current run (a single Esc shows "Press Esc again to cancel") |
Ctrl+C (once) |
Cancel current LLM turn or close approval prompt |
Ctrl+C (twice) |
Quit |
Ctrl+G |
Open current input in external editor ($VISUAL / $EDITOR / vi) |
Ctrl+A / Ctrl+E |
Move to start / end of the input line |
Ctrl+P / Ctrl+N |
Previous / next submitted prompt (saves and restores the draft) |
Ctrl+H |
Open help overlay |
Ctrl+Right |
Focus next session |
Ctrl+Left |
Focus previous session |
Ctrl+D |
Pop last queued pending message (in the /resume browser: delete the selected session) |
PgUp / PgDn |
Scroll viewport |
@ |
Trigger file search popup (type a query after @) |
/ |
Open slash command with inline autocomplete |
Tab |
Confirm file search selection |
v |
Expand/collapse long approval prompt summary |
1–4 |
Pick option in approval prompt |
e |
Edit suggested shell pattern in approval prompt |
Esc |
Deny / close overlay / dismiss file search |
Ctrl+Y |
Copy selected timeline entry to clipboard (when cursor is active) |
When the input editor is empty, Up and Down arrow keys move a > cursor through the conversation timeline. The cursor highlights the selected entry. Press Enter on a tool or thinking entry to expand or collapse its details. Thinking blocks are expanded by default, so reasoning content is visible as it streams in.
| Command | Status |
|---|---|
/yolo |
Toggles yolo mode (skip all approval prompts) |
/tokens |
Opens token usage detail overlay |
/quit |
Exits the process |
/cancel |
Cancels the current LLM turn, clears pending message queue |
/new |
Starts a new session. Refused while a run is active |
/resume [filter] |
Opens a session browser to resume a previous session. Refused while a run is active. The argument pre-fills the filter. Type to filter, Enter resumes, Ctrl+D then y (or Ctrl+D again) deletes the selected session. The active session cannot be deleted |
/model <name> |
Switches the active model config (rebuilds the LLM client). Without arguments, opens a selector listing all configured model configs |
/mouse |
Toggles mouse tracking on/off |
/clear-queue |
Clears all pending queued messages |
/config |
Opens the config overlay showing all settings with source annotations. Pick an action from the list: edit the global config, edit the project config (both open in the external editor), or run the setup wizard |
/help |
Opens the help overlay (same as Ctrl+H) |
~/.gohome/
settings.json # global model config
whitelist.json # global auto-approve rules
denylist.json # global shell denylist (optional)
sessions/ # JSONL session transcripts, grouped by project
logs/ # structured log files (one per day)
./.gohome/ # project-level overrides (in the working directory)
settings.json # project model config overrides
whitelist.json # project whitelist; "Allow always" entries land here
denylist.json # project shell denylist (optional)
Before every tool call, gohome checks the whitelist. If no rule covers the call, it pauses and shows an approval prompt with four options:
- Allow once — permit this call only.
- Allow always — write an auto-approve rule to
./.gohome/whitelist.json. - Deny — block the call and end the run. The model sees the denial with your next message.
- Deny + steer — block the call and inject a message into the agent's context.
/yolo skips all approval prompts without writing whitelist entries. For sudo commands, yolo still opens the password dialog (password only, no approval menu).
whitelist.json has two lists. The global and project files are merged.
{
"tools": ["read"],
"shell": ["^git status$", "^ls"]
}toolslists tool names that are always allowed (read,write,edit,subagent). The shell tool is checked throughshellinstead.shelllists regexes matched against the shell command. A leading^is added when missing. A match must be followed by a space or the end of the command, so^lsallowsls -labut notlsof. Commands that contain;,&,|,<,>, a backtick,$(or a newline are never auto-approved. Invalid regexes are skipped with a log warning.
The shell denylist blocks dangerous commands (for example rm -rf / and mkfs) even in yolo mode. It is a safety net, not a sandbox: it catches common mistakes, not every way to write a harmful command. It only checks the shell tool. Runs of spaces and tabs are squeezed to one space before matching. Entries are plain substrings, or regexes with a regex: prefix. Existing denylist.json files keep working as written; only new setups get the current built-in patterns.
The denylist lives in ~/.gohome/denylist.json and ./.gohome/denylist.json, with the format {"shell": ["rm -rf /", "regex:^mkfs"]}. If neither file exists, the built-in patterns are used. If either file exists, its entries replace the built-in patterns, and the two files are merged.
When a shell command uses sudo, the approval menu works as normal. After you choose Allow once or Allow always, a password dialog opens. Every key goes to the password field. Enter runs the command, Esc goes back to the menu, and Ctrl+C denies. While an approval is open, the mouse wheel scrolls the chat; hold Shift to select text.
Sudo commands allowed by the whitelist (for example after Allow always) skip the menu but still open the password dialog; there, Esc denies the command. Shell commands run without a terminal, so programs that prompt on the terminal (for example sudo without a password, or an ssh password prompt) fail instead of taking over the screen.
When you enter a password, gohome first checks it with sudo -v in the same shell, then runs the command exactly as written. The password goes to sudo on a separate file descriptor, never on stdin, so commands such as sudo -n ... and echo x | sudo tee file work. If the check fails, the command does not run; the output shows sudo's own error (for example "Sorry, try again.") followed by gohome: sudo pre-authentication failed, command not run.
Limits: sudo started by another program (bash -c "sudo ...", xargs sudo, find -exec sudo) or inside a subshell (( ... ), backticks, or $(...) with more than one command), or behind time when /bin/sh has no time keyword (for example dash), may not see the checked password and can fail. A sudoers setting of timestamp_timeout=0 turns off this check entirely. Detection is text-based, so sudo at the start of a line inside a heredoc or a multi-line string, or after ( in a quoted string, also opens the password dialog.
By default the password is asked for on every sudo command, including whitelisted ones. To reuse it until gohome exits, set this in settings.json (or choose Yes in the setup wizard):
{ "cacheSudoPassword": true }The password is kept in memory only. If sudo rejects a cached password ("Sorry, try again"), the cache is cleared and the next sudo command asks again. Detection relies on sudo's standard messages; if several sudo commands run at once, a late rejection can also clear a newer correct password, which only costs one extra prompt.
The subagent tool spawns a fresh, isolated agent session from within the agent loop. The subagent shares the parent's guard and tool registry (but cannot itself spawn subagents), runs synchronously, and returns its final text as a tool result to the parent. The TUI shows each session in a strip at the top; Ctrl+Right / Ctrl+Left switches focus.
Subagent views are read-only. Messages typed while a subagent view is focused go to the main session, and cancel always stops the main run. Resuming a session also loads its subagent sessions as read-only views.
Windows Defender may flag gohome as a trojan. This is a false positive caused by the binary's legitimate coding agent features (shell execution, file writes, API communication) overlapping with malware behavioral patterns. Release binaries for Windows are built natively and not stripped, which lowers the risk.
To work around it, add an exclusion for the binary. In Windows Security, go to Virus & threat protection > Manage settings > Exclusions > Add an exclusion > File, and select gohome.exe. Or, in an administrator PowerShell:
Add-MpPreference -ExclusionPath "C:\path\to\gohome.exe"