The core of the lichen-site crate (lichen-cms renamed): its manifest and module list, settings, the runtime and how it is built, and what a site's work may ask of its owner and of the server it runs in. Much of it moved from lichen-server into the site crate (PER-SITE-PROCESS P2c-2b), so a site can run in a process of its own. Later SITE-FRONT-BOUNDARY units took the owner's session and the server's in-process host back out, so the site's main runtime sees only its owner's public facts; since FULL-SITE-PROCESS the site process's admin thread holds the session the front server lends it, and the admin-area code is given what it needs through the seams defined here.
AST-verified changes
- The crate rename lichen-cms → lichen-site (P2c-1, d7c4a668). Map
machine-docs/reviews/P2C1-RENAME-MOVE-MAP-2026-10-09.json. Builder (run id not recorded): "Rename move check with rn6 at f3e7470b..d7c4a668: ok (4365 items, 113 renamed, 1874 carried, 0 visibility)". Adversary: "d7c4a668 equal=true 0-err 113-renamed 1874-carried 0-vis". Allowed:lichen_cms→lichen_siterewrites,Cargo.tomland static files as other files, rustfmt rewraps. String literals were changed in a separate commit, 8eef92b4. - P2c-2b moves from lichen-server into this crate (2026-10-10; maps in
machine-docs/reviews/P2C2B-maps/, ast-checker 9a9c4144 with--crate lichen-server --crate lichen-site; run ids not recorded; "vis" meanspub(crate)→pubwidenings declared in the map):- c0 (97e70426):
AuthProviderusers.rs →owner.rs, andrandom_hexauth/token.rs →utils.rs(sources in #30). Adversary: "moved4/vis1". - c1a (ff26fefc):
token_scope.rsandruntime_registry.rsfrom the server, items intoextensions.rsandtypes.rs; the site_process files are in #19. Builder: "5 moved, 48 carried, 8 files renamed, 19 visibility as mapped". - c1b (dba66e8b):
SiteServerSettingsintosettings/server.rs. Builder: "2 moved, 3 visibility". - c1c (85a5e79e): the settings helpers from the server's
api.rsandutils.rsintosettings.rsandsettings/edit.rs(sources in #32 and #33). Builder: "10 moved, 3 visibility". - c2a (02255939): the owner seam,
credentials.rsandowner.rs, from the server. Builder: "2a recheck ok (12 moved, 5 carried, 1 renamed, 20 visibility; plant refused)". - c2b (0f6f6f57): the
SiteHosttrait,site_host.rs→host.rs. Builder: "1 moved, 1 visibility". - c5 (6c06675b): the settings page's context into
settings/page.rs(source in #33). Builder: "move 5 ok: 10 moved, 4 carried, 1 renamed, 4 vis". - c6 (247be4a2): the site's side of the server's
features.rsintofeatures.rs(source in #31). Builder: "move 6 ok: 18 moved, 0 vis". - c7b (66a7caa9):
runtime_build.rsfrom the server. Builder: "moves 7b and 7d ok, plants refused". The adversary's reruns got the same counts (A11333–11336).
- c0 (97e70426):
- ORR R7 rename by back-substitution (d52675cd), here in
features.rs,runtime.rsandtypes.rs:Made::Published→DistInstalled,PublishHook/Attempt/Record→Publication*and their kin. Builder notify-392a0b96: "names substituted back AST EQUAL, control RED". Adversary: "rename AST-equal (control RED)". The rest is in #24 and #27. - Checked on a rebuilt pure move (SFB 7b, inside 5670cd85):
enum PdsScopeand its impl leftowner.rsfor the front server'ssite_area/remote.rs(#23). Builder notify-9a972a6c: "equal, 2 moved, 4970 stayed, no errors". Adversary notify-222a9edd: "equal, 2 moved, 0 errors; 3 plants refused".
Roughly 1,120 of this PR's 3,727 changed lines are code these moves carried verbatim. A move from the front server shows here as added lines, and its other half as deleted lines in that server file's PR. What changed after the moves is the rest.
On this forge the 9 renamed files here show as a whole deletion and a whole addition, so its diff reads 7,339 changed lines; with rename detection (git diff -M full/20-shell full/21-site-core) it is 3,727.
What changed and why:
- lichen-cms became lichen-site (P2c-1).
lib.rsis the module list, andCargo.tomlis the new crate's manifest; lichen-cms's is deleted. The lichen-iroh and lichen-shell folds are in #28 and #36. - A site's work stops reaching into the front server (P2c-2a seams, then P2c-2b moves):
owner.rs:SiteOwnerandOwnerFacts. A site process's owner isLinkOwner, whose facts came with the launch; a change of them recycles the process (N8).host.rs:SiteHost, what a site needs of its server. The site process's implementation is its only one now, since the front server's in-processsite_host.rswent (SFB 11e11).credentials.rs: keeps the session's type,SiteCredentials. The front server lends it to the site process's admin thread, which holds it in memory alone (FULL-SITE-PROCESS 6d) for itspds://pushes and its records; the main runtime and its children never hold it.
- Settings (
settings.rs, new at 511 lines; lichen-cms's ownsettings.rsis deleted):SiteSectionsreads[git]and[publish]once, and a section that does not resolve is that feature's error, not an unreadable site (P2c-3).CmsSettingsholds the editor's own look;FrontendSettingsthe[frontend]choice.settings/edit.rsmakes edits inside the tree's transaction,settings/server.rsis the server's settings as a site reads them (from the launch in a site process), andsettings/page.rsgives the settings view's JSON values.
- The runtime (
runtime.rs,runtime_build.rs):- The runtime knows its hub (
HubSlot), its dashboard URL (""on the desktop, none for a single site), the server's plugin defaults, and whether the shortcode cache is on. rebuild()answers what the build installed or kept.runtime_build.rsbuilds a site's runtime the same way for every host (design note §16).
- The runtime knows its hub (
- The seams (
site_seams.rs, new, FULL-SITE-PROCESS unit 4): the plain data and narrow traits (SiteArea,SiteFacts,SiteAsks,MainMoved,OwnerCredentials, …) the admin-area code is given instead of the front server's state, defined in this crate so that code could move in unchanged (unit 5); the site process's admin thread builds them (#21'ssite_process/hub.rs). features.rs: the site's feature wiring: shell and iroh startup decisions, the git listener, the settings router,build_site_runtime.types.rs:StorageLimitState::over_nowasks now rather than trusting the cached flag (SHB-STORAGE1).ssrf_guard.rs: the SSRF guard. It moved here from the front server'sauth/atproto/client.rs(not AST-checked: 5052d193, 2026-09-25), so the frontend loader and the git remotes share one guarded client and address check.[proxy] allow_privateis renamed[egress]in its docs (SFB 12a).AllowedRangeis written and read as its text, so a site process is launched with the operator's ranges (FULL-SITE-PROCESS 6d).- Smaller:
symlink.rs: the escaping-symlink check passes git an extra environment, for the hub's pre-receive.export.rs:export_bytes, a zip never put in the site.token_scope.rs: moved from the server.atproto.rs: the module root for the PDS client.events.rs,extensions.rs,save.rs,settings_cache.rs,utils.rs: renames and small follow-ups.
Files (crates/lichen-site/ unless noted)
src/lib.rs,Cargo.toml— the crate. Read these first for the module list. Since FULL-SITE-PROCESSlib.rsnames the crate by its own name (extern crate self as lichen_site, so moved code keeps its paths) and declaresadmin_area,owner_keyandsite_seams;Cargo.toml'sgittakesflate2,atprotoimpliesgit,irohtakesiroh-blobs, andrustixandurlencodingcome in.src/owner.rs,src/host.rs,src/credentials.rs— what site work may know of its owner and its server.src/settings.rs,src/settings/edit.rs,src/settings/server.rs,src/settings/page.rs,src/settings_cache.rs— settings.src/runtime.rs,src/runtime_build.rs,src/runtime_registry.rs,src/features.rs— the runtime and its wiring.src/site_seams.rs— new: the seams.src/types.rs,src/ssrf_guard.rs,src/symlink.rs,src/token_scope.rs,src/utils.rs,src/export.rs,src/save.rs,src/events.rs,src/extensions.rs,src/atproto.rs— shared pieces.crates/lichen-cms/Cargo.toml,src/lib.rs,src/settings.rs,src/types.rs— deleted.
Moved in: settings/page.rs (round 1's dashboard PR) is placed here because it is the settings view's values, not a page. The deleted lichen-cms Cargo.toml, lib.rs, settings.rs and types.rs are placed with what they became: git pairs them below its rename threshold (lib.rs since this round, when lichen-site's grew by its new modules).
Lives elsewhere
- The site's API and its route table: #35. Frontends and plugins: #34. The shell: #36. Rooms and resync: #29. Builds and the rebuild lane: #27, #26.
- The sources of the P2c-2b moves: #30, #31, #32, #33. The site process that implements
SiteHost: #19. The PDS client underatproto.rs: #24. - Not in any PR (base commit):
static/(the starter sites,nginx.conf,r-lichen.service,settings.toml.example),contract/cms-api.json, and the tests.
Category: Site crate core: settings, runtime, features and the crate itself
Size: 29 files, +3,163/−564
Rounds: round 0 at stack ae42e3c0, unchanged at 29a7c15b and 6b650b2a; round 1 at b66397c0 (FULL-SITE-PROCESS): site_seams.rs is new (unit 4); lib.rs names the crate by its own name and declares admin_area, owner_key and site_seams; Cargo.toml takes flate2, iroh-blobs, rustix and urlencoding; credentials.rs describes the session lent to the admin thread; ssrf_guard.rs's AllowedRange is serializable for the launch; comments in features.rs and owner.rs name the admin thread. Read this round in its interdiff: https://tangled.org/notplants-bot.bsky.social/lichen.page.october/pulls/37/round/1/interdiff
Plans and ledger: FULL-SITE-PROCESS-2026-10-25.md (4, 5a2, 6d); PER-SITE-PROCESS-2026-10-09.md (P2c-1, P2c-2a seams, P2c-2b commits 0–7, P2c-3; design note PER-SITE-PROCESS-P0-DESIGN-2026-10-09.md §§15–16), SITE-FRONT-BOUNDARY-2026-10-17.md (units 9b, 11e11, 12a), OPERATOR-REVIEW-REVISIONS-2026-10-13.md (N4/R7, N8), FRONTEND-API-AND-LOADER-2026-09-24.md (the SSRF guard), the fix SHB-STORAGE1. Adversary review records machine-docs/reviews/PER-SITE-PROCESS-P2C2B-*.md.
Inline #[cfg(test)] modules: none. 10 files point to a test file with #[path] (credentials.rs, export.rs, runtime.rs, runtime_registry.rs, save.rs, settings.rs, settings_cache.rs, ssrf_guard.rs, symlink.rs, utils.rs), and lib.rs has test-only items.
Bucket moves: settings/page.rs from round 1's dashboard PR; the four lichen-cms deletions placed with what they became (see Moved in). Round 1's site core is split in this set into this PR, #35, #34 and #36.
Round 1: #13 (Site crate core) covered most of these files; #12 (Dashboard) covered settings/page.rs. atproto.rs, export.rs, extensions.rs, runtime_registry.rs, save.rs, settings/edit.rs, settings_cache.rs, ssrf_guard.rs, token_scope.rs and utils.rs are new to the set in this range.