A coordinator that keeps long-running, multi-agent OpenCode workflows moving while you're away.
Hawk is built for multi-agent OpenCode workflows: a lead agent works through a multi-milestone build plan and dispatches subagents (developer, researcher, reviewer, and so on) for the individual steps. On a local model served by llama.cpp, such a run takes hours, and it often stops along the way: the lead finishes a step, waits for a permission prompt, asks a question, or the model server degrades. Hawk watches the whole session tree (lead and subagents) and nudges it along. It also pings your phone when a human is actually needed.
Built and tested with OpenCode v1 (1.18.x).
Hawk keeps a run going without blindly spamming "continue".
- Auto-continue. When the worker has stopped and the model is idle, Hawk
injects a self-check prompt telling the agent to re-check the plan and keep
going. It never interrupts a turn that is still generating, and sends at
most one prompt per
re_stall_minutes. - Subagent-aware. It follows the session tree, so a lead that is waiting on a running subagent counts as busy, and every subagent start and finish shows up in the timeline.
- Confirmed finish. The build counts as done only when the agent says
STOP: DONEtwice, on two separate messages. Hawk asks once to confirm. - Done means done. If the session's OpenCode task list still has pending or in-progress tasks, or the done message itself names open work ("7/9 screens", "remaining items", "deferred", "known gaps"), Hawk sends those back and the agent keeps working. The confirmation asks for every plan item with its evidence.
- Decisions go to you. When the agent stops with
STOP: NEEDS_DECISION <question>orSTOP: BLOCKED <reason>, Hawk sends it to your phone and sends nothing into the session until you answer (reply in the ntfy app); it never answers in your place. - Permissions and questions. It auto-accepts external-directory permission prompts and answers question-tool prompts (choosing the "(Recommended)" option) for sessions you mark as monitored.
- Phone alerts and replies via ntfy. Escalations and plan-complete events go to your phone. Reply in the ntfy app and Hawk routes the answer back into the session, so you can unblock a run from anywhere. No account and no port forwarding needed; each install gets its own private topic.
- Dashboard. A local web UI (
http://127.0.0.1:8765) to switch monitoring, auto-accept and auto-continue per session, change settings, and follow the timeline and the ntfy channel.
- Live telemetry. Token speed (prefill and decode), context depth, GPU load
and VRAM charts, including the VRAM used by
llama-serveritself, on Windows and Linux (AMD and NVIDIA). - llama-server watchdog. It detects a dead or degraded
llama-server(low decode speed at deep context) and restarts it, using the start script you set asllama_bat_path.
- Windows 10/11 or Linux. On Linux, GPU stats come from the amdgpu driver
(AMD) or
nvidia-smi(NVIDIA); see Platform notes. - Python 3.10+ and
psutil(pip install -r requirements.txt) - OpenCode v1 (tested with 1.18.x), either the Desktop app or the CLI. Hawk reads its session database
(default
~/.local/share/opencode/opencode.db, override withOPENCODE_DB). - Optional: a local
llama-server(llama.cpp) for the idle and degradation probes and the watchdog. Defaults to port 1234. - Optional: the ntfy app on your phone.
Windows (PowerShell):
irm https://raw.githubusercontent.com/ChakraFusion/opencode-hawk/main/install.ps1 | iexLinux:
curl -fsSL https://raw.githubusercontent.com/ChakraFusion/opencode-hawk/main/install.sh | shThe installer sets up pipx if needed, installs Hawk and starts
the guided hawk setup, so no config file needs editing by hand:
- Phone alerts: a private ntfy topic is generated; subscribe to it in the ntfy app (treat the name like a password) and get a test message.
- llama-server: a running server is detected with its port; if no start script is set, one is written from the running server's exact command line, so Hawk can start the server again if it ever stops.
- Project: the folder your agent works in.
- Failsafe: the watchdog (
hawk install-watchdog) keeps Hawk and llama-server running; optionally the OpenCode restart plugin. - Start: Hawk starts with its dashboard on
http://127.0.0.1:8765.
Run hawk setup again any time to change these. Update with
pipx upgrade opencode-hawk.
Manual install: pipx install git+https://github.com/ChakraFusion/opencode-hawk.git,
then hawk setup (or hawk init and edit config.json yourself).
| Command | What it does |
|---|---|
hawk setup |
Guided setup: phone alerts, llama-server and its start script, project, watchdog, start (--yes takes the defaults) |
hawk init |
Create config.json and the ntfy topic (keeps an existing config) |
hawk run |
Monitor + dashboard (--interval N minutes, --port P, --no-open) |
hawk monitor |
The poll loop only (--interval, --dry-run, --session-id) |
hawk poll |
One pass, e.g. from Task Scheduler or cron (--dry-run) |
hawk dashboard |
The web dashboard only (--port, --open) |
hawk install-task |
Print the schtasks (Windows) or crontab (Linux) entry for hawk poll |
hawk install-plugin |
Install the optional llama-restart plugin into OpenCode (--remove uninstalls) |
hawk ensure |
Failsafe: start Hawk if it is not running; start llama-server if it stays down |
hawk install-watchdog |
Run hawk ensure every 2 minutes via Task Scheduler (no window) or cron (--remove) |
hawk where |
Show the folders Hawk uses |
git clone https://github.com/ChakraFusion/opencode-hawk.git
cd opencode-hawk
pip install -r requirements.txt
python -m opencode_hawk init
python -m opencode_hawk runOr use quickstart.bat / ./quickstart.sh, which open the monitor and the
dashboard in their own windows; quick_kill.bat / ./quick_kill.sh stops both.
Everything lives in config.json. Most timing settings can also be changed
from the dashboard.
| Key | Default | Meaning |
|---|---|---|
project_dir |
"" |
Repository the agent works in (used for git and commit checks) |
session_id |
"" |
Session to watch; empty = newest llama.cpp session |
monitored_sessions |
{} |
Per-session switches: enabled, auto_accept, auto_continue, project_dir |
idle_minutes |
8 |
Quiet time before a session counts as stopped |
poll_minutes |
10 |
Monitor interval (overridden by --interval) |
stalled_turn_minutes |
15 |
An unfinished turn silent this long counts as stopped |
re_stall_minutes |
45 |
Minimum gap between self-check prompts for one session |
continue_message / done_confirm_message |
built-in | The prompts Hawk injects |
done_claim_check |
true |
Send back a STOP: DONE while tasks are open or its own text names open items |
done_claim_max_rejects |
2 |
Send-backs per run; after that the normal confirmation applies and the done alert flags the open items |
done_open_items_message |
built-in | The send-back prompt ({items} = the quoted lines) |
auto_accept_external_dirs |
true |
Auto-accept external-directory permission prompts (monitored sessions only) |
auto_answer_questions |
true |
Auto-answer question-tool prompts |
continue_via_attach |
true |
Inject through the Desktop sidecar so the GUI streams live |
llama_api_port |
1234 |
llama-server API port. Hawk's server is the one listening on this port; llama-server instances you run on other ports are left alone |
llama_bat_path |
"" |
Script that starts llama-server (.bat on Windows, shell script on Linux); the watchdog uses it to respawn a dead server. Empty = no respawn |
llama_pid |
0 |
0 = find llama-server by process name |
gpu_vram_total_mb |
0 |
VRAM shown in charts; 0 = auto-detect |
notify.ntfy.topic |
generated | Your private ntfy topic |
notify.ntfy.server |
https://ntfy.sh |
ntfy server (self-hosted works too) |
notify.ntfy.kinds |
escalation, plan_done, test |
Which events are pushed to the phone |
Where config.json, state and logs live (hawk where prints it): COORD_HOME
when set; in a source checkout the repository folder; otherwise
%APPDATA%\opencode-hawk on Windows and ~/.config/opencode-hawk on Linux.
Other environment variables: OPENCODE_DB, OPENCODE_BIN.
llama-server gets slower as a long session fills its context. Hawk can restart it, but the least disruptive moment is right after OpenCode compacts a session. An OpenCode plugin knows that moment:
hawk install-pluginIt installs local-hawk-llama-restart.ts into OpenCode's global plugin folder
(~/.config/opencode/plugins/; restart OpenCode once to load it). After a
compaction it asks the Hawk dashboard whether a restart is due and triggers it at
the next idle moment. A planned restart is due only when you enabled it
(llama_kill_degraded, "Kill llama when degraded" in the dashboard) and the average
decode speed is below llama_kill_tps; there is no time-based restart unless you
set llama_restart_cadence_min. A dead server is always started again. The
dashboard refuses while a request is in flight and restarts the server with its
exact command line; if that start fails, it falls back to llama_bat_path, so a
restart never leaves the server down; only one start runs at a time, so there is
never a second llama-server. Without a running dashboard the plugin does nothing.
Set HAWK_DASHBOARD_URL if the dashboard is not on http://127.0.0.1:8765.
hawk install-watchdogregisters hawk ensure with Task Scheduler (Windows, every 2 minutes, no window) or
prints the cron line (Linux). It starts Hawk again if the monitor or dashboard is not
running, and starts llama-server via llama_bat_path if it stays down for two checks
while Hawk runs. Only one Hawk monitor and one dashboard can run at a time; a second
one exits at once.
| Windows | Linux | |
|---|---|---|
| GPU load and VRAM | Performance counters (any GPU) | AMD: amdgpu sysfs, no extra tools. NVIDIA: nvidia-smi |
| VRAM used by llama-server | Per-process GPU counters | AMD: the process's DRM fdinfo. NVIDIA: nvidia-smi |
| Disk activity | Performance counters | psutil per-disk busy time |
| RAM stick inventory | WMI | Not shown (needs root) |
| OpenCode Desktop sidecar | OpenCode.exe |
Any opencode* process that exposes the server credentials |
Linux support is new. Bug reports from real Linux setups are welcome.
Windows: start Hawk on its own. Start it from Explorer, a terminal of its own, or Task Scheduler. Started from inside another app (an IDE or AI-assistant terminal), Hawk belongs to that app's process group (job), and an update or restart of that app ends Hawk with it. llama-server, which Hawk starts, always leaves that group, so it keeps running either way.
Hawk's injected prompts tell the agent which markers to use, so normally no extra setup is needed:
| Marker | Meaning |
|---|---|
STOP: DONE |
The whole plan is complete (Hawk asks once to confirm) |
STOP: NEEDS_DECISION ... |
A human decision is needed |
STOP: BLOCKED ... |
A problem the agent cannot solve alone |
Hawk runs locally. The dashboard binds to 127.0.0.1. The only outbound
traffic is to your ntfy server, and only if a topic is configured.
python tests/selftest_coordinator.py
python tests/selftest_dashboard.py
python tests/selftest_notify.py
python tests/selftest_linux.pyCI runs them on Windows and Ubuntu (Python 3.10 and 3.12) and smoke-tests the
installed hawk command.
| Module | Contents |
|---|---|
opencode_hawk/cli.py |
The hawk command |
coordinator.py |
Config and state, OpenCode session DB access, the self-check rule engine, continue injection, escalations, the monitor loop |
probes.py |
Process, llama-server, GPU, disk and RAM probes (Windows) |
hawk_linux.py |
The Linux versions of those probes |
desktop.py |
OpenCode Desktop sidecar discovery, permission and question auto-handling |
dashboard.py |
The dashboard's HTTP server, timeline and settings |
telemetry.py / llama_tasks.py |
Dashboard telemetry sampler and store; llama-server task tracking |
notify.py |
ntfy phone notifications and reply routing |
llama_restart.py |
Planned llama-server restarts |
opencode-plugin/ |
The optional OpenCode plugin (hawk install-plugin) |
probes and desktop share coordinator's namespace (they use core.<name>),
and telemetry / llama_tasks share dashboard's (dash.<name>): a patch on
the main module reaches the split-out code. Import them through the main module.
MIT © ChakraFusion

