Agents use Hum through MCP (hum mcp) or the CLI. Both talk to the same daemon, so you and your
agent see the same processes and logs.
agent ──MCP──▶ hum mcp ──┐
├──▶ hum daemon ──▶ your processes
you ───CLI──▶ hum ───────┘
Each plugin bundles the Hum skill and MCP registration. hum must be on PATH in the agent's
environment. Start a new agent session after installing.
Claude Code:
claude plugin marketplace add brettinternet/hum
claude plugin install hum@humCodex, from a Hum checkout:
codex plugin marketplace add .
codex plugin add hum@humHerdr process picker (needs Python 3.10+; see the plugin guide):
herdr plugin install brettinternet/hum/plugins/herdr --yesPoint the client straight at the hum executable with an absolute path. Do not wrap it in sh -c
or add a project path; each tool call names its project.
claude mcp add --transport stdio hum -- /absolute/path/to/hum mcp # Claude Code
codex mcp add hum -- /absolute/path/to/hum mcp # Codex CLICursor and other mcpServers clients:
{
"mcpServers": {
"hum": {
"command": "/absolute/path/to/hum",
"args": ["mcp"]
}
}
}SSH can carry Hum's CLI or MCP stream; Hum itself has no remote transport.
ssh devbox hum --project /srv/app logs web --stream stderr --tail 100{
"mcpServers": {
"hum-remote": {
"command": "ssh",
"args": ["-T", "-o", "BatchMode=yes", "devbox", "/usr/local/bin/hum", "mcp"]
}
}
}SSH login and host-key checks must work without prompts. Tool calls use remote paths, so pass a
remote absolute project_root such as /srv/app.
| Tool | CLI | Use it to |
|---|---|---|
up |
hum up |
start declarations in after order and wait until ready |
start |
hum start |
start named processes without their prerequisites |
status |
hum status |
check one process; running status automatically includes TCP listeners |
list |
hum list |
list processes; all: true covers every scope; port: 3000 finds Hum listeners machine-wide |
logs |
hum logs |
read bounded output |
wait |
hum wait |
wait for a log match or exit |
events |
hum events |
read recent starts, exits, and failures |
input |
hum input |
answer a TTY prompt once |
restart |
hum restart |
restart and apply a changed definition |
stop |
hum stop |
stop a process and keep its logs |
remove |
hum remove |
stop a process and discard its state |
down |
hum down |
stop the whole project |
signal |
hum signal |
send a signal without changing restart policy |
Every call takes an absolute project_root (resolved to its Git root), or scope: "global" for
machine-wide ad-hoc sessions. Without manifest, manifest-based tools select the nearest
.hum.yaml or hum.yaml from project_root up to the Git root. start, up, restart, and
list also accept manifest to pick an alternate file. Nothing follows forever: logs, wait, and events are bounded, and there is
no arbitrary-command tool.
Example call:
{"name": "logs", "arguments": {"project_root": "/home/me/app", "name": "api", "stream": "stderr", "tail": 50}}Named status automatically includes a running process's current TCP listeners:
hum status api --json{"name": "status", "arguments": {"project_root": "/home/me/app", "name": "api"}}The snapshot is limited to members of that launch's Unix process group or Windows Job Object. Descendants
that escape the group, container runtimes, and forwarding layers such as Docker Desktop or OrbStack are
not included. Results can change immediately after the snapshot; an empty successful result means no
listener was observed at that moment, not that the service is unreachable. Denied, partial, and unavailable
inspection are returned as states with diagnostics. Windows exposes binding-owner PIDs only, not all
inherited socket holders; its results always carry partial and an explanatory diagnostic, even when empty.
To recover a collision across worktrees, call MCP list with port: 3000 (or run hum list --port 3000).
This searches every scope; scope: "global" and explicit all: false cannot be combined with port.
Matching Hum groups include their filtered listener snapshot. Incomplete groups are listed separately so a
negative result is not mistaken for a complete search; foreign processes are never identified or reported.
Full argument, result, and error semantics: MCP adapter.
Start the stack and confirm it is up:
up ──▶ status
If up reports exited_before_ready, timed_out, or skipped (with blocked_by), read the
failing process's logs before changing anything:
logs {name, stream: "stderr", tail: 50} ──▶ fix ──▶ restart {name}
Answer an interactive prompt:
wait {match: "prompt"} ──▶ input {text: "yes\n"} ──▶ wait {match: "complete"}
input sends exact bytes with no added newline, at most once. Bounded logs can replace the first
wait.
Find a match with surrounding lines:
{"name": "logs", "arguments": {"project_root": "/home/me/app", "name": "api", "match": "panic", "context": 5}}To page forward, pass the returned next back as after.
To jump from a failed exit to its logs, read events for the process and find its launch
log_cursor; pass that cursor to logs as after to read its incarnation. The exit
log_cursor marks its last output entry (use it to read later output). If the first launch has
no cursor, omit after. For example:
events {names: ["api"], failed: true} ──▶ events {names: ["api"]} (find preceding launch)
──▶ logs {name: "api", after: <launch log_cursor>}
Pair every log cursor with its output session_id: process snapshots and logs/wait results return it,
and lifecycle events put it in log_session_id. IDs survive stop/start, restart, and automatic
relaunch, but change after hum remove, completed-record eviction, or daemon replacement. Pass both
after and session_id to MCP logs/wait, or --after-cursor and --session-id to CLI logs/wait.
MCP requires the ID whenever after is set; scripts should always pass it. A stale ID returns
cursor_stale; timestamps do not establish cursor validity.
- Prefer
upover a series ofstartcalls. It handlesafterordering, readiness, and setup steps (ready: {exit: 0});startnever pulls in prerequisites. - After editing
hum.yaml, userestart.startandupreportdefinition_driftinstead of adopting changes, and automatic restarts keep the old definition. restart: on-failureretries after 1s, 2s, 4s, 8s, and 16s. While it is retrying,upreportsrecovery_pending; rerunuponce the process is ready. Checkrestart,relaunches, andnext_launch_atinstatus.removediscards runtime state and output; it never editshum.yaml. Usestopto keep logs.signalnever stops automatic restarts, even for TERM or KILL. Usestop.- To restart with work in between,
stop, do the work, thenstart; followers stay attached. - Leave
ttyoff unless a tool truly needs a terminal. Prefer a non-interactive mode such asnpx --yes,CI=1, or--force. - Separate worktrees are separate projects. Pass each worktree's own
project_root.
MCP runs no interactive shell and does not activate mise, nvm, direnv, or similar hooks. Put what a process needs in the manifest:
environment:
inherit: true
files: [.env]
processes:
web:
argv: [bun, run, dev]
env:
PORT: "3000"
OLD_URL: nullValues are literal; Hum never expands $NAME. Environment values never appear in tool results, but
child output is not redacted, so commands should not print secrets. Rules and limits:
Environment.
Without MCP, hum skill prints the embedded Agent Skills file for the agent's skill directory.
Check the JSON contract first, then use --json on CLI commands:
$ hum version --json
{"schema_version":1,"version":"<version>","build_time":"<time>"}
$ hum logs api --stream stderr --tail 50 --json
$ hum wait api --match ready --timeout 30s --jsonSee CLI JSON v1 for the format and Canonical project scopes
for --project and --global.