Skip to content

Add Claude Code hooks: marina hooks install - #17

Open
danfry1 wants to merge 1 commit into
mainfrom
feat/agent-hooks
Open

danfry1 wants to merge 1 commit into
mainfrom
feat/agent-hooks

Conversation

@danfry1

@danfry1 danfry1 commented Oct 9, 2026

Copy link
Copy Markdown
Owner

Summary

marina's agent awareness (launchers, sessions, port leases) only took effect when someone ran a command. marina hooks install wires it into every Claude Code session:

event what the agent gets
SessionStart This project's running dev servers ("reuse them rather than starting duplicates"), its existing marina port, and counts of other/orphaned servers.
PreToolUse (Bash) Only for dev-server starts (pnpm dev, npm run dev, vite, cargo run, …): a note if this project's server is already running, or if the command hard-codes a port that belongs elsewhere. Context only.
SessionEnd The servers that session started are stopped (not on /clear or /resume). Opt out with --no-cleanup.
marina hooks install            # user settings (honours CLAUDE_CONFIG_DIR); --project for .claude/settings.json
marina hooks status
marina hooks uninstall

Design notes

  • No permission decision is ever returned. permissionDecision: "allow" would silently auto-approve the command and ask/defer change behaviour; the docs don't state whether additionalContext works without a decision, so this was verified empirically (below).
  • Fast path: the PreToolUse hook runs on every Bash call; non-matching commands return in ~20ms without building a snapshot.
  • Timeouts: each hook sets its own (SessionEnd defaults to a 1.5s budget, too short to stop a server).
  • Never in the way: hooks always exit 0; problems go to stderr (Claude's debug log).
  • Settings safety: key order preserved (serde_json/preserve_order — indexmap was already in the tree), marina's entries identified by their command, user hooks untouched, malformed files refused, atomic writes, one-time settings.json.marina-bak; uninstall restores the original structure.
  • Session-start never creates a port lease (read-only lookup).

Testing

  • cargo fmt --check, clippy -D warnings, cargo test: 136 tests (9 new) — dev-server command detection (incl. a documented harmless false positive), hard-coded port parsing, context text for duplicates / foreign ports / silence, session-target matching, idempotent install preserving key order and user hooks, --no-cleanup, exact-restore uninstall, malformed settings refused, CLI usage errors.
  • Live, with Claude's hook JSON on stdin: /clear and another session's end leave a server alone; the owning session's end stops exactly its server. Install/status/uninstall against a throwaway CLAUDE_CONFIG_DIR restored the file exactly; a malformed file was refused untouched.
  • End-to-end in real Claude Code (one headless Haiku run, project-scoped hooks in a scratch dir): the model reported both the SessionStart context and the PreToolUse note delivered next to the Bash result, and the allowed echo ran normally — confirming context-without-decision works and leaves permissions unchanged. The headless session's own SessionEnd left the other session's server running.

marina's agent awareness previously took effect only when someone ran a
command. `marina hooks install [--project] [--no-cleanup]` registers three
Claude Code command hooks (`marina hook <event>`) so every session uses it:

- SessionStart: additionalContext listing this project's running dev
  servers (reuse rather than duplicate), its existing `marina port` lease
  (read-only), and counts of other / orphaned servers.
- PreToolUse (Bash): for dev-server start commands only, notes when this
  project's server is already running or the command hard-codes a port that
  belongs elsewhere. No permissionDecision is returned, so permissions are
  unchanged ("allow" would auto-approve). Non-matching commands return in
  ~20ms without building a snapshot.
- SessionEnd: stops targets whose launcher session id matches the ended
  session (verified SIGTERM, 2s, SIGKILL). Skipped for /clear and /resume.

Each hook sets its own timeout (SessionEnd's default budget is 1.5s). Hooks
always exit 0. Settings are edited with key order preserved (serde_json
preserve_order; indexmap was already a dependency), marina's entries are
identified by command and other hooks are untouched, malformed files are
refused, writes are atomic with a one-time .marina-bak, and uninstall
restores the original structure. User scope honours CLAUDE_CONFIG_DIR.
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.

1 participant