Tenant hybrid Bun monorepo install graph
Gate bun run validate:workspaces · install policy docs/UNIFIED.md
Layout STRUCTURE.md · packages map docs/packages/
Health sibling monorepo-health.md · bun run monorepo:health
Tag v5.2.2-monorepo-workspaces-catalog (milestone: catalog SSOT + homebase gate + package exports)
FactoryWager is a hybrid monorepo: product/ops live at the root (relative lib/** imports + root scripts). A small set of @factorywager/* packages plus sports-terminal-os are Bun workspace members for linking, catalogs, and --filter. Nested trees under projects/** are separate install roots unless listed in root workspaces.packages.
factorywager-enterprise (root)
├── lib/** relative imports — primary product surface
├── tools/, tests/ root scripts (ops:*, harness:*, portal:*)
├── packages/* @factorywager/* workspace packages
├── lib/shared @factorywager/shared (lib/* glob)
├── sports-terminal-os workspace app member
└── projects/** nested monorepos / archive (not root workspaces)
Resolve offline with:
bun tools/bun-docs-catalog.ts get workspaces
bun tools/bun-doc-refs.ts suggest "workspaces"
bun tools/bun-doc-refs.ts suggest "--filter"
bun tools/bun-doc-refs.ts suggest "overrides"
bun tools/bun-doc-refs.ts suggest "bun patch"
| Topic | Canonical URL | Use for |
|---|---|---|
Workspaces + workspace: |
https://bun.com/docs/pm/workspaces | Globs, linking, publish rewrite |
Catalogs + catalog: |
https://bun.com/docs/pm/catalogs | Shared version SSOT |
--filter / scripts |
https://bun.com/docs/pm/filter | Name vs ./path, install/outdated/scripts — see § bun –filter |
| Parallel / sequential | https://bun.com/docs/pm/filter#parallel-and-sequential-mode | bun run --parallel ≠ bun test --parallel |
| Dependency order | https://bun.com/docs/pm/filter#dependency-order | Filtered scripts wait on workspace deps |
| Install CLI | https://bun.com/docs/pm/cli/install | Frozen lockfile, peers, filters |
| Outdated | https://bun.com/docs/pm/cli/outdated | --filter restricts packages |
| Isolated installs | https://bun.com/docs/pm/isolated-installs | configVersion: 1 default |
| Overrides | https://bun.com/docs/pm/overrides | Root-only metadeps |
| Patch | https://bun.com/docs/pm/cli/patch | patchedDependencies |
| bunfig install | https://bun.com/docs/runtime/bunfig | exact · frozen · scopes (TOML) |
| bun pm | https://bun.com/docs/pm/cli/pm | ls · why · pkg |
| Trusted lifecycle | https://bun.com/docs/pm/lifecycle#trusteddependencies | Allow list replaces defaults |
Related catalog pages (from bun tools/bun-docs-catalog.ts get workspaces): workspaces · catalogs · install · outdated · update · filter · isolated-installs · bunfig.
SSOT page: pm/filter · offline: bun tools/bun-doc-refs.ts suggest "--filter" →
https://bun.com/docs/pm/filter#package-name-filter-pattern
--filter / -F selects workspace packages by pattern. It is supported by:
bun install — install deps for a subset of workspacesbun outdated — report outdated deps for a subsetbun run --filter <pattern> <script> (or bun --filter …)Filters respect root workspaces: only listed members match. Nested monorepos under projects/** are invisible to root --filter.
| Kind | Pattern | Selects |
|---|---|---|
| Package name | --filter '@factorywager/*' · --filter sports-terminal-os · --filter '*' |
package.json "name" (glob) |
| Package path | --filter './packages/*' · --filter './packages/guards' |
Dirs under workspace root; must start with ./ |
| Negation | --filter '!pkg-c' · --filter '!./' |
Exclude name or path (e.g. exclude root package) |
| Root only | --filter './' |
Root package.json only (useful for outdated) |
# All homebase packages under packages/ (not STO unless path matches)
bun install --filter './packages/*'
# Exclude root package.json from install selection
bun install --filter '!./' --filter './packages/*'
# Outdated pins for @factorywager scope names
bun outdated --filter '@factorywager/*'
# Root package.json only
bun outdated --filter './'
With root frozenLockfile = true, intentional filtered installs still need the usual unlock → install → freeze cycle when the lockfile would change (UNIFIED).
# Concurrent package scripts (Foreman-style prefixes: pkg:script | …)
bun run --parallel --filter '*' --if-present test
bun run --parallel --filter '*' "build:*"
bun run --parallel --no-exit-on-error --filter '*' test
# All workspace packages, one after another
bun run --sequential --workspaces --if-present typecheck
# Named package from anywhere in the monorepo (no cd)
bun run --filter @factorywager/registry-client build
bun run --filter sports-terminal-os typecheck
# Multiple scripts per package where present
bun run --parallel --filter '*' --if-present build test
| Flag | Role |
|---|---|
--parallel |
Concurrent package scripts (≠ bun test --parallel) |
--sequential |
One package at a time |
--workspaces |
All workspace packages |
--if-present |
Skip packages missing the script (almost always required here — most packages have few scripts) |
--no-exit-on-error |
Keep fan-out running after a package fails |
Dependency order: if workspace package foo depends on bar and both have build, bun --filter '*' build starts foo only after bar finishes (dependency order).
?search=type:tomlURLs like
https://bun.com/docs/pm/filter?search=type%3Atoml
append a Mintlify docs-site search facet (type:toml = “show TOML code samples”). That is not a Bun CLI filter and not a workspace selector.
type:toml flag.bunfig.toml snippets (exact, scopes, ignoreScripts) — see runtime/bunfig and our root bunfig.toml.bun --filter type:toml or confuse docs search with package selection.# Package tests / typecheck
bun run --parallel --filter '*' --if-present test
bun run --filter @factorywager/registry-client build
bun run --filter sports-terminal-os typecheck
bun run --filter './packages/*' --if-present test
# Root product (never --filter these script names)
bun run ops:limits:check
bun run portal:snapshot:once
bun test tests/limits-e2e.test.ts
bun test tests/portal-snapshot-cron.test.ts
From root package.json (do not invent globs in prose):
"workspaces": {
"packages": [
"packages/*",
"projects/active/sports-terminal-os",
"lib/*"
]
}
| Member class | Examples |
|---|---|
Root workspace:* deps (spine imports) |
docs-tools, guards, registry-client, rip |
| Workspace-only (filter/discovery) | business, p2p, @factorywager/shared, sports-terminal-os |
| Archived (out of install graph) | projects/archive/factorywager-packages/{ab-testing,versioning} |
Gate: scripts/validate-workspaces.ts — homebase only (does not require experimental/archive package.json files to be root members).
Root catalog pins shared third-party versions (exact; matches install.exact):
| Key | Role |
|---|---|
typescript |
Toolchain (root + packages via catalog:) |
@types/bun / bun-types |
Types pin (may lag runtime 1.4.0) |
zod, react, react-dom, @types/react* |
Shared app stack |
Consumers must use "pkg": "catalog:" (or catalog:<name>). Do not re-float cataloged names with ^ / latest.
Intentional exception: sports-terminal-os pins typescript at 5.9.3 until TS 6 typecheck cleanup; zod/react/bun-types still use catalog:. See Open debt: STO TypeScript 6.
Policy table + anti-patterns: UNIFIED § Catalogs and workspace protocols.
| Current | sports-terminal-os pins typescript 5.9.3 intentionally; root catalog is 6.0.3. |
| Why | On catalog TS 6, STO tsc surfaces path imports into monorepo lib/, baseUrl/rootDir layout, Response body types, and related strictness — not ready to force the pin. |
| Exit | STO bun run typecheck green on catalog typescript → switch STO package.json to "typescript": "catalog:" → drop the UNIFIED catalog exception. |
| Owner | platform / STO maintainers |
TS 6 defaults compilerOptions.types to [] (no auto @types/*). Monorepo apps/scripts need "types": ["bun"] so editors and tsc see Bun globals. Public packages that emit clean .d.ts may keep "types": [] intentionally (e.g. packages/registry-client).
| Surface | Role |
|---|---|
tsconfig.base.json |
SSOT "types": ["bun"] for extenders |
bun run check:tsconfig-types |
Walk all tsconfig*.json; JSONC-aware extends resolution |
--strict / CI / GITHUB_ACTIONS |
Exit 1 when monorepo-owned configs omit bun after extends walk |
| Pre-commit | Staged spine tsconfigs / audit tool → check:tsconfig-types --strict (SKIP_TSCONFIG_TYPES=1) |
| CI | typescript-checks.yml step before type-check scopes |
bun run check:tsconfig-types
bun run check:tsconfig-types -- --strict
bun test tests/tsconfig-bun-types.test.ts
@see https://bun.com/docs/typescript-6 · tool tools/tsconfig-types-audit.ts
# Integrity
bun run validate:workspaces
bun run validate:workspaces --verbose
bun pm ls
bun install --dry-run # must succeed with frozenLockfile=true
bun run check:tsconfig-types -- --strict # TS6 types: monorepo_risk=0
# Package scripts — full filter semantics: § bun --filter above
bun run --parallel --filter '*' --if-present test
bun run --filter @factorywager/registry-client build
bun run --filter sports-terminal-os typecheck
bun run --sequential --workspaces --if-present typecheck
# Root product / ops (never --filter these names)
bun run ops:limits:check
bun run portal:snapshot:once
bun test tests/limits-e2e.test.ts
# Dep edits (UNIFIED)
# 1) frozenLockfile=false temporarily
# 2) bun add / bun update / catalog edit
# 3) frozenLockfile=true + commit bun.lock
Scope-aware data-plane captures (not registry bake). Operator SSOT:
portal-snapshot-cron.md · bun run docs:tenant-portal-snapshot.
| Wrong | Right |
|---|---|
bun run --filter '*' ops:limits:check |
bun run ops:limits:check |
Docs listing registry/packages/* as root workspaces |
Nested monorepo under projects/active/factorywager/registry |
bun-types: "latest" in a workspace package |
catalog: after pinning in root catalog |
Partial trustedDependencies: ["one-pkg"] |
Full list (replaces Bun defaults) |
Expecting --filter to select test files |
Path globs / bun test patterns |
Treating docs ?search=type:toml as a CLI flag |
Docs UI facet only; real filter is name/./path (pm/filter) |
bun run --parallel vs bun test --parallel confusion |
Foreman workspace scripts vs test workers (day-loop) |
bun run --workspaces test without --if-present |
Most packages lack test — always pair --if-present here |
| Doc / tool | Role |
|---|---|
monorepo-health.md |
Score · cycles · large files |
IMPORT_BOUNDARIES.md |
Package import allowlists |
bun run audit:packages |
Packages graph bake |
bun run packages:list |
Registry table refresh |
| Commit | Note |
|---|---|
205a04d45 |
homebase gate · package exports · archive · portal snapshot cron |
5245a7aca |
trim root workspace deps · STO typecheck · stable chart snaps |
623e7ac44 |
catalog SSOT · lockfile ghost · UNIFIED catalog section |
Tag: v5.2.2-monorepo-workspaces-catalog