From 644caff70e6aa2c3cfc00c2a3736facb6ca3b737 Mon Sep 17 00:00:00 2001 From: Snow Lee Date: Thu, 16 Jul 2026 10:25:07 -0700 Subject: [PATCH 1/2] =?UTF-8?q?feat(hooks):=20every=20mentioned=20file=20p?= =?UTF-8?q?ath=20gets=20a=20gated=20hub=20link=20=E2=80=94=20formula=20inj?= =?UTF-8?q?ected=20each=20turn?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Field report follow-up: an agent with a stale skill copy couldn't find the gated URL after creating a file. Instructions rot; hook output is computed fresh from the binary every turn. Claude Code's turn-start pull hook now runs 'bdrive sync --hook claude-code', which: - pulls as before, and stamps the session note from the event JSON (replacing the sh/sed pipeline for the pull leg) - emits the project's gated-link formula as UserPromptSubmit additionalContext: whenever the agent mentions a synced file path in prose, it appends the hub link on an emoji — `` [🔗]() — path plain (it's the local path), hyperlink on the emoji only; code blocks stay plain; bdrive share stays explicit-opt-in-public Blind-tested: an agent given only the injected context decorated every path mention correctly, kept the code-block command plain, and checked files were synced before linking. - hooks install now CONVERGES marker-identified groups to the current shape (command/matcher/flags), so improvements reach existing projects on reinstall instead of being frozen by the idempotency marker; hermes same - plugin: UserPromptSubmit → beardrive-pull.sh (stdout passes through); version 0.3.0 - SKILL 'Share what you make' generalized to 'Link what you mention' (URL formula documented for non-Claude platforms); install.md pointer template updated Never fails the turn: every error path in --hook mode is a silent successful exit; offline still emits (links serve online teammates). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01P5cxPQdSGJnjXCYY9GeWXt --- cmd/bdrive/cmds.go | 7 ++ cmd/bdrive/hooksync.go | 79 ++++++++++++++++++++ cmd/bdrive/hooksync_test.go | 99 ++++++++++++++++++++++++++ internal/agenthooks/agenthooks.go | 95 ++++++++++++++---------- internal/agenthooks/agenthooks_test.go | 44 ++++++++++++ plugin/.claude-plugin/plugin.json | 2 +- plugin/commands/install.md | 7 +- plugin/hooks/hooks.json | 2 +- plugin/scripts/beardrive-pull.sh | 11 +++ plugin/skills/beardrive/SKILL.md | 4 +- 10 files changed, 307 insertions(+), 43 deletions(-) create mode 100644 cmd/bdrive/hooksync.go create mode 100644 cmd/bdrive/hooksync_test.go create mode 100755 plugin/scripts/beardrive-pull.sh diff --git a/cmd/bdrive/cmds.go b/cmd/bdrive/cmds.go index 70fc458..de959ae 100644 --- a/cmd/bdrive/cmds.go +++ b/cmd/bdrive/cmds.go @@ -15,6 +15,7 @@ import ( func syncCmd() *cobra.Command { var note string var noteTTL time.Duration + var hookLabel string c := &cobra.Command{ Use: "sync [folder]", Short: "Sync a mounted folder with its remote now", @@ -24,6 +25,11 @@ func syncCmd() *cobra.Command { if err != nil { return err } + if hookLabel != "" { + // Agent-hook mode: event JSON on stdin, silent best-effort + // sync, link-formula context on stdout. Never fails. + return runHookSync(cmd, folder, hookLabel) + } sess, proj, err := openSession(cmd.Context(), folder, true) if err != nil { return err @@ -51,6 +57,7 @@ func syncCmd() *cobra.Command { } c.Flags().StringVar(¬e, "note", "", "session context stamped onto changes (e.g. an agent session id); shown in history; empty clears") c.Flags().DurationVar(¬eTTL, "note-ttl", 30*time.Minute, "how long the note keeps applying to daemon-committed changes") + c.Flags().StringVar(&hookLabel, "hook", "", "agent-hook mode: read the platform's hook event JSON from stdin, sync with a session note labeled by this value, and emit the project's link-formula context (Claude Code hook JSON) on stdout") return c } diff --git a/cmd/bdrive/hooksync.go b/cmd/bdrive/hooksync.go new file mode 100644 index 0000000..bc78ea5 --- /dev/null +++ b/cmd/bdrive/hooksync.go @@ -0,0 +1,79 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "time" + + "github.com/spf13/cobra" +) + +// `bdrive sync --hook