- 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
257 lines
11 KiB
Markdown
257 lines
11 KiB
Markdown
# 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:
|
|
|
|
```text
|
|
/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:
|
|
|
|
```text
|
|
/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:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
~/.mosaic-dev/
|
|
├── .mosaic-root
|
|
└── system-prompt.md
|
|
```
|
|
|
|
Potential future directories are reserved but not part of L0:
|
|
|
|
```text
|
|
~/.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.
|