mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
feat(hooks): user-scope agent sync hooks, one-command setup, --only scoping (#71)
* feat(hooks): register agent sync hooks per machine, not per project Agent platforms read hook config only from the directory a session starts in — never a parent, never a subfolder. Project-level hooks therefore fired only for sessions that happened to start at the mount, and, living inside a synced folder, they replicated one machine's agent config to the whole team (a second writer of a file bdrive already owns). Claude Code additionally ignores project hooks until the folder is trusted, so in practice they were often inert without any visible sign. Hooks now go to each platform's user config, once per machine, covering every session in every folder; the existing shell guard keeps them a no-op outside BearDrive projects. Install migrates away blocks older versions wrote into projects, and `bdrive hooks uninstall` removes ours while leaving foreign hooks untouched. Setup is also one command now. init absorbs the skill install, prints the hub link, and takes --server, so connecting to a named hub no longer needs a separate login; the runbook forbids preflight and command chaining, since each distinct command costs the user a permission prompt. For plugin users a PreToolUse hook auto-approves bdrive's own setup subcommands — narrowly: any shell operator in the command disqualifies it. Also drops --shared in favor of `init . --only wiki,docs`, which writes a managed block of .bdriveignore rules instead of a second scope mechanism. Because those rules sync, `sync --prune` now refuses on a scoped project rather than stripping everything outside the scope from the hub for everyone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016aYntCWwdUhpzUfEk3ddyJ * docs: fix stale claims an audit found against the new CLI An audit of every doc surface against the code turned up claims that the user-scope hook move and the one-command init made false: project-level hooks "riding the repo", the Claude trust prompt, Codex's //hooks project layer, `--no-hooks` skipping the skill (it does not), prune reconciling against a per-device scope (it now refuses on a scoped project), and `--scan-interval`/`--remote-interval` documented as init flags when they only exist on `bdrive daemon run`. Also documents the surface added today — `--server`, `bdrive hooks uninstall`, and the plugin's PreToolUse auto-approval — refreshes the two sample `init` transcripts to the real output, and corrects hook matchers that had drifted from agenthooks.go. `bdrive scope` told users to narrow an existing mount with `bdrive init . --only <dirs>`, which resume then ignored — a dead end. Init now applies --only on resume, writing the scope block, so the advice works. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016aYntCWwdUhpzUfEk3ddyJ --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
22461a3b4f
commit
4e34d03e14
@@ -54,7 +54,8 @@ overlap. Nothing is silently dropped.
|
||||
|
||||
A per-mount daemon scans the folder every few seconds and exchanges with the
|
||||
remote every ~10s — or immediately after local edits. Tune with
|
||||
`--scan-interval` and `--remote-interval` on `bdrive init`.
|
||||
`--scan-interval` and `--remote-interval` on `bdrive daemon run` (init always
|
||||
uses the defaults).
|
||||
|
||||
It re-reads `.bdrive/config.json` each tick. If that file vanishes because the
|
||||
folder was moved, renamed, or deleted, the daemon **exits cleanly without
|
||||
|
||||
@@ -29,7 +29,7 @@ bdrive url --sync wiki/report.html
|
||||
With no argument, `bdrive url` gives the project home.
|
||||
|
||||
:::tip[Agents do this automatically]
|
||||
The sync hook installed by `bdrive hooks install` injects the project's
|
||||
The sync hook `bdrive init` registers injects the project's
|
||||
gated-link formula into the agent's context, so a connected agent appends
|
||||
`path` [🔗](link) to every synced path it mentions — without being asked. See
|
||||
[Set up with your agent](/start/setup/).
|
||||
|
||||
@@ -7,39 +7,75 @@ Shared agent memory works better when it's curated. A folder holding
|
||||
`node_modules/` and build output costs sync bandwidth, buries the documents that
|
||||
matter, and gives agents thousands of irrelevant paths to wander into.
|
||||
|
||||
Two mechanisms control it: an **include list** that narrows the project to a
|
||||
subfolder, and **`.bdriveignore`** that opts individual paths out. Both are
|
||||
applied symmetrically — the same filter governs what's read from disk and what's
|
||||
written back to it.
|
||||
One mechanism controls it: **`.bdriveignore`**, a gitignore-style rule file at
|
||||
the mount root. It opts individual paths out, and — as a bdrive-managed block of
|
||||
"only these folders" rules — it narrows the project to chosen subfolders. Rules
|
||||
are applied symmetrically: the same filter governs what's read from disk and
|
||||
what's written back to it.
|
||||
|
||||
## Sync only subfolders
|
||||
|
||||
A mount is always exactly the folder you name:
|
||||
|
||||
```sh
|
||||
bdrive init --shared wiki
|
||||
bdrive init --shared wiki,docs # several subfolders, one project
|
||||
bdrive init wiki # ./wiki is the project
|
||||
```
|
||||
|
||||
This is the right shape inside a code repository: sync `wiki/` or `docs/` and
|
||||
leave the source tree alone. The agent gets a knowledge folder; the code stays
|
||||
in git where it belongs. `--shared` takes one folder or several — comma-separated
|
||||
or repeated — and they all join the same project, with one membership and one
|
||||
permission set. The interactive `bdrive init` asks the same question.
|
||||
Its contents *are* the project's contents — no `wiki/` prefix on the hub — and
|
||||
nothing outside it is ever scanned. This is the right shape inside a code
|
||||
repository: sync `wiki/` or `docs/` and leave the source tree alone. The agent
|
||||
gets a knowledge folder; the code stays in git where it belongs.
|
||||
|
||||
The result lands in `.bdrive/config.json` as an include list:
|
||||
When the project has to be the enclosing folder — several subfolders belonging
|
||||
to one project, or agents that work from the repo root — narrow it with
|
||||
`--only`:
|
||||
|
||||
```jsonc
|
||||
{ "id": "m-5a10b713", "volume": "notes",
|
||||
"remote": "https://drive.example.com/p/p-7f3a2c91", "include": ["/wiki/"] }
|
||||
```sh
|
||||
bdrive init . --only wiki,docs
|
||||
```
|
||||
|
||||
The leading slash anchors each entry to the mount root: `/wiki/` means the
|
||||
`wiki` folder at the top of this project and nothing else, so a nested
|
||||
directory that happens to share the name never syncs.
|
||||
Both folders join the same project, with one membership and one permission set.
|
||||
The interactive `bdrive init` asks the same question.
|
||||
|
||||
`--only` writes ordinary `.bdriveignore` rules, in a managed block at the top of
|
||||
the file:
|
||||
|
||||
```gitignore
|
||||
# bdrive scope — only these folders sync (managed by bdrive; change with `bdrive scope add/rm`)
|
||||
/*
|
||||
!/wiki/
|
||||
!/docs/
|
||||
# end bdrive scope
|
||||
```
|
||||
|
||||
`/*` excludes everything at the mount root; each `!` line re-includes one
|
||||
folder, anchored to that root — so a nested directory that happens to share the
|
||||
name never syncs. The block goes first because matching is last-match-wins:
|
||||
ordinary rules below it still apply, which keeps `node_modules/` excluded
|
||||
*inside* a scoped folder.
|
||||
|
||||
There is no separate scope setting to keep in step.
|
||||
|
||||
:::note[Legacy include lists]
|
||||
Projects created before the scope moved into `.bdriveignore` carry an `include`
|
||||
list in `.bdrive/config.json`. It is still honored, but never written any more —
|
||||
`bdrive scope` reports it and points you at `bdrive init . --only <dirs>` to
|
||||
move it into `.bdriveignore`.
|
||||
:::
|
||||
|
||||
## The scope is the team's
|
||||
|
||||
Because the rules live in `.bdriveignore`, and that file syncs, a narrow scope
|
||||
is the whole team's scope: every device that syncs the project picks it up.
|
||||
Widening or narrowing it is a change everyone sees, not a local preference.
|
||||
(Legacy include lists are the exception — they sit in the never-synced
|
||||
`.bdrive/config.json` and apply to one device only.)
|
||||
|
||||
## Change the scope later
|
||||
|
||||
`bdrive scope` shows the include list; `scope add` / `scope rm` edit it — no
|
||||
JSON editing, and the running daemon applies the change within seconds:
|
||||
`bdrive scope` shows what syncs; `scope add` / `scope rm` edit the managed block
|
||||
— no hand-written negation syntax, and the running daemon applies the change
|
||||
within seconds:
|
||||
|
||||
```sh
|
||||
bdrive scope # what syncs now
|
||||
@@ -47,14 +83,19 @@ bdrive scope add notes # also sync ./notes
|
||||
bdrive scope rm docs # stop syncing ./docs
|
||||
```
|
||||
|
||||
Both act on an already-narrowed project; on a whole-folder mount `scope add`
|
||||
points you at `bdrive init . --only <dirs>` and `scope rm` at a plain
|
||||
`.bdriveignore` rule.
|
||||
|
||||
Removing a folder stops syncing it but deletes nothing — local files stay, and
|
||||
the hub keeps everything already synced (the same
|
||||
[non-destructive rule](#opting-out-is-non-destructive) as `.bdriveignore`).
|
||||
Removing the *last* entry is refused, because an empty include list means the
|
||||
whole folder syncs; if you want to stop syncing entirely, that's `bdrive stop`.
|
||||
[non-destructive rule](#opting-out-is-non-destructive) as any other
|
||||
`.bdriveignore` change). Removing the *last* entry is refused, because an empty
|
||||
block means the whole folder syncs; if you want to stop syncing entirely, that's
|
||||
`bdrive stop`.
|
||||
|
||||
:::tip
|
||||
A `--shared` mount is also where the two-file
|
||||
A scoped mount is also where the two-file
|
||||
[`AGENTS.md` pattern](/guides/shared-agent-memory/) earns its keep — the synced
|
||||
map lives in `wiki/`, and the repo root gets a pointer to it.
|
||||
:::
|
||||
@@ -75,9 +116,9 @@ build/
|
||||
Supported: `#` comments, `*`, `**`, `?`, a trailing `/` for directories, a
|
||||
leading (or any) `/` for root-anchoring, and `!` to re-include.
|
||||
|
||||
It always syncs — even on an include-list mount where it sits outside the
|
||||
scope, and even if a pattern matches it — so every device shares the same
|
||||
rules: one person excluding `*.tmp` fixes it for the whole team.
|
||||
It always syncs — even when the scope block excludes everything around it, and
|
||||
even if a pattern matches it — so every device shares the same rules: one
|
||||
person excluding `*.tmp` fixes it for the whole team.
|
||||
|
||||
`bdrive init` seeds a starter one covering `node_modules`, build directories,
|
||||
caches, and `.env*`.
|
||||
@@ -89,6 +130,14 @@ but is **deleted nowhere**. The path is dropped from the local cache without a
|
||||
delete op, so opting out on your machine never removes the file from anyone
|
||||
else's.
|
||||
|
||||
To take something off the hub as well, use `bdrive forget <path>`: it writes the
|
||||
rule and removes what already synced from the hub, keeping the local copy on
|
||||
every device. `bdrive sync --prune` does the same reconciliation for rules you
|
||||
added by hand — but it **refuses on a scoped project**, because "only these
|
||||
folders" rules exclude everything else the project holds, and pruning them would
|
||||
strip all of it from the hub for every teammate, not just this device. Name the
|
||||
specific paths with `bdrive forget` instead, or widen the rules first.
|
||||
|
||||
## What never syncs
|
||||
|
||||
Regardless of configuration:
|
||||
|
||||
@@ -40,7 +40,7 @@ conventions on day one.
|
||||
|
||||
**Per machine, never synced.**
|
||||
|
||||
For `--shared` mounts inside a repository, append two or three lines to the
|
||||
For a synced subfolder inside a repository, append two or three lines to the
|
||||
repo root's `AGENTS.md` and/or `CLAUDE.md` (both, if both exist):
|
||||
|
||||
```markdown
|
||||
|
||||
@@ -20,8 +20,10 @@ Hubs track it.
|
||||
Sync replication never counts as a read, and neither does viewing a blob in
|
||||
history. Only genuine consumption.
|
||||
|
||||
Agent reads require the hooks from [Set up with your agent](/start/setup/).
|
||||
Without them you'll see human traffic only.
|
||||
Agent reads require the hooks from [Set up with your agent](/start/setup/) —
|
||||
registered once per machine, in the agent's own user config, so every device
|
||||
whose agents you want counted needs its own `bdrive init` (or `bdrive hooks
|
||||
install`). Without them you'll see human traffic only.
|
||||
|
||||
## In the file browser
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ page.
|
||||
(last-writer-wins), and the losing version is preserved as a
|
||||
`name.bdrive-conflict-<device>-<time>` file.
|
||||
- **Selective sync** — a gitignore-style `.bdriveignore` opts files out, and
|
||||
`bdrive init --shared <dir>` narrows sync to one subfolder.
|
||||
`bdrive init . --only <dirs>` narrows sync to chosen subfolders.
|
||||
- **macOS and Linux.**
|
||||
|
||||
## Hub options
|
||||
|
||||
@@ -49,9 +49,10 @@ brew upgrade beardrive
|
||||
Clients and hub are the same binary — keep them roughly in step. The sync
|
||||
protocol is append-only journals plus blobs, which old clients read forward.
|
||||
|
||||
After upgrading a client, re-run `bdrive hooks install` once per project to pick
|
||||
up hook improvements, and `bdrive skill install` once per machine to refresh the
|
||||
agent skill.
|
||||
After upgrading a client, re-run `bdrive hooks install` to pick up hook
|
||||
improvements and `bdrive skill install` to refresh the agent skill — both once
|
||||
per machine, since both write to your user config. (Re-running `bdrive init` in a
|
||||
synced folder refreshes both.)
|
||||
|
||||
## Next
|
||||
|
||||
|
||||
@@ -7,9 +7,10 @@ This is [what your agent does for you](/start/setup/), one command at a time.
|
||||
Useful on a machine with no agent, when scripting a fleet, or when you simply
|
||||
want to see the moving parts.
|
||||
|
||||
Three steps: sign the device in, start syncing a folder, work normally. Then
|
||||
[register the hooks](/manual/skills-and-hooks/) — that last step is what keeps
|
||||
an agent's files fresh, and it is the one hand-setups forget.
|
||||
Three steps: sign the device in, start syncing a folder, work normally. `init`
|
||||
installs the agent skill and [registers the hooks](/manual/skills-and-hooks/)
|
||||
along the way — that is what keeps an agent's files fresh, and it used to be the
|
||||
step hand-setups forgot.
|
||||
|
||||
## 1. Sign this device in
|
||||
|
||||
@@ -41,7 +42,10 @@ Once per project.
|
||||
```console
|
||||
$ cd ~/workspace && bdrive init
|
||||
initialized /Users/snow/workspace
|
||||
server: https://your-hub
|
||||
project: workspace (p-7f3a2c91)
|
||||
skill: installed for claude, codex
|
||||
claude hooks registered → /Users/snow/.claude/settings.json
|
||||
daemon: running (pid 55434, scan 3s, remote sync 10s)
|
||||
```
|
||||
|
||||
@@ -49,20 +53,26 @@ On a terminal, `init` walks you through two questions: **create a new project or
|
||||
connect an existing one** (picked from the server's list), and **sync the whole
|
||||
folder or only a subfolder** such as `./shared`.
|
||||
|
||||
Every question has a flag — `--name`, `--project`, `--shared`, `--yes` — and
|
||||
Every question has a flag — `--name`, `--project`, `--only`, `--yes` — and
|
||||
without a TTY init never prompts. It creates-or-joins a project named after the
|
||||
folder and syncs everything.
|
||||
|
||||
Init writes `.bdrive/config.json`, seeds a starter `.bdriveignore`
|
||||
(node_modules, build dirs, caches, `.env*`), and starts the daemon. Not signed
|
||||
in yet? It runs the login flow first.
|
||||
(node_modules, build dirs, caches, `.env*`), starts the daemon, and prints the
|
||||
project's hub link. It also installs the `beardrive` skill and registers the sync
|
||||
hooks for any agent platform it detects — in that platform's **user** config, once
|
||||
per machine, so nothing lands inside the project. `--no-hooks` skips the hooks
|
||||
(the skill is installed either way). Not
|
||||
signed in yet? It runs the login flow first.
|
||||
|
||||
:::tip[Working inside a repository]
|
||||
Sync subfolders rather than the repo root: `bdrive init --shared docs` (or
|
||||
several at once: `--shared wiki,docs`). Git directories are never synced
|
||||
(per-file last-writer-wins would corrupt a repository), but a narrower scope
|
||||
keeps the sync surface honest. Adjust it later with `bdrive scope add`/`rm` —
|
||||
see [Scoping the folder](/guides/scoping/).
|
||||
Sync a subfolder rather than the repo root: `bdrive init docs` makes `./docs`
|
||||
the project and scans nothing else. For several subfolders in one project, mount
|
||||
the repo and narrow it: `bdrive init . --only wiki,docs`, which writes the
|
||||
narrowing as `.bdriveignore` rules. Git directories are never synced (per-file
|
||||
last-writer-wins would corrupt a repository), but a narrower scope keeps the
|
||||
sync surface honest. Adjust it later with `bdrive scope add`/`rm` — see
|
||||
[Scoping the folder](/guides/scoping/).
|
||||
:::
|
||||
|
||||
## 3. Work normally
|
||||
@@ -96,8 +106,8 @@ changes.
|
||||
|
||||
## Next
|
||||
|
||||
- [Skills and hooks in detail](/manual/skills-and-hooks/) — the two commands
|
||||
that make an agent read fresh files every turn. Don't stop before this one.
|
||||
- [Skills and hooks in detail](/manual/skills-and-hooks/) — what `init` wrote to
|
||||
make an agent read fresh files every turn, and how to inspect or remove it.
|
||||
- [Shared agent memory](/guides/shared-agent-memory/) — orient agents in the
|
||||
folder so they know where to read and write.
|
||||
- [Artifacts and links](/guides/agent-artifacts/) — internal links for
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
title: Skills and hooks in detail
|
||||
description: What bdrive skill install and bdrive hooks install actually write — per-platform paths, hook events, idempotency, and when to re-run them.
|
||||
description: What bdrive skill install and bdrive hooks install actually write — the user-level config paths, hook events, idempotency, and when to re-run them.
|
||||
---
|
||||
|
||||
Setting up through your agent runs these two commands for you. This is what
|
||||
they do, for when you want to run them yourself, review what changed, or debug a
|
||||
folder that isn't syncing.
|
||||
`bdrive init` runs both of these for you — that is why setup is one command. This
|
||||
is what they do, for when you want to run them yourself, review what changed, or
|
||||
debug a folder that isn't syncing.
|
||||
|
||||
## The skill
|
||||
|
||||
@@ -35,19 +35,21 @@ beardrive@beardrive` covers Claude without this command.
|
||||
## The hooks
|
||||
|
||||
```sh
|
||||
bdrive hooks install # every detected platform, this project
|
||||
bdrive hooks install # every detected platform, this machine
|
||||
bdrive hooks install --agent claude,codex,gemini,hermes
|
||||
bdrive hooks # status table
|
||||
bdrive hooks uninstall # remove them again
|
||||
```
|
||||
|
||||
Each platform gets the same three hooks written into its own config format:
|
||||
Each platform gets the same three hooks written into its own user-level config,
|
||||
in its own format:
|
||||
|
||||
| Platform | Config it writes | Pull / push / read events |
|
||||
|---|---|---|
|
||||
| Claude Code | `<project>/.claude/settings.json` | `UserPromptSubmit` / `PostToolUse` (Write\|Edit) / `PostToolUse` (Read\|Grep\|Bash) |
|
||||
| Codex | `<project>/.codex/hooks.json` | `UserPromptSubmit` / `PostToolUse` (apply_patch) / `PostToolUse` (read_file\|shell) |
|
||||
| Gemini CLI | `<project>/.gemini/settings.json` | `BeforeAgent` / `AfterTool` (write_file\|replace) / `AfterTool` (read tools) |
|
||||
| Hermes | `~/.hermes/config.yaml` (per user) | `pre_llm_call` / `post_tool_call` (write_file\|patch) / `post_tool_call` (read_file\|grep\|bash) |
|
||||
| Claude Code | `~/.claude/settings.json` | `UserPromptSubmit` / `PostToolUse` (Write\|Edit\|MultiEdit) / `PostToolUse` (Read\|Grep\|Bash) |
|
||||
| Codex | `~/.codex/hooks.json` | `UserPromptSubmit` / `PostToolUse` (apply_patch) / `PostToolUse` (read_file\|shell) |
|
||||
| Gemini CLI | `~/.gemini/settings.json` | `BeforeAgent` / `AfterTool` (write_file\|replace\|edit) / `AfterTool` (read tools) |
|
||||
| Hermes | `~/.hermes/config.yaml` | `pre_llm_call` / `post_tool_call` (write_file\|patch) / `post_tool_call` (read_file\|grep\|bash) |
|
||||
|
||||
Three hooks, three jobs:
|
||||
|
||||
@@ -64,8 +66,15 @@ Every platform pipes hook JSON with a session id, so one hook command serves all
|
||||
four, and changes are stamped with `<agent> session <id>` — visible in
|
||||
`bdrive log` and the hub's history.
|
||||
|
||||
Codex asks once to trust the project's `.codex` layer. Answer yes, or run
|
||||
`/hooks` inside Codex.
|
||||
Codex hooks are experimental and off by default. Turn them on in
|
||||
`~/.codex/config.toml`:
|
||||
|
||||
```toml
|
||||
[features]
|
||||
codex_hooks = true
|
||||
```
|
||||
|
||||
Codex then asks once to trust the hook definition. Answer yes.
|
||||
|
||||
## Both are safe to re-run
|
||||
|
||||
@@ -73,15 +82,26 @@ Merging is idempotent and preserves hooks you already have. Each hook carries
|
||||
its own marker, so a config written before a hook existed gains just the missing
|
||||
one, and a registered hook's matcher is upgraded in place when coverage grows.
|
||||
|
||||
Re-run after a CLI upgrade: `bdrive hooks install` once per project, `bdrive
|
||||
skill install` once per machine.
|
||||
Re-run after a CLI upgrade: `bdrive hooks install` and `bdrive skill install`,
|
||||
once per machine each.
|
||||
|
||||
## Where they live matters
|
||||
|
||||
Claude Code, Codex, and Gemini CLI hooks are **project-level** — they ride the
|
||||
repository, so a teammate who clones it syncs whether or not they installed
|
||||
anything. Hermes hooks are **per-user** (`~/.hermes/config.yaml`), outside the
|
||||
repo, so each person registers their own.
|
||||
Hooks are registered **once per machine**, in each platform's own user config —
|
||||
never inside a project. Agent platforms read hook config only from the directory
|
||||
a session starts in: never a parent, never a subfolder. A file in the project
|
||||
would fire only for the sessions that happened to start exactly there, and — if
|
||||
the project is synced — would travel to the whole team. A user-level
|
||||
registration covers every session in every folder instead.
|
||||
|
||||
The hook is a fast no-op in any folder without a `.bdrive/` directory, which is
|
||||
what makes registering it globally safe.
|
||||
So BearDrive writes no agent-config directory into your project, and teammates
|
||||
don't inherit your hooks: each device registers its own the first time it runs
|
||||
`bdrive init`. Earlier versions did write project-level hooks; installing strips
|
||||
those out as it goes, so nothing ends up running twice.
|
||||
|
||||
The hook opens with a shell guard that makes it a fast no-op in any folder
|
||||
without a `.bdrive/` directory, which is what makes registering it globally safe.
|
||||
|
||||
`bdrive hooks uninstall` takes them back out — it removes only BearDrive's own
|
||||
entries and leaves every other hook in those files untouched. Syncing itself is
|
||||
unaffected; only turn-boundary sync stops.
|
||||
|
||||
@@ -11,15 +11,16 @@ One binary, `bdrive` — the CLI, the sync daemon, and the web server.
|
||||
|---|---|
|
||||
| `bdrive login [server-url]` | Sign this device in. Browser flow; `--device` forces the code flow, and shells without a TTY (agents, CI, SSH) fall back to it automatically. Default server is beardrive.ai — the managed cloud, free personal workspace on signup; pass your hub URL to self-host. Switch hubs with `bdrive login <new-url>`. `--status` shows the current server and account |
|
||||
| `bdrive logout` | Sign this device out — clear the saved token and account. `--forget` also drops the remembered server |
|
||||
| `bdrive init [folder]` | Create or connect a project and start syncing. Interactive on a TTY; flags (`--name`, `--project`, `--shared`, `--yes`) for scripts. Re-run to resume |
|
||||
| `bdrive init [folder]` | Create or connect a project and start syncing — the mount is always exactly the folder named. Interactive on a TTY; flags (`--name`, `--project`, `--server`, `--only`, `--yes`) for scripts. Also installs the agent skill, registers agent sync hooks for detected platforms (`--no-hooks` skips the hooks only), and prints the project's hub link. Re-run to resume |
|
||||
| `bdrive stop [folder]` | Stop syncing — daemon and agent sync hooks both pause. Files stay on disk; `bdrive init` resumes |
|
||||
| `bdrive scope [add\|rm <dirs...>]` | Show or change which subfolders sync — the include list set by `init --shared`. Run from the mount root; the daemon picks changes up in seconds. `rm` stops syncing a folder but deletes nothing, locally or on the hub |
|
||||
| `bdrive scope [add\|rm <dirs...>]` | Show or change which subfolders sync — edits the managed block of `.bdriveignore` rules that `init --only` writes. Run from the mount root; the daemon picks changes up in seconds. `rm` stops syncing a folder but deletes nothing, locally or on the hub |
|
||||
| `bdrive forget <path>...` | Stop syncing a path and remove it from the hub. Adds the rule to `.bdriveignore` (which syncs) and prunes in one step. Local files are never touched, here or on teammates' devices |
|
||||
| `bdrive url [path]` | Internal hub link for a file or folder — sign-in and membership required. `--sync` pushes first; no argument gives the project home. Computed locally |
|
||||
| `bdrive share <file>` | Public URL for a synced file. `--list`, `--revoke`, `--expires` |
|
||||
| `bdrive sync [folder]` | Run one sync cycle now. Refuses folders this device never `init`ed and folders paused by `bdrive stop`. `--note <text>` stamps session context onto changes; `--note-ttl` (default 30m) bounds it. `--prune` also removes from the hub what `.bdriveignore` now excludes (files stay on disk everywhere). `--hook <label>` is agent-hook plumbing |
|
||||
| `bdrive hooks [install]` | Register turn-boundary sync hooks with detected agent platforms. Idempotent; `--agent` overrides detection |
|
||||
| `bdrive skill [install]` | Install the `beardrive` skill into detected agent platforms so the agent can do setup itself. Idempotent; `--agent` overrides detection |
|
||||
| `bdrive hooks [install\|uninstall]` | Register turn-boundary sync hooks in each detected agent platform's user config — once per machine, covering every folder. Run automatically by `bdrive init`; idempotent; `--agent` overrides detection. `uninstall` removes only BearDrive's own hook entries |
|
||||
| `bdrive skill [install]` | Install the `beardrive` skill into detected agent platforms so the agent can do setup itself. Run automatically by `bdrive init`; idempotent; `--agent` overrides detection |
|
||||
| `bdrive hook-approve` | Hook plumbing: answers the beardrive plugin's `PreToolUse` hook, auto-approving bare `bdrive init\|login\|hooks\|status\|sync\|url` so setup costs no permission prompts. Anything with a shell operator is left to the normal prompt |
|
||||
| `bdrive read-log [folder]` | Hook plumbing: queue agent file reads for the hub's read heatmap. Registered by `bdrive hooks install` |
|
||||
| `bdrive status [folder]` | Projects, daemon state, pending changes |
|
||||
| `bdrive log [folder] [-p path] [-n N]` | Change history: account, device, time, file |
|
||||
@@ -33,18 +34,33 @@ One binary, `bdrive` — the CLI, the sync daemon, and the web server.
|
||||
|
||||
### `bdrive init`
|
||||
|
||||
The front door. Interactive on a TTY, with survey menus for create-new versus
|
||||
connect-existing (showing a project list) and whole-folder versus
|
||||
`--shared <dirs>` (one or more subfolders, repeatable or comma-separated —
|
||||
`--shared wiki,docs` — which become the include list). Full flag bypass with
|
||||
`--name`, `--project`, `--shared`, `--yes`, and it never prompts without a TTY.
|
||||
The front door. **The mount is always exactly the folder you name** —
|
||||
`bdrive init wiki` makes `./wiki` the project, and its contents are the
|
||||
project's contents. Nothing re-roots a mount somewhere else.
|
||||
|
||||
Interactive on a TTY, with survey menus for create-new versus
|
||||
connect-existing (showing a project list) and whole-folder versus only some
|
||||
subfolders. To sync part of a folder without moving the mount, use
|
||||
`--only <dirs>` (comma-separated — `bdrive init . --only wiki,docs`), which
|
||||
writes a managed block of `.bdriveignore` rules rather than a separate scope
|
||||
setting. Full flag bypass with `--name`, `--project`, `--only`, `--yes`, and
|
||||
it never prompts without a TTY.
|
||||
|
||||
It runs the login flow first when there is no session, writes
|
||||
`.bdrive/config.json`, seeds `.bdriveignore`, and starts sync. Re-running it
|
||||
resumes — including after a folder move.
|
||||
`.bdrive/config.json`, seeds `.bdriveignore`, installs the `beardrive` skill and
|
||||
registers agent sync hooks for every detected platform (Claude Code, Codex,
|
||||
Gemini CLI, Hermes — `--no-hooks` skips the hooks; the skill is installed either way), starts sync, and prints the
|
||||
project's hub link. That is deliberate: one command means one permission prompt
|
||||
for an agent, instead of four. Re-running it resumes — including after a folder
|
||||
move.
|
||||
|
||||
Daemon intervals are tunable here: `--scan-interval` (default 3s) and
|
||||
`--remote-interval` (default 10s).
|
||||
The hooks land in each platform's **user** config (`~/.claude/settings.json` and
|
||||
friends), once per machine, so they cover every session in every folder; nothing
|
||||
is written inside the project. See
|
||||
[Skills and hooks in detail](/manual/skills-and-hooks/).
|
||||
|
||||
The daemon scans every 3s and talks to the hub every 10s; those intervals are
|
||||
tunable on `bdrive daemon run`, not on init.
|
||||
|
||||
### `bdrive sync --note`
|
||||
|
||||
@@ -79,11 +95,17 @@ and on every teammate's machine. Nothing is destroyed either: blobs are
|
||||
retained forever, so the removal shows in `bdrive log` and every past version
|
||||
stays in the hub's history.
|
||||
|
||||
Prune reconciles against `.bdriveignore` only, never against this device's own
|
||||
sync scope (`bdrive scope` / `init --shared`). Ignore rules are shared; the
|
||||
scope is per-device, and a narrow scope means "not on my disk", not "not on the
|
||||
hub". To clean up something your scope excludes, `bdrive forget` it — that
|
||||
writes the exclusion into the shared rules first, which is what makes it safe.
|
||||
Prune reconciles against `.bdriveignore`, which is shared — so it refuses
|
||||
outright when those rules contain `!` scope rules (the "only these folders"
|
||||
block that `init --only` and `bdrive scope` write). With such a scope, pruning
|
||||
would mean deleting everything outside it from the hub for every teammate. To
|
||||
remove a specific path, `bdrive forget` it — that writes the exclusion into the
|
||||
shared rules first, which is what makes it safe.
|
||||
|
||||
Mounts created before the scope moved into `.bdriveignore` may still carry a
|
||||
per-device `include` list in `.bdrive/config.json`; prune never reconciles
|
||||
against that, so a narrow legacy scope still means "not on my disk", not "not
|
||||
on the hub".
|
||||
|
||||
If a teammate edits the file between your prune and their next sync, their
|
||||
version wins and the path comes back. Run `--prune` again once they have synced.
|
||||
|
||||
@@ -9,18 +9,20 @@ project.
|
||||
## `.bdrive/`
|
||||
|
||||
The folder's settings directory. `config.json` holds the **stable mount id**
|
||||
plus project, remote, and include settings.
|
||||
plus the project and remote (older mounts may also carry a legacy `include`
|
||||
list — still honored, never written now).
|
||||
|
||||
```jsonc
|
||||
// .bdrive/config.json
|
||||
{ "id": "m-5a10b713", "volume": "notes",
|
||||
"remote": "https://drive.example.com/p/p-7f3a2c91", "include": ["/shared/"] }
|
||||
"remote": "https://drive.example.com/p/p-7f3a2c91" }
|
||||
```
|
||||
|
||||
Written by `bdrive init` and safe to hand-edit — a running daemon picks changes
|
||||
up automatically. The `include` list (which subfolders sync, set by
|
||||
`init --shared`) has a friendlier editor: `bdrive scope add`/`rm` from the
|
||||
mount root.
|
||||
up automatically. Which subfolders sync is *not* stored here: that lives in
|
||||
`.bdriveignore` (see below), edited with `bdrive scope add`/`rm`. Mounts created
|
||||
before that change may still carry an `include` list here; it is still honored,
|
||||
but nothing writes it any more.
|
||||
|
||||
It is **never synced** and holds **no credentials**; the session token stays in
|
||||
`~/.bdrive`.
|
||||
@@ -34,6 +36,15 @@ A gitignore-style opt-out list at the mount root. It syncs like a normal file,
|
||||
so every device shares the same rules. See
|
||||
[Scoping the folder](/guides/scoping/).
|
||||
|
||||
## And nothing else
|
||||
|
||||
Those two are all BearDrive puts in a project: `.bdrive/config.json`,
|
||||
`.bdriveignore`, and your own files. No agent-config directory is ever created
|
||||
here — the sync hooks live in each platform's user config
|
||||
(`~/.claude/settings.json`, `~/.codex/hooks.json`, `~/.gemini/settings.json`,
|
||||
`~/.hermes/config.yaml`), written once per machine. See
|
||||
[Skills and hooks in detail](/manual/skills-and-hooks/).
|
||||
|
||||
## Global state
|
||||
|
||||
Everything else lives under `$BDRIVE_HOME` (default `~/.bdrive`):
|
||||
|
||||
@@ -75,8 +75,8 @@ container platform works the same way.
|
||||
1. Open `https://your-hub/` and create your account. Use the signup posture you
|
||||
configured; hub admins are the `admins` emails.
|
||||
2. On any machine, `bdrive login https://your-hub`, then in the folder you want
|
||||
synced: `bdrive init --name wiki --yes` — or `--shared docs` inside a
|
||||
repository to sync only that subfolder.
|
||||
synced: `bdrive init --name wiki --yes` — or, inside a repository,
|
||||
`bdrive init docs --yes` to make that subfolder the project.
|
||||
3. Invite a teammate: sidebar footer → **Manage** → **New invite**. The join
|
||||
link both creates their account and adds them to your org.
|
||||
4. Connect agents: the project's home page shows one-paste setup for Claude
|
||||
|
||||
@@ -35,10 +35,11 @@ Two more commands come with the plugin: **`/beardrive:init`** to start syncing
|
||||
without the full setup conversation, and **`/beardrive:status`** to diagnose a
|
||||
sync problem.
|
||||
|
||||
:::tip[Project-level hooks reach the whole team]
|
||||
`/beardrive:install` writes hooks into `.claude/settings.json`, which is
|
||||
committed with the repository — so **teammates sync whether or not they
|
||||
installed the plugin**.
|
||||
:::tip[Hooks are registered once per machine]
|
||||
`/beardrive:install` writes hooks into your user config (`~/.claude/settings.json`
|
||||
and friends), so **every session in every folder is covered** — not just the ones
|
||||
started where you ran setup. Nothing is written into the project, and each
|
||||
teammate registers their own the first time they set up.
|
||||
:::
|
||||
|
||||
## Codex, Gemini CLI, and Hermes
|
||||
@@ -49,7 +50,7 @@ and paste:
|
||||
|
||||
```
|
||||
Follow https://raw.githubusercontent.com/runbear-io/beardrive/main/INSTALL_FOR_AGENTS.md
|
||||
to connect this folder to BearDrive project <project-id> on <hub-url>.
|
||||
to set up BearDrive project <project-id> on <hub-url>. Ask me which folder to sync.
|
||||
```
|
||||
|
||||
The agent fetches that page and works through it — install the CLI, sign in
|
||||
@@ -76,11 +77,12 @@ Two things, worth knowing by name:
|
||||
Codex, Gemini CLI, and Hermes.
|
||||
- **The hooks** — a blocking pull when you send a message, so the agent always
|
||||
reads the team's current files, and an async push when the turn ends, so what
|
||||
it writes reaches everyone else within seconds.
|
||||
it writes reaches everyone else within seconds. They go in the agent's user
|
||||
config, once per machine, and are a no-op outside BearDrive folders.
|
||||
|
||||
The hooks are what make syncing automatic, and they are the step people skip
|
||||
when they set up by hand. [Skills and hooks in detail](/manual/skills-and-hooks/)
|
||||
covers what gets written where.
|
||||
The hooks are what make syncing automatic. `bdrive init` registers them for you,
|
||||
so there is nothing extra to run — [skills and hooks in
|
||||
detail](/manual/skills-and-hooks/) covers what gets written where.
|
||||
|
||||
## Check it worked
|
||||
|
||||
@@ -89,7 +91,7 @@ Ask the agent — "is BearDrive set up in this folder?" — or look yourself:
|
||||
```sh
|
||||
bdrive status # projects, daemon state, pending changes
|
||||
bdrive skill # which agents know the CLI on this machine
|
||||
bdrive hooks # which agents sync this project automatically
|
||||
bdrive hooks # which agents on this machine sync automatically
|
||||
```
|
||||
|
||||
## Next
|
||||
|
||||
@@ -27,9 +27,10 @@ Ask your agent, in the repo:
|
||||
|
||||
> Set up BearDrive here, syncing only `context/`.
|
||||
|
||||
That runs `bdrive init --shared context`, which writes `.bdrive/config.json`,
|
||||
creates the folder, and starts the daemon. Nothing outside `context/` is
|
||||
scanned or sent — `.git/` and `.bdrive/` never sync at all.
|
||||
That runs `bdrive init context`, which makes `./context` the project — creating
|
||||
the folder if it doesn't exist, writing `context/.bdrive/config.json`, and
|
||||
starting the daemon. Nothing outside `context/` is scanned or sent — `.git/` and
|
||||
`.bdrive/` never sync at all.
|
||||
|
||||
### Then tell git to ignore it
|
||||
|
||||
@@ -123,8 +124,8 @@ and it is also the thing to be deliberate about.
|
||||
[Turn a personal brain into a company brain](/use-cases/company-brain/) for
|
||||
how that model works.
|
||||
- **Opt things out** with `.bdriveignore` — see
|
||||
[Scoping the folder](/guides/scoping/). It always syncs, even on a
|
||||
`--shared` mount, so one person's rules apply for the whole team.
|
||||
[Scoping the folder](/guides/scoping/). It always syncs, so one person's rules
|
||||
apply for the whole team.
|
||||
- **Watch what actually gets read.** [Read heat](/guides/what-agents-read/)
|
||||
shows which context pages agents consume. Pages nothing has read in a month
|
||||
are candidates for deletion, and deleting them makes the rest work better.
|
||||
|
||||
@@ -32,8 +32,9 @@ Same as any project — [ask your agent](/start/setup/), in the brain folder:
|
||||
|
||||
> Set up BearDrive here and invite my team.
|
||||
|
||||
If the brain is a subfolder of something larger, sync just that subfolder:
|
||||
`bdrive init --shared brain/`. Teammates mount the same project on their own
|
||||
If the brain is a subfolder of something larger, name it and only it:
|
||||
`bdrive init brain` — the folder you name is the project, and nothing outside it
|
||||
is scanned. Teammates mount the same project on their own
|
||||
machines, wherever they like it on disk, and keep running their own local brain
|
||||
against the synced files.
|
||||
|
||||
|
||||
@@ -26,13 +26,15 @@ The folder does not have to match across machines. State is keyed by a stable
|
||||
project id, never a path, so `~/work` on one and `~/Documents/work` on another
|
||||
are the same project. Moving or renaming a folder later is free.
|
||||
|
||||
Install the skill and hooks **once per machine**, and the hooks once per project
|
||||
— that is what makes each agent pull before it answers. See
|
||||
The skill and the hooks are installed **once per machine** — `bdrive init` does
|
||||
both on each new device — and from then on they cover every folder that machine
|
||||
syncs. That is what makes each agent pull before it answers. See
|
||||
[skills and hooks in detail](/manual/skills-and-hooks/).
|
||||
|
||||
## More than one agent per machine
|
||||
|
||||
The skill is a cross-agent format and the hooks are written per platform, so
|
||||
The skill is a cross-agent format and the hooks are written into each platform's
|
||||
own user config, so
|
||||
Claude Code, Codex, Gemini CLI, and Hermes can all be wired into the same folder
|
||||
at once. They read the same files and their writes are stamped with which agent
|
||||
session made them, so `bdrive log` and the hub's history stay legible even when
|
||||
@@ -51,8 +53,8 @@ mechanism, just with a longer window.
|
||||
|
||||
## What matters for this case
|
||||
|
||||
- **[Skills and hooks in detail](/manual/skills-and-hooks/)** — what to run on
|
||||
each new machine, and why the pull hook is the one that matters.
|
||||
- **[Skills and hooks in detail](/manual/skills-and-hooks/)** — what each new
|
||||
machine registers, and why the pull hook is the one that matters.
|
||||
- **[How sync works](/concepts/how-it-works/)** — journals, blobs, and
|
||||
deterministic replay, if you want to know why this converges rather than
|
||||
hoping it does.
|
||||
|
||||
Reference in New Issue
Block a user