363 lines
28 KiB
Markdown
363 lines
28 KiB
Markdown
# Provisioning Repository - Changes
|
||
|
||
---
|
||
|
||
## 2026-06-08 — provisioning-desktop: NATS auto-start + configurable launchers (ADR-049)
|
||
|
||
Refines ADR-048 by extending what the shell does on the local host.
|
||
|
||
**Generalized process supervision**: the daemon supervisor is extracted into a process-agnostic `ProcessSupervisor` driven by a `ProcessSpec` (spawn + health + restart-backoff + graceful SIGTERM→SIGKILL, port pre-check). The daemon (HTTP `/health`) and a local `nats-server` (TCP-connect health) are two specs on one shared path; `DaemonStatus`/`DaemonControl` are kept as aliases so existing code is untouched and the backoff tests are preserved.
|
||
|
||
**NATS auto-start (local-or-remote, like the daemon)**: a local `nats-server` is spawned and supervised **only when `nats.spawn` is set AND `nats.url` is loopback** (`-a <host> -p <port> -js`), started *before* the daemon and awaited (bounded) so the daemon and consumer bridge find it listening. The same port pre-check **adopts** an already-running external server instead of double-spawning. Remote `nats.url` stays connect-only — never spawned. Absent `nats-server` degrades to the REST poller, not a panic.
|
||
|
||
**Configurable launchers** (replaces tray `actions`): a unified `Launcher { kind, label, target, args, params, show_output, confirm }` declared **per-connection and globally**, merged in the tray. `kind=url` opens the OS browser (platform opener); `kind=command` runs a local program host-side via `tokio::process`, capturing stdout/stderr into a reusable bundled output window (`dist/output.html`); `kind=tool` invokes a daemon `/api/v1` tool (the former action). Legacy `[[connections.actions]]` TOML migrates transparently (serde `alias = "actions"`, defaulted `kind=tool`, `tool`→`target` alias).
|
||
|
||
**Security boundary**: command execution is **host-side only** — in the Rust tray handler, sourced from the local `settings.toml`, and deliberately **not** a Tauri command — so the external `/ui/` webview (no invoke) and remote connections cannot trigger host execution. Preserves the ADR-048 host-bridge boundary.
|
||
|
||
**Settings form**: the bundled settings window gains a Launchers editor (scope selector, kind-aware fields, JSON params validation); `save_settings` now carries the `AppHandle` and rebuilds the tray so edits appear immediately.
|
||
|
||
**Verified**: `cargo clippy -p provisioning-desktop --all-targets -- -D warnings` clean; `cargo test -p provisioning-desktop` → 34 passed (incl. legacy `actions`→launcher migration, NATS loopback-spawn gating, host/port parsing).
|
||
|
||
**Also — daemon UI SPA fix** (`provisioning-daemon/ui/templates/base.html`): the SPA router dropped per-page `<head>` `<script src>`/`<link>` on client-side navigation, so Cytoscape never loaded and the workspace DAG view rendered empty **in the desktop webview** (which is SPA-only) while a full browser load worked. `_spaNavigate` now loads a fetched page's `<head>` vendor assets (deduped by resolved URL) before running its inline scripts. Fixes the DAG view and any future `{% block head %}` vendor-lib page (e.g. `ontology.html`).
|
||
|
||
**ADR-049**: `provisioning-desktop local-host surface: generalized process supervision (daemon + NATS) and configurable launchers (url/command/tool)` (Accepted). 3 constraints — 1 `Hard` (`desktop-command-launcher-host-side-only`) + 2 `Soft` on `centralized-vs-scripted` / capability granularity (`desktop-nats-spawn-loopback-only`, `desktop-launchers-config-driven`). `ontology_check.verdict = 'Safe`. Engages `centralized-vs-scripted` (new core.ncl edge, `'Complements`): local affordances beside the orchestrator path, not through it.
|
||
|
||
**Files**: `platform/crates/provisioning-desktop/src/{supervisor,settings,connection,tray,commands,state,window,lib}.rs`, `dist/{output.html,settings.html}`, `capabilities/default.json`; `provisioning-daemon/ui/templates/base.html`; `.ontoref/adrs/adr-049-desktop-local-surface.ncl`, `.ontoref/ontology/core.ncl`.
|
||
|
||
---
|
||
|
||
## 2026-06-08 — provisioning-desktop: Tauri native shell for the daemon
|
||
|
||
### New crate `platform/crates/provisioning-desktop`
|
||
|
||
**Decision**: a Tauri 2 native shell (desktop + iOS) that **wraps the daemon's existing `/ui/` in a webview** rather than reimplementing a native UI — the daemon's web surface stays the single source of UI truth. It is a workspace member but does **not** depend on `provisioning-daemon`: it mirrors the small `DaemonEvent` JSON wire enum locally and reuses only `platform-nats`, so a GUI app never drags in Axum/tera/provisioning-core (also sidesteps the surrealdb rustls lockfile pin).
|
||
|
||
**Live status — durable JetStream consumer + REST fallback**: per-device durable pull consumer (`durable_name = desktop-<id>`, `DeliverPolicy::New` on first create, `RetentionPolicy::Limits` so each device keeps an independent cursor, delete-on-logout) on a new `DAEMON` stream. The stream was added to `platform-nats::ensure_provisioning_streams` (`provisioning.daemon.>`) in the same change — this also **fixed a latent bug** where `EventBus::publish` failed its JetStream ack on every tool invocation (no stream previously covered the subject). NATS-less remotes fall back to polling `GET /api/v1/state/recent` (baseline-on-first-poll mirrors `DeliverPolicy::New`, no notification flood).
|
||
|
||
**Multi-connection profiles**: exactly one supervised-local (spawn + health + restart-backoff + graceful SIGTERM→SIGKILL; port pre-check per ADR-027 to avoid double-spawning a CLI-started daemon) plus N connect-only-remote; live switch tears down tasks and re-points the webview.
|
||
|
||
**Auth + security**: reuses the daemon matrix (`solo`/`jwt`/`password`) — the shell **carries** tokens (keyring JWT, `/ui/` cookie) but never mints or decides them, honoring the ADR-014 auth boundary. **Remote profiles must be `https://`** (loopback exempt — never crosses a network, and aligns with iOS ATS), enforced at save + activate + load-fallback. The external `/ui/` window gets **no** invoke access; only the bundled settings window does.
|
||
|
||
**Tray**: Connections submenu (live switch + rebuild-on-switch), per-connection predefined Actions with `confirm` gating via a native OK/Cancel dialog, Workspaces (informational), daemon Start/Stop/Restart (local only), status tooltip.
|
||
|
||
**iOS-ready**: `[lib] crate-type = ["staticlib", "cdylib", "rlib"]` + thin `[[bin]]`; `run()` carries `#[cfg_attr(mobile, tauri::mobile_entry_point)]`; tray/settings-window are `#[cfg(desktop)]`; local profiles coerce to connect-only-remote on mobile. `cargo tauri ios init` is a local toolchain step (not run here).
|
||
|
||
**Verified**: `cargo clippy -p provisioning-desktop --all-targets -- -D warnings` clean (built on `/Volumes/Devel` target-dir); `cargo test -p provisioning-desktop` → 27 passed.
|
||
|
||
**ADR-048**: `provisioning-desktop: a Tauri native shell wrapping the daemon /ui/, a wire-decoupled workspace member with durable-consumer status` (Accepted). 5 constraints — 3 `Hard` (remote-https-only, external-window-no-invoke, auth-carried-never-minted) + 2 `Soft` on the `monorepo-vs-split` Spiral (wire-decoupled-from-daemon, daemon-stream-durable-per-device, direction-of-motion per ondaod). `ontology_check.verdict = 'Safe`. Sub-decisions folded in as constraints rather than standalone ADRs: lib/bin split is framework-mandated; HTTPS-loopback is localized validation.
|
||
|
||
**Ontology**: core.ncl Practice node `provisioning-desktop-shell` (edges to `smart-interface-unification` [Complements], `monorepo-vs-split` [Resolves], `platform-shared-infra` [ManifestsIn], `solid-boundaries` [ValidatedBy]; `adrs = ["adr-048"]`). State: no FSM transition — a new consumer surface, not an advance of a tracked dimension.
|
||
|
||
**Files**: `platform/crates/provisioning-desktop/` (new crate: api, auth, commands, connection, events, nats_bridge, notify, poller, settings, state, supervisor, tray, window, lib, main + dist/ SPA + tauri.conf.json + capabilities + icons), `platform/crates/platform-nats/src/streams.rs`, `platform/Cargo.toml`, `justfiles/desktop.just`, `.ontoref/ontology/core.ncl`.
|
||
|
||
---
|
||
|
||
## 2026-05-29 — catalog management as a multi-surface capability (ADR-047)
|
||
|
||
### ADR-047: Catalog management dispatched through the shared Registry
|
||
|
||
**Decision**: catalog management operations are provisioning-core Registry Tools dispatched exclusively through `Registry::invoke`, so CLI, WebUI, GraphQL, and MCP share identical semantics (no per-surface reimplementation). Per the nushell-vs-rust boundary synthesis (ADR-029) the Rust Tool owns dispatch while the Nushell resolver (`contract_resolver.nu`) is the tier-3 legacy closure, retired per-operation once G3 contract-test parity passes. 3 Hard constraints: `catalog-management-via-registry`, `catalog-tools-g3-parity`, `catalog-tier3-nushell-closure`.
|
||
|
||
**Implementation — first Tool `catalog_validate`** (read-shaped: evaluate a component manifest against the contract schema via `NclCache`, report its `requires.contract`): `platform/crates/provisioning-core/src/tools/catalog.rs`, registered in `with_all_tools`. **Verified**: `cargo check -p provisioning-core` Finished; G3 parity test `catalog_tool_agrees_across_three_tiers` (CLI≡HTTP≡MCP) green via a `ct_catalog` fixture in `contract-tests`.
|
||
|
||
### Full rename: extension-registry → catalog-registry (no compatibility aliases)
|
||
|
||
Complete cut-over with zero aliases — every `extension-registry`/`extension_registry`/`ExtensionRegistry`/`provisioning-extension-registry` identifier is now `catalog-registry`/`catalog_registry`/`CatalogRegistry`/`provisioning-catalog-registry`.
|
||
|
||
- **Plano A (crate)**: package name, lib name, directory (`git mv` in the `platform` submodule), workspace member, `provisioning-core` path dependency, `use` statements.
|
||
- **Plano B (service identity)**: binary name, `CatalogRegistry` type (service.rs/lib.rs/main.rs/handlers.rs), runtime service-key strings (`is_service_enabled`/`load_service_config_from_ncl`/observability/api_catalog/user-agent), control-center `ServiceType::CatalogRegistry` + `catalog_registry_url` + `check_catalog_registry`, platform-config `CatalogRegistryConfig`, `orchestrator/config_manager`, `core/nulib` health/autostart/startup/service_check/workspace strings, docker-compose service names (multi-user/solo + examples), nginx/prometheus, justfiles, scripts, typedialog forms/scripts.
|
||
- **Files renamed on disk** (12): `api-catalog-catalog-registry.json`, `schemas/platform/catalog-registry.ncl` + `configs/catalog-registry.{solo,multiuser,enterprise,cicd}.ncl` + `defaults/catalog-registry-defaults.ncl` + `templates/catalog-registry-config.ncl.j2`, `platform/templates/catalog-registry.ncl.j2`, `platform/typedialog_templates/catalog-registry.ncl.j2`, `platform/typedialog/forms/catalog-registry-form.toml`, `platform/typedialog/scripts/configure-catalog-registry.sh`.
|
||
|
||
**Verified**: `cargo check -p catalog-registry -p control-center -p platform-config -p orchestrator -p provisioning-core` Finished; `nickel export` clean for `catalog-registry.{solo,cicd}.ncl`, `nickel typecheck` clean for `{multiuser,enterprise}` (their export-time "missing url" is a pre-existing template-completeness issue, not the rename).
|
||
|
||
**Excluded**: `CHANGELOG.md` (historical record), `platform/archive/` (archived), `data/tasks/` (runtime artifacts), one draft SVG diagram label.
|
||
|
||
### Standalone "extension" vocabulary → catalog (Tool API surface)
|
||
|
||
The catalog-discovery Tools are renamed `extension_{list,show,search,capabilities}` → `catalog_{list,show,search,capabilities}` (structs `Catalog{List,Show,Search,Capabilities}`); `tools/extension.rs` → `tools/catalog_components.rs`; daemon UI `invoke_tool` call-sites updated. The `Environment.extensions_root` field → `catalog_root`, and the env var `PROVISIONING_EXTENSIONS_ROOT` → `PROVISIONING_CATALOG_PATH` — unifying the catalog-root identifier across the Nushell (env.nu) and Rust (daemon) boundary, which previously diverged. Touches provisioning-core, provisioning-daemon, provisioning-tool, control-center-ui, backup-manager, platform-config, mcp-server, the daemon NCL schema, and CLI help/workspace tooling. **This changes Tool names on the API surface** (HTTP `/api/v1/tools/catalog_*`, MCP `tools/call`, CLI) — no aliases.
|
||
|
||
**Ontology**: core.ncl Practice node `catalog-management-multi-surface` (edges to `provisioning-registry`, `g3-contract-invariant`, `catalog-contract-distribution`, `nushell-vs-rust-boundary`).
|
||
|
||
**Files**: `adrs/adr-047-catalog-management-multi-surface.ncl`, `platform/crates/provisioning-core/src/tools/catalog.rs`, `platform/crates/provisioning-core/src/{registry.rs,tools/mod.rs}`, `platform/crates/contract-tests/{src/lib.rs,tests/g3_contract.rs}`, `platform/crates/catalog-registry/` (renamed), `platform/Cargo.toml`, `.ontology/core.ncl`
|
||
|
||
---
|
||
|
||
## 2026-05-29 — catalog externalization + content-addressed contract (ADR-046)
|
||
|
||
### Catalog relocation: configurable root, no symlink
|
||
|
||
**Change**: the catalog (providers/components/taskservs/_clusters) no longer must live under `$PROVISIONING/catalog`. A new `PROVISIONING_CATALOG_PATH` env var (→ `paths.catalog` config → `$PROVISIONING/catalog` default) sets the root; all sub-paths derive from it. Resolved in `core/nulib/env.nu`; accessor `get-catalog-path` added; the loose `path join "catalog"` sites (components, clusters/taskservs run, OCI signing, integration) now derive from the root. Lets a catalog live anywhere — importable/downloadable, no provisioning checkout dependency.
|
||
|
||
### ADR-046: Catalog component contract distributed as content-addressed Domain artifact via OCI referrers
|
||
|
||
**Decision**: `schemas/catalog/manifest.ncl` (the component contract) is distributed as a content-addressed OCI Domain artifact, never vendored by copy. A catalog declares `requires.contract = { id, version, subject }` (semver intent); resolution pins it to an immutable `sha256` digest in `catalog.lock.ncl` (`DomainLockEntry` shape), and all automated loading reads the digest. Version→digest discovery uses the OCI Referrers API exclusively — each version is attached as a referrer to a stable anchor digest with an `org.opencontainers.image.version` annotation, so no mutable tags exist in the load path. Reuses the ADR-042 Domain-artifact primitives; component-owned config schemas stay vendored as `'SchemaLibrary`.
|
||
|
||
**Implementation**: `requires.contract` field + `ContractRef` type in `schemas/catalog/manifest.ncl`; resolver `core/nulib/platform/oci/contract_resolver.nu` (real semver matching incl. `^`/`~`/comma ranges, referrers discovery, pull-by-digest, lock writing, anchor + per-version attach publishing) reusing `domain_client.nu` credential machinery; validation wiring (`read-contract-decl`, `validate-manifest-against-contract`). Automated process: `core/nulib/platform/oci/contract_cli.nu` + `justfiles/catalog-contract.just` (recipes `contract-publish-anchor`/`-version`/`-resolve`/`-validate`).
|
||
|
||
**Verification**: full round-trip proven end-to-end against a local zot (referrers) — publish anchor → attach v1.0.0+v1.1.0 → discover → resolver selects 1.1.0 for `>=1.0.0, <2.0.0` → pull-by-digest → pulled `contract.ncl` typechecks → `catalog.lock.ncl` validates against `DomainLockEntry`. Production publish targets `reg.librecloud.online` (private — unreachable from dev sandbox).
|
||
|
||
### ADR-046 extension: push-registry as a pluggable-source platform setting
|
||
|
||
**Decision**: the OCI push-registry target is a platform setting, not a property of the active workspace. A command resolves endpoint + credentials at call time from a pluggable source — `sops | api | literal | env` — and materialises them as an env setting (`PROVISIONING_REGISTRY` + `PROVISIONING_PUSH_DOCKER_CONFIG`) that the contract resolver honours before the workspace credential flow. In override mode the credential **source** is the authorization gate (the Age key decrypting the sops file, or the api's own auth), replacing the workspace-scope check — which is what decouples the push target from CWD. Precedence: explicit flag → `registry.push.*` config → workspace `registry_provides` fallback.
|
||
|
||
**Implementation**: `core/nulib/platform/oci/push_registry.nu` (`resolve-push-registry`, `select-push-registry`; sops/api/literal/env sources reusing the ADR-042 cabling idiom); `acquire-docker-config` helper in `contract_resolver.nu` honouring the `PROVISIONING_PUSH_DOCKER_CONFIG` override across all four OCI functions; `select-registry` subcommand + `contract-use-registry` recipe. ADR-046 constraint `push-registry-pluggable-source` (Hard). **Verified**: literal/env/sops resolution (real Age-key sops decrypt) + export emission + docker-config materialisation.
|
||
|
||
### Catalog management as a cross-surface invariant
|
||
|
||
Catalog management is a domain capability that MUST be exposed uniformly across CLI, WebUI, GraphQL, and MCP, dispatching through `provisioning-core::Registry` per the G3 contract invariant (no per-surface reimplementation). The Nushell modules + just recipes are the current CLI/script surface; cross-surface parity (catalog operations as Registry Tools) is the target.
|
||
|
||
**Ontology**: core.ncl Practice nodes `catalog-contract-distribution` + `push-registry-selection` (9 edges); tensions `monorepo-vs-split` and `centralized-vs-scripted` updated with the ADR-046 synthesis. QA `provisioning-catalog` (what catalogs are, contents, distribution, cross-surface management) + mode `provisioning-catalog` (inspect/validate: resolve root, enumerate by kind, typecheck manifests, report contract lock).
|
||
|
||
**Files**: `adrs/adr-046-catalog-contract-content-addressed.ncl`, `schemas/catalog/manifest.ncl`, `core/nulib/platform/oci/{contract_resolver,push_registry,contract_cli}.nu`, `justfiles/catalog-contract.just`, `core/nulib/env.nu`, `core/nulib/platform/config/accessor/functions.nu`, `.ontology/core.ncl`, `.ontoref/reflection/qa.ncl`, `.ontoref/reflection/modes/provisioning-catalog.ncl`
|
||
|
||
---
|
||
|
||
## 2026-05-20 — foundation library relocation (ADR-045 revises ADR-043)
|
||
|
||
### ADR-045: Foundation library relocation — single-consumer provider traits fold into provisioning
|
||
|
||
**Decision**: `ontoref-compute` and `ontoref-dns` relocate into `provisioning/platform/crates/` as workspace members; `ontoref-auth` and `ontoref-ui` consolidate into one external `foundation` workspace; ADR-043's γ-posture two-consumer `locked` claim for `DnsProvider`/`ComputeProvider` is revised.
|
||
|
||
**Why ADR-043's premise lapsed**: ADR-043 declared both traits γ-posture locked on a two-consumer set (lian-build + orchestrator). lian-build subsequently issued its own ADR-009 (*no-provider-knowledge*, 2026-05-18): the libre-forge fleet control plane became operational, `fleet-daemon` took ownership of VM lifecycle, and lian-build removed all provider knowledge (deleted `orchestrator_client.rs`, the `daemon::compute` module, `GET /api/providers`, the ADR-005 catalog). lian-build is no longer a consumer — `DnsProvider`/`ComputeProvider` now have a single consumer, the provisioning orchestrator.
|
||
|
||
**Placement rule**: a library is foundation (its own repo/workspace) when plural independent consumers make sharing cheaper than duplication; it folds into a consumer's repo when a single consumer makes a standalone repo pure overhead. `auth`/`ui` (3 consumers: ontoref daemon, lian-build, mirador) stay split into `foundation`; `compute`/`dns` (1 consumer: orchestrator) fold into `provisioning`.
|
||
|
||
**Unaffected**: ADR-043's orchestrator-internal decisions — `coredns_client.rs` deletion, `GET /.panel/manifest`, `compute_provider: Option<Arc<dyn ComputeProvider>>` — and its three constraints remain in force. ADR-045 revises only the consumer-count and trait-home claims.
|
||
|
||
**Files**: `adrs/adr-045-foundation-library-relocation.ncl`
|
||
|
||
---
|
||
|
||
## 2026-05-12 — orchestrator γ-posture adoption (ontoref-foundation)
|
||
|
||
### ADR-043: Orchestrator adopts DnsProvider, ComputeProvider, federation manifest
|
||
|
||
**Decision**: Replace `coredns_client.rs` with `Arc<dyn DnsProvider>`; add `compute_provider: Option<Arc<dyn ComputeProvider>>` to AppState; expose `GET /.panel/manifest` at `src/handlers/federation.rs`.
|
||
|
||
**γ-posture verdicts confirmed by this ADR**:
|
||
- `DnsProvider`: two consumers (lian-build + orchestrator) → trait locked
|
||
- `ComputeProvider`: two consumers (lian-build + orchestrator) → lifecycle surface locked; HcloudClient retained for operations outside the trait surface (volumes, floating IPs, images) per γ PARTIAL semantics
|
||
|
||
**`/.panel/manifest` endpoint**: `OrchestratorManifest` (panel_id, version, connectors, panels, workflows) returned without auth. Superset of the three-field projection consumed by `FederationResolver` — serves both machine and human consumers.
|
||
|
||
**`compute_provider: Option<Arc<dyn ComputeProvider>>`**: Populated from `HetznerCloudProvider::from_env()` when `HCLOUD_TOKEN` is present; `None` → degraded mode (read-only fleet ops), consistent with ADR-042's no-hard-startup-failure contract.
|
||
|
||
**Files**: `adrs/adr-043-ontoref-foundation-orchestrator.ncl`
|
||
|
||
---
|
||
|
||
## 2026-05-12 — nickel branch consolidation
|
||
|
||
### ADR-025 Amendments: Eager function-body parse (2026-04-17)
|
||
|
||
**Decision**: Nushell parses `use` statements inside function bodies at module-load time. Subprocess boundary is the only true lazy-load mechanism.
|
||
|
||
**Constraints added/amended**:
|
||
|
||
- `bash-wrapper-has-no-runner-reference` — now permits `provisioning-cli.nu` as transitional fallback
|
||
- `universal-fallback-is-transitional` — 22 unmapped commands are explicit migration debt;
|
||
must be resolved before lazy-load architecture is considered complete
|
||
- `every-registry-command-has-thin-handler` — made directional (progress metric, not gate)
|
||
|
||
**Rejected approach**: Single-entry `provisioning-cli.nu` for hot paths — measured at 3.1s vs 0.08–0.15s
|
||
for thin handlers. All 15 dispatcher wrappers fire at module-load regardless of invoked command.
|
||
|
||
**Files**: `adrs/adr-025-unified-lazy-loading.ncl`
|
||
|
||
---
|
||
|
||
### Platform Services Documentation (2026-02-03)
|
||
|
||
**All 10 platform services documented** with endpoint catalogue and local setup guide.
|
||
|
||
**Services**:
|
||
|
||
| Service | Endpoints | Notes |
|
||
| ------- | --------- | ----- |
|
||
| vault | 8 | Transit encryption, dynamic secrets |
|
||
| registry | 6 | OCI extension distribution |
|
||
| control-center | 12 | RBAC, audit, compliance |
|
||
| rag | 5 | Vector search, document ingestion |
|
||
| ai-service | 7 | Model routing, DAG execution |
|
||
| mcp-server | 4 | AI-powered config tools |
|
||
| daemon | 3 | State sync, health aggregation |
|
||
| orchestrator | 8 | Workflow execution, checkpoints |
|
||
| detector | 4 | Anomaly detection, alerts |
|
||
| ui | 3 | Web control center frontend |
|
||
|
||
**Added**:
|
||
|
||
- `docs/src/operations/platform-services-inventory.md` — 50+ endpoints
|
||
- `docs/src/operations/local-services-setup.md` — build, config, troubleshooting
|
||
- `scripts/start-local-binaries.nu` — dependency-ordered service startup automation
|
||
|
||
---
|
||
|
||
### TypeDialog Migration (2026-01-09)
|
||
|
||
**`forminquire` fully replaced** by TOML-driven `typedialog` with TTY wrappers.
|
||
|
||
**New form registry** (`.typedialog/`):
|
||
|
||
- `core/forms/auth-login.toml`
|
||
- `core/forms/mfa-enroll.toml`
|
||
- `core/forms/setup-wizard.toml`
|
||
- `core/forms/infrastructure/server_delete_confirm.toml`
|
||
- `core/forms/infrastructure/cluster_delete_confirm.toml`
|
||
- `core/forms/infrastructure/taskserv_delete_confirm.toml`
|
||
- `core/forms/infrastructure/generic_delete_confirm.toml`
|
||
- `platform/forms/ai-service-form.toml` (with Nickel fragment composition)
|
||
- `platform/forms/control-center-form.toml`
|
||
- `platform/forms/extension-registry-form.toml`
|
||
|
||
**Documentation**: `.typedialog/README.md`, `platform/forms/README.md`, `platform/forms/fragments/README.md`
|
||
|
||
**Architecture doc**: `docs/src/architecture/config-loading-architecture.md`
|
||
|
||
---
|
||
|
||
### Nushell 0.110.0 Compatibility (2026-01-21)
|
||
|
||
- Fixed `try`/`catch` syntax across `.typedialog/platform/scripts/`, `bootstrap/install.nu`, example deploy scripts
|
||
- Updated `external.nu`, `paths.nu`, `export-toml.nu` for Nu 0.110.0 API changes
|
||
- Removed stale session reports from `.coder/`
|
||
- Relocated `nickel-installation-guide.md` into `docs/src/setup/`
|
||
|
||
---
|
||
|
||
## 2026-01-08 — Nickel IaC migration complete
|
||
|
||
**Repository**: provisioning (standalone, nickel branch)
|
||
**Changes**: Nickel IaC migration complete — Legacy KCL and config cleanup
|
||
|
||
---
|
||
|
||
## 📋 Summary
|
||
|
||
Complete migration to Nickel-based infrastructure-as-code with consolidated configuration strategy.
|
||
Legacy KCL schemas, deprecated config files, and redundant documentation removed.
|
||
New project structure with `.cargo/`, `.github/`, and schema-driven configuration system.
|
||
|
||
---
|
||
|
||
## 📁 Changes by Directory
|
||
|
||
### ✅ REMOVED (Legacy KCL Ecosystem)
|
||
|
||
- **config/** - Deprecated TOML configs (config.defaults.toml, kms.toml, plugins.toml, etc.)
|
||
- **config/cedar-policies/** - Legacy Cedar policies (moved to Nickel schemas)
|
||
- **config/templates/** - Old Jinja2 templates (replaced by Nickel generator/)
|
||
- **config/installer-examples/** - KCL-based examples
|
||
- **docs/src/** - Legacy documentation (full migration to provisioning/docs/src/)
|
||
- **kcl/** - Complete removal (all workspaces migrated to Nickel)
|
||
- **tools/kcl-packager.nu** - KCL packaging system
|
||
|
||
### ✅ ADDED (Nickel IaC & New Structure)
|
||
|
||
- **.cargo/** - Rust build configuration (clippy settings, rustfmt.toml)
|
||
- **.github/** - GitHub Actions CI/CD workflows
|
||
- **schemas/** - Nickel schema definitions (primary IaC format)
|
||
- main.ncl, provider-aws.ncl, provider-local.ncl, provider-upcloud.ncl
|
||
- Infrastructure, deployment, services, operations schemas
|
||
- **docs/src/architecture/adr/** - ADR updates for Nickel migration
|
||
- adr-010-configuration-format-strategy.md
|
||
- adr-011-nickel-migration.md
|
||
- adr-012-nushell-nickel-plugin-cli-wrapper.md
|
||
|
||
### 📝 UPDATED (Core System)
|
||
|
||
- **provisioning/docs/src/** - Comprehensive product documentation
|
||
- API reference, architecture, guides, operations, security, testing
|
||
- Nickel configuration guide with examples
|
||
- Migrated from legacy KCL documentation
|
||
|
||
- **core/** - Updated with Nickel integration
|
||
- Scripts, plugins, CLI updated for Nickel schema parsing
|
||
|
||
- **justfiles/** - Added ci.just for Nickel-aware CI/CD
|
||
- **README.md** - Complete restructure for Nickel-first approach
|
||
- **.gitignore** - Updated to ignore Nickel build artifacts
|
||
|
||
---
|
||
|
||
## 📊 Change Statistics
|
||
|
||
| Category | Removed | Added | Modified |
|
||
| ---------- | --------- | ------- | ---------- |
|
||
| Configuration | 50+ | 10+ | 3 |
|
||
| Documentation | 150+ | 200+ | 40+ |
|
||
| Infrastructure | 1 (kcl/) | - | - |
|
||
| Plugins | 1 | - | 5+ |
|
||
| Build System | 5 | 8+ | 3 |
|
||
| **Total** | **~220 files** | **~250 files** | **50+ files** |
|
||
|
||
## ⚠️ Breaking Changes
|
||
|
||
1. **KCL Sunset**: All KCL infrastructure code removed. Migrate workspaces using `nickel-kcl-bridge` or rewrite directly in Nickel.
|
||
2. **Config Format**: TOML configuration files moved to schema-driven Nickel system. Legacy config loading deprecated.
|
||
3. **Documentation**: Old KCL/legacy docs removed. Use `provisioning/docs/` for current product documentation.
|
||
4. **Plugin System**: Updated to Nickel-aware plugin API. Legacy Nushell plugins require recompilation.
|
||
|
||
## 🔧 Migration Path
|
||
|
||
```bash
|
||
# For existing workspaces:
|
||
provisioning workspace migrate --from-kcl <workspace-name>
|
||
|
||
# For custom configs:
|
||
nickel eval --format json <your-config.ncl> | jq '.'
|
||
```
|
||
|
||
## ✨ Key Features
|
||
|
||
- **Type-Safe**: Nickel schemas eliminate silent config errors
|
||
- **Composable**: Modular infrastructure definitions with lazy evaluation
|
||
- **Documented**: Schema validation built-in, IDE support via LSP
|
||
- **Validated**: All imports pre-checked, circular dependencies prevented
|
||
- **Bridge Available**: `nickel-kcl-bridge` for gradual KCL→Nickel migration
|
||
|
||
---
|
||
|
||
## 📝 Implementation Details
|
||
|
||
### Nickel Schema System
|
||
|
||
- **Three-tier architecture**: infrastructure, operations, deployment
|
||
- **Lazy evaluation**: Efficient resource binding and composition
|
||
- **Record merging**: Clean override patterns without duplication
|
||
- **Type validation**: LSP-aware with IDE auto-completion
|
||
- **Generator system**: Nickel-based dynamic configuration at runtime
|
||
|
||
### Documentation Reorganization
|
||
|
||
- **provisioning/docs/src/** (200+ files) - Customer-facing product docs
|
||
- **docs/src/** (20-30 files) - Architecture and development guidelines
|
||
- **.coder/** - Session files and implementation records
|
||
- Separation of concerns: Product docs isolated from session artifacts
|
||
|
||
### CI/CD Integration
|
||
|
||
- GitHub Actions workflows for Rust, Nickel, Nushell
|
||
- Automated schema validation pre-commit
|
||
- Cross-platform testing (Linux, macOS)
|
||
- Build artifact caching for fast iteration
|
||
|
||
---
|
||
|
||
## ⚠️ Compatibility Notes
|
||
|
||
**Breaking**: KCL workspaces require migration to Nickel. Use schema-aware tooling for validation.
|
||
|
||
**Migration support**: `nickel-kcl-bridge` tool and guides available in `provisioning/docs/src/development/`.
|
||
|
||
**Legacy configs**: Old TOML files no longer loaded. Migrate to Nickel schema format via CLI tool.
|
||
|
||
---
|
||
|
||
**Status**: Nickel migration complete. System is production-ready.
|
||
**Date**: 2026-01-08
|
||
**Branch**: nickel
|
||
|
||
---
|
||
|
||
*Last updated: 2026-05-12*
|