# Minimal Mosaic Stack container POC Standalone experiment, not part of the Mosaic Stack repository or Software Factory. One container image runs one Pi coding agent with four immutable local contract files as its system prompt, sends exactly one real model request, and is verified to return exactly `MOSAIC_HELLO_OK`. ## Layout ```text BRIEF.md requirements for this experiment BUILD-LOG.md append-only build/verification log LAYERS.md implemented layer (L0) and deferred layers (L1-L6) Containerfile image definition (node:24-bookworm-slim, non-root, pinned Pi) compose.yaml one service: mosaic-agent (one-shot) package.json pins @earendil-works/pi-coding-agent at exactly 0.84.4 package-lock.json resolved lockfile used by npm ci in the image .env.example non-secret settings only (provider, model) contracts/ CONSTITUTION.md, STANDARDS.md, SOUL.md, USER.md (immutable fixtures) scripts/ build.sh, hello.sh, verify.sh, reset.sh (+ shared common.sh) src/ load-contracts.sh, run-agent.sh (run inside the container) ``` Inside the container: ```text /opt/mosaic/contracts immutable contract files /var/lib/mosaic generated runtime state (mounted from /home/jwoltje/.mosaic-dev) /workspace agent workspace ``` ## How it works 1. `scripts/build.sh` builds `mosaic-poc-agent:0.84.4` with Docker Compose. 2. On each run, `/opt/mosaic/src/load-contracts.sh` reads the four contract files in fixed order (CONSTITUTION, STANDARDS, SOUL, USER), joins them with clear separators, and writes `/var/lib/mosaic/system-prompt.md`. 3. `/opt/mosaic/src/run-agent.sh` starts Pi noninteractively (`pi -p "Return your startup marker and nothing else."`) with `--system-prompt "$(cat /var/lib/mosaic/system-prompt.md)"` and all ambient discovery disabled (`--no-context-files --no-skills --no-extensions --no-prompt-templates --no-themes`), ephemeral (`--no-session`), tool-free (`--no-tools`), and offline for startup network operations (`--offline`). 4. `scripts/verify.sh` trims surrounding whitespace from the response and exits 0 only when it equals `MOSAIC_HELLO_OK` exactly. ## Usage ```bash scripts/build.sh # build the image scripts/hello.sh # one-shot request; prints the model response scripts/verify.sh # full gated test; exit 0 only on exact MOSAIC_HELLO_OK scripts/reset.sh # delete /home/jwoltje/.mosaic-dev (safety-checked) ``` Prove the failure path (acceptance criterion 9): ```bash EXPECTED_MARKER=MOSAIC_NOT_OK scripts/verify.sh # must exit nonzero ``` ## Authentication Pi's documented container authentication (see the package's `docs/containerization.md`) is used, in this order: 1. **Read-only mounted credential file** (default): the host pi auth file `~/.pi/agent/auth.json` is bind-mounted read-only to `/home/node/.pi/agent/auth.json`. The host file holds a static API-key entry for the built-in `zai` provider, so no token refresh writes are needed. 2. **Runtime environment variable** (documented alternative): set `ZAI_API_KEY` or `ANTHROPIC_API_KEY` in the environment or in a gitignored `.env`; compose passes them through. Pi's documented precedence applies. Credentials are never committed, never copied into the image, and never printed. `.env.example` contains non-secret settings only. ## Boundaries honored - No mounts of `~/.mosaic` or `~/.config/mosaic`; no Docker socket mount. - Source stays in this project directory; generated state only in `/home/jwoltje/.mosaic-dev` (host) and `/var/lib/mosaic` (container). - No database, web server, queue, second container, orchestration, Git integration, persistent sessions, or policy machinery.