hive.terminal-tools-foundations
# ClaudeWave: hive.terminal-tools-foundations This skill teaches the mechanics of Claude's terminal tools, including how processes auto-promote to background jobs after 30 seconds (returning a job_id for polling), the standard output envelope (exit_code, stdout, semantic_status, output_handle for pagination), and when to use higher-level tools like files-tools or gcu-tools instead of raw shell commands. Understanding this prevents orphaned jobs, truncated output surprises, and misinterpretation of benign exit codes like grep returning 1 for no matches.
git clone --depth 1 https://github.com/aden-hive/hive /tmp/hive.terminal-tools-foundations && cp -r /tmp/hive.terminal-tools-foundations/core/framework/skills/_preset_skills/terminal-tools-foundations ~/.claude/skills/hive.terminal-tools-foundationsSKILL.md
# terminal-tools — foundations
These tools give you a real terminal: foreground exec with smart envelopes, background jobs with offset-based log streaming, persistent PTY shells, and filesystem search. Bash-only on POSIX.
## Tool preference (read first)
Before reaching for terminal-tools, check whether a higher-level tool already covers the task. Shell is for system operations the other servers don't reach.
- **Reading files** → `files-tools.read_file` (handles size, paging, line-numbered output) — NOT `terminal_exec("cat ...")`
- **Editing files** → `files-tools.edit_file` (atomic patch with diff verification) — NOT `terminal_exec("sed -i ...")`
- **Writing files** → `files-tools.write_file` — NOT `terminal_exec("echo > ...")`
- **In-project search** → `files-tools.search_files` (project-scoped, code-aware) — use `terminal_rg` only for raw paths outside the project (`/var/log`, `/etc`)
- **Browser / web pages** → `gcu-tools.browser_*` for rendered pages — NOT `terminal_exec("curl ...")`
- **Web search** → `hive_tools.web_search` — NOT scraping
- **System operations** (process exec, jobs, PTYs, raw fs search) → terminal-tools. This is its territory.
## The standard envelope
Every spawn-style call (`terminal_exec`, the auto-promoted job state) returns this shape:
```jsonc
{
"exit_code": 0, // null when auto-backgrounded or pre-spawn error
"stdout": "...", // decoded, truncated to max_output_kb (default 256 KB)
"stderr": "...",
"stdout_truncated_bytes": 0, // > 0 means more is in output_handle
"stderr_truncated_bytes": 0,
"runtime_ms": 42,
"pid": 12345,
"output_handle": null, // "out_<hex>" when truncated — paginate with terminal_output_get
"timed_out": false,
"semantic_status": "ok", // "ok" | "signal" | "error" — read THIS, not just exit_code
"semantic_message": null, // e.g. "No matches found" for grep exit 1
"warning": null, // e.g. "may force-remove files" for rm -rf
"auto_backgrounded": false,
"job_id": null // set when auto_backgrounded=true
}
```
## Auto-promotion (the core mental model)
`terminal_exec` runs commands in the foreground until the **auto-background budget** (default 30s) elapses. Past that point, the process is silently transferred to a background job and the call returns immediately with:
```jsonc
{ "auto_backgrounded": true, "exit_code": null, "job_id": "job_<hex>", ... }
```
When you see `auto_backgrounded: true`, **pivot to polling**. The job is still running:
```
terminal_job_logs(job_id, since_offset=0, wait_until_exit=true, wait_timeout_sec=60)
→ blocks server-side until the job exits or the timeout, returns logs + status
```
You're not failing — you're freed up to do other work while the long task runs.
To force pure-foreground (kill on `timeout_sec`), pass `auto_background_after_sec=0`. Use this when you genuinely don't want a background job (small commands where promotion would surprise you).
## Semantic exit codes — read `semantic_status`, not raw `exit_code`
Several common commands use exit 1 for legitimate non-error states:
| Command | exit 0 | exit 1 |
|---|---|---|
| `grep` / `rg` | matches found | **no matches** (not an error) |
| `find` | success | **some dirs unreadable** (informational) |
| `diff` | identical | **files differ** (informational) |
| `test` / `[` | true | **false** (informational) |
For these, `semantic_status` will be `"ok"` even when `exit_code == 1`, with `semantic_message` describing why ("No matches found"). For everything else, `semantic_status` defaults to `"ok"` on 0 and `"error"` on nonzero.
**Rule**: always check `semantic_status` first. Only fall back to `exit_code` when you need the exact number (e.g. distinguishing `make` errors).
## Destructive warnings — re-read your command
The envelope's `warning` field is set when the command matches a known destructive pattern (`rm -rf`, `git push --force`, `git reset --hard`, `DROP TABLE`, `kubectl delete`, `terraform destroy`, etc.). The command **still ran** — the warning is informational. Use it as a "did I mean to do that?" prompt before trusting subsequent steps that depend on the side effect.
If a `warning` appears unexpectedly, stop and verify: was the destructive action intended, or did a path/glob slip in?
## Output handles — never lose output
When `stdout_truncated_bytes > 0` or `stderr_truncated_bytes > 0`, the inline output was capped at `max_output_kb` (default 256 KB). The full bytes are stashed under `output_handle` for **5 minutes**. Paginate with:
```
terminal_output_get(output_handle, since_offset=0, max_kb=64)
→ { data, offset, next_offset, eof, expired }
```
Track `next_offset` across calls. If `expired: true`, re-run the command (the handle's TTL has lapsed).
The store has a 64 MB cap with LRU eviction. For huge outputs, prefer `terminal_job_start` + `terminal_job_logs` polling (4 MB ring buffer per stream, infinite total throughput).
## Bash, not zsh — even on macOS
`terminal_exec` and `terminal_pty_open` always invoke `/bin/bash`. The user's `$SHELL` is ignored. Explicit `shell="/bin/zsh"` is **rejected** with a clear error. This is a deliberate security stance, not aesthetic — zsh has command/builtin classes (`zmodload`, `=cmd` expansion, `zpty`, `ztcp`, `zf_*`) that bypass bash-shaped checks. The `terminal-tools-pty-sessions` skill explains the implications for PTY sessions specifically.
`ZDOTDIR` and `ZSH_*` env vars are stripped before exec to prevent zsh dotfiles leaking in. Bash dotfiles still apply when invoked interactively (e.g. PTY sessions use `bash --norc --noprofile` to keep things predictable).
## Pipelines and complex commands
Pipes (`|`), redirects (`>`, `<`, `>>`), conditionals (`&&`, `||`, `;`), and globs (`*`, `?`, `[`) are detected automatically. You can pass them with the default `shell=False` and the runtime will transparently route through `/bin/bash -c` and surfaSOP for debugging browser automation failures on complex websites. Use when browser tools fail on specific sites like LinkedIn, Twitter/X, SPAs, or sites with Shadow DOM.
Claim tasks, record step progress, and verify SOP gates in the colony SQLite queue. Applies when your spawn message includes a db_path field.
Proactively extract critical values from tool results into working notes before automatic context pruning destroys them.
Follow a structured recovery decision tree when tool calls fail instead of blindly retrying or giving up.
Maintain a free-form scratchpad of decisions, extracted values, and open questions so context pruning doesn't lose anything you still need.
Periodically self-assess output quality to catch degradation before the judge does.