config:set, config:get & config:unset
CLI commands for safely reading, modifying, and deleting keys in workspace.yaml with schema validation. Keys must be fully qualified from the workspace root (e.g., software_delivery.gates.minCoverage, not gates.minCoverage). config:set supports complete JSON replacement of the kernel lanes array and security object; config:unset validates deletions under security and policies before writing.
Key Routing
Section titled “Key Routing”When you provide a key, config:set, config:get, and config:unset route it based on its first segment:
config:set and config:unset refuse any dotpath containing __proto__, constructor, or
prototype before changing configuration. Unknown root keys are refused with the valid writable
roots listed in the error. Every writable root needs an explicit validated handler.
| First segment matches | Behavior | Example key |
|---|---|---|
| Writable subkey | Writes/reads a validated subkey at the workspace root | control_plane.sync_interval |
| Complete kernel root | config:set replaces the root from strict JSON; lanes retains managed reads, security is readable, and unset protects required roots/fields | lanes, security |
| Pack config key | Writes/reads under the pack’s config block, validated against the pack schema | software_delivery.gates.minCoverage |
| Governed subkey | Writes or removes a validated policy subkey; unset may remove optional security keys | policies.* |
| Managed root key | Error with guidance: “use <command> instead” | packs, id, name |
| Unknown key | Error with did-you-mean suggestion if possible | gates.minCoverage |
Writable subkeys
Section titled “Writable subkeys”These roots support validated subkey writes:
control_plane— Control plane connection and sync settingspolicies— Workspace policy entries
Kernel lanes and security use complete-root JSON replacement through config:set, not dotted subkey writes.
Pack config keys
Section titled “Pack config keys”Pack config keys are declared by domain packs in their manifest.yaml via the config_key field. For example, the Software Delivery pack declares config_key: software_delivery, making its schema-supported software_delivery.* paths writable via config:set. The kernel is domain-agnostic; Software Delivery is one pack, and other packs declare their own roots.
For an installed pack other than Software Delivery, config:set replaces its config_key as a whole section only. The value must be a complete object supplied with --json-value and validated against the pack’s config_schema. A pack that declares no config_schema rejects every write to its root. Software Delivery keeps nested-key writes such as software_delivery.gates.conditional_commands.
Writes to pack config keys are validated against the pack’s config schema if one is provided. Pack validation uses the kernel’s bounded JSON-Schema-to-Zod subset, not full JSON Schema conformance. Unknown assertion keywords, constraint intersections, and exact oneOf semantics are not guaranteed.
Governed and managed roots
Section titled “Governed and managed roots”Use config:set to replace the complete kernel lanes array or security
object. Supply explicit operator-chosen scopes; no grants are inferred. These
roots reject partial dotted writes and unknown nested scope keys. The write is
schema-validated before the micro-worktree starts, revalidated in the worktree,
and read back after the surgical write. Packs and software_delivery.lanes
remain untouched. For example:
Partial lanes.* and security.* writes are refused. lane:edit keeps its
existing behavior, including edits to Software Delivery lane definitions.
config:unset cannot remove required kernel roots or required schema fields.
The root-level id, name, and packs remain managed. Use lumenflow:init
to establish missing or new identity and pack:install for pack pins.
Initialization preserves existing id and name; it does not rename a
workspace. config:get continues to refuse managed lanes reads.
Did-you-mean suggestions
Section titled “Did-you-mean suggestions”If you use an unqualified key that matches a known pack sub-key, the error includes a suggestion:
config:set
Section titled “config:set”Safely updates a value in workspace.yaml.
Arguments
Section titled “Arguments”| Flag | Required | Description |
|---|---|---|
--key | Yes | Fully qualified config key in dot notation (e.g., software_delivery.gates.minCoverage) |
--value | One value flag | Scalar value or comma-separated array append |
--json-value | One value flag | Structured JSON value, still schema validated |
--help | No | Show usage information |
Examples
Section titled “Examples”Each command replaces the whole root. Supply only the scopes the workspace operator intends; the writer does not infer permissions. Partial dotted writes are rejected.
Comma-separated values are appended to existing array fields.
Value Coercion
Section titled “Value Coercion”config:set requires exactly one of --value and --json-value. The JSON flag parses a structured value and does not bypass schema validation. --value coerces scalar strings and comma-separated array values:
| Input Value | Existing Type | Coerced To |
|---|---|---|
"true" | any | true (boolean) |
"false" | any | false (boolean) |
"42" | number | 42 (number) |
"A,B,C" | array | append A, B, C |
"hello" | string | "hello" (string) |
Error Handling
Section titled “Error Handling”If the value fails Zod schema validation, the command exits with a descriptive error and no changes are written. Complete kernel root values are validated before micro-worktree creation and read back after the write:
If you use an unqualified key, you get a routing error:
If you try to write a managed key:
config:get
Section titled “config:get”Reads and displays raw values from writable or declared pack roots in workspace.yaml. It uses the same routing logic as config:set and refuses managed roots (id, name, packs, lanes) and unknown roots. Reading does not validate a write.
Arguments
Section titled “Arguments”| Flag | Required | Description |
|---|---|---|
--key | Yes | Fully qualified config key in dot notation (e.g., software_delivery.methodology.testing) |
--help | No | Show usage information |
Examples
Section titled “Examples”config:unset
Section titled “config:unset”Safely deletes a key from workspace.yaml. The delete inverse of config:set — use it to remove stale config blocks (e.g., a decommissioned agent client) without hand-editing YAML.
Arguments
Section titled “Arguments”| Flag | Required | Description |
|---|---|---|
--key | Yes | Fully qualified config key in dot notation (e.g., software_delivery.agents.clients.gemini-cli) |
--help | No | Show usage information |
Examples
Section titled “Examples”Behavior
Section titled “Behavior”- Routes the key with the same prefix rules as
config:set, including validatedsecurityandpoliciessubkeys - Errors if the key does not exist (nothing to unset)
- Deletes the key, then validates the complete affected object against its owning schema
- If validation passes, writes through the governed configuration writer
Unknown-key detection is deliberately not applied to the deleted path: removing a key the schema no longer recognizes is exactly what config:unset is for (stale config blocks). Only the complete remaining affected object must validate; unrelated retired keys do not block sequential cleanup. Surgical writes preserve non-target comments, ordering, and quoting, and rejected deletions leave the file unchanged.
Limitations: setting a value changes only the edited span, so it refuses, with a CONFIG_ERROR and no change to the file, any path through an alias, a map with a << merge key, or an anchored value. It also refuses a path that runs through a non-null scalar, a sequence index that does not exist or would need inserting, a sequence item that would change kind, and any edit that would not parse back to the requested value. Duplicate keys were already refused. Deleting a key still re-serializes the whole file, so byte-level details outside the deleted key are not guaranteed to survive a delete. A flow map or flow sequence (empty {} and [] included) that is the target or sits on the path is converted to block style, only that one node, and the edit then applies; comments inside it are not kept, and one holding an alias or an anchor is refused. config:set and lane:edit both use this writer.
Error Handling
Section titled “Error Handling”Deleting an entire pack config block (software_delivery), control_plane, or required kernel root (lanes or security) is refused. Deletions that would leave the remaining config schema-invalid (including removal of required security scopes) are rejected before commit.
Common Dotpaths
Section titled “Common Dotpaths”Software Delivery pack (software_delivery.*)
Section titled “Software Delivery pack (software_delivery.*)”| Dotpath | Type | Values |
|---|---|---|
software_delivery.methodology.testing | enum | tdd, test-after, none |
software_delivery.methodology.architecture | enum | hexagonal, layered, none |
software_delivery.gates.minCoverage | number | 0-100 |
software_delivery.gates.enableCoverage | boolean | true, false |
software_delivery.gates.maxEslintWarnings | number | Non-negative integer |
software_delivery.git.requireRemote | boolean | true, false |
software_delivery.git.declaresClaimRefProtection | boolean | true, false |
software_delivery.cleanup.trigger | enum | on_done, on_init, manual |
software_delivery.external_work_items.* | object | Provider close-out/readback adapters and audit settings |
software_delivery.agents.methodology.principles | string[] | Array of methodology names |
Kernel root keys
Section titled “Kernel root keys”| Dotpath | Type | Description |
|---|---|---|
control_plane.sync_interval | number | Seconds between control plane syncs |
control_plane.endpoint | string | Control plane API URL |
memory_namespace and event_namespace are retired root keys. Remove them
from existing workspace.yaml files; they cannot be re-added through current config routes. Run the native cleanup sequentially before rerunning init:
The exact namespace-root deletion exception applies only when no pinned pack declares that root. Pack-owned roots retain normal pack routing and validation. Initialization does not automatically clean legacy inputs.
security.network_default is also retired: configure network posture on the
relevant entries in security.allowed_scopes instead.
control_plane.policy_mode is temporarily accepted as a deprecated input for
backward compatibility. It is ignored when the runtime parses configuration,
and lumenflow:doctor warns while the key remains. Remove it with
pnpm config:unset --key control_plane.policy_mode. It will be removed after
at least one release. A provided value is enum validated and stripped from effective workspace configuration. The programmatic SDK Mock policy mode and Cloud database/wire contracts are unchanged.