app
hook
Public Made by Adomby adom
Registry-native cross-agent auto-update hook, plus claude-rc, the keeper for Claude Remote Control. Keeps adom/core apps and skills current from wiki.adom.inc on every Claude Code and Codex prompt, and keeps `claude rc` alive so users can open AI threads on their container from the Claude mobile app or claude.ai/code.
← Commit history
Publish 1.1.2
9 files changed
+345−21
README.md+49−1@@ -1 +1,49 @@-# hook+# adom/hook++**Registry-native, cross-agent auto-update.** Keeps your `adom/core` apps and+skills current from [wiki.adom.inc](https://wiki.adom.inc) automatically, on every+Claude Code and Codex prompt. No git, no private repository.++++## Why++The old update path fetched a private GitHub repo on every prompt. That works for+insiders but cannot be shared, and it only runs under Claude. This hook checks the+public registry instead, so it works for any user and any agent.++## How it works++A `UserPromptSubmit` hook runs a throttled, bounded check (`adompkg outdated`,+~every 30 min). When an installed package is behind the registry, it applies the+update **in the background** and drops a one-line note into the model's context. It+never blocks your prompt.++| Layer | Updates | Cadence |+| --- | --- | --- |+| `adompkg` CLI | its own binary | ~2 h, on use |+| `adom/hook` (this) | installed apps + skills | ~30 min, on prompt |++## Install++```bash+adompkg install adom/hook+```++`adom/core` already depends on it, so a normal bootstrap wires it for you.++## Controls++| Env var | Effect |+| --- | --- |+| `ADOM_HOOK_INTERVAL=<seconds>` | check cadence (default `1800`) |+| `ADOM_HOOK_FORCE=1` | force a check on the next prompt |+| `ADOM_HOOK_DISABLE=1` | disable the hook |++## Uninstall++```bash+adompkg uninstall adom/hook+```++Unwires the hook from both `~/.claude/settings.json` and `~/.codex/hooks.json`.
SKILL.md+46−2@@ -1,4 +1,48 @@ ----name: hook-description: hook+name: adom-hook+description: Registry-native cross-agent auto-update hook; keeps adom/core apps and skills current from wiki.adom.inc on every Claude Code and Codex prompt. ---++# adom-hook++The registry-native, cross-agent auto-update hook. It keeps your `adom/core` apps+and skills current from the wiki registry (wiki.adom.inc) without git or any+private repository.++## What it does++On every Claude Code and Codex prompt (`UserPromptSubmit`), a throttled check runs+`adompkg outdated`. When something installed is behind the registry, it applies the+update in the background (`adompkg update` + `adompkg install adom/core`) and prints+a one-line note into the model's context. It never blocks the prompt.++This is the registry-native replacement for the old gallia `git fetch` hook: same+"stay current automatically" behavior, but sourced from the public registry so it+works for any user and any agent, with no private-GitHub dependency.++## Two layers of auto-update++- **CLI layer** -- `adompkg` self-updates its own binary on use (throttled ~2h).+- **Content layer (this hook)** -- keeps the installed packages (`adom/core`'s apps+ and skills) current, throttled ~30 min.++## Controls++- `ADOM_HOOK_INTERVAL=<seconds>` -- check cadence (default 1800).+- `ADOM_HOOK_FORCE=1` -- force a check on the next prompt (testing).+- `ADOM_HOOK_DISABLE=1` -- disable the hook entirely.++## Install++```+adompkg install adom/hook+```++It is also a dependency of `adom/core`, so a normal bootstrap installs it for you.+`adompkg uninstall adom/hook` unwires it from both agents.++## Note on Codex++The Codex wiring (`~/.codex/hooks.json`) targets Codex's `UserPromptSubmit` event+and its additionalContext channel. Verify against a live Codex install before+relying on it there; the Claude Code path is the verified one.
check-updates.shadded+50@@ -0,0 +1,50 @@+#!/usr/bin/env bash+# adom auto-update hook -- registry-native and cross-agent.+#+# Keeps the adom/core apps and skills current from wiki.adom.inc. No git, no+# private repo. Runs under BOTH Claude Code and Codex `UserPromptSubmit`; its+# stdout becomes the model's additionalContext. Throttled and backgrounded so it+# never blocks a prompt or interrupts the agent.+#+# Tunables (env):+# ADOM_HOOK_INTERVAL seconds between checks (default 1800 = 30 min)+# ADOM_HOOK_FORCE any non-empty value forces a check this run+# ADOM_HOOK_DISABLE any non-empty value disables the hook entirely++[ -n "${ADOM_HOOK_DISABLE:-}" ] && exit 0++# A UserPromptSubmit hook can fire from a non-login shell whose PATH lacks+# ~/.local/bin (where the bootstrap installs adompkg). Without this the check+# silently no-ops ("command -v adompkg" fails). Put the CLI dir on PATH first.+export PATH="$HOME/.local/bin:$PATH"++STAMP="${HOME}/.adom/last-core-check"+INTERVAL="${ADOM_HOOK_INTERVAL:-1800}"+mkdir -p "$(dirname "$STAMP")" 2>/dev/null++now=$(date +%s 2>/dev/null || echo 0)+last=0+[ -f "$STAMP" ] && last=$(stat -c %Y "$STAMP" 2>/dev/null || echo 0)+if [ -z "${ADOM_HOOK_FORCE:-}" ] && [ "$last" -gt 0 ] && [ $(( now - last )) -lt "$INTERVAL" ]; then+ exit 0+fi+# Stamp the attempt up front: a slow or failed check must not re-fire every prompt.+touch "$STAMP" 2>/dev/null++command -v adompkg >/dev/null 2>&1 || exit 0++# Cheap, bounded staleness probe. `adompkg outdated --quiet` exits non-zero when+# an installed package is behind the registry.+if timeout 12 adompkg outdated --quiet >/dev/null 2>&1; then+ exit 0 # everything current+fi++# Behind: apply in the background (detached) so the prompt is never blocked.+# `adompkg update` bumps in-range versions; `install adom/core` re-resolves and+# pulls any newly added core deps. adompkg is resilient (skips needs-sudo+# packages with a note, idempotent on re-run).+( adompkg update >/dev/null 2>&1; adompkg install adom/core >/dev/null 2>&1 ) </dev/null >/dev/null 2>&1 &+disown 2>/dev/null++echo "adom: core skills/apps were behind wiki.adom.inc and are updating in the background now. They will be current within a moment. Continue with the user's request."+exit 0
docs/shot.pngadded⋯ 1 unchanged line ⋯
docs/shot.svgadded+28@@ -0,0 +1,28 @@+<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="600" viewBox="0 0 1000 600">+ <rect width="1000" height="600" rx="14" fill="#0d1117"/>+ <rect x="0" y="0" width="1000" height="44" rx="14" fill="#161b22"/>+ <rect x="0" y="30" width="1000" height="14" fill="#161b22"/>+ <circle cx="26" cy="22" r="6" fill="#ff5f56"/>+ <circle cx="48" cy="22" r="6" fill="#ffbd2e"/>+ <circle cx="70" cy="22" r="6" fill="#27c93f"/>+ <text x="500" y="27" text-anchor="middle" font-family="monospace" font-size="14" fill="#8b949e">adom-hook - UserPromptSubmit</text>+ <g font-family="monospace" font-size="19">+ <text x="30" y="92" fill="#8b949e"># every prompt (throttled ~30m): is core behind the registry?</text>+ <text x="30" y="128" fill="#58a6ff">$</text>+ <text x="56" y="128" fill="#c9d1d9">adompkg outdated --quiet</text>+ <text x="56" y="160" fill="#e3b341"> adom/screenshot-paste 2.1.0 -> 2.3.0</text>+ <text x="56" y="188" fill="#e3b341"> adom/wiki 4.0.1 -> 4.2.0</text>+ <text x="30" y="236" fill="#7ee787">adom: core skills/apps were behind wiki.adom.inc and are</text>+ <text x="30" y="262" fill="#7ee787">updating in the background now. They will be current shortly.</text>+ <text x="30" y="310" fill="#8b949e"># background, detached - the prompt is never blocked</text>+ <text x="30" y="342" fill="#58a6ff">$</text>+ <text x="56" y="342" fill="#c9d1d9">adompkg update && adompkg install adom/core</text>+ <text x="56" y="374" fill="#c9d1d9"> updated adom/screenshot-paste -> 2.3.0</text>+ <text x="56" y="402" fill="#c9d1d9"> updated adom/wiki -> 4.2.0</text>+ <text x="56" y="430" fill="#7ee787"> adom/core is current (16 packages)</text>+ <text x="30" y="486" fill="#8b949e"># no git. no private repo. Claude + Codex. zero clicks.</text>+ </g>+ <rect x="0" y="540" width="1000" height="60" fill="#161b22"/>+ <text x="30" y="577" font-family="monospace" font-size="17" fill="#58a6ff">adom/hook</text>+ <text x="150" y="577" font-family="monospace" font-size="17" fill="#8b949e">registry-native cross-agent auto-update</text>+</svg>
install.sh+74−5@@ -1,6 +1,75 @@-#!/bin/bash-set -e+#!/usr/bin/env bash+# Wire the adom auto-update hook into Claude Code and Codex, idempotently.+set -euo pipefail PKG_DIR="$(cd "$(dirname "$0")" && pwd)"-mkdir -p "$HOME/.claude/skills/hook"-[ -f "$PKG_DIR/SKILL.md" ] && cp "$PKG_DIR/SKILL.md" "$HOME/.claude/skills/hook/SKILL.md"-echo "Installed hook"++HOOK_DIR="${HOME}/.adom/hooks"+HOOK="${HOOK_DIR}/adom-core-update.sh"+mkdir -p "$HOOK_DIR"+install -m 0755 "$PKG_DIR/check-updates.sh" "$HOOK"+HOOK_CMD="bash $HOOK"++if ! command -v python3 >/dev/null 2>&1; then+ echo " warning: python3 not found; cannot wire agent configs. Hook script staged at $HOOK." >&2+ exit 0+fi++# --- Claude Code: ~/.claude/settings.json -> hooks.UserPromptSubmit ---+CLAUDE="${HOME}/.claude/settings.json"+mkdir -p "$(dirname "$CLAUDE")"+python3 - "$CLAUDE" "$HOOK_CMD" <<'PY'+import json, os, sys+path, cmd = sys.argv[1], sys.argv[2]+try:+ with open(path) as f: d = json.load(f)+ if not isinstance(d, dict): d = {}+except Exception:+ d = {}+ups = d.setdefault("hooks", {}).setdefault("UserPromptSubmit", [])+present = any(+ h.get("command") == cmd+ for g in ups if isinstance(g, dict)+ for h in g.get("hooks", []) if isinstance(h, dict)+)+if present:+ print(" adom-core-update already wired in ~/.claude/settings.json")+else:+ ups.append({"hooks": [{"type": "command", "command": cmd, "timeout": 15}]})+ with open(path, "w") as f: json.dump(d, f, indent=2)+ print(" wired adom-core-update into ~/.claude/settings.json")+PY++# --- Codex: ~/.codex/hooks.json -> hooks.UserPromptSubmit ---+# Codex mirrors Claude's hook events and additionalContext channel. This shape is+# best-effort; verify against a live Codex install before relying on it there.+CODEX="${HOME}/.codex/hooks.json"+mkdir -p "$(dirname "$CODEX")"+python3 - "$CODEX" "$HOOK_CMD" <<'PY'+import json, os, sys+path, cmd = sys.argv[1], sys.argv[2]+try:+ with open(path) as f: d = json.load(f)+ if not isinstance(d, dict): d = {}+except Exception:+ d = {}+ups = d.setdefault("hooks", {}).setdefault("UserPromptSubmit", [])+present = any(+ h.get("command") == cmd+ for g in ups if isinstance(g, dict)+ for h in g.get("hooks", []) if isinstance(h, dict)+)+if present:+ print(" adom-core-update already wired in ~/.codex/hooks.json")+else:+ ups.append({"hooks": [{"type": "command", "command": cmd}]})+ with open(path, "w") as f: json.dump(d, f, indent=2)+ print(" wired adom-core-update into ~/.codex/hooks.json")+PY++# Stage the skill doc for discovery.+if [ -f "$PKG_DIR/SKILL.md" ]; then+ mkdir -p "$HOME/.claude/skills/adom-hook"+ cp "$PKG_DIR/SKILL.md" "$HOME/.claude/skills/adom-hook/SKILL.md"+fi++echo "Installed adom-hook (auto-update wired for Claude + Codex; checks every ${ADOM_HOOK_INTERVAL:-1800}s)"
package.json+29−1@@ -1 +1,29 @@-{"slug": "hook", "version": "1.0.1", "type": "app", "org": "adom", "org_id": "681d18d2a224243b0d62c9b2", "description": "Periodic update check hook. Warns when newer versions of installed packages are available.", "dependencies": {}, "scripts": {"install": "./install.sh", "uninstall": "./uninstall.sh"}}+{+ "slug": "hook",+ "version": "1.1.2",+ "type": "app",+ "org": "adom",+ "bundled": true,+ "description": "Registry-native cross-agent auto-update hook. Keeps adom/core apps and skills current from wiki.adom.inc on every Claude Code and Codex prompt, in the background.",+ "dependencies": {},+ "scripts": {+ "install": "./install.sh",+ "uninstall": "./uninstall.sh"+ },+ "tags": ["hook", "auto-update", "bootstrap", "claude-code", "codex", "registry"],+ "discovery_triggers": [+ "auto update skills and apps",+ "keep core packages current",+ "core packages are behind",+ "adompkg update hook",+ "claude code update hook",+ "codex update hook",+ "registry auto update"+ ],+ "hero": {+ "headline": "Always current. Zero clicks.",+ "subhead": "Registry-native auto-update for Claude + Codex",+ "screenshot": "docs/shot.png",+ "accent": "#7ee787"+ }+}
page.json+32−8@@ -1,18 +1,42 @@ { "slug": "hook",- "version": "1.0.1",+ "version": "1.1.2", "type": "app", "org": "adom",- "org_id": "681d18d2a224243b0d62c9b2",- "description": "Periodic update check hook. Warns when newer versions of installed packages are available.",+ "bundled": true,+ "description": "Registry-native cross-agent auto-update hook. Keeps adom/core apps and skills current from wiki.adom.inc on every Claude Code and Codex prompt, in the background.", "dependencies": {}, "scripts": { "install": "./install.sh", "uninstall": "./uninstall.sh" },- "integrity": "sha256-7b2484a6096f147bb768e964d77c9acb12f25d8824a54cfc6f635da6a1b6344c",- "org_name": "adom",- "signature": "AS0NRxP+HUE/7TM+BxUbv/hdxg6hKXu6vpNtfxKqR72fqxHQgySks99V4aXPUWjpzvY1mD9kYVdldFlu9wTYDA==",- "signing_key_id": "fa82062fd5524493",- "_type": "app"+ "tags": [+ "hook",+ "auto-update",+ "bootstrap",+ "claude-code",+ "codex",+ "registry"+ ],+ "discovery_triggers": [+ "auto update skills and apps",+ "keep core packages current",+ "core packages are behind",+ "adompkg update hook",+ "claude code update hook",+ "codex update hook",+ "registry auto update"+ ],+ "hero": {+ "type": "billboard",+ "headline": "Always current. Zero clicks.",+ "subhead": "Registry-native auto-update for Claude + Codex",+ "screenshot": "docs/shot.png",+ "accent": "#7ee787"+ },+ "visibility": "public",+ "author": {+ "name": "Kyle Bergstedt",+ "email": "[email protected]"+ } }
uninstall.sh+37−4@@ -1,4 +1,37 @@-#!/bin/bash-set -e-rm -rf "$HOME/.claude/skills/hook"-echo "Uninstalled hook"+#!/usr/bin/env bash+# Unwire the adom auto-update hook from Claude Code and Codex.+set -euo pipefail+HOOK="${HOME}/.adom/hooks/adom-core-update.sh"+HOOK_CMD="bash $HOOK"++unwire() {+ local path="$1"+ [ -f "$path" ] || return 0+ command -v python3 >/dev/null 2>&1 || return 0+ python3 - "$path" "$HOOK_CMD" <<'PY'+import json, sys+path, cmd = sys.argv[1], sys.argv[2]+try:+ with open(path) as f: d = json.load(f)+except Exception:+ sys.exit(0)+ups = d.get("hooks", {}).get("UserPromptSubmit")+if isinstance(ups, list):+ kept = []+ for g in ups:+ if isinstance(g, dict):+ g["hooks"] = [h for h in g.get("hooks", []) if not (isinstance(h, dict) and h.get("command") == cmd)]+ if g.get("hooks"):+ kept.append(g)+ else:+ kept.append(g)+ d["hooks"]["UserPromptSubmit"] = kept+ with open(path, "w") as f: json.dump(d, f, indent=2)+PY+}++unwire "${HOME}/.claude/settings.json"+unwire "${HOME}/.codex/hooks.json"+rm -f "$HOOK"+rm -rf "${HOME}/.claude/skills/adom-hook"+echo "Removed adom-hook (unwired from Claude + Codex)"