⭐ Optional support: the interactive repo-local install paths (
./install.shandclawhip installfrom a clone) can offer to star this repo after a successful install whenghis installed and authenticated. Skip it with--skip-star-promptorCLAWHIP_SKIP_STAR_PROMPT=1.
gajae-claw (clawhip) is the control plane for agents: route events from GitHub, Discord, tmux, and other tools to the right human or agent, record what happened, and separate automatic actions from approval-required actions.
Use clawhip when you have an event, a destination, and a policy for whether the next step can happen automatically or needs a human/operator approval. These recipes use placeholder channel IDs and names; replace them with your own public-safe values.
When GitHub reports a pull request event, route it to the project channel so the right maintainer sees it.
# ~/.clawhip/config.toml
[[routes]]
event = "github.pr-status-changed"
filter = { repo = "my-app" }
sink = "discord"
channel = "PROJECT_CHANNEL_ID"
format = "compact"Example event shape:
{
"source": "github",
"event": "pull_request.opened",
"repo": "my-app",
"pr": 42,
"action": "notify",
"target": "PROJECT_CHANNEL_ID"
}Result: clawhip records the routed event and posts a compact PR notification to the project channel.
Let routine CI status flow to the project channel, but reserve an escalation route for repeated failures. Your CI watcher or automation can emit the second-failure event after it observes two failed runs for the same PR or branch.
# ~/.clawhip/config.toml
[[routes]]
event = "github.ci-failed"
filter = { repo = "my-app" }
sink = "discord"
channel = "PROJECT_CHANNEL_ID"
format = "compact"
[[routes]]
event = "ci.failed-twice"
filter = { repo = "my-app" }
sink = "discord"
channel = "ESCALATION_CHANNEL_ID"
format = "alert"Example escalation payload:
{
"source": "ci-watcher",
"event": "ci.failed-twice",
"repo": "my-app",
"branch": "feature/auth-flow",
"summary": "CI failed twice on the same PR; test logs point at integration/auth_test.",
"action": "summarize_and_escalate",
"target": "ESCALATION_CHANNEL_ID"
}Result: normal failures stay low-noise; repeated failures get a short summary in the escalation channel.
Some requests should notify an operator instead of letting an agent act immediately. Send those events to an approval channel and keep the requested action in the message body.
# ~/.clawhip/config.toml
[[routes]]
event = "agent.approval-requested"
filter = { repo = "my-app" }
sink = "discord"
channel = "APPROVAL_CHANNEL_ID"
format = "alert"Example approval event:
{
"source": "agent",
"event": "agent.approval-requested",
"repo": "my-app",
"request": "merge PR #42 after checks pass",
"reason": "merge changes the shared branch and should be operator-approved",
"policy": "approval_required",
"action": "notify_operator",
"target": "APPROVAL_CHANNEL_ID"
}Result: clawhip records the request and alerts an operator; the agent waits for explicit approval before cleanup, merge, or config-changing work.
Human install pitch:
Just tag @openclaw and say: install this https://github.com/Yeachan-Heo/clawhip
Then OpenClaw should:
- clone the repo
- run
install.sh - read
SKILL.mdand attach the skill - scaffold config / presets
- start the daemon
- run live verification for issue / PR / git / tmux / install flows
- Typed event model — incoming events are normalized and validated into typed envelopes before dispatch.
- Multi-delivery router — one event can resolve to zero, one, or many deliveries instead of stopping at the first match.
- Source extraction — git, GitHub, and tmux monitoring now run as explicit sources feeding the daemon queue.
- Sink/render split — rendering is separated from transport; v0.3.0 ships with the Discord sink and default renderer.
- Config compatibility —
[providers.discord]is the preferred config surface, while legacy[discord]still loads.
See ARCHITECTURE.md for the release architecture that ships in v0.3.0.
clawhip no longer treats provider-specific launch wrappers as the public integration surface. Codex and Claude own session launch plus hook registration; clawhip stays the routing, normalization, and delivery layer.
Shared v1 hook events:
SessionStartPreToolUsePostToolUseUserPromptSubmitStop
Local ingress for sample payloads and manual verification:
clawhip native hook --provider codex --file payload.json
clawhip native hook --provider claude --file payload.json
cat payload.json | clawhip native hook --provider codexRecommended installation model:
- install the shared clawhip bridge in
~/.clawhip/hooks/native-hook.mjs - for Codex, align with the official hook contract: use either
~/.codex/hooks.jsonor<repo>/.codex/hooks.json - for Claude Code, install the provider-native hook config globally in
~/.claude/settings.json - keep provider config in the provider-owned config files
- keep routing metadata in
.clawhip/project.json - use
.clawhip/hooks/only for additive augmentation such as frontmatter or recent context
clawhip still pairs well with tmux when you want keyword/stale monitoring, but tmux is now optional and no longer the primary hook-registration surface.
For tmux-backed recovery into an already-running hooked session, use:
clawhip deliver --session <tmux-session> --prompt "..." --max-enters 4clawhip deliver validates repo-local prompt-submit hook setup, confirms the target pane is an
active Codex/Claude (including OMC/OMX wrapper) session, then retries Enter until
.clawhip/state/prompt-submit.json changes or the bounded retry limit is reached.
clawhip now documents a Claw OS-style memory pattern where MEMORY.md is the hot pointer/index layer and detailed memory lives in structured filesystem shards under memory/.
Use this when you want:
- a small, fast memory surface for agents
- durable project/channel/daily memory in files
- explicit read/write routing instead of one giant note
- ongoing memory refactoring as part of operations
Start here:
- docs/memory-offload-architecture.md
- docs/memory-offload-guide.md
- docs/examples/MEMORY.example.md
- skills/memory-offload/SKILL.md
Runtime support now includes a small bootstrap/inspection surface:
# create a scaffold in the current repo
clawhip memory init --project clawhip --channel discord-alerts --agent codex
# inspect whether the expected files and directories exist
clawhip memory status --project clawhip --channel discord-alerts --agent codexclawhip memory init creates MEMORY.md, memory/README.md, a daily shard, a project shard,
topic files, and optional channel/agent shards without overwriting existing files unless you pass
--force.
clawhip now includes a simple plugins/ directory for tool-specific shell bridges.
Each plugin lives in its own subdirectory with:
plugin.tomlfor lightweight metadatabridge.shfor shell hook entrypoints
Built-in starter plugins:
plugins/codex/plugins/claude-code/
List installed plugins with:
clawhip plugin listOperational spec for OpenClaw / Clawdbot agents consuming this repo.
Repo role:
- executable/runtime repo
- daemon-first Discord notification gateway
- typed event routing runtime
- extracted Git/GitHub/tmux source monitors
- multi-delivery router with renderer/sink separation
- lifecycle surface: install / update / uninstall / start / status
Attachment model:
- repo = runtime
SKILL.md= attach/install/usage instructions for OpenClaw / Clawdbot- README = agent-facing operational spec
Default daemon endpoint:
http://127.0.0.1:25294
Primary install entrypoint:
@openclaw install <repo_url>
Expected downstream automation behavior:
- clone repo
- run
./install.sh - read
SKILL.md - attach skill
- scaffold config / presets
- start daemon
- run live verification
Reference repo URL:
https://github.com/Yeachan-Heo/clawhip
Recommended: Create a dedicated Discord bot for clawhip. Do not reuse your Clawdbot / OpenClaw bot token.
clawhip sends high-volume notifications (commits, PRs, tmux keyword alerts, stale warnings). Using a separate bot keeps these cleanly separated from your AI chat bot.
- Create a new bot at Discord Developer Portal (e.g. "CCNotifier")
- Copy the bot token
- Invite to your server with Send Messages permission
- Set the token in config:
[providers.discord]
token = "your-dedicated-clawhip-bot-token"
default_channel = "your-default-channel-id"
[dispatch]
routine_batch_window_secs = 5
ci_batch_window_secs = 300Legacy [discord] config is still accepted and normalized at load time.
[dispatch].routine_batch_window_secs controls the default Discord-only routine burst batch window. Leave it unset to keep the 5-second default, or set it to 0 to disable routine batching entirely. In v1, grouped routine bursts suppress route/event mentions for 2+ items, while explicit failure/stale/CI paths still bypass the routine batcher.
[dispatch].ci_batch_window_secs controls how long clawhip waits before flushing a GitHub CI batch summary. Leave it unset to keep the 30-second default, or increase it for longer workflows that finish jobs over several minutes.
Webhook mode works without a bot token.
Quick start:
clawhip setup --webhook "https://discord.com/api/webhooks/..."Bounded setup presets also support:
clawhip setup \
--bot-token "discord-bot-token" \
--default-channel "1234567890" \
--default-format alert \
--daemon-base-url "http://127.0.0.1:25294"clawhip setup stays non-interactive and intentionally limited to five presets only:
- Discord webhook quickstart route
- Discord bot token
- Default channel
- Default message format
- Daemon base URL
Advanced routes and monitor definitions are still edited manually in the config file or revisited through the bounded clawhip config editor surface.
Route example:
[[routes]]
event = "tmux.keyword"
sink = "discord"
webhook = "https://discord.com/api/webhooks/..."Slack webhook routes work without a bot token.
- In Slack, open the app settings for your workspace and enable Incoming Webhooks
- Add a new webhook to the channel you want clawhip to notify
- Copy the generated
https://hooks.slack.com/services/...URL into a route
Route examples:
[[routes]]
event = "git.commit"
filter = { repo = "my-app" }
slack_webhook = "https://hooks.slack.com/services/T.../B.../xxx"
format = "compact"
[[routes]]
event = "tmux.keyword"
sink = "slack"
webhook = "https://hooks.slack.com/services/T.../B.../yyy"
format = "alert"[CLI / webhook / git / GitHub / tmux]
-> [sources]
-> [mpsc queue]
-> [dispatcher]
-> [router -> renderer -> Discord/Slack sink]
-> [Discord REST / Slack webhook delivery]
Input sources in v0.3.0:
- CLI thin clients and custom events
- GitHub webhook ingress plus GitHub polling source
- git monitor source
- tmux monitor source
clawhip tmux new/clawhip tmux watchregistration path
Input:
clawhip send --channel <id> --message "text"Behavior:
- POST to daemon
/api/event - daemon routes event
- Discord message emitted
Verification:
clawhip status- inspect configured Discord channel for rendered payload
Input:
- GitHub webhook
issues.opened - built-in GitHub issue monitor detection
- CLI thin client
clawhip github issue-opened ...
Behavior:
- emit
github.issue-opened - route via
github.* - apply repo filter
- prepend route mention if configured
- send to Discord
Verification:
- create real issue
- confirm final Discord body contains:
- repo
- issue number
- title
- mention when configured
Input:
- GitHub webhook
issue_comment.created - built-in GitHub issue monitor comment delta
Behavior:
- emit
github.issue-commented - route via
github.* - apply repo filter
- prepend route mention if configured
Verification:
- add real issue comment
- confirm final Discord message body in target channel
Input:
- GitHub webhook
issues.closed - built-in GitHub issue monitor state transition
Behavior:
- emit
github.issue-closed - route via
github.* - apply repo filter
- prepend route mention if configured
Verification:
- close real issue
- confirm final Discord message body in target channel
Input:
- GitHub webhook
pull_request.* - built-in PR monitor state changes
- CLI thin client
clawhip github pr-status-changed ...
Behavior:
- emit
github.pr-status-changed - route via
github.* - apply repo filter
- prepend route mention if configured
Verification:
- open real PR
- merge / close PR
- confirm final Discord message body in target channel
Input:
- built-in git monitor polling local repo
- CLI thin client
clawhip git commit ...
Behavior:
- emit
git.commit - route through git/github family matching
- preserve repo-based route filtering
- prepend route mention if configured
Verification:
- create real empty commit in monitored repo
- confirm final Discord body contains commit summary and mention
Canonical native routing now starts from provider-native Codex and Claude hook payloads and
enters clawhip through clawhip native hook.
Shared v1 hook events:
SessionStartPreToolUsePostToolUseUserPromptSubmitStop
Stable routing metadata (when available):
providereventsession_iddirectoryworktree_pathrepo_nameprojectbranchtool_namecommandsummaryevent_timestamp
Augmentation rules:
- provider input + clawhip project metadata define the immutable base contract
.clawhip/hooks/scripts may only add fields or enrich message/context- augmenters must not remove or overwrite base routing keys
Route guidance:
- prefer filters like
provider,event,repo_name,project, andbranch - avoid route logic that depends on rendered message text
- keep provider-specific extras out of the shared v1 route surface until explicitly adopted
See docs/native-event-contract.md for the routing/augmentation
guide and docs/event-contract-v1.md for the frozen shared-event
reference.
Input:
clawhip agent started --name worker-1 --session sess-123 --project my-repo
clawhip agent blocked --name worker-1 --summary "waiting for review"
clawhip agent finished --name worker-1 --elapsed 300 --summary "PR created"
clawhip agent failed --name worker-1 --error "build failed"Behavior:
- emit
agent.started,agent.blocked,agent.finished, oragent.failed - route via
agent.* - apply optional project/session filters
- include status / elapsed / summary / error details in rendered messages
- prepend route mention if configured
Verification:
- send each CLI event against a running daemon
- confirm final Discord body contains agent name and lifecycle state
- confirm
agent.*route rules match each event type
Input:
- built-in tmux monitor detects configured keyword
- CLI thin client
clawhip tmux keyword ...
Behavior:
- emit
tmux.keyword - route via
tmux.* - prepend route mention if configured
Verification:
- print configured keyword in real monitored tmux session
- confirm final Discord body in target channel
Input:
- built-in tmux stale detection
- CLI thin client
clawhip tmux stale ...
Behavior:
- emit
tmux.stale - route via
tmux.* - prepend route mention if configured
Verification:
- let real tmux session idle past threshold
- confirm final Discord body in target channel
Preferred input:
clawhip native hook --provider codex --file payload.json
clawhip native hook --provider claude --file payload.json
clawhip tmux listFallback/debug input:
clawhip tmux new -s <session> \
--mention '<@id>' \
--keywords 'error,PR created,FAILED,complete' \
--stale-minutes 10 \
--format alert \
--retry-enter true \
--retry-enter-count 4 \
--retry-enter-delay-ms 250 \
--shell /bin/zsh \
-- command args
clawhip tmux watch -s <existing-session> \
--mention '<@id>' \
--keywords 'error,PR created,FAILED,complete' \
--stale-minutes 10 \
--format alert \
--retry-enter true
clawhip deliver \
--session <existing-session> \
--prompt "continue from the latest blocker and open a PR to dev" \
--max-enters 4Behavior:
- Codex and Claude should own session launch and hook registration
clawhip native hookis the local thin-client ingress for provider payloadstmux new/tmux watchare fallback paths for debugging or manual recoverydeliveris the prompt recovery path for an already-running hooked tmux-backed provider sessiontmux listshows active daemon-known watches with source, registration timestamp, and parent-process info- final delivery still goes through daemon routing
deliverrefuses arbitrary shells and requires prompt-submit-aware hook setup (clawhip hooks install --provider codex --scope global|projectfor Codex, with the bridge in~/.clawhip, orclawhip hooks install --provider claude-code --scope globalfor Claude Code)
Routing note:
- session names are labels for operators, not routing authority
- project metadata should be the source of truth for routing
- broad prefix monitors like
clawhip*are dangerous because they can overlap with launcher-registered watches and create stale/keyword noise
Verification:
- launch a real Codex or Claude session with provider-native hooks enabled
- verify the tmux pane is actually alive
- confirm routed delivery in Discord
- if alert text conflicts with pane reality, trust the pane and inspect monitor registrations
Input:
./install.sh
clawhip install
clawhip update --restart
clawhip uninstall --remove-systemd --remove-configBehavior:
- install binary from git clone
- ensure config dir exists
- optional systemd install
- optional post-install GitHub star prompt on interactive local installs
- update rebuilds/reinstalls and optionally restarts daemon
- uninstall removes runtime artifacts
Verification:
clawhip --helpclawhip statussystemctl status clawhipwhen systemd-enabled
github.issue-openedgithub.issue-commentedgithub.issue-closedgithub.pr-status-changed
git.commitgit.branch-changed
agent.startedagent.blockedagent.finishedagent.failed
session.startedsession.blockedsession.finishedsession.failedsession.retry-neededsession.pr-createdsession.test-startedsession.test-finishedsession.test-failedsession.handoff-needed
tmux.keywordtmux.stale
Config file:
~/.clawhip/config.toml
Route model:
[[routes]]
event = "github.*"
filter = { repo = "clawhip" }
sink = "discord"
channel = "PROJECT_CHANNEL_ID"
mention = "@maintainer-or-team"
format = "compact"
allow_dynamic_tokens = false
[[routes]]
event = "session.*"
filter = { tool = "omx", repo_name = "clawhip" }
sink = "discord"
channel = "PROJECT_CHANNEL_ID"
format = "compact"
allow_dynamic_tokens = false
[[routes]]
event = "session.*"
filter = { tool = "omx", repo_name = "clawhip", session_id = "sess-123" }
sink = "discord"
thread = "DISCORD_THREAD_ID"
format = "compact"
allow_dynamic_tokens = false
[[routes]]
event = "agent.*"
filter = { project = "clawhip" }
sink = "discord"
channel = "PROJECT_CHANNEL_ID"
format = "alert"
allow_dynamic_tokens = falseResolution rules:
- event family match
- payload filter match
- route sink / target / format / template / mention applied
- default fallback used if route fields absent
Discord thread targets:
- Use
thread = "DISCORD_THREAD_ID"on a Discord route to deliver directly into a thread. This is explicit; clawhip does not infer threads fromchannelIDs, names, session labels, or payload fields. - A Discord route may set exactly one delivery target:
channel,thread, orwebhook. - Thread delivery uses the configured thread ID as the Discord message target. If Discord reports the thread as archived, missing, forbidden, or otherwise unreachable, clawhip records a concise delivery error and does not automatically fall back to the parent channel.
- Diagnostics and binding verification only reference configured IDs and status outcomes; clawhip does not list or dump private channel/thread inventories.
When clawhip sends through a local Clawdbot gateway, route channel IDs must also be present in the gateway's Discord allowlist. Check that boundary with:
clawhip config verify-gateway-allowlist
clawhip config verify-gateway-allowlist --gateway-config ~/.clawdbot/clawdbot.json
clawhip config verify-gateway-allowlist --jsonThe default gateway config path is ~/.clawdbot/clawdbot.json when HOME is
available; use --gateway-config <path> for any other local file. The command
reads only channels.discord.guilds[*].channels.<channel_id>.allow = true,
compares it with clawhip's configured Discord channel destinations, and exits
non-zero when any destination is missing or not explicitly allowed.
Output is public-safe by design: text and JSON reports include counts, clawhip source labels, and channel IDs only. They do not dump gateway tokens, webhook URLs, raw config payloads, or unrelated gateway fields. Webhooks, Slack routes, localfile routes, and thread-only targets are outside this allowlist check.
Only for routes with:
allow_dynamic_tokens = trueSupported tokens:
{repo}{number}{title}{session}{keyword}{sh:...}{tmux_tail:session:lines}{file_tail:/path:lines}{env:NAME}{now}{iso_time}
Safety:
- allowlisted token kinds only
- route-level opt-in only
- short timeout
- output cap
cargo install clawhipPublished at crates.io/crates/clawhip. Requires Rust toolchain.
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/Yeachan-Heo/clawhip/releases/latest/download/clawhip-installer.sh | shThis installs the latest prebuilt clawhip binary from GitHub Releases into $CARGO_HOME/bin (typically ~/.cargo/bin).
Release artifacts are generated for these Rust target triples: x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu, x86_64-apple-darwin, and aarch64-apple-darwin.
./install.sh
./install.sh --systemdinstall.sh now tries the latest prebuilt release first and falls back to cargo install --path . --force when a matching release asset is unavailable. If Cargo is needed for the fallback path but not installed, the script prints Rustup setup instructions. When --systemd is used, the installed binary is also copied to /usr/local/bin/clawhip so the bundled service unit can start it.
In interactive terminals, both the repo-local installer and clawhip install may offer an optional post-install GitHub star prompt via authenticated gh api access. It never runs automatically, is skipped when gh is missing or unauthenticated, and can be disabled with ./install.sh --skip-star-prompt, clawhip install --skip-star-prompt, or CLAWHIP_SKIP_STAR_PROMPT=1.
clawhip install
clawhip install --systemd
clawhip install --skip-star-prompt
clawhip update --restart
clawhip uninstall
clawhip uninstall --remove-systemd --remove-configclawhip install now matches the repo-local installer's optional GitHub star prompt behavior: it only appears in interactive terminals, is skipped when gh is missing or unauthenticated, never stars automatically, and can be disabled with clawhip install --skip-star-prompt or CLAWHIP_SKIP_STAR_PROMPT=1 clawhip install.
Unit file:
deploy/clawhip.service
Expected install path:
- copy to
/etc/systemd/system/clawhip.service systemctl daemon-reloadsystemctl enable --now clawhip
Use:
docs/live-verification.mdscripts/live-verify-default-presets.shscripts/internal-pr-format-gate.shfor cheap local format gating before internal PR create/update flows
Required live sign-off presets:
- issue opened
- issue commented
- issue closed
- PR opened
- PR status changed
- PR merged
- git commit
- provider-native shared hook events
- tmux keyword
- tmux stale
- tmux wrapper
- tmux watch
- install/update/uninstall
clawhip # start daemon
clawhip status # daemon health
clawhip config # bounded preset editor / config inspection
clawhip config verify-gateway-allowlist # check Clawdbot gateway allowlist coverage
clawhip send ... # thin client custom event
clawhip github ... # thin client GitHub event
clawhip git ... # thin client git event
clawhip agent ... # thin client agent lifecycle event
clawhip native hook ... # provider-native hook thin client
clawhip tmux ... # thin client / wrapper surface
clawhip plugin list # list installed/bundled shell-hook plugins
clawhip gajae status # check local GAJAE CLI bridge availabilityclawhip gajae provides a small Rust CLI bridge for local GAJAE dogfooding:
clawhip gajae status
clawhip gajae profile install
clawhip gajae preflight
clawhip gajae doctor --repo owner/repo
clawhip gajae profile verifystatus discovers GAJAE from GAJAE_BIN first, then the gajae executable on PATH, and verifies it by running gajae --help. profile install forwards to gajae clawhip profile install with stdout/stderr attached so GAJAE owns the profile update flow. preflight is the #257 public-safe readiness check: it verifies GAJAE discovery, required receipt validators, the installed clawhip profile, public-safe output mode, and disabled raw-payload export, then prints a concise JSON summary safe to paste into issues or PRs. Preflight does not mutate cron/config, does not contact GitHub, and does not require GAJAE for baseline clawhip routing. doctor extends those bounded diagnostics with schema capability, handler-command drift, and optional dry-run onboard-plan checks. profile verify checks the installed profile and handler commands without executing routes. Doctor and verify never run gajae clawhip profile install and never mutate live profiles.
GAJAE route handlers are daemon-side and default off. Enable them explicitly and attach a bounded handler to an approved route:
[gajae]
handlers_enabled = true
handler_timeout_ms = 5000
handler_max_output_bytes = 16384
[[routes]]
event = "github.pr-*"
filter = { repo = "clawhip" }
sink = "discord"
channel = "OPS_CHANNEL_ID"
gajae = { subcommand = "handle-event", args = ["--profile", "safe"] }Handler execution uses the GAJAE_BIN override or gajae on PATH, runs only fixed allowlisted GAJAE handler subcommands, passes the event JSON on child stdin, closes parent stdin, enforces timeout/output caps, and emits gajae.handler.completed, gajae.handler.failed, gajae.handler.timeout, or gajae.handler.approval-required through normal routing. Handler output is data-only; mutation-shaped output is converted to an approval-required event instead of being applied automatically.
Before opening or updating an internal PR from a Rust worktree, run:
scripts/internal-pr-format-gate.shIf you already know the tree just needs formatting, auto-fix first:
scripts/internal-pr-format-gate.sh --fixThis catches the cheapest class of red CI (cargo fmt only) locally before PR create/update churn.
clawhip includes a geobench product spec for measuring LLM hit rate, MRR, share of voice, and citations for event-to-channel AI-agent operations queries.
- Spec:
geobench/clawhip.yaml - Runbook:
docs/geobench.md
