Documents the project-wide rule that Red Bear OS local forks are the complete, authoritative source of truth for every component they cover. Key points: - A fork that delegates to upstream/crates.io is not a fork — it's a wrapper. - Missing fork functionality is implemented in the fork, not papered over. - Path deps + [patch.crates-io] everywhere; no version strings for forks. - Adapt to upstream at the same pace — never pin back. Adds a cross-reference from local/AGENTS.md DESIGN PRINCIPLE section.
12 KiB
Local Fork Supremacy Policy
Status: ABSOLUTE — Do not violate.
Established: 2026-07-10 (reinforced during setrens namespace debug session)
Scope: All Red Bear OS components, all agents, all operators.
Core Principle
Red Bear OS local forks are the COMPLETE, AUTHORITATIVE source of truth.
Everything else — upstream Redox, crates.io, third-party registries — exists ONLY as reference material and raw material that flows INTO our local forks. Our local forks are NOT thin wrappers, NOT compatibility shims, and NOT delegators that "just call upstream".
If a component is forked, it is forked COMPLETELY. Our fork contains every piece of functionality our system needs, implemented in our tree, maintained by us.
The Fork Model
What Red Bear OS Is
Red Bear OS is a full fork of Redox OS, based on frozen Redox snapshots
(currently 0.1.0 at build-system commit f55acba68). We are NOT a downstream
distributor of Redox. We are NOT a configuration overlay on top of Redox.
We took Redox as a starting point and are building our own complete operating system on top of it. The fork boundary is real: every component we depend on lives in our tree.
The 9 Declared Submodules
| Submodule | Branch | Path |
|---|---|---|
| base | submodule/base |
local/sources/base |
| bootloader | submodule/bootloader |
local/sources/bootloader |
| installer | submodule/installer |
local/sources/installer |
| kernel | submodule/kernel |
local/sources/kernel |
| libredox | submodule/libredox |
local/sources/libredox |
| redoxfs | submodule/redoxfs |
local/sources/redoxfs |
| relibc | submodule/relibc |
local/sources/relibc |
| syscall | submodule/syscall |
local/sources/syscall |
| userutils | submodule/userutils |
local/sources/userutils |
9 submodules. No more, no less. The fork inventory is closed by policy.
Adding a new submodule requires explicit operator justification (see
local/AGENTS.md § BRANCH AND SUBMODULE POLICY).
Tracked Trees (Not Submodules)
Some components live as full tracked trees under local/sources/<name>/ instead
of as submodules. They have the same fork-supremacy guarantee — the local tree is
the source of truth. Examples include libredox, redox-scheme, and other
smaller but critical components that don't have upstream worth tracking on a
dedicated branch.
Local Recipes (Original Red Bear Code)
Components with NO upstream origin (e.g. tlc, redbear-sessiond,
redbear-authd, redbear-greeter, cub) live as local recipes under
local/recipes/<category>/<name>/source/. These are 100% Red Bear original code
and are the only authoritative implementation.
The Five Rules of Local Fork Supremacy
Rule 1: Local Fork First, Always
If a component has a local fork, EVERY dependency on that component MUST route through the local fork. Period.
- ✅
path = "../../../../local/sources/<fork>"in any Cargo.toml - ✅
[patch.crates-io]entry pointing at the local fork - ❌ Version-string dependency (
redox_syscall = "0.9") - ❌ Exact-pin dependency (
redox_syscall = "=0.9.0") - ❌ "Let's just use crates.io for now, we'll fix it later"
- ❌ "Upstream has a newer version, let's skip our fork this once"
Crates.io may resolve the SAME crate independently of our fork, creating two copies in the build graph and producing silent ABI mismatches. This is not a hypothetical risk — it has caused real, hard-to-debug build failures in Red Bear history. The path dependency eliminates the ambiguity entirely.
Rule 2: Local Fork Complete, Not Partial
A local fork must implement everything Red Bear OS needs from that component. If the fork is missing functionality, implement it IN THE FORK.
There is no acceptable shortcut where our fork "defers to upstream" or "passes through to crates.io" or "re-exports from the system version". A fork that delegates is not a fork — it is a wrapper.
When the kernel needs a syscall (SYS_SETRENS, SYS_SETNS, SYS_MKNS) and the
upstream Redox kernel does not implement it, the Red Bear kernel fork MUST
implement it. The relibc fork MUST route through it. The syscall crate fork
MUST define the number. No layer says "we don't support this, use a different
API". We adapt our entire stack to be complete.
Concrete example from this very session: the setrens(0, 0) call in
local/sources/base/init/src/main.rs:192 panicked on bare metal because the
SYS_SETRENS/SYS_SETNS/SYS_MKNS namespace syscalls were not implemented in
the kernel fork. The fix is not to make init tolerate the failure (a workaround)
— the fix is to implement the missing functionality in the kernel fork properly.
Rule 3: Adapt to Upstream, Never Pin Back
When upstream Redox changes a dependency version, API, or ABI, Red Bear adapts — fully.
- Upstream bumps
redox_syscallto0.9→ every Red Bear crate that touchesredox_syscallmoves to0.9— we fix our code, not theirs. - Upstream renames a type → our fork renames it too (or wraps it with a compat layer inside the fork).
- Upstream drops a function we depended on → we either reimplement it or re-architect around it. We never pin back.
This is not just convenience. It is the long-term maintenance contract that keeps the fork healthy: as upstream evolves, our local forks track and adapt at the same pace. Pinning back creates "dead branches" of the fork that accumulate divergence and become impossible to rebase.
Rule 4: Single Source of Truth Per Concept
If two places in Red Bear OS can answer the same question, we have a bug.
The local fork is the single source of truth for how Redox syscalls work, how relibc functions behave, how the kernel allocates memory. There is exactly one implementation, in exactly one tree, and every other tree imports from it.
This is why we use path dependencies and [patch.crates-io]. This is why we
ban "stub" implementations that pretend to provide an interface. This is why
we remove duplicate files (e.g. the redox.patch symlinks from before we
switched to local forks — see local/AGENTS.md § LOCAL FORK MODEL).
If a feature appears in both the local fork and in some "in-tree copy", the "in-tree copy" is dead code and must be removed.
Rule 5: Document the Fork Boundary
Every local fork commit that diverges from upstream MUST include:
- A clear commit message explaining what changed and why.
- The upstream commit/tag the fork is based on (in the commit body).
- If the divergence is significant, an entry in
local/docs/orlocal/AGENTS.mddescribing the architectural choice.
This is what makes the fork auditable. An operator looking at the fork history six months from now needs to be able to understand: what did we take from upstream, what did we change, and why.
What "Complete" Looks Like (Concrete Checklist)
For every local fork at local/sources/<name>/:
Cargo.toml(orMakefile) exists and declares all dependencies as path deps to other local forks, with[patch.crates-io]if needed.Cargo.tomlversionfield follows the fork versioning convention:<upstream-version>+rb<redbear-branch>(e.g.0.6.0+rb0.3.0).authorsfield credits both upstream maintainers AND every Red Bear contributor who has commits on the fork.- All functions/types/syscalls that Red Bear OS uses are implemented in the fork — none fall through to "unimplemented" stubs.
- No
unimplemented!(),todo!(), orunreachable!()in code paths Red Bear exercises (warnings policy fromlocal/AGENTS.mdapplies). - All cross-fork references use relative
path = "..."dependencies, not absolute paths or crates.io versions. - Source tree is tracked in git and pushed to the
submodule/<name>branch ongitea.redbearos.org/vasilito/RedBear-OS.
For the syscall crate specifically:
- Every syscall number used by relibc MUST be defined in
local/sources/syscall/src/number.rs. - If relibc calls a syscall that is not yet defined, ADD the syscall number to the syscall crate AND implement it in the kernel fork. Both edits go in the same work session.
For the kernel fork specifically:
- Every syscall called from relibc/redox-rt MUST have a handler in
local/sources/kernel/src/syscall/mod.rs(or a sub-module it dispatches to). Unhandled syscalls returnENOSYS— which is the correct behavior, not a bug. But if relibc ACTUALLY uses the syscall in its startup path, the kernel MUST implement it. - No panic/abort paths in kernel code. Errors propagate via
Result.
For relibc/redox-rt specifically:
- Every public function used by Red Bear binaries (init, bootstrap, base daemons, libredox wrappers) MUST be implemented. If upstream removed or renamed a function, we reimplement or wrap — we do not delete the function from the API surface.
Anti-Patterns (Strictly Forbidden)
| Anti-Pattern | Why It's Forbidden |
|---|---|
redox_syscall = "0.9" (version string) |
Pulls from crates.io, creates dual-copy ABI mismatches |
as any / @ts-ignore / unwrap() on fork APIs |
Hides real bugs; kernel fork must not have panic paths |
| Commenting out a fork function to fix a build | Deletes functionality; the function exists for a reason |
| "Let's wait for upstream to add this" | We are a fork. We adapt or reimplement, we don't wait |
| Delegating fork work to crates.io | Two implementations of the same concept = guaranteed divergence |
| Skipping a fork submodule because "it's not used" | Every declared submodule is used somewhere in the build graph |
Adding an unimplemented!() with #[allow(dead_code)] |
This is a stub. Stubs are forbidden (see local/AGENTS.md) |
Enforcement
- Build preflight (
local/scripts/build-preflight.sh+verify-fork-versions.sh):- Rejects builds that use version-string deps for any Cat 2 fork crate.
- Rejects builds where fork version labels don't match upstream base + branch.
- CI gates:
sync-versions.sh --checkverifies Cat 1/Cat 2 version compliance.- Fork version drift is a build-blocking error.
- Operator review:
- Any new submodule addition requires operator sign-off and a documented
necessity case (see
local/AGENTS.md§ BRANCH AND SUBMODULE POLICY). - Any removal of fork functionality requires explicit user request.
- Any new submodule addition requires operator sign-off and a documented
necessity case (see
When This Policy Was Last Verified
- 2026-07-10: Reinforced during bare-metal boot debugging. The
setrens(0, 0)panic in init'smain.rs:192was traced to missing kernel-side namespace syscall implementations (SYS_MKNS,SYS_SETNS,SYS_SETRENS). The Red Bear fork policy requires implementing these in the kernel fork — not papering over them with.expect()→ panic bypass.
Related Documents
local/AGENTS.md— full Red Bear agent guidance (branches, submodules, durability)local/docs/SOURCE-ARCHIVAL-POLICY.md— how sources are frozen and archivedlocal/docs/PATCH-GOVERNANCE.md(referenced inlocal/AGENTS.md) — how patches are rebased and appliedREADME.md(project root) — high-level description including the fork model