The workspace manifest globs crates/*, so cargo fetch parses every
member's Cargo.toml; rhema-sandbox-ecrou joined the tree without its
manifest joining the COPY list, and both image builds died at manifest
parse ("failed to read /build/crates/rhema-sandbox-ecrou/Cargo.toml").
Add the line to claw.Dockerfile and sandboxd.Dockerfile, in the
alphabetical position the list keeps.
The images resolve the whole workspace graph before cargo fetch, so
every member manifest has to be in the build context by then, and
the copied list had fallen six crates behind the workspace: the
backend split added sandbox-local, sandbox-lxd, and sandbox-server,
and the cloud frontends added cloud-agent, cloudflare-code, and
vercel-agent. rhema-code path-depends on the sandbox backends, so
the claw image was the first to break — the fetch died reading the
lxd manifest.
privacy.rs bound the opened handle in a name only the unix build
used, so `-D warnings` failed the wasm target; the bind is now
`_file` and the unix branch uses it.
The docker images resolve the whole workspace manifest graph before
`cargo fetch`, so they now copy the tools contract with its workspace
root plus the sandbox manifests rhema-code path-depends on, and the
stub loop covers tools/*/ too.
The crate was missing from the per-member manifest COPY list, so the
workspace failed to resolve in the registry-cache layer: rhema-claw
path-depends on rhema-transcript, whose Cargo.toml never landed in
the context.
rhema-code grew a path dependency on the new rhema-subagents crate, but
the image's manifest-only staging layer never copied its Cargo.toml, so
workspace resolution died before cargo fetch could run.
The stored `colors` key names a palette — rhema (the default,
Jadeite), aquamarine, black-and-white, or dracula — and the
Appearance page of /settings cycles it live, like the theme and
icon toggles beside it. Each palette carries a dark and a light
appearance under the existing `theme` key; dracula's light side is
derived, the official palette ships only dark.
The appearance decision moves off token comparison: Theme now
answers is_dark() from the ground/text luminance, so palettes
beyond the original two get the right per-profile fallback tones.