Skip to content

Config Path Ops (openclaw path)

Config Path Ops (openclaw path)

OpenClaw state is spread across human-edited markdown, commented JSONC config, append-only JSONL logs, and YAML specs. Scripts, hooks, and agents constantly need one small value from those files — a plugin setting, a frontmatter key, a log field. The usual tools (jq + tempfile + mv, ad-hoc sed, a Python json.load/json.dump round-trip) either can’t address the value cleanly or destroy the file’s comments and formatting on write.

openclaw path gives every such value a stable address — oc://… — that you can validate, read, search, dry-run, and write from the terminal, preserving the rest of the file. It’s the recommended way to make small, surgical edits to openclaw.json and other workspace files.

Enable it

path comes from the bundled optional oc-path plugin:

Terminal window
openclaw plugins enable oc-path

The oc:// scheme

oc://FILE/SECTION/ITEM/FIELD?session=SCOPE

Slots nest left-to-right: field requires item, item requires section. The adapter is chosen from the file extension — .md, .jsonc, .json, .jsonl, .yaml, .yml, .lobster — and the slots resolve against that kind’s structure (markdown headings/items, JSON object keys/array indexes, JSONL line records, YAML map/sequence nodes).

Segment features:

  • Quoted segments"a/b.c" survives / and . separators. The file slot is quote-aware too: oc://"skills/email-drafter"/Tools/$last.
  • Predicates[k=v], [k!=v], [k<v], [k<=v], [k>v], [k>=v] (numeric comparisons require both sides to coerce to numbers).
  • Unions{a,b,c} matches any alternative.
  • Wildcards* (one sub-segment) and ** (recursive). find accepts them; resolve and set reject them as ambiguous.
  • Ordinals$last, $first address array/list positions.

Subcommands

SubcommandPurpose
resolve <oc-path>Print the concrete value at a path (or “not found”).
find <pattern>Enumerate matches for a wildcard / union / predicate path.
set <oc-path> <value>Write a leaf at a concrete path. Supports --dry-run.
validate <oc-path>Parse only; print the file / section / item / field breakdown.
emit <file>Round-trip a file through parse + emit (byte-fidelity diagnostic).

Global flags

FlagPurpose
--cwd <dir>Resolve the file slot against this directory (default: cwd).
--file <path>Override the file slot’s resolved path — use for absolute access.
--dry-run(set only) print the bytes that would be written, without writing.
--diff(with set --dry-run) print a unified diff instead of full bytes.
--jsonForce JSON output (default when stdout isn’t a TTY).
--humanForce human output (default when stdout is a TTY).

Examples

Read one value:

Terminal window
openclaw path resolve 'oc://openclaw.json/meta/lastTouchedVersion'

Preview a write before touching disk (always do this first on live config):

Terminal window
openclaw path set 'oc://openclaw.json/plugins/entries/policy/enabled' 'true' --dry-run --diff

Append to an array using an insertion marker:

Terminal window
openclaw path set 'oc://openclaw.json/plugins/allow/$append' 'policy'

Find records in an append-only JSONL log:

Terminal window
openclaw path find 'oc://session.jsonl/[event=tool_call]/name'

Address a markdown instruction by section + item instead of line number:

Terminal window
openclaw path resolve 'oc://AGENTS.md/runtime-safety/openclaw-gateway'

Resolving the file slot

The file slot resolves against --cwd (default: the current directory), not necessarily ~/.openclaw. To target the live gateway config from anywhere, pass an absolute override:

Terminal window
openclaw path resolve 'oc://openclaw.json/meta/lastTouchedVersion' \
--file ~/.openclaw/openclaw.json
# or run the command from ~/.openclaw, or pass --cwd ~/.openclaw

When to use it — and when not to

Use openclaw path for small, addressable edits where a repeatable terminal command beats another bespoke parser, and especially when the target file has comments you must preserve (JSONC config, markdown).

Reach for the owner command or a full rewrite instead when:

  • You’re doing a rich migration — restructuring many keys, reshaping a subtree, creating a whole new section. A json.load/json.dump pass (or the owning plugin’s command) is clearer there.
  • The value isn’t a simple leaf or array insertion.

Lobster’s rule of thumb (from its AGENTS.md): 1–5 scalar leaves or array appends → openclaw path set; structural migrations (≥10 keys, subtree reshape) → a scripted JSON rewrite. The old jq + tempfile + mv pattern on JSONC is retired — it strips comments; the substrate preserves them.

Caveats

  • Preview writes with --dry-run --diff before applying to live config — the gateway reads these files continuously.
  • Deeply nested object values: the addressing favors leaves and array inserts; very deep paths and writing whole object values are weaker than scalar edits. For those, prefer a scripted rewrite.
  • The gateway must be able to load the plugin. If openclaw path reports “does not know the command path”, the oc-path plugin isn’t enabled (or the gateway is down because the config is currently invalid — fix the config first, then use path).

Lobster’s wrappers

Lobster wraps the two common verbs in plugins/lobster-ops/scripts/lib.sh as oc_path_get / oc_path_set, so ops skills can do narrow config edits without re-deriving the addressing each time.

See also