Skills Config Reference: Schema, Allowlists, and Sandbox

Full reference for the skills.* config schema, agent allowlists, workshop settings, and sandbox env var handling. For developers configuring custom skills in OpenClaw.

Read this when

  • Configuring skill loading, install, or gating behavior
  • Setting per-agent skill visibility
  • Adjusting Skill Workshop limits or approval policy

Most skills configuration is defined under skills inside ~/.openclaw/openclaw.json. Which agents can see what is controlled separately through agents.defaults.skills and agents.entries.*.skills.

{
  skills: {
    allowBundled: ["gemini", "peekaboo"],
    load: {
      extraDirs: ["~/Projects/agent-scripts/skills"],
      allowSymlinkTargets: ["~/Projects/manager/skills"],
      watch: true,
    },
    install: {
      preferBrew: true,
      nodeManager: "npm",
      allowUploadedArchives: false,
    },
    workshop: {
      autonomous: { mode: "auto" },
      allowSymlinkTargetWrites: false,
      approvalPolicy: "auto",
      maxPending: 50,
      maxSkillBytes: 40000,
    },
    entries: {
      "image-lab": {
        enabled: true,
        apiKey: { source: "env", provider: "default", id: "GEMINI_API_KEY" },
        env: { GEMINI_API_KEY: "GEMINI_KEY_HERE" },
      },
      peekaboo: { enabled: true },
      sag: { enabled: false },
    },
  },
}

Note

For built-in image generation, go with agents.defaults.mediaModels.image together with the core image_generate tool rather than skills.entries. Skill entries exist only for custom or third-party skill workflows.

Loading (skills.load)

  • skills.load.extraDirs (string[]), Extra skill directories to search, taking the lowest priority (below bundled and plugin skills). Paths get expanded with ~ support.

  • skills.load.allowSymlinkTargets (string[]), Trusted real target directories that symlinked skill folders may point into, even when the symlink sits outside the configured root. This is meant for intentional sibling-repo layouts like <workspace>/skills/manager -> ~/Projects/manager/skills. Keep this list tight, avoid broad roots such as ~ or ~/Projects.

  • skills.load.watch (boolean, default: true), Watch skill folders and refresh the skills snapshot whenever SKILL.md files change. Nested files under grouped skill roots are included.

Install (skills.install)

  • skills.install.preferBrew (boolean, default: true), Favor Homebrew installers when brew is present.

  • skills.install.nodeManager (npm" | "pnpm" | "yarn" | "bun, default: npm), Preferred Node package manager for skill installs. Only skill installs are affected; the OpenClaw CLI and Gateway runtime need Node because the canonical state store relies on node:sqlite. openclaw setup --node-manager and openclaw onboard --node-manager accept npm, pnpm, or bun; for Yarn-backed skill installs, set "yarn" directly in config.

  • skills.install.allowUploadedArchives (boolean, default: false), Permit trusted operator.admin Gateway clients to install private zip archives staged through skills.upload.*. Regular ClawHub installs don't require this setting.

Operator Install Policy (security.installPolicy)

When operators need a trusted local command to approve or block skill and plugin installs using host-specific policy, use security.installPolicy. The policy runs after OpenClaw has staged source material and before the install or update proceeds. It covers ClawHub skills, uploaded skills, Git/local skills, skill dependency installers, and plugin install/update sources.

{
  security: {
    installPolicy: {
      enabled: true,
      // Omit targets to cover every supported target.
      targets: ["skill", "plugin"],
      exec: {
        source: "exec",
        command: "/usr/local/bin/openclaw-install-policy",
        args: ["--json"],
        timeoutMs: 10000,
        noOutputTimeoutMs: 10000,
        maxOutputBytes: 1048576,
        passEnv: ["OPENCLAW_STATE_DIR", "PATH"],
        env: { POLICY_MODE: "strict" },
        trustedDirs: ["/usr/local/bin"],
      },
    },
  },
}
  • security.installPolicy.enabled (boolean, default: false), Turns on operator-owned install policy. When enabled without a valid exec command, installs fail closed.

  • security.installPolicy.targets (("skill" | "plugin")[]), Optional target filter. If omitted, policy applies to every supported target so new installs don't unexpectedly fail open.

  • security.installPolicy.exec.command (string), Absolute path to the trusted policy executable. OpenClaw runs it without a shell and checks the path before use.

  • security.installPolicy.exec.args (string[]), Static arguments passed after command.

  • security.installPolicy.exec.timeoutMs (number, default: 10000), Maximum wall-clock runtime for a single policy decision.

  • security.installPolicy.exec.noOutputTimeoutMs (number, default: timeoutMs), Maximum time without stdout or stderr output before the policy fails closed.

  • security.installPolicy.exec.maxOutputBytes (number, default: 1048576), Maximum combined stdout and stderr bytes accepted from the policy process.

  • security.installPolicy.exec.env (true), "> Literal environment variables provided to the policy process.

  • security.installPolicy.exec.passEnv (string[]), Environment variable names copied from the OpenClaw process into the policy process. Only named variables are passed.

  • security.installPolicy.exec.trustedDirs (string[]), Optional allowlist of directories that may contain the policy executable.

The policy command and interpreter script arguments must be direct regular files with trusted ownership, restricted permissions, and verifiable parent directories. Symlinks and insecure paths are rejected.

The policy receives one JSON object on stdin with protocolVersion: 1, openclawVersion, targetType, targetName, sourcePath, sourcePathKind, optional structured source, structured origin, and request. It must write one JSON object on stdout: { "protocolVersion": 1, "decision": "allow" } or { "protocolVersion": 1, "decision": "block", "reason": "..." }. Non-zero exit, timeout, malformed JSON, missing fields, or unsupported protocol versions fail closed.

OpenClaw does not execute install policy during normal Gateway startup. Installs and updates fail closed when policy is enabled but unavailable. openclaw doctor performs static validation; openclaw doctor --deep executes a synthetic install probe against the configured command.

Bulk updates apply policy per target: a blocked skill or plugin update fails that target without disabling the policy or skipping later targets in the batch.

Example stdin:

{
  "protocolVersion": 1,
  "openclawVersion": "2026.6.1",
  "targetType": "skill",
  "targetName": "weather",
  "sourcePath": "/var/folders/.../openclaw-skill-clawhub/root",
  "sourcePathKind": "directory",
  "source": {
    "kind": "clawhub",
    "authority": "openclaw",
    "mutable": false,
    "network": true
  },
  "origin": {
    "type": "clawhub",
    "registry": "https://clawhub.openclaw.ai",
    "slug": "weather",
    "version": "1.0.0"
  },
  "request": {
    "kind": "skill-install",
    "mode": "install",
    "requestedSpecifier": "clawhub:weather@1.0.0"
  },
  "skill": {
    "installId": "clawhub"
  }
}

Minimal policy command:

#!/usr/bin/env node

let input = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => {
  input += chunk;
});
process.stdin.on("end", () => {
  const request = JSON.parse(input);
  if (request.targetType === "plugin" && request.source?.kind === "local-path") {
    process.stdout.write(
      JSON.stringify({
        protocolVersion: 1,
        decision: "block",
        reason: "local plugin paths are not approved on this host",
      }),
    );
    return;
  }
  process.stdout.write(JSON.stringify({ protocolVersion: 1, decision: "allow" }));
});

Bundled skill allowlist

  • skills.allowBundled (string[]), Optional allowlist scoped exclusively to bundled skills. When present, only bundled skills appearing in the list become eligible. Managed, agent-level, and workspace skills remain untouched.

Per-skill entries (skills.entries)

By default, keys under entries correspond to the skill name. When a skill provides metadata.openclaw.skillKey, that key takes precedence. Hyphenated names should be quoted, since JSON5 permits quoted keys.

  • true, .enabled" type="boolean"> Setting false turns the skill off even if it is bundled or installed. The coding-agent bundled skill requires explicit opt-in: assign it true and verify that one of claude, codex, opencode, or another supported CLI is present and authenticated.

  • true, .apiKey" type='string | { source, provider, id }'> A shortcut for skills that declare metadata.openclaw.primaryEnv. Accepts either a plaintext string or a SecretRef: { source: "env", provider: "default", id: "VAR_NAME" }.

  • true, .env" type="Record<string, string>"> Environment variables supplied for the agent run. Injection happens only when the variable is absent from the process already.

  • true, .config" type="object"> Optional container for arbitrary per-skill configuration fields.

Agent allowlists (agents)

Agent config suits scenarios where you want identical machine/workspace skill roots but distinct visible skill sets per agent.

{
  agents: {
    defaults: {
      skills: ["github", "weather"], // shared baseline
    },
    list: [
      { id: "writer" }, // inherits github, weather
      { id: "docs", skills: ["docs-search"] }, // replaces defaults entirely
      { id: "locked-down", skills: [] }, // no skills
    ],
  },
}
  • agents.defaults.skills (string[]), Shared baseline allowlist that agents inherit unless they specify agents.entries.*.skills. Leave it out entirely to keep skills unrestricted by default.

  • agents.entries.*.skills (string[]), Definitive final skill set for that agent. Explicit lists replace inherited defaults, they never merge. Assign [] to expose no skills for that agent.

Warning

Agent skill allowlists act as a visibility and loading filter for OpenClaw skill discovery, prompts, slash-command discovery, sandbox sync, and skill snapshots. They do not constitute a shell-time authorization boundary. If an agent can run host exec, that shell retains the ability to invoke external clients or read host files visible to the execution user, including MCP client registries like ~/.openclaw/skills/config/mcporter.json. For per-agent MCP isolation, pair skill allowlists with sandbox/OS-user isolation, deny or tightly allowlist host exec, and favor per-agent credentials at the MCP server.

Workshop (skills.workshop)

  • skills.workshop.autonomous.mode (off" | "propose" | "auto, default: auto), off turns off autonomous capture while keeping the durable-instruction suggestion nudge. propose generates pending proposals from corrections and substantial completed work. auto routes the same captures through the standard scanner-gated Workshop apply path. User-prompted skill creation, /learn, and manual history scan function in every mode.

See Self-learning for eligibility, privacy, cost, proposal-only permissions, and troubleshooting.

  • skills.workshop.approvalPolicy (pending" | "auto, default: auto), auto permits agent-initiated apply, reject, or quarantine without an extra approval prompt. pending demands operator approval.

  • skills.workshop.allowSymlinkTargetWrites (boolean, default: false), Allow Skill Workshop apply to write through workspace skill symlinks whose real target is already trusted by skills.load.allowSymlinkTargets. Keep this disabled unless generated proposal applies should alter that shared skill root.

  • skills.workshop.maxPending (number, default: 50), Maximum pending and quarantined proposals held per workspace (allowed range: 1-200).

  • skills.workshop.maxSkillBytes (number, default: 40000), Maximum proposal body size in bytes (allowed range: 1024-200000). Proposal descriptions are separately hard-capped at 160 bytes, since they surface in discovery and listing output.

See Skill Workshop for the proposal lifecycle, CLI commands, agent tool parameters, and Gateway methods this config controls.

Symlinked skill roots

By default, workspace, project-agent, extra-dir, and bundled skill roots serve as containment boundaries. A symlinked skill folder under <workspace>/skills that points outside the root is skipped with a log message.

To permit an intentional symlink layout, declare the trusted target:

{
  skills: {
    load: {
      extraDirs: ["~/Projects/manager/skills"],
      allowSymlinkTargets: ["~/Projects/manager/skills"],
    },
  },
}

With this config, <workspace>/skills/manager -> ~/Projects/manager/skills is accepted after realpath resolution. extraDirs scans the sibling repo directly; allowSymlinkTargets preserves the symlinked path for existing layouts.

Skill Workshop apply does not write through those symlinks by default. To let Workshop apply mutate skills under already-trusted symlink targets, opt in separately:

{
  skills: {
    load: {
      allowSymlinkTargets: ["~/Projects/manager/skills"],
    },
    workshop: {
      allowSymlinkTargetWrites: true,
    },
  },
}

Managed ~/.openclaw/skills and personal ~/.agents/skills directories already accept skill-directory symlinks unconditionally (per-skill SKILL.md containment still applies), so allowSymlinkTargets is only required for workspace, extra-dir, and project-agent (<workspace>/.agents/skills) roots.

Sandboxed skills and env vars

Warning

skills.entries.<skill>.env and apiKey apply to host runs only. Inside a sandbox they have no effect: a skill that depends on GEMINI_API_KEY will fail with apiKey not configured unless the sandbox receives the variable separately.

Pass secrets into a Docker sandbox with:

{
  agents: {
    defaults: {
      sandbox: {
        docker: {
          env: { GEMINI_API_KEY: "your-key-here" },
        },
      },
    },
  },
}

Note

If you have access to the Docker daemon, sandbox.docker.env values can be read through Docker metadata. When such exposure is unacceptable, consider a mounted secret file, a custom image, or another delivery method.

Loading order reminder

workspace/skills      (highest)
workspace/.agents/skills
~/.agents/skills
~/.openclaw/skills
bundled skills
skills.load.extraDirs (lowest)

With the watcher active, edits to skills and config apply at the start of the next new session; otherwise, they take effect on the next agent turn once the watcher notices the change.

  • Skills reference, Explains what skills are, their loading order, gating, and the SKILL.md format.

  • Creating skills, How to write custom workspace skills.

  • Skill Workshop, A queue for proposals of agent-drafted skills.

  • Self-learning, Conservative, opt-in suggestions drawn from completed work.

  • Slash commands, The built-in slash-command catalog and chat directives.

1,799 words · updated Aug 8, 2026