No description
  • Rust 95.6%
  • Shell 3.3%
  • Nix 1.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-11-09 19:20:32 +01:00
.forgejo/workflows ci: hint at the tag input when a run is a no-op 2026-11-04 23:13:52 +01:00
crates add a tag for builtin collections 2026-11-09 19:19:40 +01:00
deploy/phoneserver nix: packages.phone, the binary with how phoneserver runs it 2026-11-04 19:34:05 +01:00
docs portal tls via caddy on the phone, tls-alpn-01 2026-10-30 22:54:22 +01:00
scripts add to playlist fix 2026-11-07 15:46:23 +01:00
.gitignore initial commit 2026-10-30 00:31:00 +01:00
Cargo.lock chore: Cargo.lock for v0.3.15 2026-11-09 19:20:32 +01:00
Cargo.toml v0.3.15 2026-11-09 19:20:09 +01:00
clippy.toml initial commit 2026-10-30 00:31:00 +01:00
CORE.md ui: save the files or make it your own; streamed marks; profile pages 2026-11-02 20:33:40 +01:00
DESIGN-LOG.md add playlist interop with subsonic 2026-11-07 13:23:13 +01:00
DESIGN.md add playlist interop with subsonic 2026-11-07 13:23:13 +01:00
flake.lock static aarch64 build in a nix cross shell instead of docker 2026-11-01 20:05:36 +01:00
flake.nix ci: unify release and build into one workflow 2026-11-04 23:01:26 +01:00
IMPL.md add some docs 2026-10-30 19:54:27 +01:00
NOTES.md portal tls via caddy on the phone, tls-alpn-01 2026-10-30 22:54:22 +01:00
README.md ui: Overview and Account pages; albums without add controls; nav reordered 2026-11-01 22:17:48 +01:00

chambers (working title)

A small, self-hosted file library with sharing between servers (earlier working title: Borges).

Document What
CORE.md The core idea on one page: who owns what, how sharing works. Start here
DESIGN.md The model and protocol: the current design, the single source of truth
IMPL.md How to implement it (functional core, constructive types, testing)
DESIGN-LOG.md Design decisions, newest last: what, why, and what led to them
NOTES.md What implementing it taught us; the input to the log

v0.1: experimental, expected to be thrown away. The core is meant to last; the server and UI are for exploring.

Layout

Path What
crates/chambers-core The pure core (no_std): every type and decision of spec §6.0. No I/O.
crates/chambers-core/tests/federation.rs Simulated federation: spec §14's scenarios across several in-process servers (tests/sim).
crates/chambers-server The shell: axum HTTP, state in SQLite (<data>/chambers.db), blob store with outboards, outbound client (takes only core Requests), reconcile loop, outbox, moves (410, export/import as one SQLite file), and a plain-HTML UI.
scripts/ dev.sh (N local servers), e2e.sh (real-HTTP scenarios), phone.sh (run on an Android emulator via adb).

Core modules, in the order of the spec's model: hash, file (files, the per-file limit), member (members: files and collection refs, Members, Form), manifest (pages, roots, cut), authored (lists, published_root, history), entry (Holding, Overrides, shown), access (grants, Audience, capabilities, reach, may; read is the one right), sync (Follow, Mirror, Snapshot, Walk, Mirrors, Policy, Transfer), identity (account key, records, accept_record), links (actor documents, templates, routing, Request, with_token), refs, notice (accept_notice), and account: the one value the shell stores, whose transitions (create, edit_list, copy, delete, follow, set_mirror, keep, ...) keep its invariants and whose derived reads (shown, current, member_of, visibility, transfers, usage, ...) answer everything else. filing sits beside it, outside the model: where collections go among the user's lists (holder, home, proposal, place, the default lists), using only the account's public API. Plus names, url, token, time, json (canonical encoding), protocol (the only place the project name appears on the wire).

Develop

nix develop                 # or direnv
cargo test                  # core properties + simulated federation (~7 s)
nix flake check             # tests, clippy -D warnings, fmt, and a real no_std build (wasm32v1-none)

Run

scripts/dev.sh 3 --fresh    # http://127.0.0.1:8001, :8002, :8003 (dev mode)
scripts/e2e.sh              # in another terminal: scenarios 2, 3, 4, 9 (move), 18 (lists of
                            # albums) and links over real HTTP; PORTS="8101 8102 8103" for others

A database from an earlier schema version isn't read (the server says so and stops); start with --fresh or move dev-data away.

Open http://127.0.0.1:8001, register, upload, put a collection on your profile (public) or share it with bob@127.0.0.1:8002; on the other server, accept it under "Incoming" or browse alice@127.0.0.1:8001 under "Follow". Handles in dev mode include the port.

On an Android emulator

nix build .#static          # result/bin/chambers: static aarch64 musl
scripts/phone.sh            # builds that, pushes it, runs it on the device as 127.0.0.1:8004 (adb in PATH)

phone.sh bridges ports with adb reverse/adb forward, so the phone's server and the host's servers reach each other as 127.0.0.1:<port>. Tested: a user on the emulator follows a collection on the host (same root hash, kept copies), shares a file from the phone with a user on the host, who plays it linked through his own server.

Production (not tried yet)

chambers --data DIR --listen 0.0.0.0:8080 --base https://host behind a TLS terminator. Outbound requests then refuse loopback and private addresses (spec 13.2).

Registration is by invite unless --registration open (or closed: no new accounts). The first account's invite code is in the log (no accounts yet: make the first one with invite code ...); after that, accounts make codes on their Account page. A forgotten password is reset on the login page with the account's recovery code.