provisioning-code/CHANGELOG.md

363 lines
28 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.080.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*