feat(hooks): daemon-first shim + opt-in --daemon install (B, stage 3b)#613
Merged
Conversation
The client half of the hybrid - and the realized latency win. `ax hooks install --all --daemon` swaps the spawned dispatcher for an EFFECT-FREE shim that POSTs to the warm /hooks/eval (#612) and only pays the effect parse on fallback. - shim-core.ts (@ax/hooks-sdk/shim-core, effect-free): `withForwardedEnv` (inject the `_ax_env` bypass allowlist), `runShim` (POST daemon-first with a 2s timeout; on down/timeout/non-2xx LAZY-import the sibling dispatch bundle and run guards locally with the already-read stdin). Standalone bundle = 1.8 KB vs the dispatcher's ~0.9 MB - the fast path is a tiny spawn + a loopback fetch, no effect parse. - dispatch.ts: extract `runDispatchFromStdin` (the shim's fallback entry). - Scaffold + embed the shim (`SHIM_NAME`/`shimScaffoldContent`, sibling-ext aware so .ts falls back to dispatch.ts and the embedded .js to dispatch.js). - install: `--all --daemon` installs the shim; `dispatcherFamilyCommands` + `keepCommand` make a dispatch<->shim switch remove the other entry (no double-fire). Default `--all` (direct dispatcher) unchanged -> zero risk. LIVE-verified against a source-booted `ax serve`: - daemon up: Edit-on-main -> block (warm); + forwarded ALLOW_MAIN_WRITE=1 (in the payload, NOT process.env) -> allow; Read -> allow. - daemon killed: Edit-on-main -> still blocks via the local-bundle fallback. Plus unit tests (withForwardedEnv / isDaemonOutcome / hookEvalUrl, family-switch removal, shim scaffold). 414 hooks tests pass; typecheck (sdk + axctl) exit 0. Completes B. Default install is the dispatcher (size + correctness); `--daemon` is the opt-in latency path, transparent (falls back to the same bundle offline). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deploying ax with
|
| Latest commit: |
6a46573
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://b0a6610a.ax-62d.pages.dev |
| Branch Preview URL: | https://feat-hook-shim.ax-62d.pages.dev |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Stage 3b — the client half of the hybrid dispatcher and the realized latency win, on #612 (the
/hooks/evalendpoint).ax hooks install --all --daemonswaps the spawned dispatcher for an effect-free shim that POSTs to the warm daemon and only pays the effect parse on fallback.Opt-in — default
--all(direct dispatcher) is unchanged, so existing installs are unaffected.What
shim-core.ts(@ax/hooks-sdk/shim-core, effect-free):withForwardedEnv— inject the_ax_envbypass allowlist into the event so the daemon honors the agent'sALLOW_MAIN_WRITE/ALLOW_BRANCH_CHECKOUT/ALLOW_DIRTY_MAIN_MUTATION/AX_SPEND_MODE.runShim— POST daemon-first (2s timeout); on down / timeout / non-2xx, lazy-import the sibling dispatch bundle and run guards locally with the already-read stdin. The standalone bundle is 1.8 KB vs the dispatcher's ~0.9 MB — the fast path is a tiny spawn + a loopback fetch, no effect parse.dispatch.ts— extractrunDispatchFromStdin(the shim's fallback entry).SHIM_NAME/shimScaffoldContent, sibling-ext aware:.tsfalls back todispatch.ts, embedded.jstodispatch.js).--all --daemoninstalls the shim;dispatcherFamilyCommands+ akeepCommandarg make a dispatch↔shim switch remove the other entry so they never double-fire.LIVE-verified
Against a source-booted
ax serve(the/hooks/evalroute is DB-free, so serve boots without the DB):ALLOW_MAIN_WRITE=1process.env)Plus unit tests (
withForwardedEnv/isDaemonOutcome/hookEvalUrl, family-switch removal, shim scaffold). 414 hooks tests pass;typecheck(hooks-sdk + axctl) exit 0.B complete
ax hooks install --all+ repo-free install nudge #603install --all+ repo-free nudgeinstall --allto the dispatcher + migrate legacy (B, stage 2b) #607--all→dispatcher+migrate/hooks/evalendpoint + env-forwarding (server half)--daemonopt-in (client half, latency win)Default install = the dispatcher (install-size + correctness).
--daemon= the opt-in latency path, transparent (same bundle offline).🤖 Generated with Claude Code