CLI reference
tama hooks
The halves of adding, changing or keeping a hook, each behind one verb. declare writes the repository documents — the catalogue entry, the registry binding, the reconciled sources and the seal; undeclare is its reverse. release builds the native hooks from published main, installs the ones that changed, and stages, seals and installs the live release this machine runs. warm runs each installed binary once so the operating system's first-execution assessment is paid outside a live event. The packaging verbs — stage, seal, source-identity, install-release, integrity, digest — are the release build's and the installer's own steps, exposed so a person can run and verify each one.
#Invocation
tama hooks declare --file <declaration.json> [--dry-run]
tama hooks undeclare --file <declaration.json> [--dry-run]
tama hooks release [--dry-run] [--enforce <hook-id>,…]
tama hooks warm [--only <hook-id>,…] [--json]
tama hooks running [--json]
tama hooks abandoned [--json]
tama hooks stage --source-root <tree> --release-root <release> --cargo <cargo> [--codesign-identity <id>] [--codesign-timestamp <flag>]
tama hooks seal [--source-root <tree>] <release>
tama hooks source-identity --source-root <tree> [--shell]
tama hooks install-release --release <dir> --home <dir> [--emergency-manifest <file>] [--session-control-only]
tama hooks integrity [--release <dir>] [--home <dir>]
tama hooks digest <file-or-release>
#Verbs
| Verb | Effect on state | Documented in |
|---|---|---|
declare | Writes the catalogue entry, the registry binding and the reconciled sources for one declaration file, then reseals; --dry-run prints the plan and writes nothing. Requires DEVICE_HOOK_EDIT_APPROVED=1 in the operator's own shell; without it the command refuses before writing and prints the command for that shell | hook management |
undeclare | The reverse, in reverse order: each event the registry still binds to the hook is unbound, the catalogue entry is removed, the sources are reconciled and the release is resealed, then the declaration is removed. Same approval, same --dry-run | hook management |
release | Builds from origin/main, installs the one tama program and removes the separate programs an earlier release installed, warms every registry hook, installs the sealed release into the hook runtime, and records the checkout in ~/.tama/installed-from. Stado runs it as the install's after_install step. --enforce <hook-id>... adds those hooks to the machine's selection as tama enforcement add does, keeping every hook already selected | hook management, hook releases |
warm | Runs each installed binary once and prints the state, measured milliseconds, hook id and path per line — warm ran and exited, missing is a registry entry with no binary at that path — and the summary names the costliest. tama request hooks/warm answers the same report | hook warming |
running | Reads the records each session runtime keeps while it runs a hook — one in-flight.<core pid>.<hook pid>.json per running hook in the session-control directory (TAMA_SESSION_CONTROL_ROOT, else ~/Library/Application Support/Tama/session-control), written when the hook's process starts and removed when it ends — and prints per record the event, hook id, the session it runs for (? when the payload named none), how many milliseconds it has run, the hook and core process ids, whether each is alive, and under it every process the hook started that still runs (waiting on pid <n>: <command line>, from ps), which names the call a stuck hook waits on: the vault, a gateway request, a fleet lookup; before them it prints each session's last abandoned dispatch and last turn ending (below). --json prints them as {root, running, abandoned, turnEnds}, the running ones longest first, each with sessionId and waitingOn. A session runtime runs each tool call's hooks on their own thread, so a hook that does not end holds only the call that started it; this names that hook from any other terminal. A stop or user_prompt_submit hook still running when the same hook starts for the next such event of its session is ended by the runtime, so it does not stay listed. A record whose core is gone is reported as left behind, not as running. Exit 1 when the directory or a record cannot be read, and on another argument after its usage line | hook warming |
abandoned | Reads only the register of dispatches the harness stopped waiting for — one abandoned.<session>.json per session in the same directory, the session's last abandonment — and prints per session still running in Tama: <hook> (<event>, <ms> ms) with the session, core pid, time and the signal that proved it, or no dispatch the harness stopped waiting for is recorded (<directory>). It inspects and signals no process, so another product such as oko sessions agents reads it on every look. --json prints {"root", "abandoned", "errors"}; an unreadable record is named on stderr and the command exits one, as is any other argument after its usage line | runtime adapters |
calls --item <id> | Reads every calls.<session>.jsonl in the session-control directory — the tool calls block-unclaimed-calls admitted, each with the items the session held, its tool, its declared purpose and its time — and prints, oldest first, every call kept for that task or defect, matching it in Oko's whole id or the leading part a register prints, in either case: <atMs> <session> <tool>: <purpose>, or no call kept for <id> under <directory>. A last line still without its newline is a call being written and is not read yet. A file that cannot be read, or a complete line in it that is no record, is named with its cause and the command exits one. --json prints {"item", "root", "calls", "errors"}; oko defects show reads it to list the calls beside the item. Real test tests/hooks-running/calls.rs (cargo test -p tama-cli --test hooks_running_calls). | conduct |
stage | Builds, from the source tree, every native program the prepared release's registry runs plus the one tama program, and places them in the release | scripts |
seal | Computes the release's tree digest — every file except release.json and bin/, in sorted path order, each file's path, permission bits and bytes — and writes it as releaseId; refuses the whole release with External hook source is missing for the first external source it cannot open | seal, hook releases |
source-identity | Prints the revision and dirtiness a release of that tree carries; --shell prints them as shell assignments. A missing Git revision reports the failed Git operation and checkout path | scripts |
install-release | Installs a sealed release into a home as one transaction behind two integrity gates, rewriting the registry for that home; one JSON result on stdout on success, and on any failure one line on stderr — Tama hook release installation failed: <reason> — and exit one | scripts, runbook |
integrity | Reports, without writing, whether a release still digests to its seal (--release: recorded vs actual digest and every file written after the seal) and whether every installed tree digests to its directory name (--home, marking current). Without either it reads the installed releases under HOME. A release folder that cannot be listed, or a current link that exists and cannot be read, is refused naming the path (cannot list <path>: …, cannot read <home>/…/current: …) and exits two; no current link marks no release current | scripts, runbook |
digest | Prints a directory's release digest or a file's SHA-256; artifact not found: <path> exits two | seal |
#Records of hooks that ended
A core removes a hook's running record when the hook ends and ends every run it holds when its input closes; a core the system kills does neither. tama hooks running then says which case a record is: core gone; hook still running with nobody waiting for it names an orphaned hook that still runs, with what it waits on. It signals an orphaned hook's process group only when the record carries the hook's birth identity and the process at that id still has it, because a hook process id a dead core recorded may already belong to another program; otherwise the record stays until the hook ends. A record whose hook process has ended runs nothing, whether its core lives or not, and a record that cannot be parsed and that no live supervisor holds locked was left by a writer that ended mid-write (a record is published whole, renamed into place locked). tama hooks running and each core as it starts serving remove both kinds and list them as removed ended hook record <path>: <why> (removed in --json), never as running and never as a lasting error. The real test is tests/hooks-running/left_behind.rs (cargo test -p tama-cli --test hooks_running_left_behind).
#Dispatches the harness stopped waiting for
When a session's harness refuses a tool call at its own handler limit, its refusal names no hook. The session's core learns of it from the harness's next signal and keeps that session's last abandonment as abandoned.<session>.json beside the running records. tama hooks running prints one line per session before the running hooks: still running in Tama: <hook> (<event>, <ms> ms) — session <id>, core pid <pid>, at <ms> ms since the epoch: <signal>, where the signal is the caller's cancel, the call's result arriving, a newer turn event or the end of the turn. --json carries the records under abandoned. A record that cannot be read is named on stderr as abandoned-dispatch register: cannot read abandoned-dispatch record <path>: <error> and the command exits one. The real test is tests/hooks-running/pipes/abandoned.rs (cargo test --manifest-path rust/Cargo.toml -p tama-cli --test hooks_running_abandoned).
Every abandoned run is also a signal: the core hands each hook it still ran to Oko's reflection queue (oko reflection observe --input -) as an observed infrastructure failure of product tama, service tama hook runtime, operation <hook> on <event>, this machine's name as the kernel reports it, the harness's signal as the cause and the run time and session as the state, so Oko's assessment admits the defect without anyone noticing the abandonment first; one observation is kept per machine, hook and event, and a recurrence replaces its cause and state. A refusal of that hand-off is said on the core's stderr with Oko's words. So that the stop gates need not settle a session's open work inside their handler, the core also asks Oko for it after it answers each prompt and stop of the session (oko tasks snapshot --session ID, one settling per session at a time) and records the prompt's arrival as open-work.<session>.json beside these records; the gates refuse a snapshot settled before that prompt.
#How each session's last turn ended
Every stop a session's core receives is kept as turn-end.<session>.json beside the running records, the session's latest turn ending only. The core writes it with reading, the sentence that says what it means: the core has not answered this stop (if the turn ended, it ended with no stop gate's verdict), the stop gates refused this ending; if the turn ended anyway, the harness settled it without the core's answer, the stop gates refused this ending and the core let it through (a provider's refusal of the request or a gate cycle, with the reason it gave), the core could not decide this stop with the error, or every stop gate let the turn end. tama hooks running prints one turn end of session <id> (core pid, received at, answered at): <reading> line per session, then refused by <hook> when one refused and each hook the decision ran with its exit code and run time. --json carries the records under turnEnds; a record that cannot be read is named on stderr as turn-end register: cannot read turn-end record <path>: …, under turnEndErrors in JSON, and the command exits one. Tama Desktop's Session screen shows the selected session's record as Last turn ending with the same reading. The real test is tests/hooks-running/turn-ends/listed.rs (cargo test --manifest-path rust/Cargo.toml -p tama-cli --test hooks_running_turn_ends): a stop the built check-stop-asking refuses is listed with its refusal and hook, an attested stop as let through, and an unreadable record fails the listing by name.
#Exit status
A verb other than those above prints unknown hooks command <name> and the usage, exit two; tama hooks alone, help, -h or --help print the usage and exit zero. Each verb's own refusals are listed on the page that documents it.
Return to the complete CLI tree.