Skip to content
jhyoongPublic

About

GoHome play with your homelab

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

88 Commits

Folders and files

Repository files navigation

gohome

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.

Why am I building this

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.


Install

Download a pre-built binary

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

macOS / Linux

# 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

Windows

  1. Download gohome-windows-amd64.exe from the latest release.
  2. Rename it to gohome.exe (optional, for convenience).
  3. Move it to a directory on your PATH, or run it directly.

Build from source

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/gohome

Windows note: Do not use -ldflags "-s -w" (strip flags) when building for Windows. Stripped binaries score higher on antivirus heuristics.

Run

./bin/gohome --model <name>

CLI flags

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

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 Compaction event 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 autoCompactPct of 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

Quickstart

1. Create ~/.gohome/settings.json

{
  "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

2. Run

export GOHOME_API_KEY=<your-key>
./bin/gohome --model local-anthropic

Project-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).


Keybindings

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)

Timeline cursor

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.


Slash commands

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)

File layout

~/.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)

Guardrails and approval

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 file format

whitelist.json has two lists. The global and project files are merged.

{
  "tools": ["read"],
  "shell": ["^git status$", "^ls"]
}
  • tools lists tool names that are always allowed (read, write, edit, subagent). The shell tool is checked through shell instead.
  • shell lists 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 ^ls allows ls -la but not lsof. Commands that contain ;, &, |, <, >, a backtick, $( or a newline are never auto-approved. Invalid regexes are skipped with a log warning.

Denylist

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.

Sudo commands

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.


Subagents

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.


Troubleshooting

Windows Defender False Positive

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"

About

GoHome play with your homelab

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages