Skip to content

Scoping the folder

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.

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.

A mount is always exactly the folder you name:

Terminal window
bdrive init wiki # ./wiki is the project

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.

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:

Terminal window
bdrive init . --only wiki,docs

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:

# 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.

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. Narrowing it is a change everyone sees immediately, 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.)

One direction is deliberately not automatic. A rule a teammate pushes that widens what syncs — a ! re-include — takes effect on your machine for what comes down from the hub, but it does not start uploading files off your disk that your own rules held back. Uploading something that was never shared is a decision your machine makes, not one a teammate makes for it.

You accept the current rules the moment you author them yourself: bdrive init --only, bdrive scope add / scope rm, or editing .bdriveignore by hand. Any of those makes the file as it stands your device’s rules, widenings included.

This matters most in the shape this guide recommends for a repository — bdrive init . --only docs,notes puts the whole repository under the mount, with only .bdriveignore holding the rest of it back. Without the rule above, one teammate adding !.env to the shared file would upload every other member’s local .env on their next sync.

A device joining a project has authored nothing yet, so the project’s rules stand on their own — team-wide scope still works for a new member on day one.

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:

Terminal window
bdrive scope # what syncs now
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 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.

Rules are one thing; their effect is another. bdrive scope --explain walks the folder and prints every path it found, split into what syncs and what does not:

Terminal window
bdrive scope --explain
synced (4)
.bdriveignore
docs/architecture.md
docs/onboarding.md
specs/BEA-24.md
not synced (2,486)
.DS_Store
.bdrive/ (1 file)
.env
.git/ (312 files)
node_modules/ (2,481 files)
scratch/notes.md
vendor/acme/ (own project — syncs separately)
4 files sync, 2,486 do not.

A directory that is excluded whole collapses to one counted line, so a folder with node_modules in it prints a handful of lines, not thousands. A nested mount is labelled rather than called “not synced” — it does sync, through its own project.

The decisions come from the same walk the sync cycle itself uses, so what this prints cannot drift from what actually leaves. It is a pure read: safe to run while the daemon is running and while you are offline, it takes no lock and makes no network call. Output is sorted and stable, which makes it diffable — the way to prove a rule change did what you meant:

Terminal window
bdrive scope --explain > before.txt
# edit .bdriveignore
bdrive scope --explain > after.txt
diff before.txt after.txt

One thing it does not answer: whether a path you exclude today is already on the hub from before the rule existed. Excluding it stops future syncs but leaves the copy up there — bdrive forget <path> is what takes it off.

.bdriveignore sits at the mount root and works like .gitignore:

# comments
node_modules/
*.log
build/
!build/keep.txt
/only-at-root

Supported: # comments, *, **, ?, a trailing / for directories, a leading (or any) / for root-anchoring, and ! to re-include.

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*.

When a pattern starts matching an already-synced file, the file stops syncing 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.

Regardless of configuration:

  • .git directories — per-file last-writer-wins would corrupt a repository. If git is the content you want synced, you want git, not BearDrive.
  • .DS_Store.
  • The .bdrive/ settings directory — and it holds no credentials; the session token stays in ~/.bdrive.
  • BearDrive’s own temp files (.bdrive-tmp-*).
  • Nested mounts — a subdirectory with its own .bdrive/config.json syncs only through its own project. The parent never scans into it, writes over it, or propagates deletes for it.
  • Empty directories — not tracked, the same as git.

.bdriveignore is the mechanism for keeping .env* and key material out, and the seeded default covers the common cases. But treat it as hygiene, not a security control: any org member can mint a public link for any synced file. Secrets belong in a secret manager, not in a folder you hand to agents.

Minting a share link is the one place the hub reads the bytes first: it scans the first 1 MiB for credential-shaped strings (AWS access key, private key block, GitHub/Slack/GitLab/OpenAI token) and refuses, naming the rule and the line but never the matched text. bdrive share --force — or Share anyway in the web UI — overrides it. Know what that check does not cover: it runs at the moment you share, and a link serves the file’s latest content forever, so a key written into an already-shared file is never caught. It is a last-line backstop, not a reason to sync a folder you wouldn’t otherwise.