From ff7a79a441aac553a072cf1a5d227dd54f08dac9 Mon Sep 17 00:00:00 2001 From: Danil Silantyev Date: Sat, 11 Jul 2026 03:18:52 +0700 Subject: [PATCH] fix: add explicit ZCode model bootstrap --- CHANGELOG.md | 22 +++++++ README.md | 11 ++-- VERSION | 2 +- build/manifest.json | 8 ++- build/version.json | 2 +- cli-tools/scripts/lib/build.sh | 63 +++++++++++++++++++ config/nddev-contract.json | 7 +++ docs/architecture.md | 18 ++++-- docs/install.md | 7 ++- docs/secrets.md | 15 +++-- references/zcode-baseline.json | 11 +++- .../marketplaces/nddev-builder/AGENTS.md | 7 ++- .../nddev-builder/cli-config.template.json | 21 ++++++- .../nddev-builder/marketplace.json | 2 +- .../plugins/core/.zcode-plugin/plugin.json | 2 +- .../core/commands/nddev-add-marketplace.md | 9 ++- .../core/commands/nddev-add-provider.md | 11 ++-- .../core/skills/add-marketplace/SKILL.md | 13 +++- .../plugins/core/skills/add-provider/SKILL.md | 17 +++-- .../nddev-builder/v2-config.template.json | 10 +-- .../nddev-designer/cli-config.template.json | 21 ++++++- .../nddev-designer/v2-config.template.json | 6 +- .../nddev-developer/cli-config.template.json | 21 ++++++- .../nddev-developer/v2-config.template.json | 6 +- 24 files changed, 259 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8eba0e7..97eadf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,28 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [2.1.2] - 2026-07-10 + +### Fixed + +- Added the explicit `provider/model` bootstrap and matching secret-free + provider definition required by ZCode CLI 0.15.2, so every rendered setup can + create a desktop agent session before ZCode mounts the restored OAuth + credential. +- Moved optional API-key providers to distinct `custom:*` identities instead + of shadowing ZCode-owned `builtin:*` providers. Restored Z.ai OAuth state can + now reactivate its app-managed coding-plan provider without inheriting a + template-level `enabled: false` override. +- Made plan and apply fail closed when a setup omits its main model reference, + the referenced provider/base URL/model declaration, or assigns a custom + provider a reserved `builtin:*` identity. + +### Changed + +- Bumped the public build and `nddev-builder/core` component to 2.1.2. The + verified ZCode 3.3.4 application, CLI 0.15.2, runtime model, and native + artifact identity pins are unchanged. + ## [2.1.1] - 2026-07-10 ### Changed diff --git a/README.md b/README.md index b987031..d83f078 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ changes. - **Author:** Danil Silantyev (github:rldyourmnd), CEO NDDev - **License:** AGPL-3.0-or-later -- **Build version:** 2.1.1 +- **Build version:** 2.1.2 - **Verified ZCode runtime:** app 3.3.4, CLI 0.15.2, model GLM-5.2 ## What this repository contains @@ -57,10 +57,11 @@ cli-tools/scripts/install.sh status --json Plan mode performs no writes and does not invoke a locally installed `zcode` binary. It still parses and merges config, setting, provider, MCP, and hook -inputs and rejects unresolved active placeholders in keys or values. Setup -installation in apply mode performs a bounded live runtime probe and rejects -open task/session databases or SQLite recovery sidecars before it changes the -target. +inputs, requires the explicit CLI model/provider bootstrap expected by ZCode +0.15.2, rejects custom providers that reuse reserved `builtin:*` identities, +and rejects unresolved active placeholders in keys or values. Setup installation +in apply mode performs a bounded live runtime probe and rejects open +task/session databases or SQLite recovery sidecars before it changes the target. See [docs/install.md](docs/install.md) for install, update, switch, backup, restore, remove, and custom-target usage. diff --git a/VERSION b/VERSION index 3e3c2f1..eca07e4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.1 +2.1.2 diff --git a/build/manifest.json b/build/manifest.json index 74b2c9b..df522d3 100644 --- a/build/manifest.json +++ b/build/manifest.json @@ -1,6 +1,6 @@ { "name": "nddev-zcode-app", - "build_version": "2.1.1", + "build_version": "2.1.2", "source_root": "zcode_tools/marketplaces/", "installer": "cli-tools/scripts/install.sh install --setup ", "layout": { @@ -55,6 +55,12 @@ "advisory_failure": "timeout, nonzero exit, excessive output, decode/runtime error, or missing executable becomes unknown/not-installed without aborting install", "bootstrap_postcondition": "bootstrap remains strict and rejects an unknown or mismatched CLI version" }, + "model_provider_policy": { + "cli_bootstrap": "every setup declares an explicit provider/model main reference and matching provider kind, options.baseURL, and model metadata", + "oauth_boundary": "the CLI bootstrap is secret-free; ZCode supplies restored account OAuth credentials through its runtime provider registry", + "custom_provider_identity": "explicit API-key providers use custom:* identities and never reuse ZCode-owned builtin:* ids", + "validation": "plan and apply fail closed on a missing or inconsistent CLI model/provider bootstrap or a reserved builtin:* identity on a custom provider" + }, "version_policy": { "syntax": "SemVer 2.0.0 for module, runtime, managed-stamp, adopted-envelope, and backup-name versions", "release_lockstep": [ diff --git a/build/version.json b/build/version.json index 593c243..eebbe03 100644 --- a/build/version.json +++ b/build/version.json @@ -1,5 +1,5 @@ { - "build_version": "2.1.1", + "build_version": "2.1.2", "zcode_app_version": "3.3.4", "zcode_cli_version": "0.15.2", "zcode_runtime": "GLM-5.2", diff --git a/cli-tools/scripts/lib/build.sh b/cli-tools/scripts/lib/build.sh index 7843526..dbdf510 100644 --- a/cli-tools/scripts/lib/build.sh +++ b/cli-tools/scripts/lib/build.sh @@ -1021,6 +1021,66 @@ def unresolved_values(value, path): failures.extend(unresolved_values(item, child_path(path, key))) return failures +def validate_cli_model_provider(value): + model = value.get("model") + if isinstance(model, str): + main = model.strip() + elif isinstance(model, dict) and isinstance(model.get("main"), str): + main = model["main"].strip() + else: + raise SystemExit("cli.model must declare an explicit main provider/model reference") + + provider_id, separator, model_id = main.partition("/") + if not separator or not provider_id.strip() or not model_id.strip(): + raise SystemExit("cli.model main reference must use provider/model format") + + provider_map = value.get("provider") + if not isinstance(provider_map, dict): + raise SystemExit("cli.provider must be a JSON object") + provider = provider_map.get(provider_id) + if not isinstance(provider, dict): + raise SystemExit(f"cli.provider is missing the configured model provider: {provider_id}") + + kind = provider.get("kind") + if kind not in {"anthropic", "openai", "openai-compatible"}: + raise SystemExit(f"cli.provider.{provider_id}.kind is unsupported") + options = provider.get("options") + if not isinstance(options, dict) or not isinstance(options.get("baseURL"), str): + raise SystemExit(f"cli.provider.{provider_id}.options.baseURL is required") + if not options["baseURL"].strip(): + raise SystemExit(f"cli.provider.{provider_id}.options.baseURL must not be empty") + + models = provider.get("models") + if not isinstance(models, dict): + raise SystemExit(f"cli.provider.{provider_id}.models must be a JSON object") + declared = models.get(model_id) + if declared is None: + declared = next( + ( + item + for item in models.values() + if isinstance(item, dict) and item.get("id") == model_id + ), + None, + ) + if not isinstance(declared, dict): + raise SystemExit( + f"cli.provider.{provider_id}.models does not declare the configured model: {model_id}" + ) + +def validate_custom_provider_identities(value): + provider_map = value.get("provider") + if not isinstance(provider_map, dict): + raise SystemExit("provider-config.provider must be a JSON object") + for provider_id, provider in provider_map.items(): + if not isinstance(provider, dict): + raise SystemExit(f"provider-config.provider.{provider_id} must be a JSON object") + if provider.get("source") == "custom" and provider_id.startswith("builtin:"): + raise SystemExit( + "custom provider identities must not reuse ZCode-owned builtin:* ids: " + + provider_id + ) + cli = substitute(load("cli-config.template.json")) providers = substitute(load("v2-config.template.json")) settings = substitute(load("v2-setting.template.json")) @@ -1051,6 +1111,9 @@ if mcp is not None: raise SystemExit("mcp.servers must be a JSON object") configured.update(servers) +validate_cli_model_provider(cli) +validate_custom_provider_identities(providers) + failures = [] for root_name, value in ( ("provider-config", providers), diff --git a/config/nddev-contract.json b/config/nddev-contract.json index b360a96..954c699 100644 --- a/config/nddev-contract.json +++ b/config/nddev-contract.json @@ -31,6 +31,12 @@ "marketplace_root": "zcode_tools/marketplaces//marketplace.json", "plugin_manifest": "plugins//.zcode-plugin/plugin.json", "plugin_components_convention": true, + "cli_model_reference": "model: provider/model", + "cli_provider_map": "provider", + "cli_provider_base_url": "provider..options.baseURL", + "cli_provider_model_map": "provider..models", + "custom_provider_id_prefix": "custom:", + "reserved_provider_id_prefix": "builtin:", "plugin_mcp_key": "mcpServers", "installed_mcp_key": "mcp.servers", "hooks_require_enabled_flag": true, @@ -63,6 +69,7 @@ "bootstrap_policy_ref": "build/manifest.json:bootstrap_policy", "command_option_policy_ref": "build/manifest.json:command_option_policy", "runtime_probe_policy_ref": "build/manifest.json:runtime_probe_policy", + "model_provider_policy_ref": "build/manifest.json:model_provider_policy", "version_policy_ref": "build/manifest.json:version_policy", "transaction_policy_ref": "build/manifest.json:transaction_policy", "adoption_policy_ref": "build/manifest.json:adoption_policy", diff --git a/docs/architecture.md b/docs/architecture.md index a2205cc..a0b104f 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -36,6 +36,13 @@ 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. +ZCode CLI 0.15.2 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 @@ -59,6 +66,8 @@ 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 @@ -80,10 +89,11 @@ shared libraries and execute the same lifecycle: and selectively restore credentials, certificates, the desktop task index, legacy session snapshots, bot definitions, CLI session databases, and runtime artifacts into the stage, -5. reject unresolved placeholders in keys or values across active - config/setting/provider/MCP/hook branches, symlinks, special files, and - hardlink aliases; normalize private permissions, verify the complete staged - result, and fsync it before commit, +5. reject a missing or inconsistent CLI model/provider bootstrap, reserved + `builtin:*` identities on custom providers, unresolved placeholders in keys + or values across active config/setting/provider/MCP/hook branches, symlinks, + special files, and hardlink aliases; normalize private permissions, verify + the complete staged result, and fsync it before commit, 6. hold any occupied rotation slot, move the previous live target into its backup, and atomically rename the verified stage into place, 7. roll back both the live target and held backup occupant on errors or handled diff --git a/docs/install.md b/docs/install.md index 64202ee..b6fdc95 100644 --- a/docs/install.md +++ b/docs/install.md @@ -277,10 +277,11 @@ you stay logged in. If the auth token expired, re-authenticate in the app. The verified preference uses Z.ai account OAuth. To use an explicit Z.ai API key instead, populate `ZAI_API_KEY`, set that custom provider's `enabled` field -to `true`, reinstall, and select the provider backed by +to `true`, reinstall, and select `custom:zai-api-key`, which is backed by `https://api.z.ai/api/anthropic`. BigModel API-key access remains a separate, -disabled-by-default provider backed by `https://open.bigmodel.cn/api/anthropic`; -enable it only after populating `BIGMODEL_API_KEY`. +disabled-by-default `custom:bigmodel-api-key` provider backed by +`https://open.bigmodel.cn/api/anthropic`; enable it only after populating +`BIGMODEL_API_KEY`. ### Runtime version probe diff --git a/docs/secrets.md b/docs/secrets.md index 39e2428..e550bb3 100644 --- a/docs/secrets.md +++ b/docs/secrets.md @@ -36,11 +36,18 @@ Z.ai account authentication and explicit provider API keys are separate: - `modelProviderFamilyModes.zai: oauth` in `v2/setting.json` is the verified ZCode 3.3.4 default for account login. It does not require `ZAI_API_KEY`. - `ZAI_API_KEY` configures the explicit custom Z.ai provider at - `https://api.z.ai/api/anthropic`. That provider is disabled by default; set - its `enabled` field to `true` only after supplying the key. + `https://api.z.ai/api/anthropic` under `custom:zai-api-key`. That provider is + disabled by default; set its `enabled` field to `true` only after supplying + the key. - `BIGMODEL_API_KEY` configures the separate BigModel provider at - `https://open.bigmodel.cn/api/anthropic`; that provider is also disabled by - default and must be enabled deliberately after supplying the key. + `https://open.bigmodel.cn/api/anthropic` under + `custom:bigmodel-api-key`; that provider is also disabled by default and must + be enabled deliberately after supplying the key. + +The secret-free `builtin:zai-coding-plan` entry in `cli/config.json` is only the +explicit provider/model bootstrap required by CLI 0.15.2. It does not contain +an API key and must not be repurposed as a custom provider. ZCode owns that +identity and supplies the restored OAuth credential at runtime. Provider secrets are rendered into `v2/config.json`. MCP secrets referenced in `mcp.json` are rendered before their entries are merged into `cli/config.json`. diff --git a/references/zcode-baseline.json b/references/zcode-baseline.json index 96ed9ce..c84cba2 100644 --- a/references/zcode-baseline.json +++ b/references/zcode-baseline.json @@ -1,6 +1,6 @@ { - "baseline_version": 1, - "_comment": "ZCode runtime baseline for this build. The app and CLI versions are pinned in build/version.json, compared during setup installation, and enforced as strict bootstrap postconditions. Account-mode Z.ai authentication uses the verified OAuth preference; explicit API-key providers are separate custom provider entries. Update verified_date and versions when the baseline changes.", + "baseline_version": 2, + "_comment": "ZCode runtime baseline for this build. The app and CLI versions are pinned in build/version.json, compared during setup installation, and enforced as strict bootstrap postconditions. CLI 0.15.2 requires an explicit provider/model reference and matching provider base URL before desktop session creation. Account-mode Z.ai authentication uses the verified OAuth preference; explicit API-key providers are separate custom provider entries. Update verified_date and versions when the baseline changes.", "zcode": { "app_version": "3.3.4", "app_build": "3.3.4.2877", @@ -12,7 +12,12 @@ "provider_domain_default": "zai", "provider_kind": "anthropic", "provider_account_auth_mode": "oauth", + "cli_model_ref": "builtin:zai-coding-plan/GLM-5.2", + "cli_model_provider_id": "builtin:zai-coding-plan", + "cli_model_provider_base_url": "https://api.z.ai/api/anthropic", "provider_api_key_source": "custom", + "provider_zai_api_key_id": "custom:zai-api-key", + "provider_bigmodel_api_key_id": "custom:bigmodel-api-key", "provider_zai_api_key_base_url": "https://api.z.ai/api/anthropic", "provider_bigmodel_api_key_base_url": "https://open.bigmodel.cn/api/anthropic", "marketplace_format": "root marketplace.json (name + owner + plugins[])", @@ -37,5 +42,5 @@ "artifact_contract": "build/version.json:zcode_download_artifacts" }, "verified_date": "2026-07-10", - "verified_against": "ZCode app 3.3.4 (build 3.3.4.2877), CLI 0.15.2, all six native distribution artifacts, and the task/session storage layout" + "verified_against": "ZCode app 3.3.4 (build 3.3.4.2877), CLI 0.15.2 config parser and desktop model-selection adapter, all six native distribution artifacts, and the task/session storage layout" } diff --git a/zcode_tools/marketplaces/nddev-builder/AGENTS.md b/zcode_tools/marketplaces/nddev-builder/AGENTS.md index 22367d0..3a190e0 100644 --- a/zcode_tools/marketplaces/nddev-builder/AGENTS.md +++ b/zcode_tools/marketplaces/nddev-builder/AGENTS.md @@ -31,8 +31,11 @@ the primary workflow for changes to ZCode extension sources. - `skills/`, `commands/`, and `agents/` hold optional user-scope components. - `marketplaces/nddev-builder/` contains the installed marketplace and its self-contained plugin bundles. -- `cli/config.json` contains plugin state, hooks, and MCP server definitions. -- `v2/config.json` contains explicit API-key providers. +- `cli/config.json` contains the required secret-free model/provider bootstrap, + plugin state, hooks, and MCP server definitions. ZCode supplies the restored + OAuth credential at runtime. +- `v2/config.json` contains optional explicit API-key providers under + `custom:*` identities; they never reuse ZCode-owned `builtin:*` identities. - `v2/setting.json` contains desktop preferences, including the verified Z.ai account OAuth mode. - `.env`, provider configs, MCP configuration, `v2/credentials.json`, and diff --git a/zcode_tools/marketplaces/nddev-builder/cli-config.template.json b/zcode_tools/marketplaces/nddev-builder/cli-config.template.json index 77b9208..629042c 100644 --- a/zcode_tools/marketplaces/nddev-builder/cli-config.template.json +++ b/zcode_tools/marketplaces/nddev-builder/cli-config.template.json @@ -1,5 +1,24 @@ { - "_comment": "Config-file hooks shape: events live under hooks.events. (NOT hooks.). hooks.enabled must be true. See the official diagnosing-hooks skill.", + "_comment": "ZCode CLI 0.15.2 requires an explicit model reference and matching provider bootstrap. The provider entry is secret-free: ZCode mounts the restored Z.ai OAuth credential at runtime. Config-file hook events live under hooks.events. and hooks.enabled must be true.", + "model": "builtin:zai-coding-plan/GLM-5.2", + "provider": { + "builtin:zai-coding-plan": { + "name": "Z.ai - Coding Plan", + "kind": "anthropic", + "options": { + "baseURL": "https://api.z.ai/api/anthropic" + }, + "models": { + "GLM-5.2": { + "limit": { "context": 1000000 }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + } + } + } + }, "plugins": { "enabled": true, "enabledPlugins": { diff --git a/zcode_tools/marketplaces/nddev-builder/marketplace.json b/zcode_tools/marketplaces/nddev-builder/marketplace.json index d9f6a10..c5759af 100644 --- a/zcode_tools/marketplaces/nddev-builder/marketplace.json +++ b/zcode_tools/marketplaces/nddev-builder/marketplace.json @@ -10,7 +10,7 @@ "name": "core", "source": "./plugins/core", "description": "Reusable toolkit: skills, slash commands, and a reviewer subagent for building plugins, managing MCP servers and providers, authoring skills, and listing or removing components.", - "version": "2.1.1", + "version": "2.1.2", "author": { "name": "Danil Silantyev (github:rldyourmnd), CEO NDDev" }, diff --git a/zcode_tools/marketplaces/nddev-builder/plugins/core/.zcode-plugin/plugin.json b/zcode_tools/marketplaces/nddev-builder/plugins/core/.zcode-plugin/plugin.json index 7c545c3..db98c60 100644 --- a/zcode_tools/marketplaces/nddev-builder/plugins/core/.zcode-plugin/plugin.json +++ b/zcode_tools/marketplaces/nddev-builder/plugins/core/.zcode-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "core", - "version": "2.1.1", + "version": "2.1.2", "description": "Reusable ZCode toolkit: skills, slash commands, and a reviewer subagent for building plugins, managing MCP servers and providers, authoring skills, and listing or removing components.", "author": { "name": "Danil Silantyev (github:rldyourmnd), CEO NDDev", diff --git a/zcode_tools/marketplaces/nddev-builder/plugins/core/commands/nddev-add-marketplace.md b/zcode_tools/marketplaces/nddev-builder/plugins/core/commands/nddev-add-marketplace.md index 00e405a..d33f47b 100644 --- a/zcode_tools/marketplaces/nddev-builder/plugins/core/commands/nddev-add-marketplace.md +++ b/zcode_tools/marketplaces/nddev-builder/plugins/core/commands/nddev-add-marketplace.md @@ -12,9 +12,12 @@ Follow the `add-marketplace` skill exactly: - `marketplace.json` → set `name` and `description`. - `AGENTS.md` → set the `` marker and write substantive, purpose-specific operating instructions. - - Keep `recentProjects: []`; update providers and enabled plugins - deliberately. Empty plugins/hooks/MCP are valid only when the profile - documents why workspace-specific tooling is intentional. + - Retain an explicit CLI `provider/model` bootstrap with a matching + secret-free provider/base URL/model declaration. + - Keep `recentProjects: []`; define optional API-key providers only under + `custom:*` identities, and update enabled plugins deliberately. Empty + plugins/hooks/MCP are valid only when the profile documents why + workspace-specific tooling is intentional. 4. Validate by running: `cli-tools/scripts/install.sh install --marketplace --plan` — it must pass `validate_marketplace`. 5. Confirm it appears in `install.sh list`. 6. Remind to bump the build version if this is a release change. diff --git a/zcode_tools/marketplaces/nddev-builder/plugins/core/commands/nddev-add-provider.md b/zcode_tools/marketplaces/nddev-builder/plugins/core/commands/nddev-add-provider.md index 6c18ea7..f4cf098 100644 --- a/zcode_tools/marketplaces/nddev-builder/plugins/core/commands/nddev-add-provider.md +++ b/zcode_tools/marketplaces/nddev-builder/plugins/core/commands/nddev-add-provider.md @@ -8,9 +8,12 @@ Follow the `add-provider` skill exactly: 1. Ask the user for: provider name, API kind (anthropic/openai), base URL, API key env var name, model ID(s), and enabled status. 2. Add the provider entry to `v2-config.template.json` under `provider`. - Explicit API-key providers use `source: custom`. For Z.ai, use - `https://api.z.ai/api/anthropic` and preserve the separate `zai: oauth` - account preference; BigModel uses `https://open.bigmodel.cn/api/anthropic`. + Explicit API-key providers use `source: custom` and a `custom:*` identity; + they never reuse ZCode-owned `builtin:*` identities. For Z.ai, use + `https://api.z.ai/api/anthropic` and preserve both the separate `zai: oauth` + account preference and the secret-free CLI model bootstrap. BigModel uses + `https://open.bigmodel.cn/api/anthropic`. 3. Add the `${API_KEY_VAR}` placeholder to `build/.env.example` (empty value). 4. Remind the user to fill the real value in `build/.env` (gitignored). -5. Validate JSON and run `install --plan`. +5. Validate JSON and run `install --plan`; it must retain a valid explicit + `provider/model` bootstrap in `cli-config.template.json`. diff --git a/zcode_tools/marketplaces/nddev-builder/plugins/core/skills/add-marketplace/SKILL.md b/zcode_tools/marketplaces/nddev-builder/plugins/core/skills/add-marketplace/SKILL.md index d89580b..c70d5c6 100644 --- a/zcode_tools/marketplaces/nddev-builder/plugins/core/skills/add-marketplace/SKILL.md +++ b/zcode_tools/marketplaces/nddev-builder/plugins/core/skills/add-marketplace/SKILL.md @@ -44,8 +44,13 @@ the installer merges them into `cli/config.json` if present): is a clean, minimal starting point) and edit the marketplace-specific values: - `marketplace.json` → set `name` to ``, write a one-sentence `description`. - `AGENTS.md` → set the `` marker and describe this setup. - - `cli-config.template.json` → keep the default (plugins/hooks/mcp skeleton). - - `v2-config.template.json` → set the provider definitions (default: Z.ai GLM-5.2). + - `cli-config.template.json` → keep an explicit `provider/model` main-model + reference, the matching secret-free provider/base URL/model declaration, + and the plugins/hooks/MCP skeleton. ZCode CLI 0.15.2 will not create a + desktop session without this bootstrap. + - `v2-config.template.json` → define only optional explicit API-key + providers under `custom:*` identities. Never reuse app-owned `builtin:*` + identities; the default Z.ai OAuth provider is managed by ZCode. - `v2-setting.template.json` → set portable preferences; start `recentProjects` as `[]` and let ZCode populate device-local paths. - `mcp.json`, `hooks.json` → start empty (with the `_comment` key). @@ -74,6 +79,10 @@ the installer merges them into `cli/config.json` if present): - Every marketplace is self-contained — it owns its AGENTS.md and all config templates, not shared at the `zcode_tools/` root. +- Every CLI template owns a valid main model reference and matching provider + definition. OAuth credentials remain restored runtime state, not template + values. +- Custom API-key providers never use ZCode-owned `builtin:*` identities. - The marketplace name must match its directory name. - Empty `skills/`/`commands/`/`agents/`/`plugins/` are valid only for a deliberately minimal profile whose `AGENTS.md` and marketplace description diff --git a/zcode_tools/marketplaces/nddev-builder/plugins/core/skills/add-provider/SKILL.md b/zcode_tools/marketplaces/nddev-builder/plugins/core/skills/add-provider/SKILL.md index f9b8d59..68ef755 100644 --- a/zcode_tools/marketplaces/nddev-builder/plugins/core/skills/add-provider/SKILL.md +++ b/zcode_tools/marketplaces/nddev-builder/plugins/core/skills/add-provider/SKILL.md @@ -36,6 +36,7 @@ Adds a model provider definition to `v2-config.template.json`. - **``** — unique key. Use the repository's established key when updating an existing provider; use `custom:` for a new API-key provider. + A custom provider must never reuse a ZCode-owned `builtin:*` identity. - **`name`** — human-readable display name. - **`kind`** — `"anthropic"` (Anthropic-compatible API) or `"openai"` (OpenAI-compatible API). Determines the request format ZCode uses. @@ -51,7 +52,7 @@ Adds a model provider definition to `v2-config.template.json`. (`"text"`, `"image"`). Optional model fields: `limit.output` (max output tokens), `name` (upstream API model id if it differs from the map key), `reasoning` (`{enabled, variants, defaultVariant}` for reasoning-capable - models — see `builtin:bigmodel-coding-plan` → `GLM-5-Turbo` in the builder + models — see `custom:bigmodel-api-key` → `GLM-5-Turbo` in the builder template for a real example). ## Procedure @@ -70,9 +71,12 @@ Adds a model provider definition to `v2-config.template.json`. 3. Add the provider entry to the `provider` object. For an explicit Z.ai API-key provider, use kind `anthropic`, source - `custom`, and base URL `https://api.z.ai/api/anthropic`. Do not replace the - separate `modelProviderFamilyModes.zai: oauth` account preference. BigModel - API-key providers use `https://open.bigmodel.cn/api/anthropic`. + `custom`, an identity such as `custom:zai-api-key`, and base URL + `https://api.z.ai/api/anthropic`. Do not replace the separate + `modelProviderFamilyModes.zai: oauth` account preference or the secret-free + `builtin:zai-coding-plan` bootstrap in `cli-config.template.json`. BigModel + API-key providers use an identity such as `custom:bigmodel-api-key` and base + URL `https://open.bigmodel.cn/api/anthropic`. 4. Add the secret placeholder to `build/.env.example`: @@ -103,6 +107,11 @@ Adds a model provider definition to `v2-config.template.json`. - API key is ALWAYS a `${VAR}` placeholder — never a real value in the template. - The env var name must be uppercase (`[A-Z0-9_]`). - Add the matching key to `build/.env.example` (committed, empty value). +- Custom API-key providers use `custom:*` identities and never shadow + ZCode-owned `builtin:*` providers. +- `cli-config.template.json` must retain an explicit `provider/model` main + model reference plus a matching secret-free provider/base-URL/model + declaration; OAuth credentials are mounted by ZCode at runtime. - `credentials.json` contains account auth tokens and is restored from backup, not templated. Treat it as a secret. - English only. diff --git a/zcode_tools/marketplaces/nddev-builder/v2-config.template.json b/zcode_tools/marketplaces/nddev-builder/v2-config.template.json index 48f5847..2252529 100644 --- a/zcode_tools/marketplaces/nddev-builder/v2-config.template.json +++ b/zcode_tools/marketplaces/nddev-builder/v2-config.template.json @@ -1,8 +1,8 @@ { - "_comment": "Disabled-by-default explicit API-key provider definitions for v2/config.json. Z.ai API-key access uses the custom api.z.ai endpoint; BigModel uses open.bigmodel.cn. Enable an entry only after supplying its key. The verified Z.ai account preference remains OAuth in v2/setting.json and is independent of these entries. API keys are injected from build/.env; credentials.json contains restored account auth tokens and is never templated.", + "_comment": "Disabled-by-default explicit API-key providers for v2/config.json. Custom provider identities never reuse ZCode-owned builtin:* IDs, so the restored Z.ai OAuth provider remains app-managed. Enable a custom entry only after supplying its key through build/.env; credentials.json is restored runtime state and is never templated.", "provider": { - "builtin:zai-coding-plan": { - "name": "Z.ai - Coding Plan", + "custom:zai-api-key": { + "name": "Z.ai - API Key", "kind": "anthropic", "options": { "apiKey": "${ZAI_API_KEY}", @@ -20,8 +20,8 @@ } } }, - "builtin:bigmodel-coding-plan": { - "name": "BigModel - Coding Plan", + "custom:bigmodel-api-key": { + "name": "BigModel - API Key", "kind": "anthropic", "options": { "apiKey": "${BIGMODEL_API_KEY}", diff --git a/zcode_tools/marketplaces/nddev-designer/cli-config.template.json b/zcode_tools/marketplaces/nddev-designer/cli-config.template.json index 5592743..b1f6f92 100644 --- a/zcode_tools/marketplaces/nddev-designer/cli-config.template.json +++ b/zcode_tools/marketplaces/nddev-designer/cli-config.template.json @@ -1,5 +1,24 @@ { - "_comment": "This portable profile intentionally enables no global plugins, hooks, or MCP servers; project-specific tooling belongs to the active workspace. Event placeholders retain the ZCode hooks.events. shape and hooks.enabled contract.", + "_comment": "This portable profile intentionally enables no global plugins, hooks, or MCP servers; project-specific tooling belongs to the active workspace. ZCode CLI 0.15.2 requires an explicit model reference and matching secret-free provider bootstrap; ZCode mounts the restored Z.ai OAuth credential at runtime.", + "model": "builtin:zai-coding-plan/GLM-5.2", + "provider": { + "builtin:zai-coding-plan": { + "name": "Z.ai - Coding Plan", + "kind": "anthropic", + "options": { + "baseURL": "https://api.z.ai/api/anthropic" + }, + "models": { + "GLM-5.2": { + "limit": { "context": 1000000 }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + } + } + } + }, "plugins": { "enabled": true, "enabledPlugins": {} diff --git a/zcode_tools/marketplaces/nddev-designer/v2-config.template.json b/zcode_tools/marketplaces/nddev-designer/v2-config.template.json index 5dbd41a..3c77e97 100644 --- a/zcode_tools/marketplaces/nddev-designer/v2-config.template.json +++ b/zcode_tools/marketplaces/nddev-designer/v2-config.template.json @@ -1,8 +1,8 @@ { - "_comment": "Disabled-by-default explicit API-key provider definitions for nddev-designer. Z.ai API-key access uses the custom api.z.ai endpoint; enable it only after supplying the key. The verified Z.ai account preference remains OAuth in v2/setting.json and is independent of this entry. API keys are injected from build/.env; credentials.json contains restored account auth tokens and is never templated.", + "_comment": "Disabled-by-default explicit API-key provider for nddev-designer. Its custom identity never reuses a ZCode-owned builtin:* ID, so restored Z.ai OAuth remains app-managed. Enable it only after supplying ZAI_API_KEY through build/.env; credentials.json is restored runtime state and is never templated.", "provider": { - "builtin:zai-coding-plan": { - "name": "Z.ai - Coding Plan", + "custom:zai-api-key": { + "name": "Z.ai - API Key", "kind": "anthropic", "options": { "apiKey": "${ZAI_API_KEY}", diff --git a/zcode_tools/marketplaces/nddev-developer/cli-config.template.json b/zcode_tools/marketplaces/nddev-developer/cli-config.template.json index 1a0e835..fffc5af 100644 --- a/zcode_tools/marketplaces/nddev-developer/cli-config.template.json +++ b/zcode_tools/marketplaces/nddev-developer/cli-config.template.json @@ -1,5 +1,24 @@ { - "_comment": "This portable profile intentionally enables no global plugins, hooks, or MCP servers; language and project tooling belongs to the active workspace. Event placeholders retain the ZCode hooks.events. shape and hooks.enabled contract.", + "_comment": "This portable profile intentionally enables no global plugins, hooks, or MCP servers; language and project tooling belongs to the active workspace. ZCode CLI 0.15.2 requires an explicit model reference and matching secret-free provider bootstrap; ZCode mounts the restored Z.ai OAuth credential at runtime.", + "model": "builtin:zai-coding-plan/GLM-5.2", + "provider": { + "builtin:zai-coding-plan": { + "name": "Z.ai - Coding Plan", + "kind": "anthropic", + "options": { + "baseURL": "https://api.z.ai/api/anthropic" + }, + "models": { + "GLM-5.2": { + "limit": { "context": 1000000 }, + "modalities": { + "input": ["text"], + "output": ["text"] + } + } + } + } + }, "plugins": { "enabled": true, "enabledPlugins": {} diff --git a/zcode_tools/marketplaces/nddev-developer/v2-config.template.json b/zcode_tools/marketplaces/nddev-developer/v2-config.template.json index a2b3b56..ddbbacd 100644 --- a/zcode_tools/marketplaces/nddev-developer/v2-config.template.json +++ b/zcode_tools/marketplaces/nddev-developer/v2-config.template.json @@ -1,8 +1,8 @@ { - "_comment": "Disabled-by-default explicit API-key provider definitions for nddev-developer. Z.ai API-key access uses the custom api.z.ai endpoint; enable it only after supplying the key. The verified Z.ai account preference remains OAuth in v2/setting.json and is independent of this entry. API keys are injected from build/.env; credentials.json contains restored account auth tokens and is never templated.", + "_comment": "Disabled-by-default explicit API-key provider for nddev-developer. Its custom identity never reuses a ZCode-owned builtin:* ID, so restored Z.ai OAuth remains app-managed. Enable it only after supplying ZAI_API_KEY through build/.env; credentials.json is restored runtime state and is never templated.", "provider": { - "builtin:zai-coding-plan": { - "name": "Z.ai - Coding Plan", + "custom:zai-api-key": { + "name": "Z.ai - API Key", "kind": "anthropic", "options": { "apiKey": "${ZAI_API_KEY}",