openclaw-json-editing
Advanced JSON editing for OpenClaw configuration files, tools, and data structures. Handles JSON5 configs, schema validation, merge patching, env var substitution, and type-safe modifications.
What this skill does
# OpenClaw JSON Editing
Expert guidance for editing JSON in the OpenClaw ecosystem. OpenClaw uses **JSON5** for configuration (allows comments, trailing commas), has sophisticated config merging, and validates with **Zod schemas**.
## Quick Reference
| Task | Command/Pattern |
|------|-----------------|
| Validate config | `openclaw config validate` |
| Apply config patch | `openclaw config patch <file.json>` |
| Safe JSON parse | Use `safeParseJson()` wrapper |
| Check config location | `openclaw config path` |
| Pretty print | `JSON.stringify(data, null, 2)` |
## OpenClaw JSON5 Config
OpenClaw config files use **JSON5** (not strict JSON):
```json5
{
// Single-line comments are allowed
"gateway": {
"mode": "http", // Trailing commas are allowed
},
/* Multi-line comments
are also supported */
"agents": {
"main": {
"model": "anthropic/claude-opus-4-6",
},
},
}
```
### Key Differences from JSON
- **Comments**: Single-line (`//`) and multi-line (`/* */`)
- **Trailing commas**: Allowed in arrays and objects
- **Unquoted keys**: `{ key: "value" }` is valid
- **Single quotes**: `'string'` is valid
### Config File Locations
| Type | Path |
|------|------|
| User config | `~/.openclaw/config.json` |
| Project config | `./openclaw.config.json` |
| Agent config | `~/.openclaw/agents/<id>/config.json` |
| Session store | `~/.openclaw/sessions/` |
| State dir | `~/.openclaw/` (or `$OPENCLAW_STATE_DIR`) |
## Safe JSON Operations
### Reading Config Files
OpenClaw uses `JSON5.parse()` for configs and safe wrappers:
```typescript
// OpenClaw's safeParseJson pattern
function safeParseJson<T>(raw: string): T | null {
try {
return JSON.parse(raw) as T;
} catch {
return null;
}
}
// For OpenClaw configs, use JSON5
import JSON5 from "json5";
function loadConfigFile(path: string): unknown {
try {
const raw = fs.readFileSync(path, "utf8");
return JSON5.parse(raw); // Allows comments, trailing commas
} catch {
return undefined;
}
}
```
### Writing Config Files
OpenClaw writes with specific formatting and permissions:
```typescript
function saveJsonFile(pathname: string, data: unknown) {
const dir = path.dirname(pathname);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
}
// 2-space indentation, trailing newline
fs.writeFileSync(pathname, `${JSON.stringify(data, null, 2)}\n`, "utf8");
fs.chmodSync(pathname, 0o600); // User read/write only
}
```
### Type Guards
Always validate before assuming structure:
```typescript
// OpenClaw's isPlainObject (strictest)
function isPlainObject(value: unknown): value is Record<string, unknown> {
return (
typeof value === "object" &&
value !== null &&
!Array.isArray(value) &&
Object.prototype.toString.call(value) === "[object Object]"
);
}
// Less strict version
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
```
## Config Merging & Patching
### Merge Patch (RFC 7386)
OpenClaw uses merge patching for config updates:
```typescript
// Apply a merge patch to base config
function applyMergePatch(base: unknown, patch: unknown): unknown {
if (!isPlainObject(patch)) {
return patch;
}
const result: Record<string, unknown> = isPlainObject(base) ? { ...base } : {};
for (const [key, value] of Object.entries(patch)) {
if (value === null) {
delete result[key]; // null = delete key
continue;
}
if (isPlainObject(value)) {
const baseValue = result[key];
result[key] = applyMergePatch(
isPlainObject(baseValue) ? baseValue : {},
value
);
continue;
}
result[key] = value;
}
return result;
}
```
### Usage Examples
```javascript
// Add/update nested field
const patch = {
agents: {
main: {
model: "anthropic/claude-opus-4-6"
}
}
};
// Delete a field (set to null)
const deletePatch = {
agents: {
main: {
temperature: null // Removes temperature
}
}
};
// Replace entire section
const replacePatch = {
channels: {
telegram: null, // Delete old
discord: { token: "new-token" } // Add new
}
};
```
## Environment Variable Substitution
OpenClaw configs support `${VAR}` and `${VAR:-default}` syntax:
```json5
{
"auth": {
"profiles": {
"openai": {
"apiKey": "${OPENAI_API_KEY}" // Substituted at load time
},
"anthropic": {
"apiKey": "${ANTHROPIC_API_KEY:-fallback-key}"
}
}
}
}
```
### Handling in Code
```typescript
// Check if string contains env var reference
function containsEnvVarReference(value: string): boolean {
return /\$\{[^}]+\}/.test(value);
}
// Collect all env var paths in an object
function collectEnvRefPaths(
value: unknown,
path: string,
output: Map<string, string>
): void {
if (typeof value === "string") {
if (containsEnvVarReference(value)) {
output.set(path, value);
}
return;
}
if (Array.isArray(value)) {
value.forEach((item, index) => {
collectEnvRefPaths(item, `${path}[${index}]`, output);
});
return;
}
if (isPlainObject(value)) {
for (const [key, child] of Object.entries(value)) {
const childPath = path ? `${path}.${key}` : key;
collectEnvRefPaths(child, childPath, output);
}
}
}
```
## Schema Validation
### Zod Schema Pattern
OpenClaw uses Zod for runtime validation:
```typescript
import { z } from "zod";
// Define schema
const AgentConfigSchema = z.object({
model: z.string().optional(),
temperature: z.number().min(0).max(2).optional(),
maxTokens: z.number().positive().optional(),
enabled: z.boolean().default(true),
});
// Validate
type AgentConfig = z.infer<typeof AgentConfigSchema>;
function validateConfig(data: unknown): AgentConfig {
return AgentConfigSchema.parse(data);
}
// Safe validation
function safeValidateConfig(data: unknown): AgentConfig | null {
const result = AgentConfigSchema.safeParse(data);
return result.success ? result.data : null;
}
```
### Common OpenClaw Schema Types
```typescript
// Model reference: "provider/model-name"
const ModelRefSchema = z.string().regex(/^[a-z0-9-]+\/[a-z0-9-]+$/i);
// Channel ID
const ChannelIdSchema = z.enum([
"telegram", "discord", "slack", "whatsapp",
"signal", "imessage", "irc", "web"
]);
// Duration string: "30s", "5m", "1h"
const DurationSchema = z.string().regex(/^\d+[smhd]$/);
```
## Config Includes
OpenClaw supports config file includes:
```json5
{
"include": [
"./base-config.json",
"~/.openclaw/shared-channels.json"
],
"agents": {
// Local overrides
}
}
```
### Processing Order
1. Load included files (recursive, depth-limited)
2. Merge in order (later files override earlier)
3. Apply env var substitution
4. Validate against schema
5. Apply runtime overrides
## jq Patterns for OpenClaw
### Common Operations
```bash
# Pretty print OpenClaw config
jq . ~/.openclaw/config.json
# Get gateway mode
jq '.gateway.mode' ~/.openclaw/config.json
# List all agent IDs
jq '.agents | keys[]' ~/.openclaw/config.json
# Find agent using specific model
jq '.agents | to_entries[] | select(.value.model == "anthropic/claude-opus-4-6") | .key' ~/.openclaw/config.json
# Get all channel types
jq '.channels | keys[]' ~/.openclaw/config.json
# Check if Telegram is configured
jq '.channels.telegram != null' ~/.openclaw/config.json
# Extract all model references
jq '.. | objects | select(has("model")) | .model' ~/.openclaw/config.json
# Merge patch using jq
jq '.agents.main.model = "anthropic/claude-opus-4-6"' ~/.openclaw/config.json > tmp.json \
&& mv tmp.json ~/.openclaw/config.json
```
### Advanced jq
```bash
# Deep search for all API keys (for audit)
jq '.. | objects | .apiKey? // .token? // .password? | select(.)' ~/.openclaw/config.json
# Collect all environment variable references
jq -r '.. | strings | select(conRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.