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