Skip to content

Latest commit

 

History

History
235 lines (180 loc) · 8.56 KB

coding-agents.md

File metadata and controls

235 lines (180 loc) · 8.56 KB

Coding agents

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 ───────┘

Install a plugin

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@hum

Codex, from a Hum checkout:

codex plugin marketplace add .
codex plugin add hum@hum

Herdr process picker (needs Python 3.10+; see the plugin guide):

herdr plugin install brettinternet/hum/plugins/herdr --yes

Register the MCP server manually

Point 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 CLI

Cursor and other mcpServers clients:

{
  "mcpServers": {
    "hum": {
      "command": "/absolute/path/to/hum",
      "args": ["mcp"]
    }
  }
}

Over SSH

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.

Tools

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.

Workflows

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.

Tips

  • Prefer up over a series of start calls. It handles after ordering, readiness, and setup steps (ready: {exit: 0}); start never pulls in prerequisites.
  • After editing hum.yaml, use restart. start and up report definition_drift instead of adopting changes, and automatic restarts keep the old definition.
  • restart: on-failure retries after 1s, 2s, 4s, 8s, and 16s. While it is retrying, up reports recovery_pending; rerun up once the process is ready. Check restart, relaunches, and next_launch_at in status.
  • remove discards runtime state and output; it never edits hum.yaml. Use stop to keep logs.
  • signal never stops automatic restarts, even for TERM or KILL. Use stop.
  • To restart with work in between, stop, do the work, then start; followers stay attached.
  • Leave tty off unless a tool truly needs a terminal. Prefer a non-interactive mode such as npx --yes, CI=1, or --force.
  • Separate worktrees are separate projects. Pass each worktree's own project_root.

Deterministic environments

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: null

Values 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.

Shell-only fallback

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 --json

See CLI JSON v1 for the format and Canonical project scopes for --project and --global.