# Hook CLI
The `hook` binary is built from `crates/cli` and uses `silicon-hook-client` for
all backend and local-service networking. Build it with
`cargo build -p silicon-hook-cli`; the executable is `target/debug/hook`.
Install with `honeycomb install 'tos>hook'`, then run `hook login <slt>` and `hook webhook <webhook-url>`.
Maintainers bundle canonical `docs/` guides into the crate with
`python3 scripts/bundle-cli-docs.py` before publishing; CI rejects stale copies.
## First session
Ask IAM for a short-lived token for `tos>hook`, then provide the token to Hook:
```sh
hook --profile cos iam --json
hook --profile cos --org tos login <slt>
hook --profile cos login status --json
hook --profile cos webhook http://127.0.0.1:9000/events
hook --profile cos --silicon cos:tos create GitHub
hook --profile cos --silicon cos:tos list
```
`hook login <slt>` is the short form required for agents. `--slt-file -` reads
from stdin, and `--slt` remains available for compatibility. Literal tokens can
appear in shell history/process arguments, so use a file or stdin when possible.
Hook does not request your
password, OTP or browser callback. Start the recipient server at the provided
URL before expecting delivery. The login response never prints session tokens.
A successful login saves tokens and a separate local API token, then starts the
persistent daemon and local request gateway. Configure delivery afterward with
`hook webhook <webhook-url>`. Until then, events stay pending. The optional
`login --webhook-url <url>` flag still configures delivery in the same command.
Silicon identities subscribe to their own stream automatically. A Carbon supplies
`--silicon` during login or uses `hook daemon subscribe <silicon-id>...` afterward;
IAM must authorize each Silicon.
`hook iam --json` discovers the actual backend-configured `app_id`, `iam_url`,
`testing` flag and `login_method` before login. With `--test <id>`, it discovers
that environment's IAM application using the locally attached Hook test key.
It never returns an app secret or environment key.
`hook login status --json` refreshes an expiring session, then checks the current
bearer and organization membership online with IAM. Organization selection uses
`--org`, then the selected profile/environment organization, then the session
token organization. For an unscoped Silicon session, Hook derives the organization
from its `name:organization` identity and still verifies it online with IAM. Test
sessions never borrow the production organization. A successful response contains
`authenticated: true`, `actor: {"type": "carbon" | "silicon", "id": "..."}`,
organization, expiry, and local delivery configuration. No saved session or an
invalid/revoked credential reports `authenticated: false`. Transport and permission
failures remain errors, so an outage is not reported as a successful login.
`whoami` remains an offline view of saved metadata.
`hook webhook <webhook-url>` sets or replaces the selected profile/environment's
recipient. It validates the URL locally, stores it beside the tokens, and starts
the daemon if needed. The destination is never sent to the backend. HTTP is
accepted only on loopback: `localhost`, any `*.localhost` name, or a loopback IP
address; remote recipients require HTTPS. Embedded credentials
and fragments are rejected.
`hook unhook` clears only the selected identity's recipient, retaining its login,
stream selection, and local request API. Other identities keep their destinations.
The daemon applies changes within five seconds and cancels old relay work;
in-flight requests may already have reached the old recipient. Events without
an acknowledgment replay after `hook webhook <webhook-url>` reconnects delivery.
Use `hook logout` to revoke authentication.
## Context
Global flags may appear before or after a command:
| `--profile <name>` | Independent local identity and backend; default `default` |
| `--url <origin>` | Override service origin for a new/unbound profile |
| `--org <handle>` | Select the production or test organization |
| `--silicon <id>` | Silicon whose hooks/history/deliveries the action addresses |
| `--test <uuid>` | Select a saved IAM application sandbox and its separate test session |
| `--json` | Machine output with no contextual next-step prose |
| `--idempotency-key <key>` | Stable logical mutation identifier for retries |
`SILICON_HOOK_URL` and `SILICON_HOOK_ORG` provide origin/organization defaults.
A profile with credentials is bound to its backend. Use another profile for a
different backend; this prevents sending saved credentials to the wrong host.
Test commands never fall back to the production session. A signed-in Silicon
is the default target; a Carbon normally supplies `--silicon`.
State lives in `${SILICON_HOME:-~}/.silicon-hook/state.json`. A nonempty
`SILICON_HOME` supplies the default base home. Set another base home with
`hook config home <directory>` (the state then lives below
`<directory>/.silicon-hook`). The location must already be a directory.
`SILICON_HOOK_HOME` remains an environment override for the complete state
directory. Directory mode is 0700 and files are 0600 on Unix. A process
lock serializes refresh and state updates, and replacement is atomic. Keep
this directory private: it contains access/refresh tokens and test root keys.
Do not share it between independent machines refreshing the same token family.
Before rotating a refresh token, the CLI saves an idempotency key in that
session. If the response is lost, retrying the command reuses this key. The key
is cleared only when the replacement tokens are saved successfully; the daemon
uses the same locked refresh path.
## Command reference
Run `hook <command> --help` for complete options and required arguments.
`hook commands` lists every command path; `hook commands --json` includes full
help. `hook docs <topic>` bundles these guides for offline reading.
| `iam --json` | Discover the public IAM app configuration before login |
| `login <slt>` | Save a session and start its local gateway (`--slt-file` and optional `--webhook-url` are supported) |
| `login status --json` | Check authentication and actor online with IAM |
| `webhook <webhook-url>` | Configure or replace local delivery for this identity |
| `unhook` | Detach local delivery while retaining authentication |
| `logout` | Revoke the refresh-token family and remove the selected local session |
| `whoami` | Show actor, organization, expiry and local recipient; no tokens |
| `create <name>` | Create a signed hook; optional description/time-zone/signature |
| `list [--include-deleted]` | List hooks and their current endpoints |
| `show <uuid>` | Read hook metadata and signature policy |
| `update <uuid> --patch <JSON-or-@file>` | Change metadata, activation or signature policy |
| `delete <uuid>` / `restore <uuid>` | Soft-delete or recover within 45 days |
| `enable <uuid>...` / `disable <uuid>...` | Atomically resume/pause several hooks |
| `rotate endpoint <uuid>` | Permanently retire the old URL and issue a new URL |
| `rotate secret <uuid>` | Invalidate the old signing secret immediately |
| `events [--hook <uuid>] [--limit N] [--cursor ...]` | Verified history, per hook or all hooks |
| `blocked [same filters]` | Withheld requests, separate from delivered history |
| `deliveries list [--limit N] [--after N]` | Pull retained pending deliveries |
| `deliveries ack <sequence>` | Cumulative acknowledgment for this identity/Silicon |
| `deliveries cursor` | Read the durable acknowledgment position |
| `connect-iam` | Register a Silicon's IAM webhook connection |
| `listen [--ack]` | Foreground stream inspection; Ctrl-C closes it |
| `system version` / `system health` | Compatibility and backend readiness |
| `env ...` | See the [testing CLI guide](../testing/cli.md) |
| `daemon ...` | Persistent relay and local request interface |
| `config show` / `config profiles` | Inspect local settings and names |
| `config home <directory>` | Set the base home directory for local state |
| `config set <key> <value>` | Set url, org, silicon or telemetry |
Hook deliveries printed by `listen` and posted to the configured webhook use
`{"type":"new_event","data":{"sender":"<provider>","metadata":{...}}}`.
Event details, including the ACK sequence and captured request, are inside
`data.metadata`. See the [complete relay format](../client/relay.md).
History limits are 1–10000, but a byte-bounded page may return fewer items.
Follow `next_cursor` until null. Delivery pull limit is at most 1000.
`listen` answers pings automatically. `listen --ack` ACKs after printing;
without it inspection fills the outstanding window and then waits. Use the
daemon for persistent recipient delivery and reconnect. A daemon using the same
identity may ACK events while you inspect that identity's foreground stream.
## Signature examples
```sh
hook --silicon cos:tos create GitHub --signature @github-policy.json
hook --silicon cos:tos create LocalDemo --unsigned
hook --silicon cos:tos update <uuid> --patch '{"description":null}'
hook --silicon cos:tos update <uuid> --patch '{"signature":{"required":true}}'
```
Create/secret-rotation/environment-key output can contain secrets; redirect
those responses into private files if retaining them. `show` never retrieves a
hook's original signing secret. Use rotation if that secret is lost.
See [the signature reference](../api/README.md#signature-expressions) for the
full expression grammar, algorithms and encodings. Default verification uses
HMAC-SHA256 over `webhook-id.webhook-timestamp.raw-body` and base64 signatures.
## Daemon
```sh
hook daemon start
hook daemon status
hook --profile reviewer daemon subscribe cos:tos helper:tos
hook --profile reviewer daemon token
hook --profile reviewer daemon request --file request.json
hook daemon stop
hook daemon run
```
`run` stays in the foreground and is suitable for a service manager. The
background daemon shares one loopback port across all profiles and environments.
Changes are picked up within five seconds. `subscribe` replaces a selected
identity's list; no IDs unsubscribes all. `token` intentionally prints a secret
for programs calling `http://hook.localhost:18479/request`.
The daemon log is `~/.silicon-hook/relay.log`. Recipient failures retry without
acknowledging upstream. Logging out removes that identity from the daemon.
Stopping it leaves backend events pending. A machine reboot requires starting
the daemon again (login and `daemon start` do this); for boot-time startup run
`hook daemon run` through your operating system's service manager.
The [local API guide](../client/relay.md) defines request/receipt JSON, exact body
echoes, identity tokens and downstream acknowledgment behavior.
## Updates and troubleshooting
Honeycomb manages CLI updates. Hook never replaces its executable. After upgrading, restart a running daemon with `hook daemon stop`, then `hook daemon start`. Source builds are updated explicitly by their owner.
## Bring your own secret (BYOS)
Create with your provider's secret, or set it after registration:
```sh
hook create Stripe --signature @stripe-policy.json --secret-file provider-secret.txt
hook set-secret <hook-uuid> --secret-file provider-secret.txt
hook set-secret <hook-uuid> --secret-file encoded-secret.txt --secret-encoding hex
hook --test <environment-uuid> set-secret <hook-uuid> --secret-file -
```
`--secret-file -` reads stdin. Files preserve spaces and remove only one trailing
LF/CRLF. Empty, multiline, control-character, or over-4096-byte secrets fail.
`create --signature` configures verification and may itself contain `secret`;
do not also supply `--secret-file` in that case. Omitting a secret at creation
generates one. `set-secret` preserves the current encoding unless specified,
and preserves the URL, verification scheme and enabled/required settings.
The previous secret stops verifying immediately. Only creation/rotation prints
a secret; `set-secret` returns public hook metadata.
To update the scheme and secret together, use the existing merge patch:
```sh
hook update <hook-uuid> --patch @byos-patch.json
```
The file can contain `{"signature":{"secret":"provider-secret","secret_encoding":"utf8"}}`
alongside `algorithm`, `payload`, `signature`, and other policy members. These
commands work identically in production and paired testing environments.
## Select an IAM sandbox
Run `hook env use --app-secret-file ./hook-test-app-secret`, then `hook login your-silicon:tos --webhook-url http://127.0.0.1:8080/events`. The selector is validated online and never grants actor authority. Run `hook env exit` to restore the production session. `--production` uses production for one invocation. The active sandbox is printed after every command, error and help output. See [testing instructions](../testing/cli.md).
`hook about` prints project links. `hook report "description" --pr https://github.com/teamofsilicons/silicon-hook/pull/123` submits an explicit issue using authenticated GitHub CLI. Diagnostic telemetry excludes report text.