You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Solo developer, eight projects, one beads instance. Issue prefixes handle namespacing. The setup was deliberate: one dependency graph, one dolt database, atomic backup, cross-project blocking chains that resolve naturally. Multi-repo hydration — the intended model — doesn't offer this.
Four gaps emerge at this scale:
Issue creation requires mutating global config state for every non-default prefix. There is no --prefix flag on bd create. Silent failure when the unset-then-set ceremony is skipped means wrong-prefix issues are a recurring problem, especially with AI agents handling creation.
Project lifecycle has no tooling representation. Archived and prototype prefixes are treated identically to active ones. bd ready, bd stats, and global queries don't scope by prefix or lifecycle state.
Stealth mode is per-repo by design, but a junction-based multi-project layout inverts this assumption. Each new project requires manual stealth setup the tool doesn't automate or verify. For a public-facing repo in the workspace, artifacts from bd init may already be visible to contributors.
Remote and backup are all-or-nothing. bd dolt push carries all projects in every operation. bd export produces a single unscoped JSONL stream. Per-prefix migration or selective sync requires external post-processing.
The data model handles multiple prefixes cleanly — the friction is in the tooling, not the schema. It's an open question whether usage patterns in the community reflect user preference or the functional limitations of the tooling; the friction documented here is worth weighing as that question gets answered.
Full write-up
The Setup
Solo developer, eight projects, one beads instance, one dolt database. Issue prefixes handle project namespacing. The workspace git repo is the beads host; individual project repos live as subdirectories, each with their own git history and remotes.
The portfolio isn't static. At any given point:
Two or three projects are in active development
One is a public repository with a growing contributor community and external issue tracker
One is in maintenance mode — rare patches, no new features
Two are archived — no active work, but their issue history and cross-project dependency context remain relevant
One is a new prototype that may or may not survive
This configuration was chosen deliberately for cross-project visibility — a unified dependency graph, a single bd ready across all work, cross-project blocking chains that resolve naturally because they're in the same database.
The workspace itself is also a project. Some work is holistic — code scanning, dependency auditing, shared tooling, CI infrastructure — and doesn't belong to any single project. The workspace prefix serves as the default for these cross-cutting concerns, making the workspace root a first-class participant in the issue graph rather than just a container for project repos.
How the Tool Expects This to Work
The intended beads model is one prefix per beads instance, set once at init, never changed. The issue_prefix config key is project identity — it's how bd context --json verifies backend identity, how workspace preflight checks work, and why bd create --force exists as a safety guard against prefix mismatch.
Multi-project visibility is addressed through multi-repo hydration: separate beads instances per project, aggregated into a unified read view via repos.additional config. Each project keeps its own database, prefix, remote, and backup. The unified bd list pulls from all of them.
The multi-project single-database pattern inverts this. It places many prefixes in one database for tighter integration — same dependency graph, same dolt commit history, atomic backup. The intended design places one prefix in many databases and achieves cross-visibility through aggregation.
Friction at Issue Creation
The issue_prefix config key lives in the database and applies globally. Creating an issue for a different project requires mutating global state: bd config unset issue_prefix && bd config set issue_prefix <project>, then restoring after. This must happen for every create targeting a non-default project.
bd config set silently no-ops if the key already has a value. The unset-then-set ceremony is mandatory but the failure mode is invisible — an agent or script that omits the unset proceeds with the stale prefix, creating issues under the wrong project with no error or warning.
There is no --prefix flag on bd create. The --id flag accepts a full explicit ID but doesn't combine a user-supplied prefix with auto-generated hash — it takes the literal string as the complete ID.
With eight project prefixes in rotation and AI agents performing the majority of issue creation, wrong-prefix issues are a recurring problem. The workaround is a chained one-liner that sets prefix, creates, and restores in a single command — functional, but a ceremony that a --prefix flag would eliminate.
Project Lifecycle Has No Representation
Archived projects still occupy the same namespace. Their closed issues appear in global queries. There is no concept of a project being retired, active, or dormant at the prefix level. bd ready mixes prototype tasks with maintenance-mode patches with active development work. bd stats aggregates across all projects with no way to scope by prefix. There is no mechanism to archive, freeze, or filter a prefix out of day-to-day views without closing every issue under it.
Stealth Mode Doesn't Compose
bd init --stealth is designed per-repository — it configures .git/info/exclude so beads files don't appear in commits. In a multi-project workspace, the beads database lives at the workspace root, not inside individual project repos. The project repos access the database through NTFS junction points (.beads/ in each project directory is a junction back to the workspace-level .beads/).
This creates a split responsibility:
The workspace repo's .gitignore correctly excludes .beads/. That repo only goes to a private remote.
Each project repo needs its own protection against the junction point leaking into commits. .git/info/exclude or .gitignore must list .beads/ independently in every repo.
bd setup --stealth configures exclusions for one repo at a time and doesn't know about the junction-based layout. It doesn't discover or protect other repos in the workspace.
For the public-facing project, the situation is more nuanced. The junction itself is protected by gitignore, so the database doesn't leak. But bd init or bd setup may have created artifacts inside the project directory — AGENTS.md, hook configurations, beads.role in local git config — that are visible to contributors or have already been committed. These aren't database leaks, but they're metadata that reveals internal tooling to the public. The .gitignore entries themselves (.beads, AGENTS.md, CONTEXT.md) are tracked and visible in the public repo, signaling beads usage to anyone reading the ignore file. In stealth terms, the file contents are hidden but the footprint is visible.
Stealth mode's per-repo design assumes beads is initialized inside the repo it's protecting. The junction-based multi-project layout inverts this — the repos point outward to a shared database, and each new project added to the workspace requires manual stealth setup that the tool doesn't automate or verify.
The broader security question — what beads reveals and to whom — is raised but unanswered in #2684.
Remote and Backup Are All-or-Nothing
bd dolt push and bd dolt pull operate on the entire database. There is no per-prefix scoping. All project data — active, archived, public, private — moves together in every push. For a single user this is operationally acceptable, but the backup granularity doesn't match the project granularity: if the database corrupts, all projects are affected; if recovery is needed, it's all-or-nothing. There is no per-prefix access control or selective sync, which constrains where the database can be pushed if any project in the portfolio has different visibility requirements.
bd export dumps all issues into a single JSONL stream. There is no flag to scope the export by prefix. Restoring a single project's issues independently — for example, migrating one project to its own beads instance — requires post-processing the JSONL externally.
What Works
The unified view delivers on its promise. bd list, bd ready, bd blocked, bd stats operate across the full portfolio. Cross-project dependencies resolve naturally. The single dolt server avoids the port collision problems that motivated the shared Dolt server mode introduced in #2416, and that surface unanswered in #2098. What that failure mode looked like in practice — silent cross-project issue leakage, foreign prefixes appearing with no error or warning — is documented by the community in this Gist. The shared-server assumption surfaces independently in #2798, where worktrees that don't inherit the redirect spin up isolated dolt servers rather than sharing the workspace instance — confirming that a single shared database is an independently motivated goal, not just an artifact of this setup. Auto-backup captures everything in one operation. The data model handles multiple prefixes cleanly — the friction is entirely in the tooling around it, not in the schema.
The Gap
Beads supports multiple projects in a single database through prefixes. It supports a shared server serving multiple databases. But the intersection — multiple prefixed projects in a single database as a first-class workflow — has ergonomic gaps in creation, lifecycle management, stealth, and backup granularity that push users toward per-project isolation, which then sacrifices the unified dependency graph that makes the single-database approach worth the tradeoff.
It's an open question whether usage patterns in the community reflect user preference or the functional limitations of the tooling. The friction documented above is worth weighing as that question gets answered.
The portfolio lifecycle dimension compounds this. Projects aren't permanent. They're born, grow, go public, attract contributors, enter maintenance, get archived. The tooling doesn't model this evolution — not when every prefix is treated as equally live, every push as all-or-nothing, and every backup as monolithic.
The single-database approach scales well as an issue graph. The tooling around it doesn't yet treat the multi-project workspace as a distinct operational mode with its own needs. With the project in active pre-1.0 design (v0.62.0 — The Road to 1.0), this feels like the right time to put it on the map.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Solo developer, eight projects, one beads instance. Issue prefixes handle namespacing. The setup was deliberate: one dependency graph, one dolt database, atomic backup, cross-project blocking chains that resolve naturally. Multi-repo hydration — the intended model — doesn't offer this.
Four gaps emerge at this scale:
Issue creation requires mutating global config state for every non-default prefix. There is no
--prefixflag onbd create. Silent failure when the unset-then-set ceremony is skipped means wrong-prefix issues are a recurring problem, especially with AI agents handling creation.Project lifecycle has no tooling representation. Archived and prototype prefixes are treated identically to active ones.
bd ready,bd stats, and global queries don't scope by prefix or lifecycle state.Stealth mode is per-repo by design, but a junction-based multi-project layout inverts this assumption. Each new project requires manual stealth setup the tool doesn't automate or verify. For a public-facing repo in the workspace, artifacts from
bd initmay already be visible to contributors.Remote and backup are all-or-nothing.
bd dolt pushcarries all projects in every operation.bd exportproduces a single unscoped JSONL stream. Per-prefix migration or selective sync requires external post-processing.The data model handles multiple prefixes cleanly — the friction is in the tooling, not the schema. It's an open question whether usage patterns in the community reflect user preference or the functional limitations of the tooling; the friction documented here is worth weighing as that question gets answered.
Full write-up
The Setup
Solo developer, eight projects, one beads instance, one dolt database. Issue prefixes handle project namespacing. The workspace git repo is the beads host; individual project repos live as subdirectories, each with their own git history and remotes.
The portfolio isn't static. At any given point:
This configuration was chosen deliberately for cross-project visibility — a unified dependency graph, a single
bd readyacross all work, cross-project blocking chains that resolve naturally because they're in the same database.The workspace itself is also a project. Some work is holistic — code scanning, dependency auditing, shared tooling, CI infrastructure — and doesn't belong to any single project. The
workspaceprefix serves as the default for these cross-cutting concerns, making the workspace root a first-class participant in the issue graph rather than just a container for project repos.How the Tool Expects This to Work
The intended beads model is one prefix per beads instance, set once at init, never changed. The
issue_prefixconfig key is project identity — it's howbd context --jsonverifies backend identity, how workspace preflight checks work, and whybd create --forceexists as a safety guard against prefix mismatch.Multi-project visibility is addressed through multi-repo hydration: separate beads instances per project, aggregated into a unified read view via
repos.additionalconfig. Each project keeps its own database, prefix, remote, and backup. The unifiedbd listpulls from all of them.The multi-project single-database pattern inverts this. It places many prefixes in one database for tighter integration — same dependency graph, same dolt commit history, atomic backup. The intended design places one prefix in many databases and achieves cross-visibility through aggregation.
Friction at Issue Creation
The
issue_prefixconfig key lives in the database and applies globally. Creating an issue for a different project requires mutating global state:bd config unset issue_prefix && bd config set issue_prefix <project>, then restoring after. This must happen for every create targeting a non-default project.bd config setsilently no-ops if the key already has a value. The unset-then-set ceremony is mandatory but the failure mode is invisible — an agent or script that omits the unset proceeds with the stale prefix, creating issues under the wrong project with no error or warning.There is no
--prefixflag onbd create. The--idflag accepts a full explicit ID but doesn't combine a user-supplied prefix with auto-generated hash — it takes the literal string as the complete ID.With eight project prefixes in rotation and AI agents performing the majority of issue creation, wrong-prefix issues are a recurring problem. The workaround is a chained one-liner that sets prefix, creates, and restores in a single command — functional, but a ceremony that a
--prefixflag would eliminate.Project Lifecycle Has No Representation
Archived projects still occupy the same namespace. Their closed issues appear in global queries. There is no concept of a project being retired, active, or dormant at the prefix level.
bd readymixes prototype tasks with maintenance-mode patches with active development work.bd statsaggregates across all projects with no way to scope by prefix. There is no mechanism to archive, freeze, or filter a prefix out of day-to-day views without closing every issue under it.Stealth Mode Doesn't Compose
bd init --stealthis designed per-repository — it configures.git/info/excludeso beads files don't appear in commits. In a multi-project workspace, the beads database lives at the workspace root, not inside individual project repos. The project repos access the database through NTFS junction points (.beads/in each project directory is a junction back to the workspace-level.beads/).This creates a split responsibility:
.gitignorecorrectly excludes.beads/. That repo only goes to a private remote..git/info/excludeor.gitignoremust list.beads/independently in every repo.bd setup --stealthconfigures exclusions for one repo at a time and doesn't know about the junction-based layout. It doesn't discover or protect other repos in the workspace.For the public-facing project, the situation is more nuanced. The junction itself is protected by gitignore, so the database doesn't leak. But
bd initorbd setupmay have created artifacts inside the project directory —AGENTS.md, hook configurations,beads.rolein local git config — that are visible to contributors or have already been committed. These aren't database leaks, but they're metadata that reveals internal tooling to the public. The.gitignoreentries themselves (.beads,AGENTS.md,CONTEXT.md) are tracked and visible in the public repo, signaling beads usage to anyone reading the ignore file. In stealth terms, the file contents are hidden but the footprint is visible.Stealth mode's per-repo design assumes beads is initialized inside the repo it's protecting. The junction-based multi-project layout inverts this — the repos point outward to a shared database, and each new project added to the workspace requires manual stealth setup that the tool doesn't automate or verify.
The broader security question — what beads reveals and to whom — is raised but unanswered in #2684.
Remote and Backup Are All-or-Nothing
bd dolt pushandbd dolt pulloperate on the entire database. There is no per-prefix scoping. All project data — active, archived, public, private — moves together in every push. For a single user this is operationally acceptable, but the backup granularity doesn't match the project granularity: if the database corrupts, all projects are affected; if recovery is needed, it's all-or-nothing. There is no per-prefix access control or selective sync, which constrains where the database can be pushed if any project in the portfolio has different visibility requirements.bd exportdumps all issues into a single JSONL stream. There is no flag to scope the export by prefix. Restoring a single project's issues independently — for example, migrating one project to its own beads instance — requires post-processing the JSONL externally.What Works
The unified view delivers on its promise.
bd list,bd ready,bd blocked,bd statsoperate across the full portfolio. Cross-project dependencies resolve naturally. The single dolt server avoids the port collision problems that motivated the shared Dolt server mode introduced in #2416, and that surface unanswered in #2098. What that failure mode looked like in practice — silent cross-project issue leakage, foreign prefixes appearing with no error or warning — is documented by the community in this Gist. The shared-server assumption surfaces independently in #2798, where worktrees that don't inherit the redirect spin up isolated dolt servers rather than sharing the workspace instance — confirming that a single shared database is an independently motivated goal, not just an artifact of this setup. Auto-backup captures everything in one operation. The data model handles multiple prefixes cleanly — the friction is entirely in the tooling around it, not in the schema.The Gap
Beads supports multiple projects in a single database through prefixes. It supports a shared server serving multiple databases. But the intersection — multiple prefixed projects in a single database as a first-class workflow — has ergonomic gaps in creation, lifecycle management, stealth, and backup granularity that push users toward per-project isolation, which then sacrifices the unified dependency graph that makes the single-database approach worth the tradeoff.
It's an open question whether usage patterns in the community reflect user preference or the functional limitations of the tooling. The friction documented above is worth weighing as that question gets answered.
The portfolio lifecycle dimension compounds this. Projects aren't permanent. They're born, grow, go public, attract contributors, enter maintenance, get archived. The tooling doesn't model this evolution — not when every prefix is treated as equally live, every push as all-or-nothing, and every backup as monolithic.
The single-database approach scales well as an issue graph. The tooling around it doesn't yet treat the multi-project workspace as a distinct operational mode with its own needs. With the project in active pre-1.0 design (v0.62.0 — The Road to 1.0), this feels like the right time to put it on the map.
Beta Was this translation helpful? Give feedback.
All reactions