Skip to content

Commands

All commands follow the pattern wh <domain> <verb> [args] [--flags]. Global flags --repo, --json, --live, --format, and --profile (-P) are available on most commands. Pass --no-update-check on any invocation to skip the CLI update notice for that run.

--format controls output mode: pretty (default), json, or jsonl. When --live is active, json and jsonl emit structured output per update; pretty (or unset) renders a human-readable display.

CommandDescription
wh use <org/repo>Set the default repo for the current directory
wh useShow the active repo context and where it comes from
wh use --clearRemove the .wh context file

Writes a .wh JSON file in the current directory. The CLI resolves the target repo using this priority: --repo flag > WARMHUB_REPO env > .wh file. The repo is validated against the backend before writing.

Terminal window
wh use myorg/world # writes .wh, validates repo exists
wh use # shows active context with provenance
wh use --clear # removes .wh
wh thing list # uses .wh repo (no --repo needed)
CommandDescription
wh org create <name> [--display-name "..."] [--description "..."]Create a new organization. Description is trimmed; max 2000 characters.
wh org view <name>View organization details
wh org list [--include-archived]List organizations (archived hidden by default)
wh org rename <oldName> <newName>Rename an organization
wh org member add <org> <email> [--role role]Add a member or send an invite. Only owners can assign owner role. If the email is not a WarmHub user, a pending invite is created and an invite email is attempted (best-effort, async).
wh org member remove <org> <email>Remove a member or revoke a pending invite
wh org member list <org> [--pending]List members of an organization. Requires authentication and org membership. --pending filters to pending invites only.
wh org member set-role <org> <email> --role <role>Change a member’s role. Only owners can promote to or demote from owner. Cannot demote the last owner.
wh org archive <name> [--yes]Archive an organization (blocks new repos and members)
wh org update <name> --description "..."Update org description. Trimmed; empty strings clear the value; max 2000 characters.
wh org unarchive <name>Unarchive an organization

Aliases: infoview; getview

Roles: owner (full control), admin (manage members and repos), editor (read/write data), viewer (read-only). Default: editor.

wh org create and wh org rename both reject these reserved slugs (case-insensitive): admin, api, billing, blog, docs, help, login, public, settings, signup, status, support, system, warmhub, www.

When a user signs in for the first time, WarmHub provisions a personal org for them. GitHub-linked personal orgs use a login-based slug when available, and collisions receive a suffix. GitHub-linked personal orgs can’t be renamed — wh org rename returns FORBIDDEN. Personal orgs without a linked GitHub login can be renamed normally.

Terminal window
wh org create acme --display-name "Acme Corp"
wh org list
wh org member add acme alice@example.com --role editor
wh org member list acme
wh org member remove acme alice@example.com
CommandDescription
wh repo create <org/name> [--description "..."] [--visibility <public|private>]Create a repo (auto-creates org if needed). Description is trimmed; max 2000 characters.
wh repo list [org] [--include-archived]List repos in an org (archived hidden by default)
wh repo view [org/repo]Show repo details
wh repo describe [org/repo]Describe repo schema: shapes, fields, inline descriptions, and per-shape counts. Shapes from installed component manifests appear with count 0 when no things have been written yet.
wh repo rename <org/oldName> <newName>Rename a repo
wh repo archive <org/repo> [--yes]Archive a repo (blocks new commits)
wh repo update <org/repo> --description "..."Update repo description. Trimmed; empty strings clear the value; max 2000 characters.
wh repo visibility <org/repo> <public|private>Set repo visibility
wh repo unarchive <org/repo>Unarchive a repo
wh repo delete <org/repo> [--hard] [--yes]Delete a repo. Soft by default (hidden immediately; purged after 30-day grace window). --hard runs the purge cascade immediately (owner-only, irreversible). Blocks if another repo holds inbound cross-repo references or subscriptions.

Aliases: initcreate; infoview; getview

wh repo create also accepts --org <org> as a tolerance fallback — wh repo create <name> --org <org> is combined into <org>/<name> and the CLI prints a one-line hint pointing at the canonical positional form. Prefer <org>/<name> in scripts.

Terminal window
wh repo create myorg/world -d "Game world"
wh repo create myorg/world -d "Game world" --visibility public
wh repo list myorg

repo content — README, AGENTS.md, llms.txt

Section titled “repo content — README, AGENTS.md, llms.txt”

WarmHub stores per-repo markdown content as built-in Content instances. Two are stored and editable: Content/Readme (human-facing) and Content/Agents (agent-facing). A third, Content/LlmsTxt, is synthesized per request from the repo’s shapes and content and is read-only.

CommandDescription
wh repo content get <org/repo> --kind readme|agents|llms-txtFetch repo Content markdown by kind.
wh repo content set <org/repo> --kind readme|agents|llms-txt [--content "..." | --file <path>]Set Content markdown (file, inline, or piped stdin). llms-txt is read-only — set attempts are rejected.
wh repo content generate <org/repo> --kind readme|agents|llms-txt [--save]AI-generate Content from the repo’s shapes; --save commits it. llms-txt is read-only — generate attempts are rejected.

set reads from --file <path>, --content "...", or stdin when neither flag is passed. Use --file - to force stdin.

Terminal window
wh repo content get myorg/world --kind readme
wh repo content set myorg/world --kind readme --file README.md
cat README.md | wh repo content set myorg/world --kind readme
wh repo content set myorg/world --kind agents --content "# Agents"
wh repo content generate myorg/world --kind agents --save
wh repo content get myorg/world --kind llms-txt
CommandDescription
wh shape list [--match "glob"] [--include-retracted] [--component id] [--exclude-components]List shapes. Use --include-retracted to show retracted shapes and --exclude-components to hide component-owned shapes.
wh shape view <name> [--include-retracted]Show shape details with field definitions
wh shape create <name> --fields '<json>' [--description '...']Create a new shape
wh shape revise <name> --fields '<json>' [--description '...']Revise shape fields (creates new version)
wh shape retract <name> [--reason '<text>'] [-m msg] [--committer <wref>]Retract a shape, marking it inactive
wh shape history <name> [--include-retracted] [--limit n] [--cursor c] [--all]Show shape version history
wh shape rename <oldName> <newName>Rename a shape

Aliases: headlist; getview; updaterevise

Teaching rejection: wh shape retract <name> exits with a hint to use wh shape retract <name>.

Terminal window
wh shape create Location --fields '{"x":"number","y":"number"}'
wh shape list
wh shape view Location
wh shape revise Location --fields '{"x":"number","y":"number","label":"string"}'
wh shape retract OldShape -m "Withdraw old shape"
CommandDescription
wh thing list [--shape s] [--kind k] [--limit n] [--cursor c] [--all] [--match glob] [--include-retracted] [--count] [--component id] [--exclude-components]Show current HEAD state. Use --count to return only the count of matching items. System-managed component infrastructure records are hidden by default. Use --exclude-components to also hide component-owned data things.
wh thing create <name|Shape/name> [--shape s] --data '<json>' [-m msg] [--committer <wref>]Create a thing. Pass either a qualified Shape/name or an unqualified name with --shape, not both.
wh thing view [<wref>...] [--file <path>] [--version n] [--depth n] [--include-retracted]Show a thing’s details. Variadic: a single wref routes to the single-thing path; multiple wrefs or --file routes to batch fetch (max 500). --depth returns an embedded graph view and cannot be combined with --live. Pretty output includes a by: row with the committer wref when the version was written with --committer. Batch returns { requested, items, missing } in --json; --format jsonl emits one record per deduped requested wref.
wh thing history [wref] [--shape] [--about] [--resolve-collections] [--limit] [--cursor] [--all] [--include-retracted]Show version history. Each version line ends with by <committerWref> when attribution is recorded; the field is also exposed on --json output as versions[].committerWref.
wh thing resolve <wref>Resolve wref to thing identity
wh thing lease <wref> [--ttl <ms>]Acquire a short read lease on a thing and read it in one step. Prints the lease id and expiry. --ttl defaults to 5000 (min 1000, capped at a maximum); a value outside that range is rejected, never clamped.
wh thing revise <name> --data '<json>' [-m msg] [--committer <wref>] [--expected-version <n>] [--lease-id <id>]Revise a thing. --committer is optional; omit to attribute the commit to the authenticated user. Pass --expected-version to apply the revise only if the thing is still at that version (optimistic concurrency). Pass --lease-id to write under a read lease; the lease auto-releases on a successful or no-op write.
wh thing retract <wref> [--kind thing|assertion|shape|collection] [--reason '<text>'] [-m msg] [--committer <wref>] [--lease-id <id>]Retract an entity (thing, assertion, shape, or collection), marking it inactive. --kind is an optional safety check that errors if the resolved entity’s kind doesn’t match. --committer is optional; omit to attribute the commit to the authenticated user. --lease-id writes under a read lease.
wh thing release-lease <wref> --lease-id <id>Release a read lease early when you decide not to write. Idempotent — a non-matching or already-released lease is not an error.
wh thing query [--shape s] [--kind k] [--about wref] [--resolve-collections] [--limit n] [--cursor c] [--all] [--match glob] [--include-retracted] [--count] [--component id] [--exclude-components]Query by filters. Use --count to return only the count. When no --shape is given, system-managed component infrastructure records are hidden by default.
wh thing search <query> [--shape s] [--kind k] [--about wref] [--mode text|vector|hybrid] [--resolve-collections] [--include-retracted] [--limit n] [--cursor c] [--all] [--component id] [--exclude-components]Search by text content. --cursor and --all only apply in text mode. --component and --exclude-components only apply in text mode. In text mode, system-managed component infrastructure records are hidden by default when no --shape is given. --resolve-collections also only applies in text mode.
wh thing refs <wref> [--inbound|--outbound] [--field path] [--limit n --cursor c] [--all]Show things that store this wref in a field (inbound, default) or wrefs stored in this thing’s fields (outbound). Use wh thing about when you want assertions whose about target is this thing. --field filters inbound refs by field path. --cursor requires --limit (cursors are scoped to a specific page size).
wh thing about <wref> [--shape s] [--match glob] [--depth n] [--resolve-collections] [--limit n --cursor c] [--all] [--include-retracted]Show assertions whose about target is this thing. Use --shape or --match to narrow the assertions, --depth to include child assertions about the returned assertions, and --resolve-collections to include assertions about collections containing the target. --cursor requires --limit (cursors are scoped to a specific page size).
wh thing rename <Shape/oldName> <newName>Rename a thing

Aliases: headlist; statuslist; showview; getview

Terminal window
wh thing list --shape Location
wh thing view Location/cave --version 3
wh thing view Location/cave --depth 2
wh thing query --kind assertion --about Location/cave
wh thing search "safe location" --shape Belief --mode hybrid
wh thing history Location/cave --limit 10
wh thing refs Location/cave # inbound refs (default)
wh thing refs Location/cave --field target # filter by field path
wh thing refs Observation/obs1 --outbound # outbound refs
wh thing about Location/cave # assertions about this thing
wh thing about Location/cave --shape Belief # filter assertions by shape
wh thing about Location/cave --depth 2 # include child assertions
wh thing list --count # count all active items
wh thing list --shape Location --count # count by shape
wh thing query --about Location/cave --count # count matching query results
# wh thing view is variadic — batch fetch up to 500 wrefs in one call
wh thing view Player/alice Player/bob Player/cara # variadic positionals
cat wrefs.txt | wh thing view # piped stdin (one wref per line)
wh thing view --file wrefs.txt --version 3 # pin all to @v3 (implies --include-retracted)
wh thing view Player/alice@v1 Player/bob@v2 # per-wref pinning
wh thing view --file=- < wrefs.txt --format jsonl # `--file=-` reads stdin (use the `=`; `--file -` errors with `Flag --file requires a value`)

Batch wh thing view (multiple wrefs or --file) supports three output modes:

  • Pretty (default): Requested N, found N, missing N header, then one line per resolved item with kind label and [RETRACTED]/[draft] markers, then a Missing: block listing wrefs that didn’t resolve.

  • --json (or --format json): a single { requested, items, missing } object — items[] carries the same fields as single-thing view, missing[] is string[] of unresolved wrefs (qualified when applicable).

  • --format jsonl: one JSON record per deduped requested wref, in input order. Inputs from positionals + --file + stdin are unioned and deduped before the round-trip, so a wref supplied twice produces one row. Each row is {requested, found, wref, ...}. The fields below distinguish two wref shapes — the local form (Shape/name, repo-relative) and the canonical form (wh:org/repo/Shape/name, fully qualified for cross-repo reads):

    • requested — the original input string verbatim, so canonical inputs like wh:org/repo/Loc/cave are still identifiable downstream after the backend normalizes them to local form.
    • wref — the local form on hits (e.g. Loc/cave even when the input was canonical), or the version-qualified form from result.missing on misses.
    • found — boolean.

    Correlate input lines to result lines by requested and filter by found without reconstructing the envelope.

Passing --version automatically implies --include-retracted, so retract versions can be retrieved by their pinned id.

--live is rejected in batch mode — batch reads are one-shot. Use wh thing view <wref> --live for per-thing polling.

A read lease gives you a short, exclusive window on a single thing for a read-modify-write cycle. While you hold the lease, another caller’s revise/retract of that thing fails fast with a recoverable LEASE_UNAVAILABLE error. You learn about the conflict before computing a new value, not after the write. Leasing is opt-in: plain wh thing view reads are unaffected, and an expired or released lease falls back to a normal optimistic write.

Terminal window
# 1. Acquire + read in one step (prints lease id and expiry).
wh thing lease Player/alice --ttl 5000
# 2. Compute the new value, then write it back under the lease.
# The lease auto-releases on a successful or no-op write.
wh thing revise Player/alice --data '{"score":2}' --lease-id <id>
# Or hand the lease back early if you decide not to write.
wh thing release-lease Player/alice --lease-id <id>

Notes:

  • wh thing lease is the acquire verb; the plain read verb stays wh thing view. Acquiring requires write access. If another caller already holds an active lease, it fails fast with LEASE_UNAVAILABLE instead of waiting.
  • TTL defaults to 5s and has a fixed 1s floor and an upper bound. An out-of-range --ttl is rejected, never silently clamped.
  • On wh commit submit, --lease-id binds to a single --revise/--retract short-form op and is broadcast to every op of a multi-target --retract. For --ops/--file/--stream writes, carry leaseId inline on the operation instead.
  • A LEASE_UNAVAILABLE error tells you when the current holder’s lease expires, so you can retry after that time.

wh thing graph is a sub-command of the thing domain. It returns a thing with readable about assertions and wref fields embedded as objects. Depth defaults to 2 and is capped at 5. Only data the caller can read is resolved — inaccessible refs stay as string wrefs and the output does not expose internal IDs or denial reasons.

Terminal window
wh thing graph Location/cave
wh thing graph Location/cave --depth 3
wh thing graph Location/cave --depth 2 --json
CommandDescription
wh assertion list [--about wref] [--shape s] [--depth n] [--limit n] [--cursor c] [--all] [--match glob] [--resolve-collections] [--include-retracted] [--count]Browse assertions in HEAD, optionally scoped to assertions about a thing. Use --count to return only the count.
wh assertion view <wref> [--version n] [--depth n] [--include-retracted]Show an assertion’s details (equivalent to wh thing view — assertions are things). --depth returns an embedded graph view instead of the flat assertion record and cannot be combined with global --live.
wh assertion create --shape <s> --about <wref|type:members> [--name n] --data '<json>' [-m msg] [--committer <wref>]Create an assertion. --about accepts either a single wref or a collection (pair:a,b, triple:a,b,c, set:a,b,..., list:a,b,...).
wh assertion revise <wref> --data '<json>' [-m msg] [--committer <wref>]Revise an assertion
wh assertion retract <wref> [--reason '<text>'] [-m msg] [--committer <wref>]Retract an assertion, marking it inactive
wh assertion history <wref> [--include-retracted] [--limit n] [--cursor c] [--all]Show assertion version history

Aliases: headlist; aboutlist --about; assertcreate; showview; getview

Prefer --about for target-scoped assertion lists. A bare target after list is accepted as an agent convenience when translating user phrasing like “assertions about X”.

wh thing view <Assertion/name> also works since assertions are things.

Terminal window
wh assertion create --shape Belief --about Location/cave --data '{"safe":true}'
wh assertion create --shape Pairing --about pair:Location/cave,Location/lake --data '{"connected":true}'
wh assertion list --about Location/cave --shape Belief
wh assertion view Belief/cave-safe --depth 2
wh assertion revise Belief/cave-safe --data '{"safe":true,"confidence":0.9}'
wh thing view Belief/cave-safe
wh assertion list --shape Belief
wh assertion list --count
wh assertion history Belief/cave-safe --include-retracted
CommandDescription
wh commit submit [--ops json] [-f file] [--stream] [--skip-existing] [--add name] [--revise wref] [--retract wref] [--reason text] [flags]Submit a stream of operations. Bare wh commit is equivalent.

wh commit submit is the write entrypoint. Use wh thing history <wref> for the per-thing version trail.

See Commit Submit Deep-Dive for the full breakdown of commit submit flags, including JSONL streaming with --stream, --file *.jsonl, --progress, --chunk-size, and --skip-existing.

Terminal window
wh commit submit --add cave --shape Location --data '{"x":3,"y":7}' -m "Add cave"
wh commit submit --retract Location/old-cave --reason "duplicate" -m "Retract duplicate cave"
wh commit submit --add alice --data '{"score":1}' --add bob --data '{"score":2}' --shape Player -m "seed players"
wh commit submit --file dataset.jsonl --progress -m "Bulk import"
wh commit submit --file dataset.jsonl --skip-existing -m "Resume seed"
cat ops.jsonl | wh commit submit --stream -m "Pipe stream"

--add is repeatable up to 20 operations; pair each with its own --data. See Commit Submit Deep-Dive for cardinality rules.

shape template — Scaffold write operations

Section titled “shape template — Scaffold write operations”

wh shape template is a sub-command of the shape domain. It generates sample operations from shape definitions for use with wh commit submit.

CommandDescription
wh shape template <shape> [shape2 ...] [--operation add|revise|retract] [--kind thing|assertion|shape|collection] [--about wref] [--count n] [--output file]Generate sample operations from shapes. --kind shape and --kind collection are only valid with --operation retract; add/revise accept thing or assertion.
Terminal window
wh shape template Hypothesis
wh shape template Hypothesis --operation retract
wh shape template Hypothesis Evidence --count 3 -o experiment.json
wh shape template Hypothesis --kind assertion --about ResearchTopic/example
CommandDescription
wh init [org/repo] [-d "description"]Install harness hooks and optionally onboard a repo

Aliases: init passes unknown verbs as positional args, so wh init myorg/myrepo works directly.

Terminal window
wh init
wh init myorg/myrepo
wh init myorg/myrepo --description "Demo repo"
CommandDescription
wh doctor [--fix]Run environment and backend health checks

Checks API URL, default repo, backend connectivity, authenticated identity (email plus server-validated scopes and token name for PATs), Claude hooks, and AGENTS.md. If the backend doesn’t recognize your token — for example, when it was issued for a different API URL — the auth check warns, shows the API URL it tried, and suggests running wh auth login. The auth check is skipped when the backend is unreachable. Use --fix to auto-install missing hooks and stanzas.

Terminal window
wh doctor
wh doctor --fix

See Subscriptions for concepts (kinds, filters, retry behavior) and Creating Subscriptions for detailed setup guides.

CommandDescription
wh sub create <name> --kind webhook --on <shape> --filter '<json>' --webhook-url <url> [flags]Create an event-driven webhook subscription bound to a target shape
wh sub create <name> --kind webhook --filter '{"kind":"shape", ...}' --webhook-url <url> [flags]Create a shape lifecycle subscription--on is omitted because the filter scopes matching to shape ops
wh sub create <name> --kind cron --cronspec '<expr>' --webhook-url <url> [flags]Create a cron subscription
wh sub update <name> [flags]Update an existing subscription
wh sub view <name>View subscription details
wh sub list [--limit n]List all subscriptions
wh sub log <name> [--limit n]Tail subscription delivery feed (shows run status and errors)
wh sub attempts <runId>View per-attempt detail for a specific run
wh sub pause <name>Pause a subscription
wh sub resume <name>Resume a paused subscription
wh sub delete <name>Delete a subscription
wh sub bind <name> --credentials <credentialSet>Bind a credential set for webhook auth
wh sub unbind <name>Remove credential binding

Aliases: getview

Delivery / fallback flags

FlagDescription
--onTarget shape — required for most webhook subscriptions; omit for shape lifecycle subscriptions whose filter is {"kind":"shape", ...}
--filterJSON filter expression
--webhook-urlDestination URL for webhook deliveries and cron subscriptions
--fallback-webhook-urlOptional fallback URL called after a terminal delivery failure
--clear-fallback-webhook-urlRemove the configured fallback URL on wh sub update for any subscription kind

Webhook flags

FlagDescription
--onTarget shape — required for most webhook subscriptions; omit for shape lifecycle subscriptions whose filter is {"kind":"shape", ...}
--filterJSON filter expression
--allow-trace-reentryAllow same-chain reentry (write-triggered only)

Cron flags

FlagDescription
--cronspecCron schedule expression
--timezoneIANA timezone for the schedule

Shared flags (webhook only)

FlagDescription
--sourceWatch a different repo in the same org; accepts repoName or orgName/repoName. Not supported for cron subscriptions.

--source pins the subscription to watch a different repo in the same organization. When set, the subscription lives in the repo specified by --repo but fires on writes to the source repo. The action runs in the context of the subscription’s home repo. Not supported for cron subscriptions.

--allow-trace-reentry defaults to false. When omitted, a write-triggered subscription runs at most once in the same causal chain for the same shape. When present, same-chain reentry is allowed, but a global chain-depth safety limit still stops runaway recursion. Cron subscriptions ignore this flag.

Terminal window
# Create a webhook subscription
wh sub create signal-hook --on Signal --kind webhook \
--filter '{"shape":"Signal"}' --webhook-url https://example.com/hook \
--fallback-webhook-url https://example.com/fallback
# Create a shape lifecycle subscription (no --on; filter scopes to shape ops)
wh sub create shape-changes --kind webhook \
--filter '{"kind":"shape"}' --webhook-url https://hooks.example.com/shapes
# Create a cross-repo subscription (watch signals in another repo)
wh sub create cross-hook --on Signal --kind webhook \
--filter '{"shape":"Signal"}' --source myorg/other-repo \
--webhook-url https://example.com/hook
# Allow same-trace reentry for a self-chaining webhook subscription
wh sub create signal-loop --on Echo --kind webhook \
--filter '{"shape":"Echo"}' --webhook-url https://example.com/hook \
--allow-trace-reentry
# Create a cron subscription
wh sub create daily-sync --kind cron \
--cronspec "0 8 * * *" \
--timezone America/New_York \
--webhook-url https://example.com/daily-sync
# Update a webhook subscription
wh sub update signal-hook --on Signal \
--filter '{"shape":"Signal"}' \
--webhook-url https://example.com/new-hook
# Clear a fallback webhook URL
wh sub update signal-hook --clear-fallback-webhook-url
# List and inspect
wh sub list
wh sub view signal-hook
# Tail delivery feed (shows run status, attempt count, errors)
wh sub log signal-hook
wh sub log signal-hook --live
# Drill into a specific run's attempts
wh sub attempts 019d90f0-0000-7000-8000-000000000000
# Credential binding
wh sub bind signal-hook --credentials webhook-keys
wh sub unbind signal-hook

wh sub attempts expects the full dashed run UUID shown by wh sub log. MCP and HTTP action-attempt surfaces use the same canonical run ID.

CommandDescription
wh notifications [--limit n] [--since ts]List repo-scoped action failure notifications
wh notifications [--limit n] [--since ts]Explicit form of the same command

These commands return repo-scoped terminal failure notification records for action deliveries. They are distinct from the web app’s cross-repo user notification feed.

--since accepts either epoch milliseconds or an ISO timestamp.

Terminal window
wh notifications
wh notifications --since 2026-03-30T12:00:00Z
wh notifications --limit 10
CommandDescription
wh auth loginLog in via browser (device authorization)
wh auth login --with-tokenLog in with a JWT piped via stdin
wh auth login --profile <name>Log in to a named profile
wh auth logoutLog out the default profile
wh auth logout --profile <name>Log out a specific profile
wh auth statusShow all profiles and their auth state
wh auth status --profile <name>Show auth state for a specific profile
wh auth whoamiShow the authenticated identity for all profiles
wh auth whoami --profile <name>Show the authenticated identity for a specific profile

The --profile (-P) flag selects which named credential set to use. Without it, commands use the default profile. Each profile stores its own tokens and the API endpoint used at login time.

If you pass a named --profile that doesn’t exist in ~/.warmhub/auth.json, the CLI fails early with a clear error that names the missing profile, lists your available profiles, and suggests wh auth login --profile <name> to create it. (The default profile still returns the standard “not logged in” path when missing, so interactive users aren’t forced through a login hint on first run.)

Terminal window
# Default profile
wh auth login
wh auth status
wh auth logout
# Named profiles (e.g. for different environments)
wh auth login --profile staging --api-url https://api.example.com
wh auth login --profile prod
wh auth status --profile staging
wh auth logout --profile staging
# Piped token into a named profile
echo "$TOKEN" | wh auth login --with-token --profile ci
# Use a profile for any command
wh thing list --repo myorg/myrepo --profile staging

See Getting Access for the full authentication guide.

CommandDescription
wh token create --name <name> [--scope scope]... [--scopes-json json] [-d desc] [--expires duration]Create a new PAT
wh token listList all your tokens
wh token get --name <name>View a token’s details
wh token revoke --name <name>Revoke a token

All token commands require interactive login — PATs cannot manage other PATs. --scope and --scopes-json are mutually exclusive — use one or the other, not both.

Terminal window
# Repo-scoped token
wh token create --name ci-bot --scope myorg/myrepo=repo:read,repo:write
# Org-level wildcard (all repos in org, capped by role)
wh token create --name org-reader --scope myorg=repo:read
# Global wildcard (all resources, capped by role)
wh token create -n deploy --scope repo:write -d "Deploy pipeline" --expires 90d
# Multiple scopes — repeat --scope for each entry
wh token create --name ci-bot \
--scope myorg/private-repo=repo:read,repo:write \
--scope myorg=repo:read \
--expires 90d
# Full access (no --scope flag)
wh token create --name full-access
# Name-restricted scopes (--scopes-json, mutually exclusive with --scope)
wh token create --name scoped-bot --scopes-json '[
{"resource":"myorg/myrepo","permissions":["repo:read"],"allowedMatches":["Signal/*"]}
]'
wh token list
wh token get --name ci-bot
wh token revoke --name ci-bot

See Personal Access Tokens for scopes, lifecycle, and security details.

Credential sets store named keys that subscriptions and actions can bind to. Key names are visible in list/view; values are only accessible via export with a short-lived token.

CommandDescription
wh credential create <name> [--repo org/repo | --org org] [--scope org|repo] [--description "..."]Create an empty credential set. Org-scoped sets are available across repos in the org; repo-scoped sets are repo-only.
wh credential list [--repo org/repo | --org org]List credential sets accessible from a repo or org
wh credential view <name> [--repo org/repo | --org org]View a credential set (key names only, no values)
wh credential set <name> <key> [--repo org/repo | --org org] [--value <value>]Add or update a single key. Reads value from --value or stdin.
wh credential set <name> [--repo org/repo | --org org]Bulk add or update keys. Reads a JSON object from stdin, e.g. {"KEY":"val"}.
wh credential unset <name> <key> [--repo org/repo | --org org]Remove a key
wh credential audit <name> [--repo org/repo | --org org] [--limit n]View the audit log for a credential set
wh credential revoke <name> [--repo org/repo | --org org] [--reason "..."]Revoke the set (blocks new binds and strips auth from existing webhook deliveries)
wh credential delete <name> [--repo org/repo | --org org]Delete a credential set

Aliases: getview

CommandDescription
wh component init <name>Scaffold a new component repository
wh component install com.warmhub.identity --repo org/repoInstall the bundled Identity system component into an existing repo. Bundled system components do not require registry registration or a component package.
wh component install <github-url[@ref]> [--ref ref]Install a component from GitHub. Use @ref suffix or --ref to pin a git ref.
wh component install <org/name> [--ref ref]Install a registered component identity. The CLI resolves the registry entry, downloads source via the backend, and runs optional setup.
wh component install <local-path>Install a component from a local directory
wh component listList installed components
wh component search <query>Search GitHub for component repositories
wh component view <name>Show component details
wh component validate <path>Validate a component package without installing
wh component update <name> [--ref ref]Update a GitHub-sourced or registered component. Local-path installs must be reinstalled with install <path>.
wh component doctor <name>Run health checks on an installed component
wh component teardown <name>Pause subscriptions and mark the component as torn down (non-destructive — shapes and data are preserved)
wh component register <name> --org <org> [flags]Register a component identity in an org for reuse via install <org/name>
wh component unregister <org/name>Remove a registered component identity
wh component registry list --org <org>List registered components in an org
wh component registry view <org/name>View one registered component
wh component registry update <org/name> [flags]Update a registered component

Aliases: showview; getview

Components are declarative packages that bundle shapes, subscriptions, credentials, and seed data into a single installable unit. Each component is identified by a unique componentId and owns the resources it creates — external writes to component-owned shapes, things, and assertions are blocked.

Terminal window
wh component init my-component
wh component install https://github.com/acme/my-component
wh component install warmhub/veritas --repo myorg/world
wh component install ./local-component --repo myorg/world
wh component register veritas --org warmhub --source-url https://github.com/warmhub/veritas-component
wh component registry list --org warmhub
wh component search research
wh component list --repo myorg/world
wh component view my-component --repo myorg/world
wh component validate ./local-component
wh component doctor my-component --repo myorg/world
wh component teardown my-component --repo myorg/world
CommandDescription
wh primePrint CLI context in markdown
wh prime --jsonPrint CLI context as structured JSON

See wh prime for details on output format and token budget.

channel — Real-time repo events in Claude Code

Section titled “channel — Real-time repo events in Claude Code”
CommandDescription
wh channel --repo <org/repo> [--repo <org/repo> ...] [--profile name]Start an MCP channel server that pushes repo events into a Claude Code session

wh channel runs as an MCP server subprocess. Claude Code receives a notification each time a commit is applied or an action run status changes in any watched repo. Each notification includes the affected shapes and things.

Pass --repo multiple times to watch several repos in parallel from one channel server. Use --profile to select a named auth profile.

Setup

Register the channel as an MCP server using the Claude Code CLI:

Terminal window
claude mcp add warmhub -- wh channel --repo org/repo

Or add it manually to your project’s .mcp.json:

{
"mcpServers": {
"warmhub": {
"command": "wh",
"args": ["channel", "--repo", "org/repo"]
}
}
}

During the research preview, start Claude Code with the --dangerously-load-development-channels flag:

Terminal window
claude --dangerously-load-development-channels server:warmhub

Example usage

Terminal window
# Watch a repo and push events into Claude Code
wh channel --repo acme/world
# Watch multiple repos in parallel
wh channel --repo acme/world --repo acme/datasets
# With a named auth profile
wh channel --repo acme/world --profile staging

Notification format

When a commit is applied, Claude sees:

Commit applied to acme/world — affected Player/alice, Score/round-1 (shapes: Player, Score)

When an action run status changes:

Action updated in acme/world — affected Player/alice (shapes: Player)

Limitations

  • Claude Code only — not supported in Claude Desktop, claude.ai, or the web app
  • Events are one-way; use existing wh commands or MCP tools to query data
  • Requires --dangerously-load-development-channels during the research preview