Files
stack/docs/plans/2026-09-02_atomic-mosaic-foundation.md
T
jason.woltje c2365ae519 chore: baseline container POC and atomic foundation plan
- Containerized Pi hello-world proof (image mosaic-poc-agent:0.84.4, non-root)
- Four immutable contract fixtures loaded into a generated system prompt
- build/hello/verify/reset scripts with exact-match gating and reset safety
- Documented Pi discovery (v0.84.4, -p mode, --system-prompt, container auth)
- Append-only BUILD-LOG with corrections; deferred layers in LAYERS.md
- Architecture plan: docs/plans/2026-09-02_atomic-mosaic-foundation.md
2026-09-02 18:24:36 -05:00

11 KiB

Atomic Mosaic Foundation Plan

Date: 2026-09-02
Status: Planning; configuration-driven L0 not yet implemented
Project: Standalone Mosaic Stack rebuild experiment

Purpose

Reimplement Mosaic Stack from atomic, independently verifiable layers. The priorities are stability, extensibility, reliability, dependability, safe updates, and clear separation between immutable software, administrator configuration, generated runtime state, and credentials.

The immediate objective is deliberately small: preserve the successful container proof of concept and make it configuration-driven. Mission/task abstraction comes only after the foundation is stable.

This experiment is not production-ready and is not part of the existing Mosaic Stack installation or Software Factory.

Current state

The existing L0 proof of concept demonstrates that the basic approach works:

  1. One container image builds successfully.
  2. It runs as a non-root user.
  3. It contains a pinned Pi installation (@earendil-works/[email protected]).
  4. It loads four local contract files in a deterministic order.
  5. It generates /var/lib/mosaic/system-prompt.md.
  6. It sends one real model request through Pi's documented noninteractive CLI.
  7. The request does not contain the expected marker.
  8. The model returns exactly MOSAIC_HELLO_OK.
  9. Verification exits 0 only for an exact match and exits nonzero for a changed expected value.
  10. Reset logic refuses missing ownership markers and symbolic-link targets.
  11. Resetting and rerunning produces the same successful result.

The proof uses:

  • Immutable implementation and contracts in the container image
  • /home/jwoltje/.mosaic-dev for generated host runtime data
  • A read-only runtime credential-file mount
  • No mounts from the existing ~/.mosaic or ~/.config/mosaic

The current proof is not yet driven by a central Mosaic configuration file.

Problem being addressed

The existing ~/.mosaic and ~/.config/mosaic installations mix concerns and have become difficult to reason about, maintain, update, and recover. The rebuild must avoid repeating that design.

Primary questions for later layers include:

  • Bare-metal versus containerized installation
  • Directional control and enforceable agent capabilities
  • Pseudo-sandboxing and privilege containment
  • Integration with Pi, Claude, OpenCode, Codex, and other harnesses
  • Predictable scaling
  • A configurable software factory / agentic operating environment without forcing one workflow

These questions must not all be solved in L0.

Architectural direction

Use a hybrid architecture:

  • A minimal host launcher/control plane reads configuration, validates paths, selects a release, starts workers, and records lifecycle results.
  • Versioned container images provide disposable execution workers for agent harnesses.
  • Agent execution does not occur directly in the host control plane.
  • Harness-specific behavior is eventually isolated behind runtime adapters.

Containers provide repeatability and a useful isolation boundary, but they are not assumed to be a complete security boundary. Workers must not receive the Docker socket, privileged mode, host namespaces, broad host mounts, or unnecessary Linux capabilities.

Storage model

Use only two Mosaic-owned persistent host locations during development:

/home/jwoltje/.config/mosaic-dev/config.json
/home/jwoltje/.mosaic-dev/

Their ownership and lifecycles are intentionally different:

Location Owner Purpose Mutation policy
~/.config/mosaic-dev/config.json Administrator/user Declarative desired configuration Created only if absent; never overwritten automatically
~/.mosaic-dev/ Mosaic runtime Generated and durable runtime state Mutable, but protected by ownership/path checks
Container image Mosaic release Core implementation, dependencies, immutable contracts/defaults Immutable; replaced rather than edited
Credential provider/store External Authentication secrets Supplied only at runtime; never copied into an image or Mosaic configuration

After the design is proven, the configuration location may become:

/home/jwoltje/.config/mosaic/config.json

The existing ~/.mosaic and ~/.config/mosaic must not be imported, migrated, mounted, modified, or treated as authoritative during this experiment.

Why configuration and data remain separate

Keeping configuration outside the runtime data root prevents reset, cleanup, or runtime failures from deleting administrator intent. Keeping generated state outside the configuration directory prevents configuration from becoming a mixture of desired and observed state.

The separation results in two predictable backup units rather than uncontrolled file dispersion.

Minimal development configuration

The first configuration should contain only what the Hello World layer needs:

{
  "configVersion": 1,
  "environment": "development",
  "dataRoot": "/home/jwoltje/.mosaic-dev",
  "execution": {
    "backend": "docker",
    "provider": "zai",
    "model": "glm-5.3-flash"
  }
}

The exact image version belongs to the immutable release definition, not administrator configuration. Credentials must not appear in this file.

Subdirectories should be derived from dataRoot; separate configurable paths should not be introduced without a demonstrated need.

Configuration invariants

  1. ~/.config/mosaic-dev/config.json is the sole Mosaic discovery entry point during development.
  2. Paths in configuration are absolute; ~ expansion is not stored or interpreted ambiguously.
  3. Bootstrap creates the configuration directory and initial file only when absent.
  4. Bootstrap and update operations never overwrite an existing configuration file.
  5. Configuration has an explicit configVersion.
  6. Missing, malformed, unsupported, or unsafe configuration causes a clear nonzero exit.
  7. Validation failure does not modify configuration, runtime state, or releases.
  8. Generated and observed values are never written back into config.json.
  9. Secrets and credential contents are never stored in config.json.
  10. Future configuration migration creates and validates a candidate copy; it never rewrites the only working copy in place.

The configuration file is declarative. The bootstrap and activation operations around it must be idempotent.

Update-safety invariants

The design target is that software updates cannot corrupt an active installation:

  1. Releases are immutable and versioned.
  2. A new release is installed beside existing releases.
  3. Active implementation files are never patched in place.
  4. Configuration and state are not owned by a release directory.
  5. Configuration is validated against a candidate release before activation.
  6. Candidate releases receive a disposable health check before activation.
  7. Activation is an atomic pointer/reference change.
  8. The prior release remains available for rollback.
  9. State migrations are deferred until required.
  10. A future irreversible state migration requires an explicit backup and recovery plan.

Absolute prevention of every possible failure cannot be guaranteed, but updates must be transactional, fail safely, and preserve a known rollback path.

Container data flow

For the first configuration-driven layer:

Host launcher
  reads: ~/.config/mosaic-dev/config.json
  validates: configVersion, backend, provider, model, dataRoot
  resolves: container invocation and safe bind mounts

Container image
  contains: pinned runtime, implementation, immutable contracts
  receives: resolved non-secret runtime settings
  mounts: configured dataRoot at /var/lib/mosaic
  receives: runtime credential through a read-only file or supported environment variable

The complete host configuration should not be exposed to an agent worker unless required. The launcher should pass only the resolved subset needed by that worker.

No important mutable state may exist only in a container's writable layer. Containers must remain disposable.

Initial runtime data layout

Do not create a hierarchy before concepts need it. L0 requires only:

~/.mosaic-dev/
├── .mosaic-root
└── system-prompt.md

Potential future directories are reserved but not part of L0:

~/.mosaic-dev/
├── runs/
├── state/
└── workspaces/

Next milestone: configuration-driven Hello World

Implement only the following path:

  1. Create a small bootstrap/launcher.
  2. If absent, bootstrap creates ~/.config/mosaic-dev/config.json with the minimal development configuration.
  3. If configuration already exists, bootstrap does not change it.
  4. The launcher reads and validates the configuration.
  5. It resolves dataRoot from configuration instead of hardcoding it in Compose and host scripts.
  6. It safely creates or validates the data-root ownership marker.
  7. It builds or selects the current immutable container image.
  8. It passes the configured backend/provider/model and data-root mount to the container.
  9. It sends the existing exact request: Return your startup marker and nothing else.
  10. It receives and verifies exactly MOSAIC_HELLO_OK.

L0 acceptance criteria

  1. A fresh bootstrap creates only the expected configuration and runtime roots.
  2. Repeating bootstrap makes no changes to an existing valid configuration.
  3. Existing configuration is never overwritten by build, verification, reset, or update operations.
  4. Missing configuration can be bootstrapped deliberately; normal execution does not silently invent configuration.
  5. Malformed JSON exits nonzero without modifying files.
  6. Unsupported configVersion exits nonzero without modifying files.
  7. A relative or unsafe dataRoot exits nonzero without modifying files.
  8. The container receives the configured data root at /var/lib/mosaic.
  9. The image and container contain no credentials.
  10. The real model request returns exactly MOSAIC_HELLO_OK.
  11. Changing the expected marker produces a nonzero verification exit.
  12. Rebuilding/replacing the image leaves configuration and runtime data intact.
  13. Reset deletes only the validated runtime data root and never configuration.
  14. Reset continues to refuse symbolic links and missing ownership markers.

Explicitly deferred

Do not implement in the next milestone:

  • Mission and task schemas
  • Persistent sessions
  • Multiple agents
  • Claude, OpenCode, or Codex adapters
  • Tool permission policy
  • Network policy engine
  • Contract bundle versioning
  • Orchestration or scheduling
  • Agent communication
  • Databases or knowledge stores
  • API or web interface
  • Portal or dashboard
  • Automatic configuration migration
  • State schema migration
  • Production deployment architecture

Following layer: mission and task abstraction

Only after configuration-driven L0 passes should the first mission/task layer be designed. Its initial concepts should remain minimal:

  • Mission: desired outcome and governing constraints
  • Task: one bounded unit of work assigned to one runtime
  • Run: one attempt to execute a task
  • Result: immutable completion evidence and exit status

No mission/task implementation decision is made by this plan.

Immediate documentation and implementation scope

Maintain one clear architecture plan (this document), one example/default configuration, one strict configuration reader, and the existing Hello World proof. Avoid new services, generalized frameworks, and abstractions until a passing acceptance test requires them.