Skip to content

Add hooks extension family across harnesses (+ Antigravity harness support)#46

Open
execsumo wants to merge 12 commits into
mode-io:mainfrom
execsumo:hooks-upstream
Open

Add hooks extension family across harnesses (+ Antigravity harness support)#46
execsumo wants to merge 12 commits into
mode-io:mainfrom
execsumo:hooks-upstream

Conversation

@execsumo

Copy link
Copy Markdown

Summary

Adds a hooks extension family to Skill Manager, harmonized across harnesses, following the existing MCP family architecture. Hooks are stored as normalized records using canonical events (pre_tool_use, post_tool_use, user_prompt_submit, session_start, stop, pre_compact) and canonical tool categories (shell, file_read, file_write, mcp, web, any); each harness codec translates a canonical record into that harness's native event names and config shape and merges it in under managed-state + content-hash tracking.

Because the hooks family includes hooks-for-Antigravity, this branch also includes the Antigravity (agy) harness integration it depends on. Unrelated fork changes (a light theme, a default data-path change) are intentionally excluded from this PR.

Coverage

Harness Hooks Config
Claude Code Full ~/.claude/settings.jsonhooks
Codex Full inline [hooks] in ~/.codex/config.toml
Cursor Full ~/.cursor/hooks.json (category → dedicated event)
OpenCode Partial experimental.hook (file-write + stop only)
Antigravity (agy) Partial name-keyed ~/.gemini/config/hooks.json

Harnesses differ, so not every canonical event maps everywhere. Skill Manager exposes a representability matrix that surfaces gaps and caveats rather than failing silently — e.g. an Antigravity user_prompt_submit hook maps to PreInvocation, which fires before every model invocation (not only on prompt submit), and that caveat is shown in the UI.

Safety / managed-state

Skill Manager owns only the hook entries it writes. Merges preserve foreign hooks and unrelated config keys (verified per harness for each distinct file shape: subtree JSON, inline TOML, version-wrapped JSON, experimental.hook, and name-keyed maps). Managed entries are tracked by content hash; out-of-band edits surface as drifted; pre-existing harness hooks surface as unmanaged for review. Empty/whitespace/malformed config is handled without raising.

Testing

All green locally:

  • Backend: 400 tests pass (bash scripts/test_backend.sh)
  • Frontend: 247/247 pass (npm test)
  • npm run typecheck: clean
  • npm run build: clean

Coverage includes per-harness canonical↔native round-trips, foreign-entry preservation against each file shape, representability gaps/caveats, drift detection, and malformed-config handling, plus a manual cross-harness verification under an isolated HOME.

🤖 Generated with Claude Code

execsumo and others added 12 commits June 13, 2026 12:55
- Add hooks router, schemas, container setup and business logic
- Add comprehensive integration and unit tests for the hooks capability

Co-Authored-By: agy <antigravity-cli>
… registry

- Create hooks feature with components, sheets, API queries, models and localizations
- Add routes and wire hooks into App.tsx and capability registries (overview, sidebar, invalidation)
- Update README with Antigravity (agy) integration details

Co-Authored-By: agy <antigravity-cli>
Add Hooks column to the harness capability matrix (Claude Code: Yes,
others: Not Yet), a How-it-works Hooks section, the hooks manifest
paths, the local-first action, and check off Hook support on the
roadmap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… category terms

- Update HookSpec to utilize canonical event and match properties
- Add data migration path in store from-dict loader for raw Claude Code strings
- Update FastAPI endpoints and request/response validation schemas

Co-Authored-By: agy <antigravity-cli>
…sses

- Add specific hook codecs and representation filters for Codex, Cursor, OpenCode, and Antigravity
- Generalize FileBackedHooksAdapter to delegate layout formatting to codec mappers
- Register hook binding profiles to supported harness definitions in catalog

Co-Authored-By: agy <antigravity-cli>
…sheet views

- Update forms and state keys to submit and read canonical match categories and events
- Re-run OpenAPI type generator to sync typescript clients
- Adjust localizations and controllers to map new schemas

Co-Authored-By: agy <antigravity-cli>
…ecks

- Update HookStoreTests and FileBackedHooksAdapterTests to verify canonical parameters
- Add comprehensive HookRoutesTests verifying config updates for all 5 harnesses
- Add unit mappers tests covering round-tripping and format layout checks

Co-Authored-By: agy <antigravity-cli>
Map canonical user_prompt_submit to Antigravity PreInvocation (flat handler list, no matcher), surface representability caveat, and add round-trip + caveat + foreign-preservation tests.

Co-Authored-By: agy <antigravity-cli>
Hooks now sync across all feasible harnesses, not just Claude Code:
Codex and Cursor are full, OpenCode and Antigravity are partial. Update
the capability matrix and rewrite the How-it-works Hooks section to
describe the canonical event/category model and the representability
matrix (including the Antigravity PreInvocation caveat).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chzh12

chzh12 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Thanks for the PR. I’m not comfortable approving this in the current form.

This adds a full new hooks extension family across backend config writers, OpenAPI/generated types, frontend screens, and multiple harness codecs. That is a large new product and architecture surface, so it needs tighter review and a clear design agreement before merge.

I also see concrete correctness risk in the hook identity model. Some harness mappers appear to key native hook updates/removals by command when the native format does not store an id. That means two different managed hooks using the same command but different events or matchers can overwrite or remove each other. A normalized managed-record model should either preserve identity across those cases or explicitly reject duplicate command shapes with tests.

This PR also inherits the Antigravity managed-location test inconsistency from the Antigravity branch: the label ordering adds Antigravity before Codex while the next assertion still expects that index to point at the Codex root.

Please address the identity/overwrite behavior, fix the inherited Antigravity assertion issue, and consider breaking this into smaller reviewable PRs before it moves forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants