Agentic AI Atlasby a5c.ai
OverviewWikiGraphFor AgentsEdgesSearchWorkspace
/
GitHubDocsDiscord
iiRecord
Agentic AI Atlas · Spec 40 — Packaging (WP-PKG-*)
page:docs-specs-platform-gaps-40-packaginga5c.ai
Search record views/
Record · tabs

Available views

II.Record viewspp. 1 - 1
overviewarticlejsongraph
II.
Page overview

page:docs-specs-platform-gaps-40-packaging

Reference · live

Spec 40 — Packaging (WP-PKG-*) overview

Inspect the raw attributes, linked wiki pages, and inbound or outbound graph edges for page:docs-specs-platform-gaps-40-packaging.

PageOutgoing · 0Incoming · 1

Attributes

nodeKind
Page
sourcePath
docs/specs/platform-gaps/40-packaging.md
sourceKind
repo-docs
title
Spec 40 — Packaging (WP-PKG-*)
displayName
Spec 40 — Packaging (WP-PKG-*)
slug
docs/specs/platform-gaps/40-packaging
articlePath
wiki/docs/specs/platform-gaps/40-packaging.md
article
# Spec 40 — Packaging (WP-PKG-*) Date: 2026-09-27 · Status: Gate-B draft · Binding decisions: **D3** (all three packaging forms, spec proposes priorities — `docs/specs/platform-gaps/00-intent.md:23`), executed **PRIVATE-first under D17/D19/D21** (`00-intent.md:42-46`), constrained by D10 (break freely, major bump), D11 (packaging follows migration + coverage in the roadmap), D13 (mobile deferred), D15 (attribution). Inputs consumed in full: R3 `research/packaging-state.md` (the packaging dossier; cited `R3 §n` with underlying `path:line`), Gate-A synthesis `research/synthesis-adoption-proposal.md` (§1.5 packaging-form priority, §4.4 planned 13-WP inventory), spec 15 `15-private-isolation-rename.md` (its §2 scope, §3 name matrix, §4 registry/guards, and §5 interaction rules **govern all distribution work in this spec**), spec 10 `10-t3code-migration.md` (cross-refs only: unit row 12 at `10-t3code-migration.md:46` hands install/service/self-update landing to this spec; WP-T3-19/26/28/31/32/33 are consumed as dependencies; WP-T3-31's relay ops story is productized by WP-PKG-14), spec 20 `20-functionality-coverage.md` (cross-refs only: WP-FN-02 AC4 / WP-FN-03 AC2 hand default key provisioning to this spec's WP-PKG-04/05; WP-FN-16 FR-7 hands relay rollout to WP-PKG-14). Path conventions: fabric paths relative to `C:/work/fabric`; the t3code MIT snapshot is cited `t3:<path>` (snapshot location per `00-intent.md:51`). Spec 30 (`30-testing.md`) is not yet authored; its work packages are referenced as `WP-TEST-<nn>` under the fixed mapping Q-nn → WP-TEST-nn from the Gate-A inventory (`research/synthesis-adoption-proposal.md` §4.3) — e.g. WP-TEST-04 is Q-04, the whole-platform packaged-install e2e. **Naming discipline**: this spec introduces **no** package, binary, env prefix, directory, or chart name outside the spec 15 §3 locked matrix or its stated derivation rules. Two derived-name additions are **proposed for the Gate-B name lock** (§3.6 launcher alias, §2.4 npm platform packages) and are explicitly flagged as matrix amendments, not minted here. --- ## 1. Scope, private-first doctrine, and priority order ### 1.1 The three forms (D3) and what exists today | Form | D3 wording | Fabric today | Gap class | |---|---|---|---| | **Form 1 — single-node installer UX** | curl\|sh / winget / npx, service, self-update | npm-global only, Node-gated (`docs/user-guide/getting-started/installation.md:126-131`); **no** installer scripts, binary archives, service, self-update, or uninstaller anywhere in fabric (R3 §1.5, negative search recorded at `research/packaging-state.md:150-161`) | Total — built from the t3code blueprint (R3 §2) | | **Form 2 — cluster/Helm bundle** | versioned platform chart, GKE path | Chart exists, production-shaped, but frozen at `version: 0.1.0` vs product 6.0.x (`packages/kradle/charts/Chart.yaml:1-7` vs `package.json:3`), never published (only inert `helm push` in the non-executing nested workflow `packages/kradle/core/.github/workflows/publish.yml:94`, R3 inferred finding 1), consumed from source path by CI (`.github/workflows/publish.yml:952,1080`); the platform deploys via **three mechanisms** (chart + atlas Kustomize overlay `publish.yml:740-742` + Envoy Kustomize `Chart.yaml:31-34`) | Productization — versioning, publication, bundling | | **Form 3 — npm SDK surface** | stable publics, semver, docs | Strong publish integrity (single resolver, waves, packed-artifact verifier — R3 §1.1) but **no declared publics**: `@a5c-ai/babysitter-sdk` has zero `exports` entries and five bins (`packages/babysitter-sdk/package.json:7-14`), `@a5c-ai/adapters` exports only "." (R3 §1.6); lockstep 6.0.x with no per-package semver signal; changesets configured but dead (`.changeset/config.json:1-20`, no workflow references — R3 §1.1) | Boundary definition + versioning posture | ### 1.2 Private-first doctrine (D17/D19 — binding on every WP below) The Gate-A synthesis pre-dates amendment 2026-09-27b; this spec applies the amendment throughout: 1. **Every distribution channel in this spec is private.** npm packages publish only to the GCP Artifact Registry npm repo `fabric-npm` (`https://us-central1-npm.pkg.dev/boot-464019/fabric-npm/`, spec 15 §4.1). Renamed `@fabricstack/*` packages are **never** published to public npmjs (D19; guards G1–G6, spec 15 §4.3). 2. **Non-npm artifacts get private homes too** (§1.3): binary archives, desktop installers, and Helm charts publish to Artifact Registry repositories in the same GCP project `boot-464019` — not to public GitHub Releases, not to ghcr.io, not to winget/Homebrew/AUR (this drops the public-channel half of the planned P-08; justification in §1.5). 3. **CI/publish isolation from the public babysitter pipelines**: the public `a5c-ai/babysitter` repo keeps publishing `@a5c-ai/*` to public npmjs untouched (D17); fabric's packaging pipelines are the private train of spec 15 §4.2 (`publish-npm-private.yml`, tags `fabric/<branch>/v<version>`), and no workflow this spec adds may reference the public repo as a push target (WP-RN-02 guard) or `registry.npmjs.org`/ghcr.io in a publish context (WP-PKG-13 extends G2 to non-npm artifacts). 4. **All packaging operates on the renamed matrix**: package names, bins, env prefixes (`FABRIC_*` for platform-wide installer variables, per spec 15 §2/§3.4), data dirs (`~/.fabric/`, spec 15 §3.5), and chart names (`control-plane`, spec 15 §3.6) come from spec 15 §3. ### 1.3 Artifact-home decision table (the split-repo constraint, R3 spec input 9) R3 spec input 9 requires every new artifact channel to "pick a home repo explicitly and keep the single-resolver version discipline". Spec 15 §4.2 already settled npm bytes ("private npm artifacts live in AR under `boot-464019`; spec 40 inherits that decision"). This spec decides the rest: | Artifact class | Home (decided) | Why | |---|---|---| | npm packages (43 renamed + §2.4 platform packages) | AR npm repo `fabric-npm` (spec 15 §4.1) | inherited from spec 15 §4.2 | | Self-contained per-platform archives + `SHA256SUMS` (Form 1) | **New AR generic-format repo `fabric-dist`**, project `boot-464019`, region `us-central1` | Same project/region/WIF auth as the existing Docker AR (`publish.yml:3-6,880-893`, R3 §1.3); AR generic repos serve versioned binary blobs over authenticated HTTPS, which is exactly what a private installer needs. Alternatives rejected: *private GitHub Releases on `a5c-ai/fabric`* — asset download on private repos requires GitHub API tokens with repo scope, coupling customer machines to GitHub org membership; *GCS bucket* — loses AR's IAM/version/immutability semantics and would be the only artifact class outside AR; *public GitHub Releases* — violates D19's private-distribution posture outright | | Desktop installers + update manifests (console-desktop, WP-T3-26) | Same `fabric-dist` repo, `desktop/` artifact path family | One channel, one auth story; t3code's merged mac/win update manifests (`t3:scripts/merge-update-manifests.ts:19-24`, R3 §2.3) point at the same base URL the archives use | | Helm chart `control-plane` | **AR OCI**: `oci://us-central1-docker.pkg.dev/boot-464019/fabric-charts` (new AR Docker-format repo `fabric-charts`; Helm OCI charts are OCI artifacts) | The precedent in-tree is the inert ghcr push (`packages/kradle/core/.github/workflows/publish.yml:94`, R3 §1.2) — **rejected**: ghcr is public-facing and belongs to the public repo's org surface. AR OCI reuses WIF auth and keeps the chart beside the container images the chart references | | Container images | Existing AR Docker repo at `us-central1-docker.pkg.dev` (`publish.yml:880-893`) | Already private and working; WP-PKG-09 adds platform-version tags beside the commit-sha tags (`publish.yml:812-816`) | | Relay deployables (Cloudflare Worker bundle + Postgres migrations + cloudflared config, WP-T3-31) | **Deployed, not distributed**: the fabric-controlled Cloudflare account (Workers) and its managed Postgres — no customer-facing artifact exists for this class | The relay is a hosted service fabric operates under the broker-not-proxy trust model (WP-FN-16 FR-2); its "home" is the deployment target itself. Sources live in `infra/relay` (`10-t3code-migration.md:476`); deploy provenance is the train tag; pipeline, promotion, and guard coverage are WP-PKG-14. Publishing the Worker to any public marketplace/registry is excluded (PG1 extension, WP-PKG-14 AC5) | All four artifact-registry homes are inside `boot-464019`, authenticated by the existing WIF step (`google-github-actions/auth@v2`, R3 §1.3) in CI and by `gcloud` ADC or short-lived tokens for humans/installers. The relay's deployment target is the one deliberate non-AR home — a deploy destination, not a distribution channel — credentialed separately under the PG5 pattern (WP-PKG-14 AC6). ### 1.4 Node floor encoding (binding; synthesis risk 3, R3 spec input 5) | Floor | Value | Where encoded | |---|---|---| | Runtime floor, npm-installed surfaces | `>=22.16` workspace engines (WP-T3-32 stage 1; the strictest already-landed floor), which subsumes the `node:sqlite` floor `>=22.5` (`installation.md:199-202`; R2 §15 via `10-t3code-migration.md:483`) | root `package.json` engines + per-package engines; CI engines check (WP-T3-32 AC5) | | Runtime floor, Form 1 archives | **None for the consumer** — the SEA executables embed their runtime; "nothing in it may require Node, npm, or a compiler on the machine that unpacks it" (`t3:scripts/build-cli-archive.ts:1-16`, adopted as the archive contract) | WP-PKG-03 AC1 | | SEA **build hosts** | `>=25.7` (R3 spec input 5; synthesis risk 3) | release-pipeline build-job Node matrix, WP-PKG-03 AC6 | ### 1.5 Priority order (D3 "spec proposes priorities") and planned-inventory delta **Decision proposed: Form 3 (npm SDK publics) → Form 1 (single-node installer/service/self-update) → Form 2 (chart productization), with the private-registry substrate (WP-RN-03/04/07) preceding all three.** Rationale (inheriting synthesis §1.5, restated under the amendment): - **Form 3 first** because its blocker — no exports maps, unbounded publics (R3 §1.6) — is a *prerequisite* for D6's ACP re-platforming (new lane packages need defined publics to land against) and because spec 15 §5 rule 6 binds it to the RN-1 train: "P-01's exports-map program and the D10 major bump land in the same train as RN-1 so publics are defined once, under the new names". Doing it later means defining publics twice. - **Form 1 second**: it starts from zero (R3 §1.5) but has a complete, tested t3code blueprint (R3 §2) and its central deliverable — the environment server — only exists after WP-T3-19; the adopted desktop app (WP-T3-26) amplifies it. Under D17 the single-node private product is the commercial surface, which ranks it above Form 2. - **Form 2 last**: the chart + GKE pipeline already work internally (R3 §1.2–1.3); what remains is productization (versioning, OCI publication, bundling), and spec 15 already schedules the chart's rename for phase RN-5 — coordinating WP-PKG-09 with WP-RN-12 "so re-versioning and renaming land as one chart-consumer break, not two" (spec 15 WP-RN-12 dependency note) naturally places it last. - Consistent with D11: all of this follows the t3code migration and coverage work in the roadmap; nothing here blocks WP-T3-* except where spec 10 itself declared the dependency (WP-T3-28's bootstrap-download activation gates on WP-PKG-03 — `10-t3code-migration.md:451-453`). **Delta against the planned 13-WP inventory** (synthesis §4.4; count becomes **14** — three scope adjustments plus one addition): 1. P-01's bin-collision half moved to spec 15 (WP-RN-06 + guard G5 own it); WP-PKG-01 keeps exports maps/publics and *consumes* the collision-free bin set. 2. P-08's public OS package managers (winget/brew/AUR/deb) are **dropped**: they are public distribution channels and contradict D19's private posture (the synthesis §4.4 row pre-dates amendment 2026-09-27b). WP-PKG-08 keeps the uninstall story and records the no-public-channel decision. If a future decision opens a public channel for the private product, that is a new intent amendment, not a packaging WP. 3. P-13 narrows to non-npm artifact channels + guard extension, because spec 15 §4.2 already decided the npm artifact home. 4. **WP-PKG-14 added** — the hosted relay's production rollout had no owning WP anywhere in the program: WP-T3-31 builds the relay and documents its ops story "(Worker + Postgres + cloudflared) … for spec 40/50 consumption" (`10-t3code-migration.md:476`), and WP-FN-16 FR-7 requires that "its packaging/rollout is carried by specs 40/50" (`20-functionality-coverage.md:111`) — but the planned inventory carried no deploy-pipeline package for it. WP-PKG-14 (§7) now owns the relay artifact class (§1.3 last row) and its deploy/promotion/rollback pipeline, closing the hand-off both sibling specs already point at. ### 1.6 Scope deltas recorded for the Gate-B register (WP-RM-03) Where this spec narrows the surface of a binding decision, the narrowing is recorded here as a labeled scope delta so the Gate-B compliance matrix (WP-RM-03, spec 50) can carry it by ID — the register cites `40-packaging.md §1.6 SD-PKG-<n>` and needs no re-derivation or sibling-spec edit: - **Scope delta SD-PKG-1 — D3 narrowing: on Windows, the environment server runs foreground or desktop-app-managed only in v1; no Windows background service ships.** D3's Form 1 names "service" without OS qualification; this spec ships systemd-user (with lingering) and launchd services (§3.4) but adopts the reference implementation's explicit exclusion of Windows services (`t3:docs/user/background-service.md:90-94`). *Rationale*: there is no t3code blueprint to fork for Windows service hosting of a user-context server (service wrapper, session-0 isolation, credential plumbing would all be greenfield), and the desktop app's DesktopBackendManager (WP-T3-26, `10-t3code-migration.md:434-440`) already provides managed background operation on Windows — so v1 spends the effort where a tested reference exists. *Enforced surface*: `environment-server service install` on Windows exits with the typed unsupported-platform error naming both alternatives (WP-PKG-05 AC5); the stance is recorded in `docs/PACKAGING-DECISIONS.md` (WP-PKG-08). *Revisit condition*: a customer requirement for headless unattended Windows hosts triggers an intent-level amendment, which would mint a new work package (Windows service wrapper) rather than stretch WP-PKG-05. --- ## 2. Form 3 — npm SDK surface (priority 1) ### 2.1 Exports-map program (publics defined once, under the new names) - Every one of the 43 publishables (inventory always derived from `scripts/lib/publishable-packages.cjs:122-161`, never hand-maintained — FIX-005 discipline, R3 spec input 2) gains an `exports` map that enumerates its public entry points; everything else under `dist/` becomes unreachable. Today the SDK has **zero** exports entries and every `dist/` module is deep-importable API (`packages/babysitter-sdk/package.json:7-14`, R3 §1.6) — D6's re-platforming would otherwise land on an unbounded surface (R3 spec input 8). - Subpath policy: packages expose `"."` plus a small named-subpath set (e.g. the orchestrator SDK's storage/journal and breakpoint surfaces that other WPs cite as seams); no `"./*"` wildcard exports — a wildcard reproduces the unbounded surface with extra steps. - The packed-artifact verifier already checks "root and subpath imports, consumer typecheck and bin smoke tests" per package (`.github/workflows/release-artifact-verifier.yml:5-9`, R3 §1.6); WP-PKG-01 turns it from permissive to **exact**: the verifier asserts that the set of importable subpaths equals the exports map, and that deep imports of non-exported paths fail. - Timing is bound by spec 15 §5 rule 6: exports maps + the D10 major bump ride the RN-1 train (WP-RN-05/06/07), so the first `@fabricstack/*` publication already carries defined publics. ### 2.2 Semver posture: lockstep train kept, changesets removed (decision) **Decision proposed: keep lockstep versioning across the 43-package train; remove the dead changesets machinery; encode breaking-ness at train level, not per package.** - The lockstep 6.0.x scheme with exact-pinned internal deps and `verify-manifests` (`scripts/release-version.cjs:24-27`; R3 §1.6) is incident-hardened and matches the consumer reality of a **private** product: consumers are the platform itself, the Form 1 archives, and enterprise installs that consume whole trains via dist-tags — not a public ecosystem cherry-picking package versions. Per-package semver would decorate 43 manifests with signals nobody resolves against. - Changesets (`.changeset/config.json:1-20` + one stranded changeset file) are referenced by **no workflow** (R3 §1.1) — R3 spec input 3 requires wire-or-remove; under lockstep-kept, **remove** is the coherent half: delete `.changeset/` and the pending markdown, so the repo carries one versioning mechanism (`scripts/release-version.cjs`, the single resolver that is never bypassed — R3 spec input 3). - D10 is expressed at train level: the RN-1/exports cutover publishes as the **7.0.0** train (major bump), and subsequent breaking trains bump the train major. A one-page `docs/VERSIONING.md` records the posture: "semver encodes the release train; within-train packages are exact-pinned lockstep; majors mark breaking trains" — plus the alternative considered (per-package semver via changesets) and why it was rejected. - HYG2 closure rides here: wildcard workspace deps (e.g. `"@a5c-ai/atlas": "*"` at `packages/atlas/webui/package.json:16`, spec 15 §3.2) are eliminated; `verify-manifests` (already extended by G2(d), spec 15 §4.3) additionally fails on any `*`/`^`-ranged internal dependency. ### 2.3 Private publication and isolation (inherited, verified here) Publication mechanics are owned by WP-RN-07 (resolver + tags + waves + verifier retargeted to AR, dist-tags `main→latest / staging→staging / develop→develop` carried over — spec 15 §4.1/§4.2) and guarded by WP-RN-04's G1–G6 (spec 15 §4.3). Form 3's residual obligations, owned by WP-PKG-01/02: - Publics documentation: the docs-site SDK reference is regenerated from the exports maps (docs QA gates exist, `package.json:116-123`, R3 §1.6); the private-install page documents `.npmrc` scope routing + `google-artifactregistry-auth` per spec 15 §4.1. - No packaging WP creates a public-npm channel for `@fabricstack/*` (spec 15 §7 obligation on this spec — restated as binding). ### 2.4 npm platform packages + launcher (`npx` zero-install, private) Adopt t3code's pattern: per-platform npm packages holding the release archive's contents **verbatim**, plus a thin launcher listing them as `optionalDependencies` and exec-ing the one npm installed; publish from tarballs so npm cannot strip the flattened `node_modules` (`t3:scripts/build-npm-platform-packages.ts:2-21,16-21,184`, R3 §2.5). npm bytes therefore equal `fabric-dist` archive bytes. - Launcher: `@fabricstack/environment` (the §3.3 spec 15 unit for `apps/environment`, bin `environment-server`) doubles as the launcher package. - Platform packages: **proposed Gate-B matrix amendment** — `@fabricstack/environment-<platformKey>` for platformKey ∈ {`darwin-arm64`, `darwin-x64`, `linux-x64`, `linux-arm64`, `win32-x64`, `win32-arm64`} (the t3code six-target matrix, `t3:.github/workflows/release.yml` desktop/cli matrix — R3 §2.4), derived by the rule `<unit>-<platformKey>`. Flagged for the spec 15 §3 name lock; no WP lands them before that amendment is approved. - `npx @fabricstack/environment` against a private registry requires the consumer's `.npmrc` scope routing + AR auth; the documented trial flow includes that step (unlike t3code's anonymous `npx t3@latest`, `t3:docs/user/install.md:38-39` — the delta is the price of D19 and is documented, not hidden). --- ## 3. Form 1 — single-node installer UX (priority 2) The t3code machinery is the reference implementation (D3; R3 §2 and spec input 6); spec 10 row 12 hands its landing to this spec (`10-t3code-migration.md:46`), having itself landed only `cloud/selfUpdate.ts` inside the environment-server tree (WP-T3-19). Everything below is adapted hard-fork material (fork posture per synthesis §2.2 row "install/service/self-update machinery": hard fork, MIT attribution via WP-PKG-12). ### 3.1 What Form 1 installs The single-node unit is: **the SEA `environment-server` executable** (apps/environment, WP-T3-19 — it serves contracts RPC and the local console-web client, per WP-T3-25's "server-served local client" deployment form, `10-t3code-migration.md:427`), **the SEA `orchestrator` CLI** (metapackage bin, spec 15 §3.1 row 1), **console-web static assets**, and the native prebuilds the server needs (node-pty; optional resource-monitor sidecar — `10-t3code-migration.md:380`). Mobile shells are out (D13). The desktop app (`@fabricstack/console-desktop`, WP-T3-26) is a sibling distribution riding the same pipeline and `fabric-dist` channel (§3.7), not part of the headless archive. ### 3.2 Archives (adapting `build-cli-archive.ts`) - One self-contained archive per platform/arch, named `environment-<version>-<platform>-<arch>.tar.gz` (zip on Windows), containing the two SEA executables, console-web assets, and production-installed runtime-external native packages — the "no Node, npm, or compiler on the unpacking machine" contract (`t3:scripts/build-cli-archive.ts:1-16`). - `SHA256SUMS` published beside the archives (consumed by the installers exactly as `t3:scripts/install.sh:194-215` does). Detached trust-core signatures over `SHA256SUMS` are **deferred, with rationale**: `fabric-dist` downloads are already authenticated + TLS (unlike t3code's anonymous GitHub CDN), so checksums cover corruption and signatures add value only for offline mirrors — recorded as a follow-on in the WP-PKG-03 closing note, not built now. - Versions come from the single resolver (`scripts/release-version.cjs` — R3 spec input 3): archive versions are the same train versions npm gets; commit-pinned prereleases (`<base>-<channel>.<short-sha>`, `scripts/lib/release-version.cjs:146-151`) name staging/develop archives. ### 3.3 Installers (adapting `install.sh` / `install.ps1`) - POSIX installer adapted from the 227-line dependency-free `t3:scripts/install.sh:1-4` ("Needs only sh, tar, sha256sum or shasum, and curl or wget") and `t3:scripts/install.ps1:7-22` for Windows, kept dependency-free. - Env-var surface uses the platform-wide `FABRIC_` prefix (spec 15 §2/§3.4): `FABRIC_CHANNEL` (= `stable|staging|dev`, §5), `FABRIC_VERSION` (exact pin), `FABRIC_DIST_BASE_URL` (mirror override), `FABRIC_DIST_TOKEN` (auth), `FABRIC_HOME` (layout root, default `~/.fabric`) — mirroring `T3CODE_CHANNEL`/`T3CODE_VERSION`/`T3CODE_RELEASE_BASE_URL` (`t3:scripts/install.sh:8-16`). No new prefix is minted. - **Private-download auth (the one structural delta from t3code)**: the installer resolves credentials in order — `FABRIC_DIST_TOKEN` env; else `gcloud auth print-access-token` when gcloud ADC is present; else fail with a documented pointer to the private-install doc. Downloads hit `fabric-dist` over authenticated HTTPS. There is no anonymous path — that is D19 working as intended. - Channel/version resolution keeps t3code's safety rails: per-train version listing so a stable install can never pick a prerelease (`t3:scripts/install.sh:145-160`), un-requested trains refused (`install.sh:163-174`), targeted error on missing checksum asset (`install.sh:196`). - Versioned layout shared with the service: archives unpack to `$FABRIC_HOME/runtime/versions/<version>` (t3code's layout, `install.sh:17-19,177`, with `~/.t3` → `~/.fabric` per spec 15 §3.5); staging dir + smoke-run (`environment-server --version`) + `.install-complete` marker + atomic move (`install.sh:194-215`); user entry point symlinked `~/.local/bin/environment-server → versions/<v>/environment-server` with a PATH hint (`install.sh:220-221,223-226`). Progress UX on stderr survives piping (`install.sh:33-52,88-118`). - **First-boot key provisioning (the WP-FN-02/WP-FN-03 hand-off, made concrete here)**: the install finishes by invoking the installed binary's idempotent `environment-server keys init`, which generates — only when absent — the default **run signing key** (WP-FN-02 AC4: "spec 40 P-04 provisions a default run key so the shipped platform signs by default") and the **attestation keys** (proxy attestation key + model-decision signing key) that make WP-FN-03 AC2's default-covered posture real ("with keys present (the packaged default), proxy attestation and in-process model-decision signing are ON without env opt-ins"). Key material lands in `$FABRIC_HOME/keys/` (0700 dir, 0600 files) — a data directory per spec 15 §3.5, deliberately **outside** `runtime/versions/<v>` so keys survive updates (WP-PKG-06) and uninstall (WP-PKG-08 AC1 preserves data directories). Owned by WP-PKG-04 (generation) and WP-PKG-05 (service-start refusal when keys are missing). - Installer entry: `curl -fsSL <install-url> | sh` / `irm <install-url> | iex` where `<install-url>` is a fabric-operated HTTPS location serving the scripts (the scripts themselves are not secret; only artifact downloads are authenticated). The t3code precedent is `https://t3.codes/install.sh` (`t3:docs/user/install.md:13-21`). - Installer tests ride the t3code precedent of a real test file (`t3:scripts/install.test.ts`, R3 §2.1). ### 3.4 Background service - Adopt t3code's backends: **systemd user services with lingering** on Linux, **launchd LaunchAgent** on macOS (`t3:docs/user/background-service.md:45-54`); `service install` is a **reconciler** (install/update/repair from the CLI's own version, downgrade refused without `--allow-downgrade` — `t3:apps/server/src/cli/service.ts:38-63`); `service status` diagnoses concrete problem codes (`linger-disabled`, `user-manager-unavailable`, `service-stopped`, `restart-pending`) with repair guidance (`background-service.md:83-88`). - **Windows-service stance (decision — recorded as scope delta SD-PKG-1, §1.6)**: Windows background services are **out of scope**, adopting the reference's explicit position (`t3:docs/user/background-service.md:90-94`). On Windows the installer installs the binaries and the recommended managed path is the desktop app, whose DesktopBackendManager owns spawning the bundled environment server (WP-T3-26, `10-t3code-migration.md:434-440`). `environment-server service install` on Windows exits with a typed unsupported-platform message pointing at both alternatives (foreground run; desktop app). This narrows D3's "service" for one OS; the rationale and revisit condition live in the SD-PKG-1 entry (§1.6), which WP-RM-03's Gate-B register carries, in addition to the WP-PKG-05 doc page. - Command surface hangs off the installed binary, mirroring t3's single-binary subcommands (`t3 service install|status|restart|uninstall`, `t3 update`, `t3 uninstall` — `t3:docs/user/install.md:28-35`): `environment-server service …`, `environment-server update`, `environment-server uninstall`. ### 3.5 Self-update - Adopt the launcher-owned two-phase architecture: a **stable launcher** (from `t3:apps/server/src/serviceLauncher.ts`) is the runtime systemd/launchd selects and the only writer of durable service state; server children request updates over inherited IPC and never rewrite their own service definition (`t3:docs/internals/server-updates.md:3-8`). - Two-phase commit verbatim: pending update durably recorded → target starts as a **trial** (migrations done, HTTP bound, parked at the activation gate) → `prepared` → durable commit → live; failed/timed-out trials roll back (`server-updates.md:17-31`). **SQLite snapshot rollback**: launcher snapshots main/WAL/shm after stopping the old child so trial migrations are reversible without down-migrations, with a durable restore marker (`server-updates.md:33-43`). - Exact-version installs keep restarts independent of cache eviction and moving tags (`server-updates.md:10-14`); capability negotiation distinguishes `desktop-managed` vs `boot-service` self-update (`t3:apps/server/src/cloud/selfUpdate.ts:40-47` — this module lands with WP-T3-19 per spec 10 row 12 and is *activated* here). - `environment-server update` semantics per `t3:docs/user/background-service.md:23-36`: newest release on the channel, prompt before restarting live work, exact-version pinning, `--channel` train switching, `--allow-downgrade` guard. Update downloads hit `fabric-dist` with the §3.3 auth chain. ### 3.6 Entry-point naming (Gate-B note) The installed entry point is the `environment-server` bin — the spec 15 §3.3 name for `apps/environment`; this spec does not mint a new bin. A short launcher alias (candidate: `fabric`) would improve CLI ergonomics (`environment-server service install` is a mouthful next to `t3 service install`) but is a **new binary name requiring a spec 15 §3 matrix amendment at the Gate-B name lock**; it is proposed there, and every WP below is written to work without it. ### 3.7 Desktop channel note `@fabricstack/console-desktop` (WP-T3-26) ships as electron-builder artifacts published to `fabric-dist` under `desktop/`, with merged mac/win auto-update manifests generated at release time per the t3code pattern (`t3:scripts/merge-update-manifests.ts:19-24`; desktop's token-based two-phase update handoff per `t3:docs/internals/server-updates.md:52-57`). Desktop artifact production is an acceptance item of WP-PKG-03/06, not a separate WP: the reference implementation builds desktop targets inside the same release workflow (six-target matrix, `t3:.github/workflows/release.yml` — R3 §2.4), and splitting it would duplicate the pipeline. --- ## 4. Form 2 — cluster/Helm bundle (priority 3) ### 4.1 One versioned platform chart - The chart un-freezes: `version`/`appVersion` move from the static `0.1.0` (`packages/kradle/charts/Chart.yaml:1-7`) to the **platform train version** resolved by `scripts/release-version.cjs`, stamped at package time (never committed as a moving value). Chart name and K8s identities follow spec 15 §3.6 (`control-plane`, CRD group `control-plane.fabric.internal`, namespace `control-plane-system`) — and per spec 15 WP-RN-12's dependency note, **re-versioning and renaming land as one chart-consumer break**: WP-PKG-09 and WP-RN-12 ship in the same train. - Container image references in `values.yaml` default to platform-version tags in the private AR Docker repo (today images are only sha-tagged at deploy time, `publish.yml:812-816`); the sha tag remains as a co-tag for provenance. ### 4.2 Fold the three deploy mechanisms into the bundle Today "the platform is not one bundle" (R3 §1.2): kradle chart + atlas-webui Kustomize overlay (`publish.yml:740-742`) + Envoy AI Gateway Kustomize (`Chart.yaml:31-34`), with CRDs applied out-of-band (`publish.yml:955`). Fold decisions: | Mechanism | Disposition | Why | |---|---|---| | atlas-webui Kustomize overlay | **Folded into the chart** as `catalog-webui` templates behind an install condition (like the existing vela/kyverno/jitsi conditions, `Chart.yaml:17-35`) | It is fabric's own service; envsubst-piped Kustomize (`publish.yml:740-742`) exists only because nobody folded it — no upstream constraint | | Envoy AI Gateway Kustomize | **Stays out of the chart; becomes an operator-managed install phase** (`operator install` renders/applies it, replacing the CI-only step) | Upstream deliberately deploys Envoy via Kustomize, not as a subchart (`Chart.yaml:31-34`) — the deliberate choice is respected; the *customer-facing* unit becomes one operator command anyway | | CRDs (8 files, `packages/kradle/charts/crds/`) | Chart keeps `crds/` for first install; the **operator owns upgrades** via server-side apply, productizing what CI does today (`kubectl apply -f … --server-side --force-conflicts`, `publish.yml:955`) | Helm does not upgrade `crds/` contents; today's out-of-band step is correct and just needs an owner that is not the company CD | | Vendored subcharts (jitsi-meet 1.5.2, kyverno 3.9.1, vela-core 1.10.9 — `packages/kradle/charts/charts/`) | Remain vendored in the published chart | Private distribution must not depend on third-party chart repos at install time | ### 4.3 OCI publication and the operator as the entry point - Chart published to `oci://us-central1-docker.pkg.dev/boot-464019/fabric-charts` per train, with channel co-tags mirroring the dist-tag scheme (§5). The publish step lives in fabric's private pipeline (spec 15 §4.2), gated by the same packed/verify discipline as npm (chart render + install dry-run gate in the verifier lane). - `@fabricstack/operator` (the renamed kradle-installer, spec 15 §3.1 row 43; today `@a5c-ai/kradle-installer`, bin `kradle-install`, targets `minikube|existing|eks|aks|gke`, Terraform GKE renderer — `packages/kradle/installer/src/types.ts:3`, `SPEC.md:1-33`, `src/terraform/root.ts:115-193`) becomes the operator entry consuming **published** artifacts: it pulls the chart by OCI ref + version instead of rendering against repo paths, and drops the CI-flag coupling (`A5C_CLOUD_*`→`FABRIC_*` repo variables per spec 15 §3.4; deploy hooks currently gated at `publish.yml:1316-1321`). - Dogfooding closes the loop: the company's own `deploy_kradle` job (`publish.yml:792-1130`) switches from `helm upgrade --install kradle packages/kradle/charts` (`publish.yml:1080`) to installing the **published** OCI chart at the resolved train version — CI becomes the first customer of the bundle, so a broken publication breaks CD before it breaks a customer. --- ## 5. Channels and trains (cross-form; adapting t3code's discipline to fabric's branch model) **Decision proposed: keep fabric's three branch-mapped channels, present them installer-facing as `stable`/`staging`/`dev`, and adopt t3code's exact-commit promotion discipline; no cron-driven nightly train is added.** - Mapping: `stable` ↔ branch `main` ↔ dist-tag `latest`; `staging` ↔ `staging` ↔ `staging`; `dev` ↔ `develop` ↔ `develop` (`scripts/lib/release-version.cjs:44-46`). The same three channel names select archives in `fabric-dist`, desktop manifests, and chart co-tags — one channel vocabulary across all three forms, all resolved by the single resolver (R3 spec input 3; sha-suffixed prerelease comparison rules preserved, `release-version.cjs:162-170`). - **Exact-commit promotion**: t3code's core discipline — "stable only ever ships a build that nightly users have already run" (`t3:.github/workflows/release.yml:44-47,88-93`) — is adopted as: a `stable` release must promote the **exact commit** of a previously published `staging` release; the release job verifies this against the `fabric/staging/v*` tag set (tags per spec 15 §4.2) and refuses otherwise. Commit-pinned prerelease versions (`<base>-staging.<short-sha>`) make the check mechanical. - **No nightly cron**: t3code's 30-minute nightly cron (`release.yml:4-27`) exists to give an anonymous public user base a fresh train. Fabric's `develop` channel already publishes per-merge commit-pinned prereleases — a push-driven "nightly" with better provenance — and the private audience does not need cadence-based freshness. Adding a fourth train would complicate the resolver for zero consumers. t3code's concurrency separation (nightly never blocks stable, `release.yml:29-37`) is still adopted: `dev`-channel publication runs in a separate concurrency group from `staging`/`stable`. - Preview-train safety rail equivalent: un-requested channels are refused at install/update time (§3.3; `t3:scripts/install.sh:163-174`). --- ## 6. CI/publish isolation (cross-form) Spec 15 §4.3's G1–G6 cover npm. This spec extends isolation to every artifact class it creates (owned by WP-PKG-13; WP-PKG-14 AC5 further extends PG1 to the relay's deploy targets): | Guard | Mechanism | |---|---| | **PG1 — no public artifact endpoints** | The WP-RN-04 CI enforcement job gains assertions: no workflow file references `ghcr.io`, `registry.npmjs.org`, public GitHub `releases` upload actions, or non-`pkg.dev` helm/oci push targets in a publish context. Negative fixtures included (a deliberately-bad workflow snippet must trip it) | | **PG2 — inert-workflow removal** | The nested non-executing workflow carrying the ghcr helm push (`packages/kradle/core/.github/workflows/publish.yml:94`, R3 inferred finding 1) is deleted, so it can never be promoted to the root by a refactor | | **PG3 — installer URL pinning** | `install.sh`/`install.ps1` default `FABRIC_DIST_BASE_URL` to the `fabric-dist` AR endpoint; CI asserts the shipped scripts contain no `github.com/.../releases` or npmjs URL | | **PG4 — public-repo non-interference** | Restated invariant: no WP in this spec touches `a5c-ai/babysitter` names, publishing, tags, or workflows (intent acceptance criterion 7; enforced by WP-RN-02's guard). The public repo's npm-global install story for `@a5c-ai/*` (`installation.md:126-131`) continues to exist **there**, untouched | | **PG5 — credential starvation extended** | Fabric repo secrets contain no ghcr/npmjs/public-release credentials; CI asserts no workflow consumes such a secret (extends G3, spec 15 §4.3) | --- ## 7. Work packages Fourteen work packages: the Gate-A planned inventory (synthesis §4.4) with the three §1.5 scope adjustments, plus WP-PKG-14 (§1.5 delta item 4) owning the relay production rollout, which previously had no owner among the program's work packages. ### WP-PKG-01: Exports-map program — publics defined across the renamed 43-package matrix - **Objective**: Every publishable package declares its public API via an `exports` map (root + enumerated subpaths, no wildcards); deep imports of non-exported modules fail; the packed-artifact verifier enforces exactness; publics ship once, under `@fabricstack/*` names, in the D10 major-bump train (7.0.0) together with RN-1. - **Affected paths**: all 43 manifests enumerated by `scripts/lib/publishable-packages.cjs:122-161` (exports fields; today `packages/babysitter-sdk/package.json:7-14` has zero exports entries and `packages/adapters/sdk/package.json` exports only "." — R3 §1.6); `.github/workflows/release-artifact-verifier.yml` (exactness assertions added to the FIX-011 gate, `release-artifact-verifier.yml:1-16`); source import sites that deep-import now-private paths (workspace-wide sweep); docs-site SDK reference pages regenerated from exports maps (`package.json:116-123` docs gates). - **Acceptance criteria**: (1) `node -e "require('@fabricstack/orchestrator-sdk/dist/internal-anything')"` -style non-exported deep imports fail for every package (verifier negative matrix, at least one probe per package); (2) all declared subpaths import and typecheck in the verifier's fresh-install consumer lane (`release-artifact-verifier.yml:5-9` extended); (3) zero in-repo imports of non-exported paths (CI grep/resolver check); (4) the exports cutover and the RN-1 rename publish as one train versioned 7.0.0 (tag `fabric/<branch>/v7.0.0` exists; no intermediate train carries renamed-but-unbounded packages); (5) docs-site publics reference lists exactly the exported subpaths per package. - **Test requirements**: packed-artifact verifier full 43-package matrix green with the exactness assertions; consumer-typecheck lane green; WP-TEST-09 (Q-09) projection/parity suites compile against the declared publics only. - **Dependencies**: WP-RN-05, WP-RN-06 (same train; collision-free bin set), WP-RN-07 (train publishes to AR); blocks the public-surface claims of WP-T3-05 consumers. - **Size**: L ### WP-PKG-02: Versioning discipline — lockstep kept, changesets removed, HYG2 closed - **Objective**: Execute the §2.2 decision: one versioning mechanism (the single resolver), changesets deleted, train-level semver posture documented, wildcard internal deps eliminated. - **Affected paths**: `.changeset/config.json:1-20` + `.changeset/observer-dashboard-replacement.md` (deleted); new `docs/VERSIONING.md` (posture + rejected alternative recorded); `scripts/release-version.cjs:24-27` `verify-manifests` (new failure on `*`/range-versioned internal deps); `packages/atlas/webui/package.json:16` and every other wildcard internal dep found by the check. - **Acceptance criteria**: (1) repo-wide grep for `changeset` in `.github/workflows` and tree returns zero live references; (2) `verify-manifests` fails on a fixture manifest with `"@fabricstack/catalog": "*"` and passes on the cleaned tree; (3) `docs/VERSIONING.md` states the lockstep-train posture, the D10 major-bump rule, and the changesets-removal rationale; (4) the 7.0.0 train publishes with all internal deps exact-pinned (existing verify + new check both green). - **Test requirements**: `verify-manifests` negative fixture in CI; release train dry-run (`release-version.cjs resolve/verify`) green. - **Dependencies**: WP-RN-07 (resolver retarget lands first so this extends the retargeted script once). - **Size**: M ### WP-PKG-03: SEA executables + self-contained per-platform archives + private dist publication - **Objective**: Build `environment-server` and `orchestrator` as Node SEA executables; produce one self-contained archive per platform/arch (§3.2 contents, six-target matrix) plus `SHA256SUMS`; publish per train to the `fabric-dist` AR generic repo; desktop electron-builder artifacts + merged update manifests ride the same pipeline (§3.7). - **Affected paths**: new `scripts/build-archives/` (adapted hard-fork of `t3:scripts/build-cli-archive.ts:1-16` and `t3:scripts/merge-update-manifests.ts:19-24`; attribution per WP-PKG-12); fabric's private publish workflow (spec 15 §4.2 `publish-npm-private.yml` gains archive build/publish jobs with the §5 concurrency split); `apps/environment` + orchestrator CLI SEA entry configs; CI Node matrix (SEA build hosts ≥25.7 — §1.4); `fabric-dist` repo provisioning in `boot-464019` (WIF SA `roles/artifactregistry.writer`, mirroring spec 15 §4.1's npm setup). - **Acceptance criteria**: (1) on a clean VM per platform (no Node, no npm, no compiler), unpacking the archive and running `environment-server --version` and `orchestrator --version` succeeds — the `build-cli-archive` contract holds; (2) `SHA256SUMS` verifies for every asset; a corrupted archive fails installer verification (negative test); (3) archives exist in `fabric-dist` for a full staging train at the resolver-derived version, addressable by channel and by exact version; (4) console-web is served by the unpacked `environment-server` and loads in a browser (smoke); (5) desktop artifacts + merged mac/win update manifests published under `desktop/` for the same train; (6) build jobs run on Node ≥25.7 hosts and the workspace engines floor (≥22.16) is untouched (CI matrix asserts both); (7) zero public-endpoint references in the new jobs (PG1 green). - **Test requirements**: per-platform boot smoke in the release pipeline (t3code's `release-smoke.ts` pattern, R3 §2.4); checksum negative test; WP-TEST-04 (Q-04) consumes these archives as its packaged-install input. - **Dependencies**: WP-T3-19 (environment server exists), WP-T3-32 stage 2 (toolchain + floors), WP-T3-25 (console-web assets), WP-PKG-13 (`fabric-dist` guards live), WP-RN-07 (resolver/train); WP-T3-26 for the desktop artifacts. Unblocks WP-T3-28's bootstrap-download activation (`10-t3code-migration.md:451-453`). - **Size**: L ### WP-PKG-04: `install.sh` / `install.ps1` — channel-aware, checksum-verified, authenticated, versioned layout - **Objective**: Ship the §3.3 installers: dependency-free POSIX + PowerShell scripts installing from `fabric-dist` into `$FABRIC_HOME/runtime/versions/<v>` with symlinked entry point, channel/version/mirror/auth env-var surface (`FABRIC_CHANNEL|VERSION|DIST_BASE_URL|DIST_TOKEN|HOME`), t3code's safety rails and UX — and first-boot provisioning of the default run signing key and attestation keys (§3.3), so the installed platform satisfies WP-FN-02 AC4 and WP-FN-03 AC2 (spec 20) out of the box: signing and attested by default, no opt-in. - **Affected paths**: new `scripts/install/install.sh` + `scripts/install/install.ps1` (adapted hard-forks of `t3:scripts/install.sh` (227 lines) / `t3:scripts/install.ps1` (224 lines)); new `scripts/install/install.test.ts` (per `t3:scripts/install.test.ts` precedent); `apps/environment` `keys init` CLI surface (the idempotent generator the installers invoke, §3.3 — key formats per WP-FN-02's trust-core run-key configuration in `packages/babysitter-sdk/src/config/` and WP-FN-03's proxy/model attestation key seams, spec 20); hosting of the scripts at the fabric-operated install URL; `docs/user-guide/getting-started/installation.md` private-install rewrite (coordinated with WP-RN-13, which owns the docs sweep — spec 15 WP-RN-13 affected paths already name `installation.md:126-131`). - **Acceptance criteria**: (1) on clean Linux/macOS/Windows machines with only a `FABRIC_DIST_TOKEN`, the one-line install produces a working `environment-server --version` via the symlink, with layout exactly `$FABRIC_HOME/runtime/versions/<v>` + `.install-complete` marker; (2) checksum verification: a tampered archive aborts before the atomic move (negative test); (3) channel rails: `FABRIC_CHANNEL=stable` can never resolve a `-staging.`/`-develop.` prerelease; an unrequested channel is refused (fixture tests mirroring `install.sh:145-174` behavior); (4) `FABRIC_VERSION` exact-pin installs that version; `FABRIC_DIST_BASE_URL` mirror override honored; (5) auth chain order (token → gcloud ADC → documented failure) proven by matrix test; (6) re-running the installer over an existing install is idempotent and atomic (staging-dir + move semantics); (7) PATH hint printed when `~/.local/bin` is not on PATH; (8) **default key provisioning (WP-FN-02 AC4 / WP-FN-03 AC2, spec 20)**: a fresh install generates the run signing key and the attestation keys (proxy attestation + model-decision signing) into `$FABRIC_HOME/keys/` with 0700/0600 permissions via the idempotent `keys init` step (§3.3); the first run on a fresh install produces a trust-core-signed journal (WP-FN-02 AC1 envelope present) and journals **neither** the `journal-signing-disabled` nor the `attestation-disabled` loud marker (WP-FN-02 AC3 / WP-FN-03 AC1) — proving the shipped default is the covered posture; re-running the installer over an existing `$FABRIC_HOME` never regenerates or overwrites existing keys (idempotence fixture asserts byte-identical key files). - **Test requirements**: installer test suite in CI against a staged `fabric-dist` fixture (token-authenticated local mock acceptable for PR CI; real AR in the release lane); key-provisioning assertions in that suite (fresh vs pre-populated `$FABRIC_HOME`, permission bits, signed-first-run smoke); WP-TEST-04 uses this installer as step 1 of the whole-platform e2e and asserts the signed-by-default posture. - **Dependencies**: WP-PKG-03 (artifacts exist), WP-PKG-11 (channel vocabulary final); WP-FN-02/WP-FN-03 (spec 20 — they define the key formats, consumers, and posture semantics this provisioning must satisfy; their ACs cross-reference this WP as "spec 40 P-04"). - **Size**: M ### WP-PKG-05: Background service — systemd-user + linger, launchd; reconciling `service install`; Windows out of service scope - **Objective**: `environment-server service install|status|restart|uninstall` per §3.4: reconciler semantics with downgrade guard, diagnostic problem codes with repair guidance, launchd LaunchAgent + systemd user unit with lingering; Windows returns the typed unsupported-platform guidance (desktop app or foreground — scope delta SD-PKG-1, §1.6); service start refuses to run key-less by default, guarding the WP-FN-02/WP-FN-03 covered posture (§3.3 keys). - **Affected paths**: `apps/environment/src/cli/service.ts` + platform backends (adapted from `t3:apps/server/src/cli/service.ts:38-63` and the backend split described in `t3:docs/user/background-service.md:45-54`); service unit/plist templates (fabric identifiers, e.g. LaunchAgent label under a neutral reverse-DNS consistent with spec 15 §3.6's `.internal` posture); `docs/user-guide/` background-service page (incl. the Windows stance record, §3.4). - **Acceptance criteria**: (1) on Linux: `service install` enables lingering, installs the user unit, starts it, and `service status` reports healthy; disabling linger yields problem code `linger-disabled` with repair text (fault-injection test); (2) on macOS: LaunchAgent installed/loaded, survives logout-login (the linger-equivalent check); (3) reconciler proven: `service install` from an older binary refuses (downgrade guard) unless `--allow-downgrade`; from a newer binary it updates the service in place (`service.ts:38-63` semantics); (4) `service uninstall` removes unit/agent and leaves user data intact; (5) on Windows: `service install` exits non-zero with the typed unsupported message naming the two alternatives (test); (6) the service runs the versioned layout's launcher path, not a bare copy (layout integration with WP-PKG-04); (7) **key-presence refusal (WP-FN-02 AC4 / WP-FN-03 AC2, spec 20)**: on service start, missing or unreadable `$FABRIC_HOME/keys/` material (the WP-PKG-04 AC8 provisioned set) is a **refusal** — the service exits before binding, `service status` reports the new problem code `keys-missing` with repair guidance (`environment-server keys init`, or re-run the installer), and the service never silently starts in the unsigned/unattested posture (fault-injection test: delete the keys dir, assert refusal + problem code). The only escape is the operator's *explicit* unsigned/unattested configuration, in which case start proceeds and the run journals the loud `journal-signing-disabled` / `attestation-disabled` markers exactly per WP-FN-02 AC3 / WP-FN-03 AC1 (opt-out path test asserts the markers) — the refusal guards the shipped default; it does not remove the documented explicit posture. - **Test requirements**: per-OS service lifecycle suite in the release lane (containerized systemd for Linux; macOS runner for launchd); problem-code fault-injection matrix per `background-service.md:83-88` codes plus the fabric-added `keys-missing` code (AC7); explicit-opt-out marker assertion shared with WP-FN-02/03's posture matrix (spec 20). - **Dependencies**: WP-PKG-03, WP-PKG-04 (key provisioning it refuses without); WP-T3-19 (the server being serviced); WP-FN-02/WP-FN-03 (spec 20 — posture semantics and loud-marker contracts). - **Size**: M ### WP-PKG-06: Self-update — launcher-owned two-phase commit with SQLite snapshot rollback - **Objective**: Implement §3.5: stable launcher owning durable service state; `environment-server update` with channel switching, exact pinning, restart consent, downgrade guard; trial-activate-commit update flow with SQLite main/WAL/shm snapshot rollback; desktop-managed vs boot-service capability negotiation; desktop auto-update manifests consumed by console-desktop. - **Affected paths**: new `apps/environment/src/launcher/` (adapted hard-fork of `t3:apps/server/src/serviceLauncher.ts`); update orchestration activating the `cloud/selfUpdate.ts` module landed by WP-T3-19 (`t3:apps/server/src/cloud/selfUpdate.ts:40-47`; spec 10 row 12, `10-t3code-migration.md:46`); `update` CLI command; snapshot/restore machinery beside the environment's SQLite store (`10-t3code-migration.md:380-381` — the WP-T3-19 event store); console-desktop update consumption of the §3.7 manifests. - **Acceptance criteria**: (1) happy path: `update` on a service install downloads the exact target version from `fabric-dist`, trial-starts it (migrations complete, HTTP bound, parked at the activation gate), commits durably, goes live; the old version remains on disk in the versioned layout; (2) rollback: a trial that fails migrations or times out rolls back automatically, and the SQLite main/WAL/shm snapshot restores byte-identical pre-trial state (checksummed fixture test per `server-updates.md:33-43`); a restore marker survives a simulated crash mid-restore; (3) the launcher is the only writer of service definitions: a child attempting to rewrite service state is rejected over IPC (unit test of the `server-updates.md:3-8` invariant); (4) restart consent: with a live run in progress, `update` prompts (or defers under `--no-restart`) before restarting (`background-service.md:23-36` semantics); (5) downgrade refused without `--allow-downgrade`; channel switch `update --channel staging` moves the install to the staging train; (6) desktop capability: a desktop-managed environment reports `desktop-managed` and defers restart authority to the desktop app (capability-negotiation test per `selfUpdate.ts:40-47`). - **Test requirements**: update state-machine unit suite (all trial outcomes); crash-injection restore test; end-to-end update between two real published staging train versions in the release lane. - **Dependencies**: WP-PKG-03, WP-PKG-05; WP-T3-19 (selfUpdate module + SQLite store); WP-T3-26 for the desktop-managed path. - **Size**: L ### WP-PKG-07: npm platform packages + launcher — npm bytes equal archive bytes (private) - **Objective**: Per §2.4: `@fabricstack/environment` becomes the thin launcher with per-platform `optionalDependencies` packages holding the archive contents verbatim, published from tarballs to AR; `npx @fabricstack/environment` is the documented zero-install trial for authenticated consumers. - **Affected paths**: new `scripts/build-npm-platform-packages/` (adapted hard-fork of `t3:scripts/build-npm-platform-packages.ts:2-21`, tarball publication per `:16-21`, exec dispatch per `:184`); `apps/environment/package.json` (launcher shape: bin `environment-server`, optionalDependencies on the six platform packages); the private publish workflow (platform packages join the wave publication after the archive build); spec 15 §3 matrix amendment record for the `@fabricstack/environment-<platformKey>` names (Gate-B item, §2.4 — this WP does not start until the amendment is locked). - **Acceptance criteria**: (1) byte-equality: the files inside `@fabricstack/environment-linux-x64` match the `linux-x64` archive of the same train (checksum comparison in the release lane); (2) on a machine with Node ≥22.16, configured `.npmrc` scope routing and AR auth, `npx @fabricstack/environment --version` (or the documented two-step equivalent) runs the platform binary; `npm i -g @fabricstack/environment` installs the working `environment-server` bin; (3) publication uses tarballs so the flattened `node_modules` survives npm (verifier unpacks and asserts); (4) the launcher exits with a targeted error naming supported platforms when no platform package matched; (5) all six platform packages carry G1 `publishConfig.registry` pinning and pass G6's scope check (spec 15 §4.3); the publishable-inventory selector counts them (selector update per G1's criterion, `scripts/lib/publishable-packages.cjs:136-137`). - **Test requirements**: byte-equality gate in the release lane; published-consumer validation job pattern (`publish-packages-from-tag.yml:20-27`) extended to the launcher; per-platform npx smoke on the CI matrix. - **Dependencies**: WP-PKG-03 (archives are the byte source), WP-RN-03/04/07 (registry, guards, train); Gate-B name-lock amendment for platform-package names. - **Size**: M ### WP-PKG-08: Uninstall story + no-public-channel decision record - **Objective**: `environment-server uninstall` removes service, launcher symlink, and downloaded versions while keeping user data (`~/.fabric` run/journal state preserved), mirroring `t3 uninstall` (`t3:docs/user/background-service.md:38-41`); the §1.5 decision dropping public OS package managers (winget/brew/AUR/deb — the t3code matrix at `t3:docs/user/install.md:61-67` and AUR automation `t3:packaging/aur/t3code-bin/PKGBUILD:3-9` + `t3:.github/workflows/publish-aur.yml:5-17` are **not** adapted) is recorded as a packaging decision with its D19 rationale. - **Affected paths**: `apps/environment/src/cli/uninstall.ts`; installer docs page ("Uninstalling" section); `docs/PACKAGING-DECISIONS.md` (new: the no-public-channel record, the §1.3 artifact-home table incl. the relay row, the §3.4 Windows stance recorded verbatim as scope delta SD-PKG-1 (§1.6), and the §3.2 signature deferral — the single place packaging decisions live). - **Acceptance criteria**: (1) after `uninstall` on a machine with a service install: no service unit/agent remains, no symlink, `$FABRIC_HOME/runtime/` removed, `$FABRIC_HOME`'s data directories (runs/journal/profiles per spec 15 §3.5, and `keys/` per WP-PKG-04 AC8 — a reinstall must sign with the same identity) intact — asserted by fixture comparison; (2) `uninstall` is safe to run twice (idempotent); (3) the decision record exists, states that no `@fabricstack/*` artifact ships via winget/brew/AUR/deb/public GitHub Releases/ghcr/npmjs, carries the SD-PKG-1 scope-delta entry (§1.6) with its rationale and revisit condition, and is cross-linked from the Gate-B compliance matrix (WP-R-03 in spec 50's planned inventory); (4) repo-wide grep confirms no AUR/winget/brew publication automation was introduced. - **Test requirements**: uninstall lifecycle test in the per-OS service suite (extends WP-PKG-05's lane); docs-quality gate on the decision record. - **Dependencies**: WP-PKG-04, WP-PKG-05, WP-PKG-06. - **Size**: S ### WP-PKG-09: Helm chart productization — version-with-platform, OCI publication, one bundle - **Objective**: Execute §4.1–4.2: chart re-versioned per train (unfreezing `0.1.0`, `packages/kradle/charts/Chart.yaml:1-7`), renamed with WP-RN-12 in the same consumer break, atlas-webui overlay folded in as conditional `catalog-webui` templates, image references platform-version-tagged, chart published per train to `oci://us-central1-docker.pkg.dev/boot-464019/fabric-charts` with channel co-tags, render/install gates in the verifier lane. - **Affected paths**: `packages/kradle/charts/` (post-RN-10 home per spec 15 WP-RN-12; `Chart.yaml`, `values.yaml` (617 lines), new `templates/catalog-webui/*` replacing the Kustomize overlay consumed at `publish.yml:740-742`); the private publish workflow (chart package/push job, version stamped from `scripts/release-version.cjs`); `fabric-charts` AR repo provisioning; image tag co-tagging in the build jobs (`publish.yml:812-816,880-893`); deletion of the inert nested workflow (`packages/kradle/core/.github/workflows/publish.yml`, PG2). - **Acceptance criteria**: (1) a staging train publishes chart `control-plane` at the train version to AR OCI; `helm show chart oci://…/control-plane --version <v>` returns matching `version`/`appVersion`; (2) `helm install` of the published chart (no source checkout) on a clean minikube brings up the platform including catalog-webui when enabled — replacing the source-path flow documented at `packages/kradle/charts/README.md:30-56`; (3) the atlas-webui Kustomize overlay step is deleted from CI, with catalog-webui served from the chart in all three GKE environments; (4) default image references resolve to platform-version tags in the private AR Docker repo (rendered-values golden test); (5) chart render + install dry-run gate wired into the verifier lane and red on a template error (negative fixture); (6) vendored subcharts still install with no external chart-repo fetch (air-gap render test); (7) lands in the same train as WP-RN-12 (one chart-consumer break — tag audit). - **Test requirements**: chart render golden tests; clean-minikube install e2e; three-environment GKE deploy green post-cutover (`publish.yml:1131` smoke per environment). - **Dependencies**: WP-RN-07 (train), WP-RN-12 (same-train rename partner), WP-PKG-13 (`fabric-charts` + PG guards), WP-PKG-11 (channel co-tags). - **Size**: L ### WP-PKG-10: Operator alignment — consume published artifacts, decouple from CI flags and repo paths - **Objective**: `@fabricstack/operator` (spec 15 §3.1 row 43) installs/upgrades from the **published** OCI chart by version/channel, owns CRD upgrade applies (productizing `publish.yml:955`) and the Envoy install phase (§4.2), keeps its Terraform/target surface (`minikube|existing|eks|aks|gke`, `packages/kradle/installer/src/types.ts:3`; GKE module `src/terraform/root.ts:115-193`), and drops CI-variable coupling; the company's own CD becomes its first consumer. - **Affected paths**: `packages/kradle/installer/` (post-RN home `packages/control-plane/operator`): chart source resolution switched from repo path (`buildKradleHelmPlan`/`renderHelmValuesYaml`, `src/index.ts:4-6`) to OCI ref + resolver-derived version; new CRD-lifecycle phase (server-side apply of the published chart's `crds/`); new Envoy phase (renders/applies the gateway Kustomize the chart deliberately excludes, `Chart.yaml:31-34`); config surface renamed `A5C_CLOUD_*`→`FABRIC_*` (spec 15 §3.4; today's gating at `publish.yml:1285-1357,1316-1321`); `deploy_kradle` (`publish.yml:792-1130`) retargeted to run `operator install --env <env>` against the published chart (dogfooding, §4.3). - **Acceptance criteria**: (1) on a clean workstation with only AR reader credentials and the operator installed from AR npm, `operator install --target minikube` deploys the full bundle — chart + CRDs + Envoy — with zero fabric source checkout; (2) `operator upgrade` against a cluster running train N installs train N+1 including CRD changes (server-side apply proven by a CRD-schema-change fixture between two staging trains); (3) grep: zero repo-path chart references and zero `A5C_CLOUD_*` reads remain in the operator; (4) CI's three GKE environments deploy via the operator consuming published artifacts (pipeline diff shows `helm upgrade --install … packages/kradle/charts` at `publish.yml:1080` replaced); (5) `operator status` reports chart version, app version, and channel for a deployed environment. - **Test requirements**: operator install e2e on minikube in CI; upgrade-with-CRD-change fixture test; deployed-stack smoke (`publish.yml:1131`) green in all three environments after the CD retarget. - **Dependencies**: WP-PKG-09; WP-RN-05 (operator's renamed package identity). - **Size**: L ### WP-PKG-11: Channel/train semantics unified across all artifact classes - **Objective**: Implement §5: one channel vocabulary (`stable`/`staging`/`dev`) mapped onto the existing branch/dist-tag scheme across npm dist-tags, `fabric-dist` archive channels, desktop manifests, and chart OCI co-tags; exact-commit stable promotion enforced; concurrency separation between dev and staging/stable publication. - **Affected paths**: `scripts/lib/release-version.cjs:44-46` (channel alias layer — branch mapping unchanged, user-facing names added); the private publish workflow (promotion job: `stable` release verifies its commit equals a published `fabric/staging/v*` tag's commit and refuses otherwise; concurrency groups per `t3:.github/workflows/release.yml:29-37` pattern); `fabric-dist` channel index objects the installers resolve (per-train listing enabling the `install.sh:145-160` rails); chart co-tag push step. - **Acceptance criteria**: (1) a `stable` release attempt from a commit never published to `staging` fails with a targeted error (negative test using a scratch commit); the passing path records the promoted staging version in the release notes metadata; (2) for one full train, the same version string is resolvable by channel across all four artifact classes (npm dist-tag, archive channel index, desktop manifest, chart co-tag) — cross-class consistency test; (3) `FABRIC_CHANNEL=stable` installs can never resolve commit-pinned prereleases (rail test shared with WP-PKG-04 AC3); (4) a dev-channel publication running concurrently with a staging release neither blocks nor corrupts it (concurrency-group test); (5) `docs/VERSIONING.md` (WP-PKG-02) gains the channel table and the no-nightly-cron rationale verbatim from §5. - **Test requirements**: promotion-guard negative test in CI; cross-class channel consistency check in the release lane; resolver unit tests over the alias layer (sha-suffix comparison rules untouched, `release-version.cjs:162-170`). - **Dependencies**: WP-RN-07 (retargeted resolver/train is the substrate); feeds WP-PKG-03/04/09. - **Size**: M ### WP-PKG-12: Third-party license/attribution machinery (D15) - **Objective**: Extend WP-T3-01's attribution machinery (spec 10, `10-t3code-migration.md:73,234-240`) to the packaging-adopted units: installer scripts, service/launcher/self-update code, archive/npm-platform-package build scripts, and update-manifest tooling adapted from t3code (MIT, T3 Tools Inc., 2026 — `00-intent.md:35`; R3 spec input 10) all carry attribution; every shipped artifact class embeds the third-party notices. - **Affected paths**: the license config + sync script adopted by WP-T3-01 (extended with the packaging units: `scripts/install/*`, `scripts/build-archives/*`, `scripts/build-npm-platform-packages/*`, `apps/environment/src/launcher/*`, `apps/environment/src/cli/{service,uninstall}.ts`); `THIRD-PARTY-NOTICES` embedding: archives ship it at root, npm platform packages include it, installers print a pointer, the chart ships it in the OCI package. - **Acceptance criteria**: (1) the license sync check fails when a file adapted from `t3:scripts/*` or `t3:apps/server/src/{serviceLauncher.ts,cloud/*,cli/service.ts}` lacks its attribution entry (negative fixture); (2) every Form 1 archive and every npm platform package of a train contains the notices file (verifier assertion); (3) the notices name t3code's MIT license and T3 Tools Inc. copyright for each adapted unit, enumerated file-by-file; (4) chart OCI package carries the notices (unpack assertion in the chart gate). - **Test requirements**: license-sync CI check with negative fixture; packed-artifact and archive verifier assertions. - **Dependencies**: WP-T3-01 (the machinery exists); touches WP-PKG-03/04/05/06/07/09 outputs as they land. - **Size**: S ### WP-PKG-13: Private artifact channels — provisioning + publish-isolation extension (PG1–PG5) - **Objective**: Provision the two new AR repos (`fabric-dist` generic, `fabric-charts` OCI/Docker) in `boot-464019`/`us-central1` with WIF-writer for CI and reader-by-default for humans (mirroring spec 15 §4.1's npm IAM posture); implement guards PG1–PG5 (§6) so no packaging artifact can ever ship to a public endpoint; delete the inert ghcr-push workflow. - **Affected paths**: GCP project `boot-464019` (two AR repos + IAM bindings); the WP-RN-04 CI enforcement job (`ci.yml` guard job extended with PG1/PG3/PG5 assertions + negative fixtures); `packages/kradle/core/.github/workflows/publish.yml` (deleted — PG2; its only live-relevant line was the never-executing `helm push … oci://ghcr.io/…` at `:94`); `docs/PACKAGING-DECISIONS.md` (artifact-home table §1.3 recorded); repo secret audit note (PG5). - **Acceptance criteria**: (1) authenticated upload+download smoke against both new repos from CI via WIF and from a developer machine following only the written doc (mirroring spec 15 WP-RN-03 AC2); (2) PG1: a fixture workflow snippet pushing to ghcr/npmjs/public releases trips the guard (red-until-green demonstrated); (3) PG2: the nested workflow file is gone and the guard fails if any `.github/workflows/**` file reappears under a package directory with publish verbs; (4) PG3: shipped installer scripts contain only `pkg.dev`/`FABRIC_DIST_BASE_URL`-derived endpoints (static assertion in the installer test suite); (5) PG5: secret audit recorded — no ghcr/npmjs/public-release credential exists in fabric repo secrets; a CI assertion fails on any workflow consuming such a secret name; (6) IAM review recorded: CI SA writer on both repos, humans reader-by-default. - **Test requirements**: guard job negative-fixture suite (one per PG); provisioning smoke as a workflow-dispatch job; secret-scan over workflow files. - **Dependencies**: WP-RN-03 (project/WIF/npm-repo precedent), WP-RN-04 (the guard job this extends). First mover for this spec: WP-PKG-03/07/09/14 depend on it. - **Size**: M ### WP-PKG-14: Relay artifact class & production rollout — deploy pipeline, channel promotion, runbook execution, guard coverage - **Objective**: Own the hosted relay's path to production — the hand-off WP-T3-31 documents "(Worker + Postgres + cloudflared) … for spec 40/50 consumption" (`10-t3code-migration.md:476`) and WP-FN-16 FR-7 requires carried by specs 40/50 (`20-functionality-coverage.md:111`): a repeatable, train-versioned deploy pipeline for the Cloudflare Worker + managed Postgres + cloudflared stack, per-channel environment promotion under §5 discipline, executed deploy/rollback runbook procedures, and publish-guard coverage so relay deployment can never leak onto a public distribution surface. - **Affected paths**: `infra/relay/` deploy tooling (per-environment wrangler configuration; invocation of the `@effect/sql-pg`/drizzle migration runner — relay sources per WP-T3-31, `10-t3code-migration.md:476`); the private publish workflow (spec 15 §4.2 — new relay deploy jobs for `dev`/`staging`/`prod` in their own §5 concurrency group); Cloudflare account + managed-Postgres provisioning records and credential setup (Worker-scoped deploy token; migration-role DB credential; PG5-pattern secret-audit entries); `docs/remote-access-runbook.md` deployment/rollback sections (runbook ownership stays with WP-FN-16 — this WP writes and executes its deploy/rollback procedures); the WP-RN-04 CI enforcement job (PG1 extension for relay deploy targets); `docs/PACKAGING-DECISIONS.md` (the §1.3 relay-home row recorded). - **Acceptance criteria**: (1) **channel promotion**: relay deploys are train-versioned and channel-mapped per §5 — `dev` and `staging` relay environments deploy from their trains, and the production relay only ever deploys a build whose exact commit a staging relay already ran (the §5 exact-commit promotion rule applied to the relay class; negative test: a prod deploy attempt from a commit never deployed to staging is refused with a targeted error); (2) **staging is the proving ground**: the staging relay deployment that WP-T3-31 AC1's broker e2e and WP-FN-16 AC7's runbook execution run against is produced by this pipeline (workflow-dispatch or train publication), not hand-rolled — asserted by deploy-provenance metadata (train tag + commit) on the staging Worker; (3) **migrations gated**: Postgres schema migrations run as an explicit, logged pipeline step; the migration up/down fixture passes in staging before any prod promotion (pipeline ordering asserted); (4) **rollback proven**: following the runbook's rollback procedure restores the previous Worker version + compatible schema — demonstrated in staging by fault injection (deploy a known-bad build, roll back, WP-T3-31's broker e2e green again); (5) **guard coverage (PG1 extension)**: the WP-RN-04 guard job asserts relay deploy jobs target only the fabric-controlled Cloudflare account (account-id allowlist) and that no workflow publishes the Worker or any relay artifact to a public marketplace/registry endpoint — a deliberately-bad fixture snippet trips it (red-until-green demonstrated, same discipline as WP-PKG-13 AC2); (6) **credential posture (PG5 pattern)**: the Cloudflare deploy token is scoped to the relay Worker and the DB credential to the migration role; both are recorded in the PG5 secret audit and a CI assertion fails if any non-relay workflow consumes them; (7) **environment-side channel consistency**: the cloudflared managed-tunnel/relay endpoints that environments consume (WP-T3-31's `apps/environment/src/cloud/` activation) resolve per channel from the same §5 vocabulary — the WP-PKG-11 AC2 cross-class consistency check is extended to cover relay endpoints as a fifth class; (8) **steady-state observability**: the production relay emits a minimum production signal set — Worker error rate, bootstrap-grant failure count, cloudflared managed-tunnel liveness, and managed-Postgres disk-utilization + connection-count — each wired to an alert routed to the fabric on-call channel with a documented threshold in the runbook's observability section; a synthetic fault (forced bootstrap-grant failure and a stopped tunnel in staging) fires the corresponding alert (fault-injection test), so the production rollout ships with alerting, not just deploy/rollback tooling. - **Test requirements**: post-deploy staging smoke reusing WP-T3-31's broker e2e as the gate; migration up/down fixture; staged rollback fault-injection drill (AC4); PG1-extension negative fixture in the guard suite; the WP-FN-16 AC7 runbook execution consumes this pipeline's staging deployment (cross-spec, asserted there). - **Dependencies**: staged per the roadmap's stage split (spec 50 §3 note 5) — **stage 1** (deploy pipeline): WP-T3-31 (relay code + documented ops story exist); **stage 2** (production rollout): WP-PKG-11 (channel vocabulary + exact-commit promotion rule), WP-PKG-13 (guard-job framework + PG discipline). Consumed by WP-FN-16 (FR-7 acceptance runs against this WP's staging/prod deployments). - **Size**: M --- ## 8. Cross-spec obligations honored (D21 checklist) - **Spec 15 §7 row for this spec, satisfied**: P-01 (→WP-PKG-01) lands with RN-1 in one major bump; P-07 (→WP-PKG-07) publishes to AR only; P-09/P-13 (→WP-PKG-09/13) inherit §3.6 chart names and the §4.2 artifact-home decision; no packaging WP creates a public-npm — or any public — channel for `@fabricstack/*` (§6 extends the guard set beyond npm). - **Spec 10 hand-offs consumed**: row 12's install/service/self-update landing (WP-PKG-03…08); WP-T3-26's desktop artifacts productized (§3.7); WP-T3-28's bootstrap-download unblocked by WP-PKG-03; WP-T3-32's Node floors encoded (§1.4); WP-T3-31's relay ops story (Worker + Postgres + cloudflared, documented "for spec 40/50 consumption") productized as WP-PKG-14. - **Spec 20 hand-offs consumed**: WP-FN-02 AC4 and WP-FN-03 AC2's default key provisioning ("spec 40 P-04") now has its concrete owner — WP-PKG-04 AC8 (first-boot generation into `$FABRIC_HOME/keys/`) plus WP-PKG-05 AC7 (service-start refusal without keys, explicit opt-out preserving the WP-FN-02 AC3 / WP-FN-03 AC1 loud markers); WP-FN-16 FR-7's relay packaging/rollout is owned by WP-PKG-14, whose staging/prod deployments FR-7's runbook-execution acceptance runs against. - **Spec 30 (planned)**: WP-TEST-04's whole-platform e2e ("packaged install → create run → dispatch → agent session → journal → UI assertions", D7(b)) consumes WP-PKG-03/04 outputs and installs from Artifact Registry, never npmjs (spec 15 §7 row for spec 30). - **Spec 50 (planned)**: sequencing input — WP-PKG-13 → {03 → 04 → 05 → 06 → 08, 07} and {09 → 10} after WP-RN-12; WP-PKG-14 after WP-T3-31 + WP-PKG-11/13 (relay rollout cannot precede the relay or the guard/channel substrate); WP-PKG-01/02 ride the RN-1 train; all packaging follows migration + coverage per D11. Scope delta SD-PKG-1 (§1.6) is written for direct citation by WP-RM-03's Gate-B register — no sibling-spec edit required to carry it. - **Public repo untouched** (intent acceptance criterion 7): no WP above modifies `a5c-ai/babysitter` names, publishing, tags, or workflows; PG4 restates it as a standing guard. - **Gate-B items raised by this spec**: (a) launcher alias bin (§3.6, candidate `fabric`); (b) `@fabricstack/environment-<platformKey>` platform-package names (§2.4) — both proposed as spec 15 §3 matrix amendments for the name lock; WP-PKG-07 is gated on (b); (c) scope delta SD-PKG-1 (§1.6, D3 narrowing: no Windows background service in v1) — recorded for the WP-RM-03 Gate-B register. Work-package count in this spec: **14** (WP-PKG-01 … WP-PKG-14).
documents
[]

Outgoing edges

None.

Incoming edges

contains_page1
  • page:docs·PageBabysitter Docs

Related pages

No related wiki pages for this record.

Shortcuts

Open in graph
Browse node kind