Before I go to bed, I tell my agents: good night, have fun
TypeScript
4,091
153 commits
updated Sep 22, 2026
Before I go to bed, I tell my agents:
Never wake up empty-handed.
gnhf is a ralph, autoresearch-style orchestrator that keeps your agents running while you sleep - each iteration makes one small, committed, documented change towards an objective. You wake up to a branch full of clean work and a log of everything that happened.
~ are estimates$ gnhf "reduce complexity of the codebase without changing functionality"
# have a good sleep
$ gnhf "reduce complexity of the codebase without changing functionality" \
--max-iterations 10 \
--max-tokens 5000000
# have a good nap
# Run multiple agents on the same repo simultaneously using worktrees
$ gnhf --worktree "implement feature X" &
$ gnhf --worktree "add tests for module Y" &
$ gnhf --worktree "refactor the API layer" &
# Commit directly on the current branch and push after each successful iteration
$ gnhf --current-branch --push "keep improving this app"
Run gnhf from inside a Git repository with a clean working tree. If you are starting from a plain directory, run git init first.
gnhf supports macOS, Linux, and Windows.
npm
npm install -g gnhf
From source
git clone https://github.com/kunchenguid/gnhf.git
cd gnhf
corepack enable
pnpm install
pnpm run build
pnpm link --global
The npm package includes an agent-facing skill at skills/gnhf/SKILL.md. Agents that support local skills can copy or reference this file to learn how to run GNHF in Hands-Off mode for bounded overnight work, or Companion mode when the outer agent should steer and review a long-running GNHF run.
After installing from npm, the skill is available under the installed package directory. From a source checkout, use skills/gnhf/SKILL.md directly.
┌─────────────┐
│ gnhf start │
└──────┬──────┘
▼
┌──────────────────────┐
│ validate clean git │
│ create or use branch │
│ write prompt.md │
└──────────┬───────────┘
▼
┌────────────────────────────┐
│ build iteration prompt │◄──────────────┐
│ (inject notes.md context) │ │
└────────────┬───────────────┘ │
▼ │
┌────────────────────────────┐ │
│ invoke your agent │ │
│ (non-interactive mode) │ │
└────────────┬───────────────┘ │
▼ │
┌─────────────┐ │
│ success? │ │
└──┬──────┬───┘ │
yes │ │ no │
▼ ▼ │
┌──────────┐ ┌───────────┐ │
│ commit │ │ reset or │ │
│ append │ │ repair │ │
│ notes.md │ │ │ │
│maybe wait│ │ maybe wait│ │
└────┬─────┘ └─────┬─────┘ │
│ │ │
│ ┌──────────┘ │
▼ ▼ │
┌────────────┐ yes ┌──────────┐ │
│ 3 consec. ├─────────►│ abort │ │
│ failures │ └────▲─────┘ │
│ or perm. ├───────────────┘ │
│ error? │ │
└─────┬──────┘ │
no │ │
└──────────────────────────────────────┘
git commit fails, gnhf preserves the uncommitted work and asks the next agent iteration to repair itgit reset --hard except commit failures, which preserve uncommitted work for repair; agent-reported failures proceed to the next iteration immediately, retryable hard agent errors use exponential backoff, and permanent agent errors such as Claude low credit balance abort immediately and print the run log path. Complete no-op iterations are reported as failures and count toward the consecutive-failure abort limit. If the run exits with a pending commit failure, the exit summary warns that uncommitted changes were left for repair.--fallback-model <model> with --agent claude to retry the first rejected iteration on that model instead; without the flag, gnhf never changes models. If no reset time is reported for a rejection, it retries on a bounded escalating interval instead. When usage credits are enabled the provider serves the request and bills the overage rather than rejecting it. A billed iteration that succeeded keeps its committed work and is counted normally; one that failed is rolled back and counted as a failure like any other. Either way gnhf then waits for the reset before starting the next iteration, so the run stops spending credits without throwing away finished work. If the reported reset time has already passed, the included window is back and the run simply continues - if the provider is still billing, the next iteration reports it again with a fresh reset time. If no reset time comes with it at all, or one so far out that gnhf cannot sleep through it in a single wait, gnhf aborts the run rather than keep buying iterations by probing. Use --max-rate-limit-wait to set a total wait leash for the run; if the next wait would exceed it, gnhf aborts cleanly. Ctrl+C during the wait works as usual.--max-iterations stops before the next iteration begins, --max-tokens can abort mid-iteration once reported usage reaches the cap across input, output, cache-read, and cache-write tokens, and --stop-when ends the loop after an iteration whose agent output reports the natural-language condition is met unless a commit failure needs repair first; resumed runs reuse the saved stop condition unless you pass a new value, or --stop-when "" to clear it; pending commit-failure repair work is preserved and other uncommitted work is rolled back, and in the interactive TUI the final state remains visible until you press Ctrl+C to exitSIGTERM also force-stops immediatelynotes.md (built up from prior iterations) to communicate across iterationsend-state.json sidecar with the exit status, stop condition, agent error, and counters under .gnhf/runs/, and ignores it locally, so your branch only contains intentional workgnhf while on an existing gnhf/ branch to pick up where a previous run left off; if you provide a different prompt, gnhf asks whether to update the saved prompt and continue with the existing history, start a new branch, or quit. New runs whose generated branch already exists use a numeric suffix such as gnhf/<slug>-1.Pass --current-branch to run on the branch you are already on instead of creating a gnhf/ branch.
Pass --push to push the current branch after each successful iteration.
Together, --current-branch --push is useful for loose projects where you want a deployed or locally watched branch to update throughout the run.
--current-branch resumes the existing .gnhf/runs/<runId>/ history on a clean working tree and continues iteration numbering.--push also works with the default gnhf/ branch mode and sets origin as the upstream when needed.--current-branch with --worktree; gnhf exits with an error because those modes choose different working directories.Pass --worktree to run each agent in an isolated git worktree. This lets you launch multiple agents on the same repo simultaneously - each gets its own working directory and branch without interfering with the others or your main checkout.
<repo>/ ← your repo (unchanged)
<repo>-gnhf-worktrees/
├── <run-slug-1>/ ← worktree for agent 1
└── <run-slug-2>/ ← worktree for agent 2
--worktree resumes a preserved matching worktree when possible; otherwise gnhf creates a suffixed worktree such as <run-slug>-1 if the original name is unavailable.systemd-inhibit, a worktree with no commits is left in place instead of being removed; remove it manually with git worktree remove. Tracked as gnhf-reexec-worktree-leak-l1.--worktree must be run from a non-gnhf branch (typically main).| Command | Description |
|---|---|
gnhf "<prompt>" | Start a new run with the given objective |
gnhf | Resume a run (when on an existing gnhf/ branch) |
echo "<prompt>" | gnhf | Pipe prompt via stdin |
cat prd.md | gnhf | Pipe a large spec or PRD via stdin |
If you run gnhf on an existing gnhf/ branch with a different prompt, gnhf asks whether to update prompt.md and continue the existing run history, start a new branch, or quit. When the prompt came from stdin, that confirmation is read from the controlling terminal, so it must be available.
| Flag | Description | Default |
|---|---|---|
--agent <agent> | Agent to use: a native agent name or acp:<target-or-command>; see Agents | config file (claude) |
--model <model> | Model for the agent; overrides agentModel.<agent> from the config file | config file |
--max-iterations <n> | Abort after n total iterations | unlimited |
--max-tokens <n> | Abort after n total input+output+cache tokens | unlimited |
--max-rate-limit-wait <duration> | Abort after this much total Claude usage-limit wait (30m, 2h, or 0) | 24h safety cap |
--stop-when <cond> | End when the agent reports this condition, after any commit-failure repair; persists across resume | unlimited |
--prevent-sleep <mode> | Prevent system sleep during the run (on/off or true/false) | config file (on) |
--worktree | Run in a separate git worktree (enables multiple agents concurrently) | false |
--current-branch | Run on the current branch instead of creating a gnhf/ branch | false |
--push | Push the current branch after each successful iteration | false |
--meteor-frequency <n> | Set TUI meteor frequency from 0 to 5 (0 disables meteors) | 3 |
--version | Show version |
Config lives at ~/.gnhf/config.yml.
If the file does not exist yet, gnhf creates it on first run with its defaults.
A supplied --agent is written as the default agent.
With the default configuration, it has this exact content:
# Agent to use by default: native agent name or acp:<target-or-command>
agent: claude
# Custom paths to native agent binaries (optional)
# Paths may be absolute, bare executable names on PATH,
# ~-prefixed, or relative to this config directory.
# Note: rovodev overrides must point to an acli-compatible binary.
# agentPathOverride:
# claude: /path/to/custom-claude
# codex: /path/to/custom-codex
# copilot: /path/to/custom-copilot
# pi: /path/to/custom-pi
# cursor: /path/to/custom-cursor-agent
# Native agent CLI arg overrides (optional)
# ACP targets do not support path or arg overrides.
# agentArgsOverride:
# codex:
# - -m
# - gpt-5.4
# - -c
# - model_reasoning_effort="high"
# - --full-auto
# copilot:
# - --model
# - gpt-5.4
# pi:
# - --provider
# - openai-codex
# - --model
# - gpt-5.5
# - --thinking
# - high
# cursor:
# - --model
# - composer-2.5
# Models for supported native agents (optional)
# Values are forwarded to the CLI except opencode, which receives
# its model in the request body.
# agentModel:
# claude: sonnet
# codex: gpt-5.4
# opencode: fireworks-ai/accounts/fireworks/models/qwen3p6-plus
# Custom ACP target commands (optional)
# Maps acp:<target> names to spawn commands. Useful for naming a
# local or beta build of an ACP agent.
# acpRegistryOverrides:
# my-fork: "/usr/local/bin/my-claude-code-fork --acp"
# staging: "node /opt/staging/agent.mjs"
# Commit message convention (optional)
# Defaults to: gnhf <iteration>: <summary>
# Use Conventional Commits semantic-release headers:
# commitMessage:
# preset: conventional
# Abort after this many consecutive failures
maxConsecutiveFailures: 3
# Prevent the machine from sleeping during a run
preventSleep: true
CLI flags override config file values. --prevent-sleep accepts on/off as well as true/false; the config file always uses a boolean.
The iteration, token, and rate-limit-wait caps are runtime-only flags and are not persisted in config.yml; --stop-when is persisted per run for resume, but not in config.
agentArgsOverride.<name> lets you pass through extra CLI flags for any native agent in the Agents table.
ACP targets do not support path or arg overrides in this version.
Use acpRegistryOverrides to map acp:<target> names to custom spawn commands for local, forked, or beta ACP agents.
You can also pass a raw custom ACP server command directly as a quoted acp: spec, for example gnhf --agent 'acp:./bin/dev-acp --profile ci' "fix the tests".
gnhf config field. Set a model with agentModel.<name> in config or --model <model> for a run; --model wins. OpenCode requires a provider/model pair, and its --model/-m overrides are rejected because opencode serve does not accept them. Rovo Dev model overrides are unsupported; set agent.modelId in Rovo Dev settings instead.codex, claude, copilot, and cursor, gnhf adds its usual non-interactive permission default only when you do not provide your own permission or execution-mode flag. If you set one explicitly, gnhf treats that as user-managed and does not add its default on top.gnhf manages itself for a given agent, such as output-shaping or local-server startup flags, are rejected during config loading so you get a clear error instead of duplicate-argument ambiguity. For pi and cursor, --api-key is also blocked; configure credentials via Pi's own config or the CURSOR_API_KEY environment variable, not via agentArgsOverride.commitMessage controls the subject line that gnhf uses for each successful iteration commit.
gnhf <iteration>: <summary> format.preset: conventional to ask the agent for type and optional scope, then commit as type(scope): summary for semantic-release style workflows. Valid types are build, ci, docs, feat, fix, perf, refactor, test, and chore; invalid or missing types fall back to chore, and empty scopes are omitted.config.yml changes later.Use agentPathOverride to point any native agent at a custom binary - useful for wrappers like Claude Code Switch or custom Codex builds that accept the same flags and arguments as the original:
agentPathOverride:
claude: ~/bin/claude-code-switch
codex: /usr/local/bin/my-codex-wrapper
copilot: ~/bin/copilot-wrapper
pi: ~/bin/pi-wrapper
cursor: ~/bin/cursor-agent-wrapper
Paths may be absolute, bare executable names already on your PATH, ~-prefixed, or relative to the config directory (~/.gnhf/). The override replaces only the binary name; all standard arguments are preserved, so the replacement must be CLI-compatible with the original agent. On Windows, .cmd and .bat wrappers are supported, including bare names resolved from PATH. For rovodev, the override must point to an acli-compatible binary since gnhf invokes it as <bin> rovodev serve ....
When sleep prevention is enabled, gnhf uses the native mechanism for your OS: caffeinate on macOS, systemd-inhibit on Linux, and a small PowerShell helper backed by SetThreadExecutionState on Windows.
A run is never aborted because that mechanism is unavailable; instead the exit summary adds a sleep line reporting either that prevention could not be started for the run, or that the helper started but never confirmed it was holding the machine awake, so the machine may have slept.
Every run writes a JSONL debug log to .gnhf/runs/<runId>/gnhf.log alongside notes.md. Lifecycle events for the orchestrator, agent, and HTTP requests are captured with elapsed timings and (for failures) the full error.cause chain, which is what you need to tell a bare TypeError: fetch failed apart from an undici UND_ERR_HEADERS_TIMEOUT. The agent's own streaming output still goes to the per-iteration iteration-<n>.jsonl file next to it.
Raw ACP command specs are redacted as acp:custom/custom in debug logs and related errors, so local paths or secrets in custom commands are not written to gnhf.log.
Including a snippet of gnhf.log is the single most useful thing you can attach when filing an issue.
gnhf sends anonymous usage telemetry to my self-hosted analytics so I can see what's actually getting used.
No prompts, repo paths, or branch names are sent.
Set GNHF_TELEMETRY=0 to turn it off.
gnhf supports seven native agents plus ACP targets. ACP support is powered by acpx, which is bundled with gnhf and provides the runtime and agent registry for acp:<target-or-command> specs.
| Agent | Flag | Requirements | Notes |
|---|---|---|---|
| Claude Code | --agent claude | Install Anthropic's claude CLI and sign in first. | gnhf invokes claude directly in non-interactive mode. After Claude emits a successful structured result, gnhf treats that result as final and shuts down any lingering Claude process tree after a short grace period. |
| Codex | --agent codex | Install OpenAI's codex CLI and sign in first. | gnhf invokes codex exec directly in non-interactive mode. |
| GitHub Copilot CLI | --agent copilot | Install GitHub Copilot CLI and sign in first. | gnhf invokes copilot directly in non-interactive JSONL mode. Copilot currently exposes assistant output tokens, but not full input/cache token totals; see https://github.com/github/copilot-cli/issues/1152. |
| Pi | --agent pi | Install the pi CLI and configure a usable provider/model first. | gnhf invokes pi directly in JSON mode, appends the final output schema to the prompt, and disables Pi session persistence with --no-session. |
| Cursor CLI | --agent cursor | Install Cursor's CLI and sign in first (cursor-agent login). | gnhf invokes cursor-agent (falling back to the agent name) directly in non-interactive --print stream-json mode, appends the final output schema to the prompt, and defaults to --force, --trust, and --approve-mcps unless you override those flags. After Cursor emits a non-error result, gnhf shuts down any lingering Cursor process tree after a short grace period. |
| Rovo Dev | --agent rovodev | Install Atlassian's acli and authenticate it with Rovo Dev first. | gnhf starts a local acli rovodev serve --disable-session-token <port> process automatically in the repo workspace. |
| OpenCode | --agent opencode | Install opencode and configure at least one usable model provider first. | gnhf starts a local opencode serve --hostname 127.0.0.1 --port <port> --print-logs process automatically, creates a per-run session, and applies a blanket allow rule so tool calls do not block on prompts. |
| ACP target | --agent acp:<target-or-command> | Install and authenticate the target supported by the bundled acpx registry, such as acp:gemini, or pass a quoted custom ACP server command. | gnhf runs the target through ACP with a persistent per-run session under .gnhf/runs/<runId>/acp-sessions; token usage and --max-tokens use ACP used deltas when available, with prompt-length plus tool-call estimates as a fallback, and agentPathOverride and agentArgsOverride do not apply. |
If you want to contribute changes back to this repo, see CONTRIBUTING.md for the required workflow, dev commands, and repo conventions.
TypeScript
98.5%
JavaScript
1.2%
Before I go to bed, I tell my agents: good night, have fun
TypeScript
4,091
153 commits
updated Sep 22, 2026
Before I go to bed, I tell my agents:
Never wake up empty-handed.
gnhf is a ralph, autoresearch-style orchestrator that keeps your agents running while you sleep - each iteration makes one small, committed, documented change towards an objective. You wake up to a branch full of clean work and a log of everything that happened.
~ are estimates$ gnhf "reduce complexity of the codebase without changing functionality"
# have a good sleep
$ gnhf "reduce complexity of the codebase without changing functionality" \
--max-iterations 10 \
--max-tokens 5000000
# have a good nap
# Run multiple agents on the same repo simultaneously using worktrees
$ gnhf --worktree "implement feature X" &
$ gnhf --worktree "add tests for module Y" &
$ gnhf --worktree "refactor the API layer" &
# Commit directly on the current branch and push after each successful iteration
$ gnhf --current-branch --push "keep improving this app"
Run gnhf from inside a Git repository with a clean working tree. If you are starting from a plain directory, run git init first.
gnhf supports macOS, Linux, and Windows.
npm
npm install -g gnhf
From source
git clone https://github.com/kunchenguid/gnhf.git
cd gnhf
corepack enable
pnpm install
pnpm run build
pnpm link --global
The npm package includes an agent-facing skill at skills/gnhf/SKILL.md. Agents that support local skills can copy or reference this file to learn how to run GNHF in Hands-Off mode for bounded overnight work, or Companion mode when the outer agent should steer and review a long-running GNHF run.
After installing from npm, the skill is available under the installed package directory. From a source checkout, use skills/gnhf/SKILL.md directly.
┌─────────────┐
│ gnhf start │
└──────┬──────┘
▼
┌──────────────────────┐
│ validate clean git │
│ create or use branch │
│ write prompt.md │
└──────────┬───────────┘
▼
┌────────────────────────────┐
│ build iteration prompt │◄──────────────┐
│ (inject notes.md context) │ │
└────────────┬───────────────┘ │
▼ │
┌────────────────────────────┐ │
│ invoke your agent │ │
│ (non-interactive mode) │ │
└────────────┬───────────────┘ │
▼ │
┌─────────────┐ │
│ success? │ │
└──┬──────┬───┘ │
yes │ │ no │
▼ ▼ │
┌──────────┐ ┌───────────┐ │
│ commit │ │ reset or │ │
│ append │ │ repair │ │
│ notes.md │ │ │ │
│maybe wait│ │ maybe wait│ │
└────┬─────┘ └─────┬─────┘ │
│ │ │
│ ┌──────────┘ │
▼ ▼ │
┌────────────┐ yes ┌──────────┐ │
│ 3 consec. ├─────────►│ abort │ │
│ failures │ └────▲─────┘ │
│ or perm. ├───────────────┘ │
│ error? │ │
└─────┬──────┘ │
no │ │
└──────────────────────────────────────┘
git commit fails, gnhf preserves the uncommitted work and asks the next agent iteration to repair itgit reset --hard except commit failures, which preserve uncommitted work for repair; agent-reported failures proceed to the next iteration immediately, retryable hard agent errors use exponential backoff, and permanent agent errors such as Claude low credit balance abort immediately and print the run log path. Complete no-op iterations are reported as failures and count toward the consecutive-failure abort limit. If the run exits with a pending commit failure, the exit summary warns that uncommitted changes were left for repair.--fallback-model <model> with --agent claude to retry the first rejected iteration on that model instead; without the flag, gnhf never changes models. If no reset time is reported for a rejection, it retries on a bounded escalating interval instead. When usage credits are enabled the provider serves the request and bills the overage rather than rejecting it. A billed iteration that succeeded keeps its committed work and is counted normally; one that failed is rolled back and counted as a failure like any other. Either way gnhf then waits for the reset before starting the next iteration, so the run stops spending credits without throwing away finished work. If the reported reset time has already passed, the included window is back and the run simply continues - if the provider is still billing, the next iteration reports it again with a fresh reset time. If no reset time comes with it at all, or one so far out that gnhf cannot sleep through it in a single wait, gnhf aborts the run rather than keep buying iterations by probing. Use --max-rate-limit-wait to set a total wait leash for the run; if the next wait would exceed it, gnhf aborts cleanly. Ctrl+C during the wait works as usual.--max-iterations stops before the next iteration begins, --max-tokens can abort mid-iteration once reported usage reaches the cap across input, output, cache-read, and cache-write tokens, and --stop-when ends the loop after an iteration whose agent output reports the natural-language condition is met unless a commit failure needs repair first; resumed runs reuse the saved stop condition unless you pass a new value, or --stop-when "" to clear it; pending commit-failure repair work is preserved and other uncommitted work is rolled back, and in the interactive TUI the final state remains visible until you press Ctrl+C to exitSIGTERM also force-stops immediatelynotes.md (built up from prior iterations) to communicate across iterationsend-state.json sidecar with the exit status, stop condition, agent error, and counters under .gnhf/runs/, and ignores it locally, so your branch only contains intentional workgnhf while on an existing gnhf/ branch to pick up where a previous run left off; if you provide a different prompt, gnhf asks whether to update the saved prompt and continue with the existing history, start a new branch, or quit. New runs whose generated branch already exists use a numeric suffix such as gnhf/<slug>-1.Pass --current-branch to run on the branch you are already on instead of creating a gnhf/ branch.
Pass --push to push the current branch after each successful iteration.
Together, --current-branch --push is useful for loose projects where you want a deployed or locally watched branch to update throughout the run.
--current-branch resumes the existing .gnhf/runs/<runId>/ history on a clean working tree and continues iteration numbering.--push also works with the default gnhf/ branch mode and sets origin as the upstream when needed.--current-branch with --worktree; gnhf exits with an error because those modes choose different working directories.Pass --worktree to run each agent in an isolated git worktree. This lets you launch multiple agents on the same repo simultaneously - each gets its own working directory and branch without interfering with the others or your main checkout.
<repo>/ ← your repo (unchanged)
<repo>-gnhf-worktrees/
├── <run-slug-1>/ ← worktree for agent 1
└── <run-slug-2>/ ← worktree for agent 2
--worktree resumes a preserved matching worktree when possible; otherwise gnhf creates a suffixed worktree such as <run-slug>-1 if the original name is unavailable.systemd-inhibit, a worktree with no commits is left in place instead of being removed; remove it manually with git worktree remove. Tracked as gnhf-reexec-worktree-leak-l1.--worktree must be run from a non-gnhf branch (typically main).| Command | Description |
|---|---|
gnhf "<prompt>" | Start a new run with the given objective |
gnhf | Resume a run (when on an existing gnhf/ branch) |
echo "<prompt>" | gnhf | Pipe prompt via stdin |
cat prd.md | gnhf | Pipe a large spec or PRD via stdin |
If you run gnhf on an existing gnhf/ branch with a different prompt, gnhf asks whether to update prompt.md and continue the existing run history, start a new branch, or quit. When the prompt came from stdin, that confirmation is read from the controlling terminal, so it must be available.
| Flag | Description | Default |
|---|---|---|
--agent <agent> | Agent to use: a native agent name or acp:<target-or-command>; see Agents | config file (claude) |
--model <model> | Model for the agent; overrides agentModel.<agent> from the config file | config file |
--max-iterations <n> | Abort after n total iterations | unlimited |
--max-tokens <n> | Abort after n total input+output+cache tokens | unlimited |
--max-rate-limit-wait <duration> | Abort after this much total Claude usage-limit wait (30m, 2h, or 0) | 24h safety cap |
--stop-when <cond> | End when the agent reports this condition, after any commit-failure repair; persists across resume | unlimited |
--prevent-sleep <mode> | Prevent system sleep during the run (on/off or true/false) | config file (on) |
--worktree | Run in a separate git worktree (enables multiple agents concurrently) | false |
--current-branch | Run on the current branch instead of creating a gnhf/ branch | false |
--push | Push the current branch after each successful iteration | false |
--meteor-frequency <n> | Set TUI meteor frequency from 0 to 5 (0 disables meteors) | 3 |
--version | Show version |
Config lives at ~/.gnhf/config.yml.
If the file does not exist yet, gnhf creates it on first run with its defaults.
A supplied --agent is written as the default agent.
With the default configuration, it has this exact content:
# Agent to use by default: native agent name or acp:<target-or-command>
agent: claude
# Custom paths to native agent binaries (optional)
# Paths may be absolute, bare executable names on PATH,
# ~-prefixed, or relative to this config directory.
# Note: rovodev overrides must point to an acli-compatible binary.
# agentPathOverride:
# claude: /path/to/custom-claude
# codex: /path/to/custom-codex
# copilot: /path/to/custom-copilot
# pi: /path/to/custom-pi
# cursor: /path/to/custom-cursor-agent
# Native agent CLI arg overrides (optional)
# ACP targets do not support path or arg overrides.
# agentArgsOverride:
# codex:
# - -m
# - gpt-5.4
# - -c
# - model_reasoning_effort="high"
# - --full-auto
# copilot:
# - --model
# - gpt-5.4
# pi:
# - --provider
# - openai-codex
# - --model
# - gpt-5.5
# - --thinking
# - high
# cursor:
# - --model
# - composer-2.5
# Models for supported native agents (optional)
# Values are forwarded to the CLI except opencode, which receives
# its model in the request body.
# agentModel:
# claude: sonnet
# codex: gpt-5.4
# opencode: fireworks-ai/accounts/fireworks/models/qwen3p6-plus
# Custom ACP target commands (optional)
# Maps acp:<target> names to spawn commands. Useful for naming a
# local or beta build of an ACP agent.
# acpRegistryOverrides:
# my-fork: "/usr/local/bin/my-claude-code-fork --acp"
# staging: "node /opt/staging/agent.mjs"
# Commit message convention (optional)
# Defaults to: gnhf <iteration>: <summary>
# Use Conventional Commits semantic-release headers:
# commitMessage:
# preset: conventional
# Abort after this many consecutive failures
maxConsecutiveFailures: 3
# Prevent the machine from sleeping during a run
preventSleep: true
CLI flags override config file values. --prevent-sleep accepts on/off as well as true/false; the config file always uses a boolean.
The iteration, token, and rate-limit-wait caps are runtime-only flags and are not persisted in config.yml; --stop-when is persisted per run for resume, but not in config.
agentArgsOverride.<name> lets you pass through extra CLI flags for any native agent in the Agents table.
ACP targets do not support path or arg overrides in this version.
Use acpRegistryOverrides to map acp:<target> names to custom spawn commands for local, forked, or beta ACP agents.
You can also pass a raw custom ACP server command directly as a quoted acp: spec, for example gnhf --agent 'acp:./bin/dev-acp --profile ci' "fix the tests".
gnhf config field. Set a model with agentModel.<name> in config or --model <model> for a run; --model wins. OpenCode requires a provider/model pair, and its --model/-m overrides are rejected because opencode serve does not accept them. Rovo Dev model overrides are unsupported; set agent.modelId in Rovo Dev settings instead.codex, claude, copilot, and cursor, gnhf adds its usual non-interactive permission default only when you do not provide your own permission or execution-mode flag. If you set one explicitly, gnhf treats that as user-managed and does not add its default on top.gnhf manages itself for a given agent, such as output-shaping or local-server startup flags, are rejected during config loading so you get a clear error instead of duplicate-argument ambiguity. For pi and cursor, --api-key is also blocked; configure credentials via Pi's own config or the CURSOR_API_KEY environment variable, not via agentArgsOverride.commitMessage controls the subject line that gnhf uses for each successful iteration commit.
gnhf <iteration>: <summary> format.preset: conventional to ask the agent for type and optional scope, then commit as type(scope): summary for semantic-release style workflows. Valid types are build, ci, docs, feat, fix, perf, refactor, test, and chore; invalid or missing types fall back to chore, and empty scopes are omitted.config.yml changes later.Use agentPathOverride to point any native agent at a custom binary - useful for wrappers like Claude Code Switch or custom Codex builds that accept the same flags and arguments as the original:
agentPathOverride:
claude: ~/bin/claude-code-switch
codex: /usr/local/bin/my-codex-wrapper
copilot: ~/bin/copilot-wrapper
pi: ~/bin/pi-wrapper
cursor: ~/bin/cursor-agent-wrapper
Paths may be absolute, bare executable names already on your PATH, ~-prefixed, or relative to the config directory (~/.gnhf/). The override replaces only the binary name; all standard arguments are preserved, so the replacement must be CLI-compatible with the original agent. On Windows, .cmd and .bat wrappers are supported, including bare names resolved from PATH. For rovodev, the override must point to an acli-compatible binary since gnhf invokes it as <bin> rovodev serve ....
When sleep prevention is enabled, gnhf uses the native mechanism for your OS: caffeinate on macOS, systemd-inhibit on Linux, and a small PowerShell helper backed by SetThreadExecutionState on Windows.
A run is never aborted because that mechanism is unavailable; instead the exit summary adds a sleep line reporting either that prevention could not be started for the run, or that the helper started but never confirmed it was holding the machine awake, so the machine may have slept.
Every run writes a JSONL debug log to .gnhf/runs/<runId>/gnhf.log alongside notes.md. Lifecycle events for the orchestrator, agent, and HTTP requests are captured with elapsed timings and (for failures) the full error.cause chain, which is what you need to tell a bare TypeError: fetch failed apart from an undici UND_ERR_HEADERS_TIMEOUT. The agent's own streaming output still goes to the per-iteration iteration-<n>.jsonl file next to it.
Raw ACP command specs are redacted as acp:custom/custom in debug logs and related errors, so local paths or secrets in custom commands are not written to gnhf.log.
Including a snippet of gnhf.log is the single most useful thing you can attach when filing an issue.
gnhf sends anonymous usage telemetry to my self-hosted analytics so I can see what's actually getting used.
No prompts, repo paths, or branch names are sent.
Set GNHF_TELEMETRY=0 to turn it off.
gnhf supports seven native agents plus ACP targets. ACP support is powered by acpx, which is bundled with gnhf and provides the runtime and agent registry for acp:<target-or-command> specs.
| Agent | Flag | Requirements | Notes |
|---|---|---|---|
| Claude Code | --agent claude | Install Anthropic's claude CLI and sign in first. | gnhf invokes claude directly in non-interactive mode. After Claude emits a successful structured result, gnhf treats that result as final and shuts down any lingering Claude process tree after a short grace period. |
| Codex | --agent codex | Install OpenAI's codex CLI and sign in first. | gnhf invokes codex exec directly in non-interactive mode. |
| GitHub Copilot CLI | --agent copilot | Install GitHub Copilot CLI and sign in first. | gnhf invokes copilot directly in non-interactive JSONL mode. Copilot currently exposes assistant output tokens, but not full input/cache token totals; see https://github.com/github/copilot-cli/issues/1152. |
| Pi | --agent pi | Install the pi CLI and configure a usable provider/model first. | gnhf invokes pi directly in JSON mode, appends the final output schema to the prompt, and disables Pi session persistence with --no-session. |
| Cursor CLI | --agent cursor | Install Cursor's CLI and sign in first (cursor-agent login). | gnhf invokes cursor-agent (falling back to the agent name) directly in non-interactive --print stream-json mode, appends the final output schema to the prompt, and defaults to --force, --trust, and --approve-mcps unless you override those flags. After Cursor emits a non-error result, gnhf shuts down any lingering Cursor process tree after a short grace period. |
| Rovo Dev | --agent rovodev | Install Atlassian's acli and authenticate it with Rovo Dev first. | gnhf starts a local acli rovodev serve --disable-session-token <port> process automatically in the repo workspace. |
| OpenCode | --agent opencode | Install opencode and configure at least one usable model provider first. | gnhf starts a local opencode serve --hostname 127.0.0.1 --port <port> --print-logs process automatically, creates a per-run session, and applies a blanket allow rule so tool calls do not block on prompts. |
| ACP target | --agent acp:<target-or-command> | Install and authenticate the target supported by the bundled acpx registry, such as acp:gemini, or pass a quoted custom ACP server command. | gnhf runs the target through ACP with a persistent per-run session under .gnhf/runs/<runId>/acp-sessions; token usage and --max-tokens use ACP used deltas when available, with prompt-length plus tool-call estimates as a fallback, and agentPathOverride and agentArgsOverride do not apply. |
If you want to contribute changes back to this repo, see CONTRIBUTING.md for the required workflow, dev commands, and repo conventions.
TypeScript
98.5%
JavaScript
1.2%