docs: ingest 11 docs from docs/ (#2387)
This commit is contained in:
parent
49ec294dea
commit
938dfb1453
32
.planning/INGEST-CONFLICTS.md
Normal file
32
.planning/INGEST-CONFLICTS.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Ingest Conflict Report
|
||||
|
||||
Mode: new (fresh bootstrap — no existing .planning/ context to check against)
|
||||
Precedence: ADR > SPEC > PRD > DOC (no per-doc overrides present)
|
||||
|
||||
## Conflict Detection Report
|
||||
|
||||
### BLOCKERS (0)
|
||||
|
||||
(none)
|
||||
|
||||
### WARNINGS (0)
|
||||
|
||||
(none)
|
||||
|
||||
### INFO (4)
|
||||
|
||||
[INFO] Overlapping locked ADRs on Nostr marketplace discovery — consistent, not contradictory
|
||||
Found: docs/adr/003-nostr-for-discovery.md and docs/adr/006-nostr-marketplace-discovery.md are both locked and both decide "Nostr relays (NIP-78, kind 30078) for app manifest discovery" over the same scope
|
||||
Note: The decisions agree; ADR-006 refines ADR-003 with concrete trust tiers (Verified/Community/Unverified), curated built-in app list, and pre-install signature verification. Both preserved as separate entries in intel/decisions.md; no resolution needed. Consider marking one as superseding/refining the other in the docs for hygiene.
|
||||
|
||||
[INFO] SPEC security validation list narrower than ADR-009 mandatory defaults
|
||||
Found: docs/adr/009-manifest-container-security.md (locked) mandates non-root UID (> 1000), pinned image tags (no `latest`), and a default seccomp profile as non-negotiable defaults; docs/app-manifest-spec.md's documented SecurityPolicy schema and AppManifest::validate() list do not mention these three (SecurityPolicy has apparmor_profile but no seccomp field)
|
||||
Note: This is SPEC silence, not contradiction — no auto-resolution applied. ADR-009 governs by precedence (ADR > SPEC) and lock status. The SPEC itself declares `core/container/src/manifest.rs` canonical over the doc, so the gap may be documentation drift rather than implementation drift. Flagged for downstream verification, recorded as absent in intel/constraints.md.
|
||||
|
||||
[INFO] ADR numbering gap — ADR-010 absent from ingest set
|
||||
Found: Classified ADRs run 001–009 and 011; no classification exists for an ADR-010
|
||||
Note: Either ADR-010 does not exist, was withdrawn, or was not included in the ingest. No action required for synthesis; noted for completeness of the decision record.
|
||||
|
||||
[INFO] Cross-reference graph is acyclic
|
||||
Found: cross_refs edges: ADR-007 → ADR-003; ADR-009 → docs/app-manifest-spec.md (+ code paths); SPEC → out-of-set docs and code only (app-developer-guide.md, manifest-hooks-design.md, marketplace-protocol.md, core/container/src/manifest.rs, api/rpc/package/stacks.rs)
|
||||
Note: DFS cycle detection found no cycles; all 11 docs were synthesized. Several SPEC cross-refs point to documents not in the ingest set — they were not followed.
|
||||
115
.planning/PROJECT.md
Normal file
115
.planning/PROJECT.md
Normal file
@ -0,0 +1,115 @@
|
||||
# Archipelago
|
||||
|
||||
## What This Is
|
||||
|
||||
Archipelago is a self-hosted personal-server platform: a Rust daemon (workspace at `core/`)
|
||||
plus a Vue 3 frontend (`neode-ui/`, built to `web/dist/neode-ui/`) running on Debian nodes
|
||||
with rootless Podman, managing ~40 declarative, manifest-driven apps (Bitcoin, Lightning,
|
||||
mesh/LoRa, federation, media, and more). It ships as OTA-updated releases to a live fleet
|
||||
and is actively shipping v1.7.x alpha releases. This milestone drives it to the
|
||||
**developer-ready app platform** north star.
|
||||
|
||||
## Core Value
|
||||
|
||||
A third-party developer can publish an app via the signed/decentralized registry and a user
|
||||
can install it on their node — every app manifest-driven, manifests shipped via the signed
|
||||
registry (not OTA disk files), all rootless, secure, robust, and 100%-uptime-capable.
|
||||
|
||||
## Current State (brownfield baseline, 2026-07-29)
|
||||
|
||||
- Single-node production gate is **GREEN** (5/5 on .228, 2026-06-23) — that exit criterion is met.
|
||||
- ~40 apps are manifest-based and Quadlet-migrated; all multi-container stacks use the
|
||||
orchestrator stack pattern; the legacy per-app installer anti-pattern is deleted.
|
||||
- Workstream B (registry-distributed manifests) phases 1+2 are code-complete; the signing
|
||||
ceremony is done (release-root pinned in `anchor.rs`); the fleet flip is not yet authorized.
|
||||
- Workstream C (marketplace) is design-only (`docs/marketplace-protocol.md`); no tooling or
|
||||
trust UX built. Developer CLI suite (`archy app …`) does not exist yet.
|
||||
- Phase-3 Quadlet default-flip is validated opt-in on .228/.198 but not default.
|
||||
- Declared next exit criteria: the multinode pass (`docs/multinode-testing-plan.md`) and the
|
||||
remaining workstreams.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Validated
|
||||
|
||||
- ✓ Single-node lifecycle gate green 5× on .228 (install/UI/stop/start/restart/reinstall/
|
||||
reboot-survive/daemon-restart-survive/uninstall) — 2026-06-23
|
||||
- ✓ Manifest-driven app packaging for all ~40 apps incl. multi-container stacks (workstream A)
|
||||
- ✓ Signed catalog + release-root signing ceremony (workstream B phases 1+2, code-complete)
|
||||
|
||||
### Active
|
||||
|
||||
See `.planning/REQUIREMENTS.md` — 20 v1 requirements across MNODE / LIFE / REG / SEC / DEV / MKT,
|
||||
all mapped to phases in `.planning/ROADMAP.md`.
|
||||
|
||||
### Out of Scope
|
||||
|
||||
- Rootful containers, Docker, privileged containers — invariant (ADR-001/ADR-009)
|
||||
- Per-app Rust installers / OS-level provisioning — the anti-pattern being deleted
|
||||
- Centralized gatekept app store — decentralized Nostr marketplace instead (ADR-006)
|
||||
- Web5 DWN spec compliance — deprioritized after TBD shutdown (ADR-011)
|
||||
- Custom live voice-call protocol — deprioritized per user 2026-07-01; revisit later
|
||||
- DHT/iroh distribution backbone (workstream D) — design-only, tracker-marked backlog; v2
|
||||
|
||||
## Context
|
||||
|
||||
- Repo: `core/` Rust workspace (no root Cargo.toml), `neode-ui/` Vue frontend, `apps/` manifests,
|
||||
`tests/lifecycle/` + `tests/multinode/` gates, `docs/` authoritative plans.
|
||||
- Authoritative narrative: `docs/PRODUCTION-MASTER-PLAN.md`; day-to-day open list:
|
||||
`docs/UNIFIED-TASK-TRACKER.md`. Codebase map: `.planning/codebase/ARCHITECTURE.md` +
|
||||
`.planning/codebase/CONCERNS.md`.
|
||||
- Known debt informing this milestone (from CONCERNS.md): federation tombstone-write errors
|
||||
swallowed; reconciler has no flap observability and no failed-unit self-healing; generated
|
||||
AppArmor profiles are never applied; multinode test harness curl calls lack timeouts;
|
||||
SPEC validation is narrower than ADR-009's mandates (non-root UID, pinned tags, seccomp).
|
||||
- Fleet is live and OTA-updated; all destructive verification happens on designated test
|
||||
nodes per the deploy roster — never uninvited on in-use nodes.
|
||||
|
||||
## Constraints
|
||||
|
||||
- **Security**: Rootless Podman only; manifest-declared secrets (0600, never logged);
|
||||
mandatory container security defaults enforced at manifest level (ADR-009)
|
||||
- **Data safety**: Migrations never destroy data — preserve `/var/lib/archipelago/<app>`,
|
||||
secrets, credentials, ports, adoption container names; always a rollback path
|
||||
- **Verification**: Real-node verification before any tag; lifecycle gate runs ON the node,
|
||||
not via RPC; mesh changes need real-RF E2E tests; re-run the gate after orchestrator changes
|
||||
- **Process**: Commit + push every unit of work (`git push gitea-ai main`); stage by explicit
|
||||
path; deploy to the dev pair before any OTA; never commit secrets
|
||||
- **Tech stack**: Rust (Tokio/Hyper, JSON-RPC 2.0) backend; Vue 3 + Pinia frontend;
|
||||
Quadlet/systemd-user container units; Ed25519-signed release artifacts
|
||||
|
||||
## Key Decisions
|
||||
|
||||
<decisions>
|
||||
|
||||
All ten ADRs below are **locked** (Status: Accepted; ingest source `docs/adr/*.md`). They are
|
||||
non-negotiable inputs to planning and cannot be overridden without a new ADR.
|
||||
|
||||
| ID | Decision | Scope |
|
||||
|----|----------|-------|
|
||||
| ADR-001 | Podman over Docker — rootless, daemonless, systemd-native; `archy-net` for inter-container DNS | Container runtime |
|
||||
| ADR-002 | `did:key` (Ed25519) node identity — self-contained, offline-capable; gaps mitigated via federation trust lists | Identity |
|
||||
| ADR-003 | Nostr relays (NIP-78, kind 30078) for node + app discovery — multi-relay query, 15-min cache, trust scoring, Tor-compatible | Discovery |
|
||||
| ADR-004 | Tor hidden services for inter-node RPC/control plane — bulk data via registries, not Tor | Federation transport |
|
||||
| ADR-005 | ChaCha20-Poly1305 + Argon2id (64MB, 3 iter) for backup encryption | Backups |
|
||||
| ADR-006 | Nostr relays for marketplace discovery — DID-signed manifests, trust tiers (Verified/Community/Unverified), signature verification before install | Marketplace |
|
||||
| ADR-007 | Bilateral DID federation trust via single-use invite codes; Trusted/Observer/Untrusted levels | Federation trust |
|
||||
| ADR-008 | Dual keys from one master seed — Ed25519 canonical identity, secp256k1 for Nostr/Bitcoin/Lightning, linked via NIP-05 | Keys |
|
||||
| ADR-009 | Manifest-level container security enforcement — readonly_root, no_new_privileges, non-root UID, drop-ALL caps, pinned tags, seccomp; overrides explicit + audited | Container security |
|
||||
| ADR-011 | DWN deprioritized — keep custom `dwn_store.rs`, stop branding as Web5, invest in Nostr + Tor federation instead | Peer data sync |
|
||||
|
||||
(ADR-010 does not exist in the repo — numbering gap, noted in `.planning/INGEST-CONFLICTS.md`.)
|
||||
|
||||
</decisions>
|
||||
|
||||
Milestone-level decisions:
|
||||
|
||||
| Decision | Rationale | Outcome |
|
||||
|----------|-----------|---------|
|
||||
| Milestone version = 1.8.0-alpha | Decided 2026-07-08 per tracker | — Pending ship |
|
||||
| Workstream D (DHT) deferred to v2 | Design-only, tracker-marked backlog; not needed for north-star metric | — Pending |
|
||||
| App manifest canonical schema = `core/container/src/manifest.rs` | SPEC self-declares code wins over doc | ✓ Good |
|
||||
| Phase-3 Quadlet flip gated on multinode gate reporting clean | Prior uncommitted-flip confusion; flip fresh as a 2-line change when gate is clean | — Pending |
|
||||
|
||||
---
|
||||
*Last updated: 2026-07-29 after intel ingest (10 ADRs + 1 SPEC) + codebase mapping*
|
||||
110
.planning/REQUIREMENTS.md
Normal file
110
.planning/REQUIREMENTS.md
Normal file
@ -0,0 +1,110 @@
|
||||
# Requirements: Archipelago (v1.8.0 — Developer-Ready App Platform)
|
||||
|
||||
**Defined:** 2026-07-29
|
||||
**Core Value:** A third-party developer can publish an app via the signed/decentralized registry and a user can install it on their node — manifest-driven, rootless, secure, robust.
|
||||
|
||||
No PRDs existed in the ingest set; these requirements are derived from the master plan's
|
||||
declared exit criteria (multinode pass + workstreams B/C/F), `.planning/codebase/CONCERNS.md`,
|
||||
`docs/UNIFIED-TASK-TRACKER.md`, and the user-chosen success metric. Constraints from
|
||||
`docs/app-manifest-spec.md` and the locked ADRs (see PROJECT.md) bound how each is built.
|
||||
|
||||
## v1 Requirements
|
||||
|
||||
### Multinode Verification (MNODE)
|
||||
|
||||
- [ ] **MNODE-01**: The 5× destructive lifecycle gate passes on a second fleet node (archy-x250-beta) with 0 failures, run on-node per gate policy
|
||||
- [ ] **MNODE-02**: Cross-node federation/mesh/transport suites (`tests/multinode/smoke.sh`, `meshtastic.sh`) pass between fleet nodes, with all harness RPC calls time-bounded (no indefinite curl hangs)
|
||||
- [ ] **MNODE-03**: Removing a federation peer sticks — tombstone-write failures are surfaced (not swallowed) and a removed peer never silently reappears after subsequent sync cycles
|
||||
|
||||
### Lifecycle Perfection (LIFE)
|
||||
|
||||
- [ ] **LIFE-01**: Quadlet backends are the default — restarting `archipelago.service` leaves every app container running (no SIGKILL-the-world, no multi-minute rebuild storm)
|
||||
- [ ] **LIFE-02**: The reconciler self-heals failed Quadlet units — a `.service` in `failed` state (and not user-stopped) is reset-failed + started automatically, with backoff against busy-looping
|
||||
- [ ] **LIFE-03**: Per-app restart/flap observability — restart counters, a threshold log line when an app restarts >N times in M minutes, and restart counts surfaced in health/status RPC output
|
||||
- [ ] **LIFE-04**: Cascade uninstall→reinstall is gate-verified for multi-container stacks and installed apps — no ghost entries, no orphan containers, data preserved per policy, reinstall returns healthy
|
||||
- [ ] **LIFE-05**: Install and uninstall report real, monotonic progress driven by backend progress events, always reaching a terminal success/failure state — asserted in the gate, never a fake or stuck bar
|
||||
|
||||
### Registry-Distributed Manifests (REG)
|
||||
|
||||
- [ ] **REG-01**: The published signed catalog embeds full app manifests; nodes install/update from signature-verified catalog manifests (disk manifests remain the fallback for build-source apps); tampered catalogs are rejected with safe fallback
|
||||
- [ ] **REG-02**: The fleet is flipped to registry-distributed manifests — adding or bumping an image-only app requires only a re-signed catalog publish, no binary OTA or disk rsync
|
||||
|
||||
### Security Enforcement (SEC)
|
||||
|
||||
- [ ] **SEC-01**: `AppManifest::validate()` enforces the full ADR-009 mandate set — non-root UID, pinned image tags (no `latest`), capability allow-list, seccomp — with explicit, documented, auditable overrides
|
||||
- [ ] **SEC-02**: Generated AppArmor/seccomp security profiles are actually applied at container creation (`--security-opt`) and verified effective on running apps
|
||||
|
||||
### Developer Tooling (DEV)
|
||||
|
||||
- [ ] **DEV-01**: `archy app validate` checks a manifest locally and returns the same pass/fail verdict the node enforces (schema + security rules)
|
||||
- [ ] **DEV-02**: `archy app render` previews the exact Quadlet/podman configuration a manifest produces
|
||||
- [ ] **DEV-03**: A developer can local-install and lifecycle-test an app against a dev node from the CLI (`archy app local-install` / `lifecycle-test`)
|
||||
- [ ] **DEV-04**: The developer guide walks a new third-party developer from an empty directory to an installed, running app using only the CLI and docs
|
||||
|
||||
### Decentralized Marketplace (MKT)
|
||||
|
||||
- [ ] **MKT-01**: A third-party developer can publish a DID-signed app manifest to public Nostr relays (NIP-78, kind 30078) via the tooling
|
||||
- [ ] **MKT-02**: A node discovers marketplace apps from multiple relays and displays each app's trust tier (Verified / Community / Unverified) per ADR-006 trust scoring
|
||||
- [ ] **MKT-03**: Manifest signatures are verified before installation; tampered or invalid marketplace manifests cannot be installed
|
||||
- [ ] **MKT-04**: End-to-end north star: a user installs a third-party marketplace-published app on their node and it runs healthy under the standard lifecycle guarantees
|
||||
|
||||
## v2 Requirements
|
||||
|
||||
Deferred to a future milestone. Tracked but not in the current roadmap.
|
||||
|
||||
### Distribution Backbone (DIST)
|
||||
|
||||
- **DIST-01**: BLAKE3 content-addressed catalog distribution via iroh swarm, origin-always-wins (workstream D — design-only today, tracker-marked backlog)
|
||||
|
||||
### Fleet & Hardening (FLEET)
|
||||
|
||||
- **FLEET-01**: Bitcoin multi-version fleet-wide OTA rollout (user-gated on timing per `docs/bitcoin-version-bulletproof-rollout.md`)
|
||||
- **FLEET-02**: App-specific health assertions for the ~34 apps with only baseline lifecycle coverage
|
||||
- **FLEET-03**: LUKS2 full-partition encryption for `/var/lib/archipelago/`
|
||||
- **FLEET-04**: Dynamic per-app resource rebalancing (cgroup-stats feedback loop)
|
||||
|
||||
## Out of Scope
|
||||
|
||||
| Feature | Reason |
|
||||
|---------|--------|
|
||||
| Rootful/privileged containers, Docker | Invariant — ADR-001/ADR-009 |
|
||||
| Per-app Rust installers / host provisioning | The anti-pattern workstream A deleted |
|
||||
| Centralized gatekept app store | ADR-006 chose decentralized Nostr marketplace |
|
||||
| Web5 DWN spec compliance | ADR-011 — deprioritized after TBD shutdown |
|
||||
| Custom live voice-call protocol | Deprioritized 2026-07-01 per user; no scope decided |
|
||||
|
||||
## Traceability
|
||||
|
||||
Which phases cover which requirements. Updated during roadmap creation.
|
||||
|
||||
| Requirement | Phase | Status |
|
||||
|-------------|-------|--------|
|
||||
| MNODE-01 | Phase 1 | Pending |
|
||||
| MNODE-02 | Phase 1 | Pending |
|
||||
| MNODE-03 | Phase 1 | Pending |
|
||||
| LIFE-01 | Phase 2 | Pending |
|
||||
| LIFE-02 | Phase 2 | Pending |
|
||||
| LIFE-03 | Phase 2 | Pending |
|
||||
| LIFE-04 | Phase 2 | Pending |
|
||||
| LIFE-05 | Phase 2 | Pending |
|
||||
| REG-01 | Phase 3 | Pending |
|
||||
| REG-02 | Phase 3 | Pending |
|
||||
| SEC-01 | Phase 4 | Pending |
|
||||
| SEC-02 | Phase 4 | Pending |
|
||||
| DEV-01 | Phase 5 | Pending |
|
||||
| DEV-02 | Phase 5 | Pending |
|
||||
| DEV-03 | Phase 5 | Pending |
|
||||
| DEV-04 | Phase 5 | Pending |
|
||||
| MKT-01 | Phase 6 | Pending |
|
||||
| MKT-02 | Phase 6 | Pending |
|
||||
| MKT-03 | Phase 6 | Pending |
|
||||
| MKT-04 | Phase 6 | Pending |
|
||||
|
||||
**Coverage:**
|
||||
- v1 requirements: 20 total
|
||||
- Mapped to phases: 20
|
||||
- Unmapped: 0
|
||||
|
||||
---
|
||||
*Requirements defined: 2026-07-29*
|
||||
*Last updated: 2026-07-29 after roadmap creation*
|
||||
108
.planning/ROADMAP.md
Normal file
108
.planning/ROADMAP.md
Normal file
@ -0,0 +1,108 @@
|
||||
# Roadmap: Archipelago — v1.8.0 Developer-Ready App Platform
|
||||
|
||||
## Overview
|
||||
|
||||
Brownfield milestone starting from a green single-node production gate (5/5 on .228,
|
||||
2026-06-23). The journey: prove the platform across the fleet (multinode pass), make the
|
||||
container lifecycle bulletproof (Quadlet default, self-healing, honest progress, no ghosts),
|
||||
flip manifest distribution from OTA disk files to the signed registry, harden manifest
|
||||
security enforcement to the full ADR-009 bar, ship the `archy app` developer CLI, and land
|
||||
the decentralized Nostr marketplace — ending at the north star: a third-party developer
|
||||
publishes an app via the signed/decentralized registry and a user installs it on their node.
|
||||
|
||||
## Phases
|
||||
|
||||
**Phase Numbering:**
|
||||
- Integer phases (1, 2, 3): Planned milestone work
|
||||
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
|
||||
|
||||
- [ ] **Phase 1: Multinode Verification Pass** - Lifecycle gate green on a second node; cross-node federation/mesh/transport suites pass; federation removal sticks
|
||||
- [ ] **Phase 2: Lifecycle Perfection & Quadlet Default** - Quadlet backends default, failed-unit self-healing, flap observability, cascade gate, truthful progress
|
||||
- [ ] **Phase 3: Registry-Distributed Manifests** - Signed catalog carries full manifests; fleet flipped off OTA disk-file distribution
|
||||
- [ ] **Phase 4: Manifest Security Enforcement** - Validation matches ADR-009 mandates; generated security profiles actually applied
|
||||
- [ ] **Phase 5: Developer Tooling CLI** - `archy app validate/render/local-install/lifecycle-test` + developer guide
|
||||
- [ ] **Phase 6: Decentralized Marketplace** - DID-signed publish to Nostr relays, trust-tier discovery, verified third-party install end-to-end
|
||||
|
||||
## Phase Details
|
||||
|
||||
### Phase 1: Multinode Verification Pass
|
||||
**Goal**: The platform's lifecycle and federation guarantees are proven across the fleet, not just on .228 — the declared next exit criterion
|
||||
**Depends on**: Nothing (first phase)
|
||||
**Requirements**: MNODE-01, MNODE-02, MNODE-03
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. The 5× destructive lifecycle gate reports 0 failures on a second fleet node (archy-x250-beta), run on-node
|
||||
2. The cross-node smoke suite (federation pairing both directions, FIPS anchors, peer content browse) passes between two fleet nodes with every harness RPC time-bounded — a slow node produces a test failure, never an indefinite hang
|
||||
3. An operator who removes a federation peer never sees it reappear in the peer list after later sync cycles; a tombstone-write failure is surfaced as an error instead of silently swallowed
|
||||
4. The on-air mesh suite passes between two radio-equipped nodes over real RF
|
||||
**Plans**: TBD
|
||||
|
||||
### Phase 2: Lifecycle Perfection & Quadlet Default
|
||||
**Goal**: An insanely-reliable container environment — every app installs, runs, restarts, uninstalls, and reinstalls cleanly with honest progress, no ghosts, and automatic recovery
|
||||
**Depends on**: Phase 1 (Quadlet default-flip is gated on the second-node gate reporting clean)
|
||||
**Requirements**: LIFE-01, LIFE-02, LIFE-03, LIFE-04, LIFE-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Restarting `archipelago.service` on a fleet node leaves every app container running — no SIGKILL-the-world, no multi-minute reconciler rebuild
|
||||
2. An app whose Quadlet unit enters `failed` state (and was not user-stopped) comes back automatically within a bounded window, with backoff on persistent failure — no operator intervention
|
||||
3. An operator can see per-app restart counts in status output, and a flapping app (>N restarts in M minutes) is flagged in logs instead of being invisible
|
||||
4. Uninstalling then reinstalling any gated app — including multi-container stacks like immich/btcpay — leaves no ghost My-Apps entries or orphan containers, preserves data per policy, and returns the app healthy, verified by the cascade gate tier
|
||||
5. Install and uninstall progress bars move monotonically from real backend progress events and always land on a terminal success/failure state — asserted in the gate, and the single-node gate stays green after all orchestrator changes
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 3: Registry-Distributed Manifests
|
||||
**Goal**: Manifests ship via the signed registry, not OTA disk files — bumping or adding an app becomes a signed catalog change
|
||||
**Depends on**: Phase 2 (fleet lifecycle stable under Quadlet default before changing the distribution channel)
|
||||
**Requirements**: REG-01, REG-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A fleet node installs and updates an image-only app from the full manifest embedded in the signed catalog, verified against the pinned release-root key, with no corresponding OTA disk file present (disk remains the fallback for build-source apps)
|
||||
2. A tampered or unsigned catalog manifest is rejected and the node falls back safely — it never installs from an unverified manifest
|
||||
3. Bumping an app version fleet-wide requires only regenerating, re-signing, and publishing the catalog — no binary OTA, no disk rsync — proven live on the fleet
|
||||
**Plans**: TBD
|
||||
|
||||
### Phase 4: Manifest Security Enforcement
|
||||
**Goal**: A third-party manifest cannot weaken node security — declared security policy is fully validated and actually enforced at runtime
|
||||
**Depends on**: Phase 3 (enforcement guards the registry channel third-party manifests will arrive through)
|
||||
**Requirements**: SEC-01, SEC-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A manifest violating ADR-009 mandates (root user, unpinned `latest` tag, capability outside the allow-list, disabled seccomp) is rejected at validation with a clear error naming the violation
|
||||
2. Security overrides (`readonly_root: false`, extra capabilities) work only when explicitly listed in the manifest and leave an audit trail
|
||||
3. Generated AppArmor/seccomp profiles are applied to containers at creation and verifiably effective on a running app — not just generated and ignored
|
||||
4. The single-node lifecycle gate stays green with enforcement on — existing catalog apps all pass the strengthened validation (or carry documented overrides)
|
||||
**Plans**: TBD
|
||||
|
||||
### Phase 5: Developer Tooling CLI
|
||||
**Goal**: A third-party developer can build, validate, and test an Archipelago app locally without reading platform internals
|
||||
**Depends on**: Phase 4 (CLI validation must mirror the final enforced rule set)
|
||||
**Requirements**: DEV-01, DEV-02, DEV-03, DEV-04
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A developer runs `archy app validate` on a manifest directory and gets the same pass/fail verdict — including security rules — that a node would enforce at install
|
||||
2. A developer runs `archy app render` and sees the exact Quadlet/podman configuration their manifest produces before ever touching a node
|
||||
3. A developer can install their app onto a dev node and run its lifecycle test (install/UI/stop/start/restart/uninstall) from the CLI
|
||||
4. A new developer following only the developer guide goes from an empty directory to a running app on a node — no tribal knowledge required
|
||||
**Plans**: TBD
|
||||
|
||||
### Phase 6: Decentralized Marketplace
|
||||
**Goal**: The north star — third-party developers publish apps via the decentralized registry and users install them on their nodes
|
||||
**Depends on**: Phase 5 (publish rides the CLI; installs ride registry distribution from Phase 3 and enforcement from Phase 4)
|
||||
**Requirements**: MKT-01, MKT-02, MKT-03, MKT-04
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A third-party developer publishes a DID-signed app manifest to public Nostr relays (NIP-78, kind 30078) using the tooling
|
||||
2. A node discovers the published app from multiple relays and the app store UI shows its trust tier (Verified / Community / Unverified) per ADR-006 scoring
|
||||
3. The node verifies the manifest signature before installation; a tampered or invalid marketplace manifest cannot be installed
|
||||
4. A user installs the third-party marketplace-published app on their node and it runs healthy under the standard lifecycle guarantees — the user-chosen success metric, demonstrated end-to-end
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
## Progress
|
||||
|
||||
**Execution Order:**
|
||||
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6
|
||||
|
||||
| Phase | Plans Complete | Status | Completed |
|
||||
|-------|----------------|--------|-----------|
|
||||
| 1. Multinode Verification Pass | 0/TBD | Not started | - |
|
||||
| 2. Lifecycle Perfection & Quadlet Default | 0/TBD | Not started | - |
|
||||
| 3. Registry-Distributed Manifests | 0/TBD | Not started | - |
|
||||
| 4. Manifest Security Enforcement | 0/TBD | Not started | - |
|
||||
| 5. Developer Tooling CLI | 0/TBD | Not started | - |
|
||||
| 6. Decentralized Marketplace | 0/TBD | Not started | - |
|
||||
79
.planning/STATE.md
Normal file
79
.planning/STATE.md
Normal file
@ -0,0 +1,79 @@
|
||||
---
|
||||
gsd_state_version: '1.0'
|
||||
status: planning
|
||||
progress:
|
||||
total_phases: 6
|
||||
completed_phases: 0
|
||||
total_plans: 0
|
||||
completed_plans: 0
|
||||
percent: 0
|
||||
---
|
||||
|
||||
# Project State
|
||||
|
||||
## Project Reference
|
||||
|
||||
See: .planning/PROJECT.md (updated 2026-07-29)
|
||||
|
||||
**Core value:** A third-party developer can publish an app via the signed/decentralized registry and a user can install it on their node — manifest-driven, rootless, secure, robust.
|
||||
**Current focus:** Phase 1 — Multinode Verification Pass
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: 1 of 6 (Multinode Verification Pass)
|
||||
Plan: 0 of TBD in current phase
|
||||
Status: Ready to plan
|
||||
Last activity: 2026-07-29 — Project initialized from doc ingest (10 ADRs + 1 SPEC) + codebase map; roadmap created (6 phases, 20 requirements, 100% coverage)
|
||||
|
||||
Progress: [░░░░░░░░░░] 0%
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
**Velocity:**
|
||||
- Total plans completed: 0
|
||||
- Average duration: —
|
||||
- Total execution time: —
|
||||
|
||||
**By Phase:**
|
||||
|
||||
| Phase | Plans | Total | Avg/Plan |
|
||||
|-------|-------|-------|----------|
|
||||
| - | - | - | - |
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
### Decisions
|
||||
|
||||
Decisions are logged in PROJECT.md (10 locked ADRs in the `<decisions>` block + milestone decisions table). Recent decisions affecting current work:
|
||||
|
||||
- Milestone version = 1.8.0-alpha (decided 2026-07-08)
|
||||
- Phase-3 Quadlet default-flip is gated on the second-node gate reporting clean (do fresh, never stage uncommitted)
|
||||
- Workstream D (DHT distribution) deferred to v2 — design-only backlog
|
||||
- Canonical manifest schema = `core/container/src/manifest.rs` (code wins over spec doc)
|
||||
|
||||
### Pending Todos
|
||||
|
||||
None yet.
|
||||
|
||||
### Blockers/Concerns
|
||||
|
||||
- [Phase 1] Multinode gate on archy-x250-beta was launched 2026-07-01 (log on-node); verify outcome before re-running
|
||||
- [Phase 1] Federation tombstone fix touches trust code — fix carefully, re-verify with `tests/multinode/smoke.sh`, don't patch blind
|
||||
- [Phase 3] Fleet registry flip awaits explicit user authorization + timing call
|
||||
- [Phase 4] Strengthened ADR-009 validation may reject existing catalog apps — audit manifests before enforcement lands
|
||||
- [Global] Live OTA fleet: deploy to the dev pair before any OTA; gate re-runs required after orchestrator changes; some verification is user/hardware-gated (radios, on-device tests)
|
||||
|
||||
## Deferred Items
|
||||
|
||||
| Category | Item | Status | Deferred At |
|
||||
|----------|------|--------|-------------|
|
||||
| Distribution | DIST-01 DHT/iroh backbone (workstream D) | v2 | 2026-07-29 |
|
||||
| Fleet | FLEET-01 Bitcoin multi-version fleet OTA (user-gated) | v2 | 2026-07-29 |
|
||||
| Fleet | FLEET-02 per-app deep health assertions (~34 apps) | v2 | 2026-07-29 |
|
||||
| Fleet | FLEET-03 LUKS2 data-partition encryption | v2 | 2026-07-29 |
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-07-29
|
||||
Stopped at: Roadmap + state initialized from ingest; next step is `/gsd-plan-phase 1`
|
||||
Resume file: None
|
||||
66
.planning/intel/SYNTHESIS.md
Normal file
66
.planning/intel/SYNTHESIS.md
Normal file
@ -0,0 +1,66 @@
|
||||
# Synthesis Summary
|
||||
|
||||
Ingest mode: new (fresh bootstrap; no existing PROJECT.md/REQUIREMENTS.md/ROADMAP.md)
|
||||
Synthesized: 2026-07-29
|
||||
Precedence applied: ADR > SPEC > PRD > DOC (no per-doc overrides)
|
||||
|
||||
## Doc counts by type
|
||||
|
||||
- ADR: 10 (all locked, Status: Accepted, confidence: high)
|
||||
- SPEC: 1 (confidence: high)
|
||||
- PRD: 0
|
||||
- DOC: 0
|
||||
- UNKNOWN: 0
|
||||
- Total: 11
|
||||
|
||||
## Decisions locked (10)
|
||||
|
||||
All in `intel/decisions.md`:
|
||||
- ADR-001 Podman over Docker — docs/adr/001-podman-over-docker.md
|
||||
- ADR-002 did:key (Ed25519) node identity — docs/adr/002-did-key-method.md
|
||||
- ADR-003 Nostr relays for node + app discovery — docs/adr/003-nostr-for-discovery.md
|
||||
- ADR-004 Tor hidden services for inter-node RPC/control plane — docs/adr/004-tor-for-peer-communication.md
|
||||
- ADR-005 ChaCha20-Poly1305 + Argon2id backup encryption — docs/adr/005-chacha20-backup-encryption.md
|
||||
- ADR-006 Nostr relays for marketplace discovery (trust tiers) — docs/adr/006-nostr-marketplace-discovery.md
|
||||
- ADR-007 Bilateral DID federation trust via single-use invite codes — docs/adr/007-did-federation-trust.md
|
||||
- ADR-008 Dual keys (Ed25519 + secp256k1) from one master seed — docs/adr/008-dual-key-strategy.md
|
||||
- ADR-009 Manifest-level container security enforcement — docs/adr/009-manifest-container-security.md
|
||||
- ADR-011 DWN deprioritization (Nostr + Tor federation instead) — docs/adr/011-dwn-deprioritization.md
|
||||
|
||||
## Requirements extracted (0)
|
||||
|
||||
No PRDs in ingest set. `intel/requirements.md` records the absence.
|
||||
|
||||
## Constraints (7 entries)
|
||||
|
||||
From docs/app-manifest-spec.md, in `intel/constraints.md`:
|
||||
- schema: 4 (top-level `app:` block, ContainerConfig, SecurityPolicy + validation, Volumes)
|
||||
- api-contract: 1 (lifecycle hooks)
|
||||
- protocol: 2 (Quadlet installation/reconciler semantics, distribution channels: signed catalog + Nostr marketplace)
|
||||
- nfr: 0
|
||||
|
||||
## Context topics (0)
|
||||
|
||||
No DOC-type documents. `intel/context.md` records the absence.
|
||||
|
||||
## Conflicts
|
||||
|
||||
- Blockers: 0
|
||||
- Competing variants: 0
|
||||
- Auto-resolved: 0
|
||||
- Informational notes: 4 (ADR-003/006 consistent overlap; SPEC validation narrower than ADR-009 mandates — silence, not contradiction; ADR-010 numbering gap; acyclic cross-ref graph)
|
||||
|
||||
Detail: `.planning/INGEST-CONFLICTS.md`
|
||||
|
||||
## Cycle detection
|
||||
|
||||
Cross-ref graph acyclic (max depth well under cap). All 11 docs synthesized; no docs excluded.
|
||||
|
||||
## Files
|
||||
|
||||
- Decisions: `.planning/intel/decisions.md`
|
||||
- Requirements: `.planning/intel/requirements.md`
|
||||
- Constraints: `.planning/intel/constraints.md`
|
||||
- Context: `.planning/intel/context.md`
|
||||
- Conflict report: `.planning/INGEST-CONFLICTS.md`
|
||||
- Raw classifications: `.planning/intel/classifications/*.json`
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"source_path": "/home/archipelago/Projects/archy/docs/adr/001-podman-over-docker.md",
|
||||
"type": "ADR",
|
||||
"confidence": "high",
|
||||
"manifest_override": false,
|
||||
"title": "ADR-001: Podman Over Docker",
|
||||
"summary": "Chose Podman over Docker as the container runtime for rootless, daemonless operation with native systemd integration.",
|
||||
"scope": ["Podman", "Docker", "container runtime", "rootless containers", "systemd integration", "archy-net network"],
|
||||
"cross_refs": [],
|
||||
"locked": true,
|
||||
"precedence": null,
|
||||
"notes": ""
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"source_path": "/home/archipelago/Projects/archy/docs/adr/002-did-key-method.md",
|
||||
"type": "ADR",
|
||||
"confidence": "high",
|
||||
"manifest_override": false,
|
||||
"title": "ADR-002: DID Key Method for Node Identity",
|
||||
"summary": "Chose did:key (Ed25519) as the primary DID method for node identity; self-contained and offline-capable, with federation trust lists mitigating rotation/revocation gaps.",
|
||||
"scope": ["did:key", "node identity", "DID methods", "Ed25519 keys", "peer authentication", "federation trust lists", "verifiable credentials"],
|
||||
"cross_refs": [],
|
||||
"locked": true,
|
||||
"precedence": null,
|
||||
"notes": ""
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
{
|
||||
"source_path": "/home/archipelago/Projects/archy/docs/adr/003-nostr-for-discovery.md",
|
||||
"type": "ADR",
|
||||
"confidence": "high",
|
||||
"manifest_override": false,
|
||||
"title": "ADR-003: Nostr Relays for Node and App Discovery",
|
||||
"summary": "Chose Nostr relays (NIP-78, kind 30078) for decentralized node discovery and marketplace app manifest distribution.",
|
||||
"scope": [
|
||||
"Nostr relays",
|
||||
"node discovery",
|
||||
"app discovery",
|
||||
"marketplace app manifests",
|
||||
"NIP-78",
|
||||
"NIP-33 replaceable events",
|
||||
"trust scoring",
|
||||
"relay caching"
|
||||
],
|
||||
"cross_refs": [],
|
||||
"locked": true,
|
||||
"precedence": null,
|
||||
"notes": ""
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"source_path": "/home/archipelago/Projects/archy/docs/adr/004-tor-for-peer-communication.md",
|
||||
"type": "ADR",
|
||||
"confidence": "high",
|
||||
"manifest_override": false,
|
||||
"title": "ADR-004: Tor Hidden Services for Peer Communication",
|
||||
"summary": "Chose Tor hidden services (.onion) for all inter-node RPC/control-plane communication; bulk data pulled from registries instead.",
|
||||
"scope": ["Tor hidden services", "inter-node communication", "federation sync", "archy-tor container", "RPC/control plane", "NAT traversal"],
|
||||
"cross_refs": [],
|
||||
"locked": true,
|
||||
"precedence": null,
|
||||
"notes": ""
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"source_path": "/home/archipelago/Projects/archy/docs/adr/005-chacha20-backup-encryption.md",
|
||||
"type": "ADR",
|
||||
"confidence": "high",
|
||||
"manifest_override": false,
|
||||
"title": "ADR-005: ChaCha20-Poly1305 for Backup Encryption",
|
||||
"summary": "Chose ChaCha20-Poly1305 AEAD with Argon2id key derivation for encrypting backups at rest, over AES-256-GCM and XChaCha20-Poly1305.",
|
||||
"scope": ["backup encryption", "ChaCha20-Poly1305", "Argon2id key derivation", "AEAD", "nonce handling"],
|
||||
"cross_refs": [],
|
||||
"locked": true,
|
||||
"precedence": null,
|
||||
"notes": ""
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"source_path": "/home/archipelago/Projects/archy/docs/adr/006-nostr-marketplace-discovery.md",
|
||||
"type": "ADR",
|
||||
"confidence": "high",
|
||||
"manifest_override": false,
|
||||
"title": "ADR-006: Nostr Relays for Marketplace Discovery",
|
||||
"summary": "Chose Nostr relays (NIP-78, kind 30078 events) for decentralized app manifest discovery instead of a centralized marketplace server.",
|
||||
"scope": ["Nostr relays", "app manifest discovery", "marketplace", "trust scoring", "trust tiers", "manifest signature verification"],
|
||||
"cross_refs": [],
|
||||
"locked": true,
|
||||
"precedence": null,
|
||||
"notes": ""
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"source_path": "/home/archipelago/Projects/archy/docs/adr/007-did-federation-trust.md",
|
||||
"type": "ADR",
|
||||
"confidence": "high",
|
||||
"manifest_override": false,
|
||||
"title": "ADR-007: DID-Based Federation Trust",
|
||||
"summary": "Chose bilateral DID-based verification with single-use invite codes over Tor for establishing federation trust between nodes, with Trusted/Observer/Untrusted levels.",
|
||||
"scope": ["federation", "DID verification", "invite codes", "trust levels", "Tor hidden services", "Ed25519 keys"],
|
||||
"cross_refs": ["ADR-003"],
|
||||
"locked": true,
|
||||
"precedence": null,
|
||||
"notes": ""
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"source_path": "/home/archipelago/Projects/archy/docs/adr/008-dual-key-strategy.md",
|
||||
"type": "ADR",
|
||||
"confidence": "high",
|
||||
"manifest_override": false,
|
||||
"title": "ADR-008: Dual Key Strategy (Ed25519 + Secp256k1)",
|
||||
"summary": "Maintain two key pairs per node identity: Ed25519 for DID/Web5 operations, secp256k1 for Nostr/Bitcoin/Lightning, both derived from one master seed.",
|
||||
"scope": ["node identity", "Ed25519", "secp256k1", "DID documents", "verifiable credentials", "federation authentication", "backup encryption", "Nostr event publishing", "node discovery", "Lightning Network", "key derivation", "master seed"],
|
||||
"cross_refs": [],
|
||||
"locked": true,
|
||||
"precedence": null,
|
||||
"notes": ""
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"source_path": "/home/archipelago/Projects/archy/docs/adr/009-manifest-container-security.md",
|
||||
"type": "ADR",
|
||||
"confidence": "high",
|
||||
"manifest_override": false,
|
||||
"title": "ADR-009: Manifest-Level Container Security Enforcement",
|
||||
"summary": "Enforce mandatory container security defaults (readonly root, no-new-privileges, non-root UID, dropped capabilities, pinned tags) at the manifest level during container creation.",
|
||||
"scope": ["container security", "app manifests", "manifest validation", "podman container creation", "security defaults", "capability restrictions", "seccomp", "core/container module"],
|
||||
"cross_refs": ["docs/app-manifest-spec.md", "core/container/src/", "core/security/src/"],
|
||||
"locked": true,
|
||||
"precedence": null,
|
||||
"notes": ""
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"source_path": "/home/archipelago/Projects/archy/docs/adr/011-dwn-deprioritization.md",
|
||||
"type": "ADR",
|
||||
"confidence": "high",
|
||||
"manifest_override": false,
|
||||
"title": "ADR-011: DWN Deprioritization",
|
||||
"summary": "Deprioritizes Web5 DWN spec compliance after TBD's shutdown; keeps existing custom DWN store code and prioritizes Nostr plus Tor federation for peer sync.",
|
||||
"scope": ["DWN (Decentralized Web Node)", "Web5", "dwn_store.rs", "Nostr", "federation", "peer discovery", "peer data sync"],
|
||||
"cross_refs": [],
|
||||
"locked": true,
|
||||
"precedence": null,
|
||||
"notes": ""
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
{
|
||||
"source_path": "/home/archipelago/Projects/archy/docs/app-manifest-spec.md",
|
||||
"type": "SPEC",
|
||||
"confidence": "high",
|
||||
"manifest_override": false,
|
||||
"title": "App Manifest Specification",
|
||||
"summary": "Defines the declarative manifest.yml schema for apps: top-level fields, container config, security policy, volumes, hooks, installation semantics, and signed-catalog/marketplace distribution.",
|
||||
"scope": [
|
||||
"app manifest.yml schema",
|
||||
"ContainerConfig (image/build, networks, derived_env, secret_env, generated_secrets, generated_certs)",
|
||||
"SecurityPolicy (capabilities allow-list, network_policy, readonly_root)",
|
||||
"volumes and bind-mount confinement",
|
||||
"lifecycle hooks (post_install, pre_start)",
|
||||
"health checks and interfaces",
|
||||
"Quadlet installation and reconciler semantics",
|
||||
"signed app catalog distribution",
|
||||
"decentralized marketplace distribution"
|
||||
],
|
||||
"cross_refs": [
|
||||
"app-developer-guide.md",
|
||||
"manifest-hooks-design.md",
|
||||
"marketplace-protocol.md",
|
||||
"core/container/src/manifest.rs",
|
||||
"api/rpc/package/stacks.rs"
|
||||
],
|
||||
"locked": false,
|
||||
"precedence": null,
|
||||
"notes": ""
|
||||
}
|
||||
38
.planning/intel/constraints.md
Normal file
38
.planning/intel/constraints.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Constraints (from SPECs)
|
||||
|
||||
Extracted from 1 classified SPEC: `docs/app-manifest-spec.md` (accurate as of 2026-07-08). The SPEC self-declares that the canonical schema is the Rust parser in `core/container/src/manifest.rs` — if doc and code disagree, the code wins.
|
||||
|
||||
## App manifest top-level schema (`app:` block)
|
||||
- source: docs/app-manifest-spec.md
|
||||
- type: schema
|
||||
- content: Every app is a directory `apps/<id>/` with a `manifest.yml` containing a single top-level `app:` block. Apps are purely declarative — the orchestrator owns the entire lifecycle; no per-app installer code. Required fields: `id` (lowercase alphanumeric + `-`/`_`, must match directory name), `name`, `version`. Optional fields: `description`, `container` (ContainerConfig), `dependencies` (storage/app_id+version/bare string), `resources` (cpu_limit, memory_limit, disk_limit), `security` (SecurityPolicy), `ports` (host/container/protocol), `volumes`, `files` (GeneratedFile: path/content/overwrite; path must sit under a declared bind mount), `environment` (static KEY=value), `health_check` (type/endpoint/path/interval/timeout/retries; `http` is what the monitor exercises), `devices` (must start with `/dev/`), `interfaces` (launch surfaces keyed by name), `hooks` (LifecycleHooks). Unknown keys are absorbed into an `extensions` map (serde flatten) as transitional metadata — not typed schema, not validated.
|
||||
|
||||
## ContainerConfig schema
|
||||
- source: docs/app-manifest-spec.md
|
||||
- type: schema
|
||||
- content: Exactly one of `image` or `build` must be present (image XOR build). Fields: `image` (registry reference), `image_signature` (optional), `pull_policy` (default `if-not-present`), `build` ({context, dockerfile default "Dockerfile", tag, build_args}), `network` (literal podman `--network` value; omitted = rootless default isolated network), `network_aliases` (extra DNS names on the network), `entrypoint`, `custom_args`, `derived_env` ({key, template} rendered against host facts at apply time; allowed placeholders only: {{HOST_IP}}, {{HOST_MDNS}}, {{DISK_GB}} plus dependency-resolved facts — never hard-code host specifics), `secret_env` ({key, secret_file} read from /var/lib/archipelago/secrets/<secret_file>, injected as a podman secret so it never appears in `podman inspect` or unit files; secret_file must be a bare filename, no `/` or `..`), `generated_secrets` ({name, kind} materialised by the orchestrator on first use, 0600, rootless service user, idempotent + self-healing; kind ∈ hex16|hex32|base64|bcrypt; bcrypt writes <name>=hash and <name>.pw=plaintext), `generated_certs` ({crt, key, common_name?, sans?} self-signed TLS materialised before create), `data_uid` ("UID:GID" applied to the app's bind-mounted data dir before create).
|
||||
|
||||
## SecurityPolicy schema and validation rules
|
||||
- source: docs/app-manifest-spec.md
|
||||
- type: schema
|
||||
- content: Security block defaults: `readonly_root: true`, `no_new_privileges: true`, `capabilities: []` (cap-drop ALL, add back only listed), `network_policy: isolated` (isolated | bridge | host), `apparmor_profile: null` (optional). Validation enforced at `AppManifest::validate()`: capabilities must come from the reviewed allow-list (CHOWN, DAC_OVERRIDE, FOWNER, NET_ADMIN, NET_BIND_SERVICE, NET_RAW, SETGID, SETUID, SYS_ADMIN); `network_policy` must be exactly isolated/bridge/host; no `container:`/`ns:` network modes; devices must be `/dev/*`; bind-mount sources confined to `/var/lib/archipelago` (reviewed exceptions: rootless podman socket and dbus); `derived_env` templates limited to the placeholder allow-list; `secret_env`/`generated_secrets` names must be bare filenames; hook steps validated against the hook allow-list. (Note: the SPEC's documented validation list does not mention ADR-009's non-root UID, pinned-image-tag, or seccomp mandates — see INGEST-CONFLICTS.md INFO entry.)
|
||||
|
||||
## Volumes schema
|
||||
- source: docs/app-manifest-spec.md
|
||||
- type: schema
|
||||
- content: Volume entries: `type` ∈ bind | volume | tmpfs; bind entries take `source` (confined to /var/lib/archipelago per validation), `target`, `options` from an allow-list (rw, ro, z, Z, shared, …); tmpfs entries take `target` and `tmpfs_options` (e.g. "rw,noexec,nosuid,size=256m").
|
||||
|
||||
## Lifecycle hooks contract
|
||||
- source: docs/app-manifest-spec.md
|
||||
- type: api-contract
|
||||
- content: Hooks are declarative, allow-listed operations that run against the app's own container — never the host (design: manifest-hooks-design.md). `post_install` runs once after install with the container running; supported steps: `copy_from_host` (src relative to an allow-listed root — data dir / web-ui; no absolute paths, no '..') and `exec` (podman exec inside the container). `pre_start` is reserved in the schema; its executor is not yet wired.
|
||||
|
||||
## Installation semantics (Quadlet + reconciler)
|
||||
- source: docs/app-manifest-spec.md
|
||||
- type: protocol
|
||||
- content: The orchestrator compiles the manifest into a rootless Podman Quadlet unit under `user.slice` — the container survives backend restarts and reboots. A level-triggered reconciler converges drift every 30 seconds. Multi-container apps are sets of per-member manifests installed together via the stack orchestrator (`api/rpc/package/stacks.rs`) on an app-local network.
|
||||
|
||||
## Manifest distribution channels
|
||||
- source: docs/app-manifest-spec.md
|
||||
- type: protocol
|
||||
- content: Manifests ship two ways. (1) Signed catalog (primary): `releases/app-catalog.json` embeds the full manifest per app with an Ed25519 detached signature verified against the pinned release-root anchor; nodes overlay catalog manifests over disk files — catalog wins for image-only apps; `apps/<id>/manifest.yml` on disk remains the fallback and is still required for build-source apps. (2) Decentralized marketplace: Nostr NIP-78 discovery with DID-signed manifests (marketplace-protocol.md); the marketplace uses its own flatter manifest schema, not this one. Tooling: validate with `scripts/validate-app-manifest.sh`, regenerate catalog with `scripts/generate-app-catalog.py`, drift-checked in CI by `scripts/check-app-catalog-drift.py`.
|
||||
5
.planning/intel/context.md
Normal file
5
.planning/intel/context.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Context (from DOCs)
|
||||
|
||||
No DOC-type documents were present in the ingest set (10 ADRs + 1 SPEC). No context notes extracted.
|
||||
|
||||
This file intentionally records absence rather than repurposing ADR/SPEC content as context.
|
||||
65
.planning/intel/decisions.md
Normal file
65
.planning/intel/decisions.md
Normal file
@ -0,0 +1,65 @@
|
||||
# Decisions (from ADRs)
|
||||
|
||||
Extracted from 10 classified ADRs. All are `locked: true` (Status: Accepted) and cannot be auto-overridden by any lower-precedence source.
|
||||
|
||||
## ADR-001: Podman Over Docker
|
||||
- source: docs/adr/001-podman-over-docker.md
|
||||
- status: locked (Accepted)
|
||||
- decision: Use Podman as the container runtime instead of Docker. Rootless by default, daemonless, Docker-compatible, native systemd integration, OCI-compliant. Use `archy-net` custom network for inter-container DNS.
|
||||
- scope: container runtime, rootless containers, systemd integration, archy-net network
|
||||
|
||||
## ADR-002: DID Key Method for Node Identity
|
||||
- source: docs/adr/002-did-key-method.md
|
||||
- status: locked (Accepted)
|
||||
- decision: Use `did:key` (Ed25519) as the primary DID method for node identity. Self-contained, offline-capable, local resolution. Known gaps (no rotation, no service endpoints, no revocation) mitigated via federation trust lists and separately-stored service endpoints; future migration to did:peer/did:web possible if rotation is needed.
|
||||
- scope: node identity, DID methods, Ed25519 keys, peer authentication, federation trust lists, verifiable credentials
|
||||
|
||||
## ADR-003: Nostr Relays for Node and App Discovery
|
||||
- source: docs/adr/003-nostr-for-discovery.md
|
||||
- status: locked (Accepted)
|
||||
- decision: Use Nostr relays (NIP-78, kind 30078) for both node discovery and marketplace app manifests. Query multiple relays in parallel with dedupe; local cache with 15-minute TTL; trust scoring (DID verification, relay consensus, federation trust); hashtag filtering (`archipelago-marketplace`); NIP-33 replaceable events for updates; Tor-compatible via SOCKS proxy.
|
||||
- scope: node discovery, app discovery, marketplace app manifests, NIP-78, NIP-33 replaceable events, trust scoring, relay caching
|
||||
|
||||
## ADR-004: Tor Hidden Services for Peer Communication
|
||||
- source: docs/adr/004-tor-for-peer-communication.md
|
||||
- status: locked (Accepted)
|
||||
- decision: Use Tor hidden services (.onion addresses) for all inter-node communication. Scoped to RPC/control plane only — bulk data (container images) pulled from registries. Retry with backoff; `archy-tor` container runs automatically with host networking; federation sync interval (5 min) tolerates occasional failures.
|
||||
- scope: inter-node communication, federation sync, archy-tor container, RPC/control plane, NAT traversal
|
||||
|
||||
## ADR-005: ChaCha20-Poly1305 for Backup Encryption
|
||||
- source: docs/adr/005-chacha20-backup-encryption.md
|
||||
- status: locked (Accepted)
|
||||
- decision: Use ChaCha20-Poly1305 (AEAD) with Argon2id key derivation for backup encryption at rest, chosen over AES-256-GCM and XChaCha20-Poly1305. Random nonce per backup stored alongside ciphertext; Argon2id with 64MB memory cost and 3 iterations for password-to-key derivation.
|
||||
- scope: backup encryption, AEAD, Argon2id key derivation, nonce handling
|
||||
|
||||
## ADR-006: Nostr Relays for Marketplace Discovery
|
||||
- source: docs/adr/006-nostr-marketplace-discovery.md
|
||||
- status: locked (Accepted)
|
||||
- decision: Use Nostr relays (NIP-78, kind 30078 events) for decentralized app manifest discovery instead of a centralized marketplace server. Developers publish signed manifests to public relays; nodes query multiple relays; trust scoring via cross-relay verification count, DID-linked developer reputation, optional community endorsements. Trust tiers: Verified (known developer, 3+ relays, DID-verified), Community (2+ relays, valid manifest, unsigned/new developer), Unverified (single relay, new developer). Local relay-response caching; built-in curated list for essential apps; manifest signature verification before installation.
|
||||
- scope: marketplace, app manifest discovery, trust scoring, trust tiers, manifest signature verification
|
||||
|
||||
## ADR-007: DID-Based Federation Trust
|
||||
- source: docs/adr/007-did-federation-trust.md
|
||||
- status: locked (Accepted)
|
||||
- decision: Use bilateral DID-based verification with single-use invite codes for federation trust establishment. Invite code carries DID, .onion address, and shared secret; exchanged out-of-band; both nodes verify DIDs via signed challenges over Tor; ongoing communication is DID-authenticated over Tor hidden services. Trust levels: Trusted (full access), Observer (read-only), Untrusted (blocked). Discovery (ADR-003) finds nodes; federation trusts them.
|
||||
- scope: federation, DID verification, invite codes, trust levels, Tor hidden services, Ed25519 keys
|
||||
- cross-refs: ADR-003
|
||||
|
||||
## ADR-008: Dual Key Strategy (Ed25519 + Secp256k1)
|
||||
- source: docs/adr/008-dual-key-strategy.md
|
||||
- status: locked (Accepted)
|
||||
- decision: Maintain two key pairs per node identity, both derived from one master seed: Ed25519 as canonical identity (DID documents, verifiable credentials, federation auth, backup encryption via X25519 DH) and secp256k1 for Nostr/Bitcoin/Lightning (event publishing, node discovery, Lightning channel auth). Secp256k1 key linked to the DID via Nostr profile (NIP-05). Backup captures the master seed; DID document includes both verification methods.
|
||||
- scope: node identity, key derivation, master seed, Ed25519, secp256k1, DID documents, federation authentication, backup encryption, Nostr event publishing, node discovery, Lightning Network
|
||||
|
||||
## ADR-009: Manifest-Level Container Security Enforcement
|
||||
- source: docs/adr/009-manifest-container-security.md
|
||||
- status: locked (Accepted)
|
||||
- decision: Enforce mandatory container security defaults at the manifest level, applied automatically during container creation. Non-negotiable defaults: `readonly_root: true`, `no_new_privileges: true`, non-root user (UID > 1000), drop ALL capabilities (add back only required), pinned image tags (no `latest`), default seccomp profile. `core/container/` validates manifests (parse → validate → reject violations → apply security context at `podman create`). Optional overrides (`readonly_root: false`, extra capabilities like NET_ADMIN) require explicit listing and documented justification, with audit trail.
|
||||
- scope: container security, app manifests, manifest validation, podman container creation, security defaults, capability restrictions, seccomp
|
||||
- cross-refs: docs/app-manifest-spec.md, core/container/src/, core/security/src/
|
||||
|
||||
## ADR-011: DWN Deprioritization
|
||||
- source: docs/adr/011-dwn-deprioritization.md
|
||||
- status: locked (Accepted)
|
||||
- decision: Deprioritize Web5 DWN spec compliance following TBD's November 2024 shutdown. Keep existing custom DWN store code (`core/archipelago/src/network/dwn_store.rs`) for peer file catalogs and federation state; stop calling it "Web5 DWN" in user-facing text; do not invest in DWN spec compliance; prioritize Nostr + Tor federation for peer discovery and data exchange; re-evaluate only if DIF produces a viable Rust SDK or the spec regains maintainers.
|
||||
- scope: DWN, Web5, dwn_store.rs, Nostr, federation, peer discovery, peer data sync
|
||||
5
.planning/intel/requirements.md
Normal file
5
.planning/intel/requirements.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Requirements (from PRDs)
|
||||
|
||||
No PRD documents were present in the ingest set (10 ADRs + 1 SPEC). No requirements extracted.
|
||||
|
||||
Downstream note: requirements for the roadmap must be derived elsewhere (e.g. from user input or a future PRD ingest); this file intentionally records absence rather than inferring requirements from ADR/SPEC content.
|
||||
Loading…
x
Reference in New Issue
Block a user