Skip to main content

The go-code Command

go-code is the single terminal entry point for the entire go-code runtime. It is a shell wrapper (scripts/go-code.sh) that sits in front of harnessd (the daemon) and harnesscli (the CLI client). You never have to start the daemon manually — go-code detects whether a server is already running, boots one if needed, and shuts it down again when you are done.

What you get from this one command:

  • An interactive, full-screen TUI for multi-turn agent conversations
  • A single-shot streaming mode for scripted or piped use
  • A daemon-only mode for long-lived background servers
  • All run-management operations (list, inspect, cancel, continue, replay, search, improve)

What the wrapper does​

When you invoke go-code, the wrapper:

  1. Checks whether harnessd is healthy at the configured port by hitting GET /healthz.
  2. If no healthy server is found, starts harnessd in the background and waits up to 10 seconds for it to become ready.
  3. Resolves your project root by walking up from the current directory.
  4. Delegates to harnesscli (for TUI and prompt modes) or passes the subcommand straight through (for run-management operations).
  5. On exit, stops the server only if the wrapper started it. A server you started independently is always left running.

The auto-start/auto-stop contract is intentional. Running go-code in two terminals at the same time is safe: the second invocation detects the already-running server and reuses it without touching its lifecycle.


Invocation modes​


Headless scripting and exit codes​

The wrapper propagates the harnesscli exit code unchanged, so shell scripts and CI can branch on $? exactly as they would when calling harnesscli directly — including when the wrapper started the server itself (the auto-stop EXIT trap does not override the exit status):

go-code "summarize the diff"
case $? in
0) echo "run completed" ;;
2) echo "run failed" ;;
3) echo "run blocked on input — answer with harnesscli input <run-id> \"<q>=<a>\", or resume interactively with go-code --resume <run-id>" ;;
6) echo "run cancelled — not resumable; harnesscli continue requires status=completed. Start a new run instead." ;;
esac

The full code table (0 completed, 1 client error, 2 failed, 3 blocked, 6 cancelled, 130 interrupted) and its per-command coverage are documented in Exit Codes.


Subcommand reference​

go-code runs and go-code list are both aliases — they both map to harnesscli list. Similarly, go-code show and go-code status both map to harnesscli status.

InvocationMaps to harnesscli subcommandWhat it does
go-code--tuiLaunches the interactive BubbleTea TUI
go-code "prompt"-prompt "..."Runs a single prompt, streams events, exits
go-code --server(server lifecycle only)Starts harnessd in background and exits
go-code --resume <run-id>--tui -resume <run-id>Launches the TUI resuming an existing conversation
go-code runslistLists known runs
go-code listlistAlias for runs
go-code show <id>statusShows one run
go-code status <id>statusAlias for show
go-code cancel <id>cancelCancels one run
go-code continue <id> "prompt"continueContinues a completed run and streams events
go-code replay <id-or-path>replayReplays a recorded run
go-code search <query>searchSearches run metadata (client-side substring match)
go-code improve [flags]improveRuns or plans the self-improvement test loop

Address and project root​

Server address: HARNESS_ADDR​

The HARNESS_ADDR environment variable controls the listen address. The default is 127.0.0.1:8080. The wrapper only uses the port from this value — the host part is ignored. A harnessd that the wrapper starts always binds 127.0.0.1 on that port, because the wrapper only ever talks to it over loopback (http://127.0.0.1:<port>).

# Run on a different port
HARNESS_ADDR=:9090 go-code "List the Go source files"

The address can also be set in your project or user config file (~/.harness/config.toml or .harness/config.toml). HARNESS_ADDR takes precedence over the TOML layers.

If you need a daemon reachable from another machine, don't go through go-code — run harnessd directly with an explicit HARNESS_ADDR (a real host, not just a port) and either a configured API key store or HARNESS_AUTH_DISABLED=true. An unauthenticated daemon that listens beyond loopback refuses to start otherwise.

Startup output and the daemon log​

When the wrapper starts harnessd itself, the daemon's stdout and stderr no longer print to your terminal. They are redirected to a log file at ${TMPDIR:-/tmp}/harnessd.<pid>.log (created with umask 077, so only you can read it), and the wrapper prints that path on a log: line after a successful start. This matters most in --server mode, where the daemon outlives the wrapper process. This keeps a healthy startup to a handful of lines instead of interleaving the daemon's own boot log into the terminal, and it stops a stray daemon log line from landing in the TUI after handoff.

If harnessd fails to become healthy, go-code prints the last 20 lines of that log under a harnessd said: heading before exiting, so the failure reason isn't just a path you have to go open yourself. Lines matching fatal:, panic:, or refusing to start are highlighted; the rest are dimmed.

The wrapper colors its own [go-code] prefix and the WARN:/ERROR: markers (cyan, yellow, red) when writing to a terminal. Color is never the only signal — the words WARN: and ERROR: always stay in the text. Color is disabled, and output is plain text, whenever NO_COLOR is set, TERM=dumb, or the given output stream (stdout or stderr) isn't a terminal — for example when you pipe go-code into another command. stdout and stderr are checked independently, since one can be redirected without the other.

Piping go-code into a command that exits early — go-code runs | head -5, or any pager you quit before it reaches the end of the output — still stops a daemon the wrapper started. Closing the read end of the pipe makes the wrapper's own status writes fail (SIGPIPE/EPIPE), but that failure can no longer stop the shutdown itself: stop_server ignores PIPE before doing anything else, and every status line is written with || true, so a write failure never skips the kill that stops harnessd.

Troubleshooting: a stale harnessd left behind​

If a harnessd the wrapper started is ever left running after go-code exits — for example after a crash rather than a normal exit — the symptom on your next go-code invocation in that project is a failure like callback workspace is already owned: resource temporarily unavailable, because the leftover daemon still holds the workspace's callback-recovery lock. Changing HARNESS_ADDR or the port does not help: the lock is scoped to the workspace, not the port. The remedy is to stop the stray process directly, for example pkill -f harnessd, then run go-code again.

Project root detection​

go-code automatically resolves the workspace root before launching TUI or prompt mode. It walks parent directories from $PWD, looking for:

  1. A .git/ directory
  2. A .harness/config.toml file

The first directory that contains either marker is used as the workspace root. If neither is found at any level, $PWD is used as the fallback.

The resolved path is passed to harnesscli as -workspace <root>, so the agent always operates relative to your project root — not the directory you happened to be in when you ran the command.

~/projects/
myapp/ ← .git/ lives here → workspace root
src/
api/ ← you run "go-code" here

In the example above, running go-code from src/api/ resolves the workspace root as ~/projects/myapp/.


Key-free smoke testing​

You can run go-code without any provider API key by setting HARNESS_PROVIDER=fake. The fake provider returns deterministic responses and is the right choice for CI smoke tests and local integration checks.

# Start the server with the fake provider
HARNESS_PROVIDER=fake go-code --server

# In another terminal, run a prompt against it
go-code "hello"

Or in a single invocation:

HARNESS_PROVIDER=fake go-code "Does this pipeline work?"

The --server flag removes the auto-stop trap. After using go-code --server, stop the daemon manually with pkill harnessd. If you need to use the PID file directly, note that it is written to ${TMPDIR:-/tmp}/harnessd.<wrapper-pid>.pid — on macOS $TMPDIR is a per-user temp directory (e.g. /var/folders/.../T/), not /tmp. The filename uses the launching wrapper's PID; the file's contents are harnessd's PID.


Prerequisites​

go-code requires three commands on your PATH: harnessd, harnesscli, and curl. If any of these are missing it exits with an error. The recommended install (brew install --HEAD dennisonbertram/go-code/go-code or ./scripts/install.sh --add-to-path) places all three in the correct location automatically.


Next steps​

  • Configure the server — set default model, cost limits, and provider keys: see the Configuration reference.
  • Understand run events — learn what run.completed, run.failed, and the rest of the SSE event stream mean: see Events.
  • Use harnesscli directly — for flag-level control over individual subcommands without the wrapper: see the harnesscli reference.