Skip to content

Latest commit

 

History

History
235 lines (196 loc) · 12.5 KB

File metadata and controls

235 lines (196 loc) · 12.5 KB

Architecture

nddev-zcode-app produces a complete, reproducible ZCode home from source. It does not run ZCode agent sessions. Its lifecycle does manage the installed configuration and only the explicitly declared runtime paths during protected backup and restore operations.

Implementation layers

zcode_tools/   SOURCE: self-contained setup catalog in ZCode-native marketplaces
cli-tools/     SETUP MANAGER: discovery, status, lifecycle, and rendering
build/         CONTRACT: versions, artifact integrity, manifest, secret template

Marketplace sources

zcode_tools/marketplaces/nddev-builder/ is the managed setup installed by default. It remains a native ZCode marketplace so the same tree can be edited, validated, and distributed using ZCode's marketplace/plugin format. --setup nddev-builder is accepted for compatibility and --marketplace nddev-builder is the storage-format alias.

Marketplace source Installed target Treatment
AGENTS.md <target>/AGENTS.md copied
skills/, commands/, agents/ same paths under target copied
full marketplace directory <target>/marketplaces/<name>/ copied
cli-config.template.json <target>/cli/config.json rendered
v2-config.template.json <target>/v2/config.json rendered
v2-setting.template.json <target>/v2/setting.json rendered
hooks.json, mcp.json keys in cli/config.json merged

Template rendering expands ${VAR} values from the process environment and the local build/.env file through structured JSON substitution. Source templates never contain real credentials. Rendered .env, provider configs, MCP configs, credentials, and backups are runtime secrets and remain private to the current user.

Every CLI template declares one explicit provider/model main-model reference, the matching provider kind and base URL, and the referenced model metadata. The pinned CLI contract in build/version.json requires that bootstrap contract before it can create a desktop agent session. The bootstrap provider entry contains no credential; ZCode mounts the restored OAuth credential through its runtime provider registry after the CLI adapter has initialized.

The local env file is accepted only when it is a current-user-owned regular non-symlink with no group/world permissions. Existing environment variables win over file values. No shell expansion occurs; only ZCODE_TARGET and ZCODE_BACKUPS_DIR recognize a leading literal $HOME or ${HOME} path prefix.

Managed Setup

  • nddev-builder enables core@nddev-builder, a native component-authoring toolkit whose exact inventory is the convention-discovered plugin tree.

install uses nddev-builder when no setup flag is supplied. --posture full-auto is the default and keeps the full automatic builder posture; --posture safe renders the same setup with a stricter installed instruction layer for explicit review before destructive work.

All preference templates keep modelProviderFamilyModes.zai set to oauth, which is the verified ZCode account-authentication mode. The provider objects in v2/config.json are a separate explicit API-key contract: Z.ai uses https://api.z.ai/api/anthropic; BigModel uses https://open.bigmodel.cn/api/anthropic. Both API-key providers are disabled by default and must be enabled deliberately after their secret is configured. Their custom:* identities never reuse ZCode-owned builtin:* provider IDs, so rendering a setup cannot disable or replace the app-managed OAuth provider.

Installer

The entry point is cli-tools/scripts/install.sh. It validates the trusted system /usr/bin/python3 interpreter, requires Python 3.9 or newer, scrubs Python injection variables, and runs cli-tools/nddev_zcode.py with -I -B. The Python manager owns setup lifecycle transactions; no fallback path bypasses it.

Target-bound commands perform host and lexical option checks before filesystem observation, then map every canonical target or backup path to one role-independent digest anchor in a fixed same-UID system temporary namespace. Path anchors retain the exact legacy anchor=target,target_digest marker bytes, so old and new managers validate the same monotonic files during an upgrade. Mutators retain the product anchor exclusively for their complete lifecycle. Before touching transaction state, they boundedly acquire every existing path anchor to wait out old managers that already completed the former product-to- target handoff. They then retain the deterministic digest-sorted target, requested-backup, and prepare-bound backup anchors through commit and recovery. Pending prepare namespace identities and bounded file bytes are reread exactly after final acquisition.

Read-only commands never create or repair anchors. Status coordinates only its target, plans coordinate the target plus requested and pending backup roots, and list --backups coordinates only its backup root. When a required path anchor does not exist, the product shared lock remains held through the read. A cold read is permitted only when the product anchor is absent and the existing product namespace is boundedly empty; if the exact namespace snapshot changes, the result is discarded and recomputed under coordination. Status preserves the public product_anchor and target_anchor fields and paths.

The apply lifecycle:

  1. validates canonical target and backup endpoints, managed setup identity, runtime quiescence, and active placeholder requirements,
  2. drains any valid pending cleanup journal before active mutation,
  3. builds a private same-filesystem stage, writes a schema-2 BUILD-VERSION bound to setup_id and posture, and selectively restores credentials, certificates, task indexes, session snapshots, bot definitions, CLI databases, and artifacts,
  4. verifies the complete staged tree, normalizes private permissions, and fsyncs it before commit,
  5. moves any previous target into a numbered backup slot, preserving exact object identity for rollback, atomically publishes the verified stage, and revalidates both complete graphs, retired-slot journal state, and parent identities at the actual commit decision before removing durable authority,
  6. promotes irreversible retired-slot cleanup through a durable prepare intent and immutable cleanup journal before destructive drain.

The cleanup namespace (.nddev-zcode-cleanup/<target-digest>/) is validated component by component before prepare, journal, or tombstone work: every manager-owned component is opened without following symlinks, checked for current-user ownership, group owner, private mode, expected kind, and exact open-vs-lstat identity. Lifecycle cleanup keeps those directory file descriptors through child inspection, publication, rename, unlink, and drain steps; status and plan expose only cleanup-pending booleans and bounded relative metadata, not cleanup deletion paths.

If post-commit cleanup cannot finish after a valid final journal or verified bootstrap runtime is visible, the command returns success with explicit cleanup-pending state instead of rolling back committed state. Read-only commands expose the same state without repairing it. Malformed or incoherent cleanup state fails closed with exit code 2 before mutation. A post-rename identity, graph, journal, or parent mismatch leaves foreign objects untouched and retains durable prepare authority for bounded recovery or operator inspection.

Backup inventory is also fail-closed without becoming an output-injection surface. It validates a complete managed stamp or adopted envelope before displaying any metadata. Invalid names and marker values are represented by fixed redacted classifications; valid historical installer SemVer and canonical UTC timestamps remain readable.

Plan mode describes the operation without writes or live zcode execution, but still parses, substitutes, merges, and validates config/setting/provider/MCP/hook inputs. Missing or empty active placeholders in keys or values fail in both modes; only explicitly disabled provider/MCP nodes may remain dormant. An existing unstamped directory is never replaced implicitly: initial adoption requires --adopt-unmanaged together with an explicit --target.

Live implementation:

  • cli-tools/nddev_zcode.py owns setup selection, target coordination, status, plan, install, remove, restore, backup rotation, rollback, cleanup journals, and rendering.
  • cli-tools/scripts/install.sh is the trusted public compatibility shim.
  • cli-tools/scripts/bootstrap.sh retains native app/CLI bootstrap behavior and still sources lib/common.sh and lib/version.sh.

Bootstrap and CLI boundaries

Bootstrap accepts only the exact canonical CDN base recorded in build/version.json and HTTPS-only redirects. It verifies size plus SHA-512 before native identity checks. macOS uses the official ZIP artifact from upstream latest.yml, not the DMG. The DEB path is fixed to /opt/ZCode/resources/glm/zcode.cjs. Before the package transaction, private extraction must find exactly one safe entry there and its CLI version must match the pin; dpkg --dry-run -i must then pass. After installation, the exact dpkg-owned path/version and SHA-512 equality with the verified payload entry are required.

Deterministically ordered locks protect the installer-managed app endpoint and the user launcher; dpkg owns the system package transaction on Debian systems. App and launcher swaps retain rollback state until exact postconditions pass. That point marks the bootstrap committed. Cleanup failure after commit is reported as cleanup_pending=true, exits success, and does not roll back verified state; pre-commit errors and handled signals recover the prior app/launcher when state is unambiguous. New and old application/launcher endpoints are identity-bound in both abort and success cleanup, and cleanup uses exclusive quarantine plus fd-relative deletion for owned state.

Normal installs treat a missing, timed-out, failed, or over-limit runtime CLI probe as advisory not-installed/unknown. Bootstrap treats the same bounded probe as a strict version postcondition.

Build contract

  • VERSION, build/version.json, build/manifest.json, the nddev-builder marketplace core entry, and the core plugin manifest carry one strict SemVer for every repository release.
  • build/version.json also pins the verified ZCode app, CLI, runtime model, launcher locations, and each CDN artifact's filename, byte size, SHA-512, and available platform-native identity metadata. Linux launcher entries are explicit for the DEB (/opt/ZCode/resources/glm/zcode.cjs) and the default AppImage extraction (${HOME}/.local/opt/ZCode/resources/glm/zcode.cjs).
  • build/manifest.json defines public layout, artifact/bootstrap, command-option, runtime-probe, transaction, backup/restore, adoption, and secrets contracts.
  • The release workflow validates every version source, requires the tagged commit to be reachable from fetched origin/main, and rejects publication before invoking the shared supply-chain workflow if any contract drifts.

ZCode-native component format

ZCode discovers plugin components by convention:

marketplaces/<marketplace>/marketplace.json
marketplaces/<marketplace>/plugins/<plugin>/.zcode-plugin/plugin.json
marketplaces/<marketplace>/plugins/<plugin>/skills/<skill>/SKILL.md
marketplaces/<marketplace>/plugins/<plugin>/commands/<command>.md
marketplaces/<marketplace>/plugins/<plugin>/agents/<agent>.md
marketplaces/<marketplace>/plugins/<plugin>/.mcp.json

Plugin manifests are metadata, not component registries. User-scope components live directly under <target>/{skills,commands,agents}/. Hooks and MCP servers are installed into <target>/cli/config.json.

The public product contract is config/nddev-contract.json version 3. It defines setup discovery, selection, status, stamp identity, and legacy recovery compatibility. It also keeps the two MCP namespaces explicit: plugin .mcp.json inputs use mcpServers, while the installed CLI configuration uses mcp.servers. The installer remains independent of this descriptive metadata and implements the same mapping directly.

Public/private repository boundary

This repository is the public implementation module. It intentionally excludes repository-local agent configuration, development memories, validation implementations, tests, and benchmarks.

The module is independently usable. Its public runtime, compatibility, and managed-surface contracts are owned by cli-tools/, build/, config/nddev-contract.json, and references/zcode-baseline.json.