II.
Page JSON
Structured · livepage:docs-specs-platform-gaps-research-packaging-state
Packaging state: fabric today vs three target forms json
Inspect the normalized record payload exactly as the atlas UI reads it.
{
"id": "page:docs-specs-platform-gaps-research-packaging-state",
"_kind": "Page",
"_file": "wiki/docs/specs/platform-gaps/research/packaging-state.md",
"_cluster": "wiki",
"attributes": {
"nodeKind": "Page",
"sourcePath": "docs/specs/platform-gaps/research/packaging-state.md",
"sourceKind": "repo-docs",
"title": "Packaging state: fabric today vs three target forms",
"displayName": "Packaging state: fabric today vs three target forms",
"slug": "docs/specs/platform-gaps/research/packaging-state",
"articlePath": "wiki/docs/specs/platform-gaps/research/packaging-state.md",
"article": "\n# Packaging state: fabric today vs three target forms\n\nResearch dossier for the platform-gaps spec effort (intent: `docs/specs/platform-gaps/00-intent.md`, decision D3).\nDate: 2026-09-27. Author: research agent (packaging dossier).\n\nScope per D3 (`docs/specs/platform-gaps/00-intent.md:22`): fabric must ship in **all three** packaging\nforms — (A) single-node installer UX (curl|sh / winget / npx, service, self-update), (B) cluster/Helm\ndistribution (GKE path), (C) npm SDK surface — with priorities proposed by the spec (not by this dossier).\n\nEvidence conventions: fabric paths are relative to `C:/work/fabric`; the t3code reference snapshot is\ncited as `t3code/<path>` and lives at\n`C:/Users/tmusk/AppData/Local/Temp/claude/C--work-company/368e0399-fd11-4960-8b4d-b4dcf1d79c43/scratchpad/t3code`.\nEvery claim below is CONFIRMED (read directly from the cited file) unless listed in the\n\"Inferred findings\" section, which is the exhaustive list of inferences.\n\n---\n\n## Part 1 — Fabric's packaging reality today\n\n### 1.1 Monorepo and npm publish setup\n\n- The repo is an **npm-workspaces** monorepo named `babysitter`, root version **6.0.3**, with ~44\n workspace entries including the genty client apps and mobile/TV/watch shells\n (`package.json:2-50`). A `pnpm-workspace.yaml` also exists at the root listing only the\n `packages/*` and adapters-hooks globs (`pnpm-workspace.yaml:1-15`), but CI installs with\n `npm ci` (`.github/workflows/publish.yml:1312`, `deploy_kradle` step at `publish.yml:896`).\n- The **authoritative publishable inventory** is derived from the root `workspaces` globs by\n `scripts/lib/publishable-packages.cjs:1-36` (every workspace member with `private !== true` and\n `publishConfig.access === \"public\"`). Running it today yields **43 public packages**, all at\n version `6.0.0` in-tree, spanning `@a5c-ai/adapters*`, `@a5c-ai/hooks-adapter-*` (12 harness\n plugins), `@a5c-ai/genty*`, `@a5c-ai/babysitter(-sdk)`, `@a5c-ai/kradle`, `@a5c-ai/kradle-installer`,\n `@a5c-ai/atlas`, `@a5c-ai/trust-core`, etc. (verified by executing the script; count printed 43).\n- **Changesets are configured but dead machinery**: `.changeset/config.json:1-20` exists (with a\n `fixed` group pinning the five adapters packages), and one pending changeset markdown sits in the\n directory (`.changeset/observer-dashboard-replacement.md`), but **no workflow references\n changesets at all** (grep of `.github/workflows` for `changeset` returns nothing). Versioning is\n instead owned by a bespoke, incident-hardened release-version resolver.\n- **Release channels are branch-mapped npm dist-tags**: `main → latest`, `staging → staging`,\n `develop → develop` (`scripts/lib/release-version.cjs:44-46`). Staging/develop releases are\n **commit-pinned prereleases** of the form `<base>-<channel>.<short-sha>`\n (`scripts/lib/release-version.cjs:146-151`), i.e. identity, not order — the resolver has special\n comparison rules because sha-suffixed prereleases do not sort\n (`scripts/lib/release-version.cjs:162-170`).\n- The release integrity machinery is extensive and traceable to a real incident\n (`docs/release-incident-2026-08-13.md`, referenced from `scripts/lib/release-version.cjs:5`):\n - `scripts/release-version.cjs:1-43` — single resolver; subcommands `resolve/verify/from-tag/\n verify-manifests/ensure-tag/tag-source/assert-channel-tags`; never mutates the registry.\n - `.github/workflows/release-tags.yml:1-14` — immutable, idempotent annotated release tags\n (`babysitter/<branch>/v<version>`), created only from the version the publish run resolved.\n - `.github/workflows/publish-packages-from-tag.yml:1-27` — recovery-only tag publication:\n derives version from the tag, refuses double publication, gates on the strict 43-package\n packed-artifact matrix, publishes in dependency-ordered waves under a candidate dist-tag,\n validates from npm via a published-consumer workflow, and only then moves the channel tag.\n - `.github/workflows/release-artifact-verifier.yml:1-16` — \"FIX-011\" full packed-artifact gate:\n build → exact tarball → surface/bin/shebang checks → fresh install without workspace links →\n root and subpath imports → consumer typecheck → bin smoke tests, over the full 43-package matrix.\n - `.github/workflows/fix-npm-tags.yml:1-5` — remediation workflow that retags `latest` when it\n points at a broken publish.\n - `scripts/release-matrix.cjs:1-27` — dependency-ordered publication \"waves\" derived from the\n inventory so workflows never carry hand-maintained package lists.\n- Split-repo publication topology: the checked-out `publish.yml` is the **private mirror\n (a5c-ai/fabric) GKE deploy pipeline**; \"npm publishing, release tags and the docs site stay in the\n public a5c-ai/babysitter repository and are deliberately absent here\"\n (`.github/workflows/publish.yml:3-6`). The tag/recovery/verifier workflows for npm publication\n nevertheless live in this same tree.\n\n### 1.2 Cluster distribution: the kradle Helm chart\n\n- One platform chart exists at `packages/kradle/charts`: `apiVersion: v2`, name `kradle`,\n **`version: 0.1.0`, `appVersion: 0.1.0`** — static, and out of step with the 6.0.x product version\n (`packages/kradle/charts/Chart.yaml:1-7` vs `package.json:3`).\n- Chart contents: 23 templates (deployments, ingress, RBAC, NATS, Gitea + token job, Argo CD\n application surface, external-secrets, network policies, org namespaces, assistant stack —\n `packages/kradle/charts/templates/`), **8 CRD files** under `crds/`\n (`packages/kradle/charts/crds/`), a 617-line `values.yaml`, and three **vendored subchart\n tarballs** (`jitsi-meet-1.5.2.tgz`, `kyverno-3.9.1.tgz`, `vela-core-1.10.9.tgz` in\n `packages/kradle/charts/charts/`). Declared dependencies: vela-core, kyverno, jitsi-meet, each\n behind an install condition; Envoy AI Gateway is deliberately deployed via Kustomize, not as a\n subchart (`packages/kradle/charts/Chart.yaml:17-35`).\n- The chart README positions it as \"the installable package surface for the Kradle\n Kubernetes-native contract\", \"production-shaped but demo-safe\", with a documented local flow\n (`npm run setup:minikube -- --apply`, requiring `minikube`, `kubectl`, `helm`) and a documented\n operator flow `helm upgrade --install kradle charts/kradle -n kradle-system --create-namespace`\n (`packages/kradle/charts/README.md:1-9,30-56`).\n- **The chart is not published anywhere by the active CI.** The only `helm push` in the tree is in a\n **nested** workflow file `packages/kradle/core/.github/workflows/publish.yml:94`\n (`helm push dist/charts/*.tgz oci://ghcr.io/${{ github.repository }}/charts`) — a workflow file\n living inside a package directory, where GitHub Actions never executes it (workflows only run\n from the repository root `.github/workflows`). The root deploy pipeline consumes the chart **from\n the source path**: `helm dependency update packages/kradle/charts`\n (`.github/workflows/publish.yml:952`), CRDs applied out-of-band with\n `kubectl apply -f packages/kradle/charts/crds/ --server-side --force-conflicts`\n (`publish.yml:955`), then `helm upgrade --install kradle packages/kradle/charts ...`\n (`publish.yml:1080`).\n- The \"platform\" is **not one bundle**: the atlas web UI deploys via a separate Kustomize overlay\n piped through `envsubst` (`.github/workflows/publish.yml:740-742`), outside the kradle chart.\n\n### 1.3 The GKE deploy pipeline\n\n- `deploy_kradle` (`.github/workflows/publish.yml:792-1130`) is a branch-driven CD job:\n branch → environment mapping `main→kradle` (kradle.a5c.ai), `staging→kradle-staging`,\n `develop→kradle-develop`, each with its own Secret Manager prefix, runtime GSA suffix, org\n namespace prefix, and same-environment atlas namespace (`publish.yml:852-877`).\n- Mechanics: Workload Identity Federation auth (`google-github-actions/auth@v2`,\n `publish.yml:871-884` region), `gcloud` + `gke-gcloud-auth-plugin`, docker builds pushed to\n Artifact Registry `us-central1-docker.pkg.dev` in GCP project `boot-464019`\n (`publish.yml:3-6,880-893`), images tagged with the checked-out commit sha\n (`publish.yml:812-816`), then the helm-from-source-path upgrade of §1.2. Post-deploy jobs:\n `e2e_smoke_kradle` (`publish.yml:1131`) and a gated live Jitsi E2E `g0_rt_jitsi_e2e`\n (`publish.yml:1230-1234`).\n- A second, config-driven deploy path exists: `deploy_staging_cloud`\n (`publish.yml:1285-1357`) builds `@a5c-ai/kradle-installer` and runs\n `npm run deploy:cloud:staging|prod` (root scripts at `package.json:88-89`), i.e.\n `node ./packages/kradle/installer/dist/cli.js install --env <env>` — driven entirely by\n `A5C_CLOUD_*` repository variables and gated behind `A5C_CLOUD_*_DEPLOY_ENABLED` flags.\n\n### 1.4 The kradle installer package (`@a5c-ai/kradle-installer`)\n\n- Published npm package (in the 43), version 6.0.0, bin `kradle-install`\n (`packages/kradle/installer/package.json:2-33`). Self-description: \"Kradle Kubernetes deployment\n installer — Helm, Terraform, and environment management.\"\n- Its spec frames it as the monorepo's **deployment control plane**: SDK + CLI for install,\n upgrade, auth bootstrap, provider setup and status; Terraform rendering/apply for cluster infra;\n Kubernetes/Helm-style rendering for repo services; CI/CD entrypoints for staging and production\n (`packages/kradle/installer/SPEC.md:1-33`).\n- Target model: `TargetType = \"minikube\" | \"existing\" | \"eks\" | \"aks\" | \"gke\"`\n (`packages/kradle/installer/src/types.ts:3`), with GKE config validation (projectId, region,\n clusterName — `packages/kradle/installer/src/sdk/config.ts:234-243`) and a complete GKE Standard\n Terraform module renderer (`packages/kradle/installer/src/terraform/root.ts:115-193`). It exports\n `renderTerraform` and `buildKradleHelmPlan`/`renderHelmValuesYaml`\n (`packages/kradle/installer/src/index.ts:4-6`).\n- This is a **cluster** installer for operators of the repo's own services; it is not a single-node\n end-user installer and does not touch services, self-update, or OS package managers.\n\n### 1.5 Single-node install story\n\n- The documented install is **npm-global only** and Node-gated: the getting-started guide's \"Quick\n Install\" is `npm install -g @a5c-ai/babysitter@latest @a5c-ai/adapters-cli`\n (`docs/user-guide/getting-started/installation.md:126-131`), with **two install tracks** (host-side\n `adapters` CLI vs in-session per-harness plugin, `installation.md:13-16`). Node.js **>=20** is a\n prerequisite, and the Adapters CLI needs **>=22.13.0** because it loads `node:sqlite`\n (`installation.md:45-49,199-202`).\n- `@a5c-ai/babysitter` is a **metapackage**: bin `babysitter`, depending on babysitter-sdk and the\n four genty runtime packages, pinned `6.0.0` (`packages/babysitter/package.json:2-27`).\n- In-harness plugin install is via harness marketplaces, e.g.\n `claude plugin marketplace add a5c-ai/babysitter-claude@staging` + scope-user install — pinned by\n a live-stack test (`packages/adapters/cli/tests/live-stack/documented-install.test.ts:41-50`);\n non-Claude harnesses use `npx --yes @a5c-ai/babysitter-codex install --workspace ...`\n (`README.md:390`).\n- **What does not exist anywhere in fabric** (searched `packages/` and `scripts/` for\n `self-update|selfUpdate|systemd|launchd|winget`; the only hits are documentation/knowledge-graph\n data files under `packages/atlas/graph/**` and prose in `packages/adapters/gateway/README.md`,\n none of them shipping code):\n - no `install.sh` / `install.ps1`, no `curl | sh` path, no standalone binary or release archive;\n - no checksum-verified download, no per-version installed layout, no channel selection at install;\n - no background service (`service install/status/restart/uninstall`) on any OS;\n - no self-update (`update` command, launcher, rollback) — updates mean re-running `npm install -g`\n (`installation.md` \"Keeping Updated\" section is npm-based);\n - no OS package-manager presence (winget/Homebrew/apt/AUR) and no GitHub-Releases binary flow —\n the root `.github/workflows/` contains no desktop/binary release workflow (directory listing);\n - no uninstaller.\n- A desktop shell exists (`@a5c-ai/genty-desktop-app`, electron + electron-builder) but it is\n `private: true` — never published, and no workflow builds or releases it\n (`packages/genty/desktop-app/package.json:4,10-26`). Per intent D2 the genty shells are slated to\n be retired in favor of adapted t3code apps (`00-intent.md:21`).\n\n### 1.6 npm SDK surface\n\n- `@a5c-ai/babysitter-sdk` ships `main: dist/index.js`, `types`, **five bins**\n (`babysitter-sdk`, `babysitter`, `babysitter-mcp-server`, `adapters-hooks`, `adapters`) and **no\n `exports` map at all** (`packages/babysitter-sdk/package.json:7-14`; programmatic check: exports\n keys = 0). Every module under `dist/` is therefore deep-importable — there is no declared public\n API boundary.\n- `@a5c-ai/adapters` (the adapters SDK) declares an `exports` map with a **single \".\" entry**\n (programmatic check on `packages/adapters/sdk/package.json`: exports keys = 1).\n- Note a bin-name collision by design or accident: both `@a5c-ai/babysitter` (metapackage) and\n `@a5c-ai/babysitter-sdk` declare a `babysitter` bin (`packages/babysitter/package.json:7-9`,\n `packages/babysitter-sdk/package.json:9-14`).\n- Versioning is **lockstep 6.0.x across all 43 packages** with internal dependencies pinned to the\n exact release version and verified (`release-version.cjs verify-manifests`,\n `scripts/release-version.cjs:24-27`); semver therefore encodes the release train, not per-package\n API compatibility. Intent D10 says \"break freely, major bump\" (`00-intent.md:30`), which this\n lockstep scheme can express, but nothing today distinguishes breaking from non-breaking releases\n per package (changesets, the tool that would, is unwired — §1.1).\n- Consumer-quality gates do exist and are strong: the packed-artifact verifier checks root and\n subpath imports, consumer typecheck and bin smoke tests per package\n (`.github/workflows/release-artifact-verifier.yml:5-9`), and docs QA is wired\n (`package.json:116-123`).\n\n---\n\n## Part 2 — The t3code reference machinery\n\nt3code is the packaging reference the intent designates (D3 cites \"t3-style install.sh/ps1, service,\nself-update\"; process brief at `C:/work/company/.a5c/processes/platform-gaps-spec.mjs:377`).\nServer/CLI version at snapshot: `0.0.42` (`t3code/apps/server/package.json:3`).\n\n### 2.1 POSIX/PowerShell installers\n\n- `t3code/scripts/install.sh` (227 lines) is a dependency-free POSIX installer: \"Needs only sh, tar,\n sha256sum or shasum, and curl or wget; no Node, npm, or compiler\"\n (`t3code/scripts/install.sh:1-4`), invoked as `curl -fsSL https://t3.codes/install.sh | sh`\n (`t3code/docs/user/install.md:13-15`).\n- Channel/version model at install time: `T3CODE_CHANNEL` = `stable|nightly|preview` (default\n stable), `T3CODE_VERSION` pins exactly, `T3CODE_RELEASE_BASE_URL` allows mirrors\n (`install.sh:8-16`). Channel resolution greps the GitHub Releases index with a **per-train tag\n pattern**, so a stable install can never accidentally pick a nightly\n (`install.sh:145-160`); un-requested preview builds are refused (`install.sh:163-174`).\n- Artifact handling: downloads `SHA256SUMS` plus `t3-<version>-<platform>-<arch>.tar.gz`, verifies\n the checksum, extracts to a staging dir, **smoke-runs the binary** (`t3 --version`), writes an\n `.install-complete` marker, then atomically moves into place\n (`install.sh:194-215`). A 404 on the checksum asset produces a targeted message pointing at the\n npm fallback for pre-binary releases (`install.sh:196`).\n- Versioned layout shared with the service: archives unpack into\n `$T3CODE_HOME/runtime/versions/<version>` — \"the same layout `t3 service install` uses, so the\n service reuses this download\" (`install.sh:17-19,177`); the user-facing entry point is a symlink\n `~/.local/bin/t3 → versions/<version>/t3` (`install.sh:220-221`), with a PATH hint printed when\n needed (`install.sh:223-226`). UX polish: ANSI branding and a live progress bar on stderr so\n piping to `sh` still shows progress (`install.sh:33-52,88-118`).\n- `t3code/scripts/install.ps1` (224 lines) mirrors this on Windows with the same env vars, layout\n and channel rules (`install.ps1:7-22,130-150`); entry is `irm https://t3.codes/install.ps1 | iex`\n (`t3code/docs/user/install.md:19-21`). The installers themselves are covered by a test\n (`t3code/scripts/install.test.ts`).\n\n### 2.2 Background service and update UX\n\n- Command surface: `t3 service install|status|restart|uninstall`, `t3 update`, `t3 uninstall`\n (`t3code/docs/user/install.md:28-35`, `t3code/docs/user/background-service.md:11-17`).\n- Platform backends: **systemd user services with lingering** on Linux, **launchd LaunchAgent**\n (`com.t3tools.t3code.service.plist`) on macOS; **Windows background services are explicitly not\n supported** (`background-service.md:45-54,90-94`). Status diagnoses concrete problem codes\n (`linger-disabled`, `user-manager-unavailable`, `service-stopped`, `restart-pending`) with repair\n guidance (`background-service.md:83-88`).\n- `t3 service install` is a **reconciler**: `reconcileService` installs, updates or repairs using\n the CLI's own version, refusing silent downgrades unless `--allow-downgrade`\n (`t3code/apps/server/src/cli/service.ts:38-63`). The service downloads release archives itself\n when needed (`service.ts:22-25`).\n- `t3 update` semantics: moves symlink + service to the newest release on the channel, prompts\n before restarting live work, supports exact-version pinning, `--channel nightly` train switching\n and `--allow-downgrade` (`background-service.md:23-36`). `t3 uninstall` removes service, launcher\n and downloaded versions but keeps user data (`background-service.md:38-41`).\n\n### 2.3 Self-update architecture (server)\n\n- A **stable launcher** (`t3code/apps/server/src/serviceLauncher.ts`) owns the runtime selected by\n systemd/launchd and is the only writer of durable service state; server children request updates\n over inherited IPC and never rewrite their own service definition\n (`t3code/docs/internals/server-updates.md:3-8`).\n- Two-phase commit: the launcher durably records the pending update, starts the target as a\n **trial** which must finish migrations, bind HTTP and park at an activation gate before reporting\n `prepared`; only after a durable commit does the child go live; failed/timed-out trials roll back\n (`server-updates.md:17-31`).\n- **Database rollback**: launcher snapshots SQLite main/WAL/shm after stopping the old child, so\n trial migrations are reversible without down-migrations; a durable restore marker survives\n interruptions (`server-updates.md:33-43`).\n- Capability negotiation distinguishes `desktop-managed` vs `boot-service` self-update\n (`t3code/apps/server/src/cloud/selfUpdate.ts:40-47`); exact-version installs keep restarts\n independent of npm cache eviction or moving tags (`server-updates.md:10-14`). Desktop app updates\n use a separate token-based two-phase handoff, with merged update manifests for mac/win generated\n at release time (`server-updates.md:52-57`, `t3code/scripts/merge-update-manifests.ts:19-24`).\n\n### 2.4 Release pipeline and version channels\n\n- One `Release` workflow (`t3code/.github/workflows/release.yml`, 1258 lines) drives everything.\n Triggers: stable tag push `v*` (nightly tags excluded), a **cron every 30 minutes**\n (`8,38 * * * *`) that decides whether a nightly is due, and manual dispatch with a channel input\n (`release.yml:4-27`). Concurrency: separate `nightly` and `stable` queue groups so a nightly can\n never block a stable release (`release.yml:29-37`).\n- **Stable promotes a tested nightly**: \"Manual stable releases build the commit of the latest\n published nightly, so stable only ever ships a build that nightly users have already run\"\n (`release.yml:44-47,88-93`). Three trains — `stable`, `nightly`, `preview` — map to npm dist-tags\n `latest`/`nightly`/`preview`, preview being a maintainers-only pipeline-exercise train that\n nothing resolves by default (`release.yml:148-204`).\n- Job graph: `resolve_commit → preflight (release identity, previous tag) → quality/test/\n test_server → build_bundle → six desktop matrix jobs (mac arm64/x64, linux x64/arm64, win\n x64/arm64) → publish_cli → release (GitHub Release) → publish_aur → deploy_web →\n deploy_marketing → finalize → announce_discord` (`release.yml:48,98,230,264,300,447,539-688,\n 689,753,938,948,1067,1121,1200`).\n- The unit of distribution is a **self-contained per-platform archive**: the `t3` single-executable,\n the web client, the Rust resource monitor, and a production install of the runtime-external\n native packages — \"nothing in it may require Node, npm, or a compiler on the machine that unpacks\n it\" (`t3code/scripts/build-cli-archive.ts:1-16`). Release assets carry `SHA256SUMS` (consumed by\n §2.1). Supporting scripts: `resolve-nightly-release.ts` (nightly version/tag derivation from date\n + run number + sha, `t3code/scripts/resolve-nightly-release.ts:14-30`),\n `resolve-previous-release-tag.ts`, `release-smoke.ts`, `notify-discord-release.ts`,\n `sign-macos.ts` (all under `t3code/scripts/`).\n\n### 2.5 npm distribution built from the same bytes\n\n- `t3code/scripts/build-npm-platform-packages.ts:2-21` converts the per-platform archives of one\n release into the npm story behind `npx t3` / `npm i -g t3`: one `@t3code/t3-<platformKey>`\n package per archive **holding the archive's contents verbatim**, plus a thin `t3` launcher\n package listing them as `optionalDependencies` and exec-ing the one npm installed\n (`build-npm-platform-packages.ts:184`). Publishing uses tarballs, not directories, so npm cannot\n strip the flattened `node_modules` (`build-npm-platform-packages.ts:16-21`). The npm bytes are\n therefore identical to the GitHub Release bytes, and `npx t3@latest` is the documented\n zero-install trial path (`t3code/docs/user/install.md:38-39`).\n\n### 2.6 OS package managers and desktop channels\n\n- Documented matrix: `winget install T3Tools.T3Code` (Windows), `brew install --cask t3-code`\n (macOS), `sudo apt install ./T3-Code-*.deb` (Debian/Ubuntu, self-updating), `yay -S t3code-bin`\n and `t3code-nightly-bin` (Arch) (`t3code/docs/user/install.md:61-67`).\n- AUR publication is automated in-repo: `packaging/aur/` holds two PKGBUILDs (stable + nightly,\n repackaging the `.deb`, `t3code/packaging/aur/t3code-bin/PKGBUILD:3-9`) and a release script;\n `publish-aur.yml` is `workflow_call`ed from the release pipeline with the release tag and pushes\n via `AUR_SSH_PRIVATE_KEY` (`t3code/.github/workflows/publish-aur.yml:5-17,36-39`,\n `release.yml:938`).\n- No winget or Homebrew publication automation exists in the t3code repo (grep for `winget` hits\n only docs; `release-desktop.yml` contains neither) — those manifests are maintained outside the\n repo. Desktop auto-update manifests for mac/win are merged per release\n (`t3code/scripts/merge-update-manifests.ts:19-24`).\n\n---\n\n## Part 3 — Gap map: fabric vs the three D3 target forms\n\n### Form A — single-node installer UX (t3-style)\n\n| Capability (t3code reference) | Fabric today | Gap |\n|---|---|---|\n| `curl\\|sh` / `irm\\|iex` installers, no Node required (`t3code/scripts/install.sh:1-4`, `install.ps1:7-22`) | npm-global install requiring Node >=20 / >=22.13 (`docs/user-guide/getting-started/installation.md:126-131,199-202`) | **Total** — no installer scripts, no binary artifact to install |\n| Self-contained per-platform archive + SHA256SUMS on GitHub Releases (`t3code/scripts/build-cli-archive.ts:1-16`) | 43 npm tarballs only; no binary build, no release-asset workflow in `.github/workflows/` | **Total** — needs a single-executable/bundling story for the server+CLI |\n| Versioned runtime layout `~/.t3/runtime/versions/<v>` shared by installer and service (`install.sh:17-19,177`) | none | **Total** |\n| Background service: systemd user + linger, launchd; reconciling `service install` (`t3code/apps/server/src/cli/service.ts:38-63`, `docs/user/background-service.md:45-54`) | none (no systemd/launchd/service code in any shipping package) | **Total** |\n| Self-update with launcher-owned two-phase commit and SQLite snapshot rollback (`t3code/docs/internals/server-updates.md:17-43`) | none; update = `npm install -g` again | **Total** |\n| Channels at install/update time: stable/nightly/preview with per-train tag patterns (`install.sh:145-160`) | npm dist-tags latest/staging/develop exist (`scripts/lib/release-version.cjs:44-46`) but are npm-only and named after git branches, not user-facing trains | **Partial** — channel *concept* exists; installer-facing train selection, nightly cadence and preview safety rails do not |\n| `npx` zero-install trial via launcher + platform packages (`t3code/scripts/build-npm-platform-packages.ts:2-21`) | `npx` used only for plugin installers (`README.md:390`); metapackage `@a5c-ai/babysitter` is Node-dependent deps, not platform binaries (`packages/babysitter/package.json:20-27`) | **Large** — no platform-package pattern; npm and (future) binary bytes are unrelated |\n| winget / brew / apt / AUR presence, AUR automated (`t3code/docs/user/install.md:61-67`, `t3code/.github/workflows/publish-aur.yml`) | none | **Total** |\n| Uninstall story (`t3 uninstall`, keeps user data) | none | **Total** |\n\n### Form B — cluster/Helm bundle (versioned platform chart)\n\n| Capability | Fabric today | Gap |\n|---|---|---|\n| A platform chart exists | Yes: `packages/kradle/charts` — 23 templates, 8 CRDs, 617-line values, vela/kyverno/jitsi subcharts (`Chart.yaml:17-35`) | Chart exists and is production-shaped |\n| Chart versioned with the product | `version: 0.1.0` static while the platform ships 6.0.x (`Chart.yaml:5-6` vs `package.json:3`); no pipeline step bumps chart version/appVersion | **Chart-release process missing** |\n| Chart published to a registry | No `helm push` in any executing workflow; the only one is in the inert nested `packages/kradle/core/.github/workflows/publish.yml:94` | **Total** — chart consumable only from a source checkout |\n| One installable bundle for the whole platform | Kradle chart + separate atlas-webui Kustomize overlay + Envoy AI Gateway via external Kustomize (`publish.yml:740-742`, `Chart.yaml:31-34`); CRDs applied out-of-band (`publish.yml:955`) | **Partial** — the \"platform\" is three mechanisms, CI-orchestrated, not a bundle a customer can `helm install` |\n| Cluster installer for non-CI operators | `@a5c-ai/kradle-installer`: published CLI/SDK, minikube/existing/EKS/AKS/GKE targets, Terraform + Helm-plan rendering (`src/types.ts:3`, `SPEC.md:16-24`) | Exists; needs alignment with a *published* chart instead of repo paths, and its deploy hooks are CI-flag-gated (`publish.yml:1316-1321`) |\n| GKE path proven | Yes — branch-driven WIF + Artifact Registry + `helm upgrade --install` to prod/staging/develop environments (`publish.yml:792-1080`) | Works, but is the *company's* CD, coupled to project `boot-464019` vars/secrets — not a distributable artifact |\n\n### Form C — npm SDK surface (stable publics, semver, docs)\n\n| Capability | Fabric today | Gap |\n|---|---|---|\n| Publish pipeline integrity | Strong: single version resolver, immutable tags, waves, packed-artifact verifier over all 43 (`scripts/release-version.cjs:1-43`, `release-artifact-verifier.yml:1-16`) | Keep; this exceeds the t3code reference for multi-package publishing |\n| Declared public API boundary | `@a5c-ai/babysitter-sdk` has **no `exports` map** (5 bins, `main` only — `packages/babysitter-sdk/package.json:7-14`); `@a5c-ai/adapters` exports only \".\" | **Large** — no enforced publics; every `dist/` file is API. D6's ACP-canonical re-platforming will land on an unbounded surface unless exports maps come first |\n| Semantic versioning | Lockstep 6.0.x + commit-pinned prereleases (`release-version.cjs:44-46,146-151`); changesets configured but unwired (§1.1) | **Medium** — no per-package semver signal; D10 (break freely, major bump) needs at least a deliberate major-bump mechanism |\n| Package count / consumer ergonomics | 43 packages incl. 12 hooks-adapter plugins; duplicate `babysitter` bin in two packages (§1.6) | **Medium** — surface consolidation and bin-collision resolution are spec material |\n| Docs of the SDK surface | docs-site + docs QA gates exist (`package.json:112-127`); getting-started documents install | Docs exist; publics-reference docs depend on first defining publics |\n\n---\n\n## Inferred findings (everything not directly read from a file)\n\n1. INFERRED: the nested `packages/kradle/core/.github/workflows/publish.yml` never executes in this\n repository's CI, because GitHub Actions only runs workflows from the repo-root\n `.github/workflows` directory. (The file's existence and its `helm push` line are CONFIRMED.)\n2. INFERRED: `pnpm-workspace.yaml` is vestigial/secondary — every observed install step in CI uses\n npm (`npm ci`/`npm install`), and the release inventory is derived from the root `package.json`\n workspaces globs by design (`scripts/lib/publishable-packages.cjs:26-33`).\n3. INFERRED: winget/Homebrew manifests for t3code are maintained outside the t3code repo, since the\n docs advertise the IDs (`t3code/docs/user/install.md:63-64`) but no repo workflow publishes them.\n4. INFERRED: fabric npm publication jobs run in the public a5c-ai/babysitter repository's copy of\n the publish workflow — stated by the private-mirror header (`publish.yml:3-6`), but the public\n repo's workflow file was not inspected here.\n5. INFERRED: the `@a5c-ai/genty-desktop-app` electron shell has never shipped to users (private,\n no release workflow); consistent with D2 retiring genty shells.\n\n## Spec inputs\n\nConcrete facts the `40-packaging.md` spec author must use:\n\n1. **Three forms bind (D3)**: single-node installer UX, cluster/Helm bundle, npm SDK surface; the\n spec proposes priority order (`docs/specs/platform-gaps/00-intent.md:22`); per D11 packaging\n follows the t3code migration and coverage work in the roadmap (`00-intent.md:30`).\n2. **Publishable inventory**: exactly **43 public packages**, derived at run time from root\n workspaces globs via `scripts/lib/publishable-packages.cjs`; any packaging work must derive\n lists from this script, never hand-maintain them (FIX-005, `publishable-packages.cjs:1-10`).\n3. **Version/channel scheme to build on**: `main→latest`, `staging→staging`, `develop→develop`;\n commit-pinned prereleases `<base>-<channel>.<short-sha>`; immutable tags\n `babysitter/<branch>/v<version>`; single resolver `scripts/release-version.cjs` (never bypass\n it). Changesets (`.changeset/config.json`) are present but unwired — the spec must either wire\n or remove them.\n4. **Release gates that already exist and must gate new artifacts too**: packed-artifact verifier\n (43-package matrix, `.github/workflows/release-artifact-verifier.yml`), dependency-wave\n publication (`scripts/release-matrix.cjs --format waves`), published-consumer validation and\n candidate dist-tags (`publish-packages-from-tag.yml:20-27`).\n5. **Single-node target (Form A) starts from zero**: no installer scripts, no binary archive, no\n GitHub-Releases asset flow, no service, no self-update, no OS package managers, no uninstall in\n fabric. Node >=22.13 is currently a hard runtime floor because of `node:sqlite` in\n adapters-gateway (`installation.md:199-202`) — a self-contained executable must bundle that\n runtime.\n6. **Reference blueprint for Form A** (all in the t3code snapshot): `scripts/install.sh` +\n `install.ps1` (channel-aware, checksum-verified, `$HOME/.t3/runtime/versions/<v>` layout,\n symlinked bin, exit-44 asset probing); `t3 service install/status/restart/uninstall` on\n systemd-user+linger and launchd, Windows service explicitly out of scope; `t3 update` with\n downgrade guard and restart consent; launcher-owned two-phase self-update with SQLite\n main/WAL/shm snapshot rollback (`docs/internals/server-updates.md`); self-contained archives\n from `scripts/build-cli-archive.ts`; npm launcher + `@t3code/t3-<platform>` optionalDependencies\n packages from `scripts/build-npm-platform-packages.ts` so npm bytes equal release bytes;\n AUR automation `packaging/aur` + `publish-aur.yml`; three trains stable/nightly/preview where\n stable promotes the tested nightly commit (`release.yml:44-47`) on a 30-minute nightly cron.\n7. **Cluster target (Form B) assets in hand**: chart `packages/kradle/charts` (Chart `version:\n 0.1.0` must be re-versioned with the platform); 8 CRD files applied today out-of-band\n (`publish.yml:955`); vendored subcharts vela-core 1.10.9 / kyverno 3.9.1 / jitsi-meet 1.5.2;\n Envoy AI Gateway deliberately Kustomize-based (`Chart.yaml:31-34`); atlas-webui deploys via a\n separate Kustomize overlay (`publish.yml:740-742`) and must be folded into or federated with the\n bundle; no chart registry publication exists (only inert `helm push` at\n `packages/kradle/core/.github/workflows/publish.yml:94` — ghcr OCI is the precedent to adopt or\n reject); `@a5c-ai/kradle-installer` (bin `kradle-install`, targets\n minikube/existing/eks/aks/gke, Terraform GKE module renderer) is the operator-facing entry point\n to evolve; the working GKE reference deployment is `publish.yml:792-1130` (WIF, Artifact\n Registry `us-central1-docker.pkg.dev`, project `boot-464019`, three branch environments).\n8. **npm SDK target (Form C) blockers**: `@a5c-ai/babysitter-sdk` has **no exports map** and five\n bins including a `babysitter` bin that collides with the metapackage's; `@a5c-ai/adapters`\n exports only \".\"; defining and enforcing exports maps across the 43 packages is prerequisite to\n any \"stable publics\" claim, and interacts directly with D6 (ACP-canonical adapters) and D10\n (break freely, major bump — the major bump should land together with the exports-map cutover).\n9. **Split-repo constraint**: npm publishing lives in public `a5c-ai/babysitter`, GKE CD in private\n `a5c-ai/fabric` (`publish.yml:3-6`); any new artifact channel (GitHub Release binaries, OCI\n charts) must pick a home repo explicitly and keep the single-resolver version discipline.\n10. **License/attribution (D15)**: t3code is MIT (T3 Tools Inc., 2026) — installer/service/update\n code adopted from `t3code/scripts/*` and `t3code/apps/server/src/cloud/*` requires third-party\n attribution work items in the packaging spec (`00-intent.md:34`).\n",
"documents": []
},
"outgoingEdges": [],
"incomingEdges": [
{
"from": "page:docs",
"to": "page:docs-specs-platform-gaps-research-packaging-state",
"kind": "contains_page"
}
]
}