Design decisions¶
Forest's architecture is recorded as short Architecture Decision Records
(ADRs), committed alongside the code in docs/adr/. They are the "why"
behind the behaviors the tutorial and
data model describe. Grouped by theme:
Where things live¶
- Keep data outside
.forest/— workspaces store pointers and metadata, never the data itself; multiple repos can point at the same data without copying. - Resolve local path bindings from the workspace root —
relative bindings in
local.yamlresolve from the workspace root, not the checkout metadata directory. - Store local data paths in local config —
stage↔path bindings are user-specific, so they live in the gitignored
local.yaml, not shared config. - Keep runtime state local —
HEAD,local.yaml, andsync_state.jsonare per-machine runtime state, ignored by git. - Default
remote_pathto<checkout>/<stage>— checkouts share physical remotes, so stage paths are namespaced by checkout name to prevent collisions.
Config & pointers¶
- Use
HEADfor the active checkout pointer — mirror git's split between the active pointer and config files; switching rewrites onlyHEAD. - Use functional workspace config —
.forest/config.yamlis the source of truth for checkout registration, not a generated summary. - Remove global
--config— one active config resolved from the workspace; no competing entry points.
Discovery & reach¶
- Halt workspace walk-up at the first repo boundary —
workspace discovery ascends to the nearest
.forest/or.gitand never pierces a nested repository. - Reach other repos with
-C <path>, not a hub — the git-style directory flag replaces any parent-registers-children hub model.
Sync semantics¶
- Give bare
checkout,push, andpullgit-like defaults — bare verbs cover bound stages (warn + skip on unbound),--allstays strict, and a single configured remote is used automatically. The contract behind chapter 5. - Support a single active machine in v1 — user-local files may ride along on file-sync tools; v1 documents the one-active-machine assumption instead of building distributed safety.
- Record content hashes in sync state, not just paths and sizes —
sync entries carry per-file SHA-256 hashes, so same-size edits re-push
instead of skipping;
status --checksumopts into re-hashing local contents. - Pull atomically and refuse to overwrite uncommitted local changes —
pulls land via temp file + atomic rename (old-or-new bytes, never
garbage), and a locally modified file refuses without
pull --force. - Verify every transfer against the remote by default —
the order is transfer → verify → record; a failed verification exits
nonzero and records nothing.
--no-verifyopts out. - Refuse to overwrite remote files that changed behind forest's back —
git's force-with-lease, adapted: push checks remote keys against the last
recorded snapshot and
push --forceoverrides. Also scopes the checkout lock around whole transfers. - Give each stage a transfer direction policy —
a per-stage
direction: push | pull | bothin shared config; bare verbs skip wrong-direction stages with a note, explicit selection hard-errors, and no flag overrides it. - Skip unchanged pulls only when source hashes prove equality — pull fingerprints the live remote unit and skips a clean local copy only when path, file set, sizes, and content hashes all agree.
Scope & lineage¶
- Extract forest from biostore as a standalone data engine — forest's origin story.
- Forest is domain-agnostic — forest moves files and tracks sync state; it never interprets contents.
- Feed the pipeline with
locate+ schemakey_outputs— keep forest pipeline-agnostic; pipelines query forest rather than hand-listing paths.
Interfaces¶
- Rebuild the interactive tui on Textual —
the hand-rolled termios loop gives way to a Textual app (mouse, unit
drill-down, testable in CI); the gather layer and the static
--once/piped frame stay renderer-agnostic and byte-identical.
Testing¶
- Require a real-S3 round-trip integration test — the local rclone backend can't exercise S3 auth or URL construction, so a real bucket round trip gates releases.
Scope¶
- Simplify forest to single-user scale —
the TUI, observability stack, circuit breaker, legacy-layout migration,
and other fleet-scale surface are cut; pre-1.0 layouts re-init, pre-hash
sync entries heal on push, and bare
forestprints help.