clawchef
v0.1.14
Published
Recipe-driven OpenClaw environment orchestrator
Readme
clawchef
Recipe-driven OpenClaw environment orchestrator.
What it does
- Parses a YAML recipe.
- Accepts recipe input from local file/dir/archive and HTTP URL/archive.
- Resolves
${var}parameters from--var, environment, and defaults. - Auto-loads environment variables from
.envin the current working directory. --verboseprints step-level debug logs including executed commands and operation timing.- Supports loading env vars from a custom
.envpath/URL via--dotenv-ref. - Requires secrets to be injected via
--var/CLAWCHEF_VAR_*(no inline secrets in recipe). - Prepares OpenClaw version (install or reuse).
- When installed OpenClaw version mismatches recipe version, prompts: ignore / abort / force reinstall (silent mode auto-picks force reinstall).
- Supports scoped execution via
--scope full|stateful|files|workspace. fullscope runs factory reset first (with confirmation prompt unless-s/--silentis used).- Factory reset includes removing local
~/.openclawdirectory. - If
openclawis missing, auto-installs the recipe version and skips factory reset. - Starts OpenClaw gateway after each recipe execution based on
--gateway-mode. - Creates workspaces and agents (default workspace path:
~/.openclaw/workspace-<workspace-name>). - Supports workspace-level assets copy via
workspaces[].assets. - Materializes files into target workspaces.
- Supports OpenClaw root-level assets/files via
openclaw.root(default root path:~/.openclaw). - Installs skills.
- Supports plugin preinstall via
openclaw.plugins[]and runtime--pluginflags. - Configures channels with
openclaw channels add. - Supports interactive channel login at the end of execution (
channels[].login: true) for channels that expose login. - Supports remote HTTP orchestration via runtime flags (
--provider remote) when OpenClaw is reachable via API. - Writes preset conversation messages.
- Runs agent and validates reply output.
Install and run
npm i -g clawchef
clawchef cook recipes/sample.yamlRun recipe from URL:
clawchef cook https://example.com/recipes/sample.yaml --provider remoteRun with custom env file (local path or HTTP URL):
clawchef cook recipes/sample.yaml --dotenv-ref ./.env.staging
clawchef cook recipes/sample.yaml --dotenv-ref https://example.com/envs/staging.envRun recipe from GitHub repository root (recipe.yaml at repo root):
clawchef cook https://github.com/renorzr/loom-plus-recipeRun recipe from archive (default recipe.yaml):
clawchef cook ./bundle.tgz --provider mockRun specific recipe in directory or archive:
clawchef cook ./recipes-pack:team/recipe-prod.yaml --provider remote
clawchef cook https://example.com/recipes-pack.zip:team/recipe-prod.yaml --provider remoteDev mode:
clawchef cook recipes/sample.yaml --verboseRun sample with mock provider:
clawchef cook recipes/sample.yaml --provider mockRun content_from sample:
clawchef cook recipes/content-from-sample.yaml --provider mockSkip reset confirmation prompt:
clawchef cook recipes/sample.yaml -sControl gateway startup mode:
clawchef cook recipes/sample.yaml --gateway-mode service
clawchef cook recipes/sample.yaml --gateway-mode run
clawchef cook recipes/sample.yaml --gateway-mode noneWarning: -s/--silent suppresses the factory-reset confirmation and auto-chooses force reinstall on version mismatch.
Use it only in CI/non-interactive flows where destructive reset behavior is expected.
Keep existing OpenClaw state (skip reset and keep current version on mismatch):
clawchef cook recipes/sample.yaml --scope statefulSync only files and assets (openclaw.root.assets/files + workspaces[].assets/files) without touching version/reset/workspace/agent/channel/skills/conversations/gateway:
clawchef cook recipes/sample.yaml --scope filesLimit files-scope changes to relative paths only:
clawchef cook recipes/sample.yaml --scope files --file "README.md"
clawchef cook recipes/sample.yaml --scope files --file "src/**" --file "docs/*.md"
clawchef cook recipes/sample.yaml --scope files --file "workspace-product-designer/**"--file is repeatable and only works with --scope files. Patterns can match any of:
- file relative path (for example
README.md,src/**) - workspace-prefixed path (for example
product-designer/**) - default workspace-dir-prefixed path (for example
workspace-product-designer/**) - root-prefixed path (
root/**) foropenclaw.root.assets/files
Update only one workspace:
clawchef cook recipes/sample.yaml --scope workspace --workspace workspace-meetingFrom-zero OpenClaw bootstrap (recommended):
CLAWCHEF_VAR_LLM_API_KEY=sk-... clawchef cook recipes/openclaw-from-zero.yaml --verboseTelegram channel setup only:
CLAWCHEF_VAR_TELEGRAM_BOT_TOKEN=123456:abc... clawchef cook recipes/openclaw-telegram.yamlTelegram mock channel setup (for tests):
CLAWCHEF_VAR_TELEGRAM_MOCK_API_KEY=test-key clawchef cook recipes/openclaw-telegram-mock.yamlInstall plugin only for this run:
clawchef cook recipes/openclaw-telegram-mock.yaml --plugin openclaw-telegram-mock-channelRemote HTTP orchestration:
CLAWCHEF_REMOTE_BASE_URL=https://remote-openclaw.example.com \
CLAWCHEF_REMOTE_API_KEY=secret-token \
clawchef cook recipes/openclaw-remote-http.yaml --provider remote --verboseValidate recipe structure only:
clawchef validate recipes/sample.yamlValidate recipe from URL:
clawchef validate https://example.com/recipes/sample.yamlValidate recipe in archive:
clawchef validate ./bundle.zip
clawchef validate ./bundle.zip:custom/recipe.yamlCreate a new recipe project scaffold:
clawchef scaffold
clawchef scaffold ./my-recipe-project
clawchef scaffold ./my-recipe-project --name meetingbotscaffold prompts for project name (default: target directory name).
Scaffold output:
package.jsonwithtelegram-api-mock-serverindevDependenciesrecipe.yamlwithtelegram-mockchannel, plugin preinstall, andworkspaces[].assetsassets/{AGENTS.md,IDENTITY.md,SOUL.md,TOOLS.md}assets/scripts/scheduling.mjstest/recipe-smoke.test.mjs
By default scaffold only writes files; it does not run npm install.
Node.js API
You can call clawchef directly from Node.js (without invoking CLI commands).
import { cook, scaffold, validate } from "clawchef";
await validate("recipes/sample.yaml");
await cook("recipes/sample.yaml", {
provider: "command",
silent: true,
vars: {
llm_api_key: process.env.OPENAI_API_KEY ?? "",
},
});
await scaffold("./my-recipe-project", {
projectName: "my-recipe-project",
});cook() options:
vars: template variables (Record<string, string>)plugins: plugin npm specs to preinstall for this run (string[])scope:full | files | workspace(default:full)workspaceName: required whenscope: "workspace"gatewayMode:service | run | none(default:service)provider:command | remote | mockremote: remote provider config (same fields as CLI remote flags)envFile: custom env file path/URL; when set, default cwd.envloading is skippeddryRun,allowMissing,verbosesilent(default:truein Node API)loadDotEnvFromCwd(default:true)
Node API silent: true has the same risk as CLI -s: no reset confirmation and force reinstall on version mismatch.
Set silent: false when you want an interactive safety prompt.
Notes:
validate()throws on invalid recipe.cook()throws on runtime/configuration errors.scaffold()createspackage.json,recipe.yaml,assets/, andtest/.
Variable precedence
--var key=valueCLAWCHEF_VAR_<KEY_IN_UPPERCASE>params.<key>.default
If params.<key>.required: true and no value is found, run fails.
If .env exists in the directory where clawchef is executed, it is loaded before recipe parsing.
If --dotenv-ref (or Node API envFile) is provided, only that env source is loaded.
Recipe reference formats
cook and validate accept:
path/to/recipe.yamlpath/to/dir(loadspath/to/dir/recipe.yaml)path/to/archive.zip(loadsrecipe.yamlfrom extracted archive)path/to/dir:custom/recipe.yamlpath/to/archive.tgz:custom/recipe.yamlhttps://host/recipe.yamlhttps://host/archive.zip(loadsrecipe.yamlfrom archive)https://host/archive.zip:custom/recipe.yamlhttps://github.com/<owner>/<repo>(loadsrecipe.yamlfrom repo root)
Supported archives: .zip, .tar, .tar.gz, .tgz.
OpenClaw provider
Provider is selected at runtime when running cook:
--provider command(default)--provider remote--provider mock
mock provider is useful for local testing of orchestration and output checks.
Remote HTTP provider
Use --provider remote when clawchef cannot run commands on the target machine and must drive configuration via an HTTP endpoint.
Required runtime config:
--remote-base-urlorCLAWCHEF_REMOTE_BASE_URL
Optional runtime config:
--remote-api-keyorCLAWCHEF_REMOTE_API_KEY--remote-api-headerorCLAWCHEF_REMOTE_API_HEADER(default:Authorization)--remote-api-schemeorCLAWCHEF_REMOTE_API_SCHEME(default:Bearer; set empty string to send raw key)--remote-timeout-msorCLAWCHEF_REMOTE_TIMEOUT_MS(default:60000)--remote-operation-pathorCLAWCHEF_REMOTE_OPERATION_PATH(default:/v1/clawchef/operation)
Request payload format (POST):
{
"operation": "create_workspace",
"recipe_version": "2026.2.9",
"payload": {
"workspace": {
"name": "demo",
"path": "/home/runner/.openclaw/workspace-demo"
}
}
}Expected response format:
{
"ok": true,
"message": "workspace created",
"output": "optional agent output",
"installed_this_run": false
}Supported operation values sent by clawchef:
ensure_version,factory_reset,start_gatewayinstall_plugincreate_workspace,create_agent,materialize_file,install_skillconfigure_channel,bind_channel_agent,login_channelrun_agent
For start_gateway, clawchef sends { mode: "service" | "run" } in payload when gateway mode is enabled.
For run_agent, clawchef expects output in response for assertions.
command provider now defaults to the current OpenClaw CLI shape (openclaw 2026.x), including:
- version check:
openclaw --version - reset:
openclaw reset --scope full --yes --non-interactive - workspace prep:
openclaw onboard --non-interactive --accept-risk --mode local --flow quickstart --auth-choice skip --skip-channels --skip-skills --skip-health --skip-ui --skip-daemon --workspace <path> - agent create:
openclaw agents add <name> --workspace <path> --model <model> --non-interactive --json - run turn:
openclaw agent --local --agent <name> --message <prompt> --json
Bootstrap config
You can provide OpenClaw onboarding and auth parameters under openclaw.bootstrap.
This is used by default workspace creation unless openclaw.commands.create_workspace is explicitly overridden.
Supported fields include:
- onboarding:
mode,flow,non_interactive,accept_risk,reset - setup toggles:
skip_channels,skip_skills,skip_health,skip_ui,skip_daemon,install_daemon - auth/provider:
auth_choice,llm_api_key,token,token_provider,token_profile_id
Plugin preinstall
Use openclaw.plugins to preinstall plugin packages before workspace/channel setup.
Example:
openclaw:
version: "2026.2.9"
plugins:
- "openclaw-telegram-mock-channel"
- "@scope/[email protected]"When openclaw.bootstrap contains llm_api_key, clawchef maps it to the provider-specific runtime env by auth_choice for openclaw agent --local.
For command provider, default command templates are:
use_version:${bin} --versioninstall_version:npm install -g openclaw@${version}uninstall_version:npm uninstall -g openclawinstall_plugin:${bin} plugins install ${plugin_spec_q}factory_reset:${bin} reset --scope full --yes --non-interactivestart_gateway:${bin} gateway startrun_gateway:${bin} gateway runbind_channel_agent: built-inopenclaw config get/set bindingsupsert (override withopenclaw.commands.bind_channel_agent)login_channel:${bin} channels login --channel ${channel_q}${account_arg}create_workspace: generated fromopenclaw.bootstrap(override withopenclaw.commands.create_workspace)create_agent:${bin} agents add ${agent} --workspace ${workspace_path} --model ${model} --non-interactive --jsoninstall_skill:${bin} skills checksend_message:true(messages are staged internally for prompt assembly)run_agent:${bin} agent --local --agent ${agent} --message ${prompt_q} --json
You can override any command under openclaw.commands in recipe.
By default, clawchef does not auto-run openclaw plugins enable <channel> during channel configuration.
If you need custom enable behavior, set openclaw.commands.enable_plugin explicitly.
Channels
Use channels[] to configure accounts via openclaw channels add.
If login: true is set, clawchef runs channel login at the end of cook (after gateway start).
Telegram does not support openclaw channels login; do not set login for channel: "telegram".
Example:
channels:
- channel: "telegram"
token: "${telegram_bot_token}"
account: "default"
agent: "main"
group_policy: "allowlist"
- channel: "telegram"
token: "${alerts_bot_token}"
account: "alerts"
agent: "alerts"
- channel: "slack"
bot_token: "${slack_bot_token}"
app_token: "${slack_app_token}"
name: "team-workspace"
- channel: "discord"
token_file: "${discord_token_file}"
extra_flags:
webhook_path: "/discord/webhook"Supported common fields:
- required:
channel - optional:
account,agent,group_policy,name,token,token_file,use_env,bot_token,access_token,app_token,webhook_url,webhook_path,signal_number,password,login,login_mode,login_account - advanced passthrough:
extra_flags(snake_casekeys become--kebab-caseCLI flags)
channels[].agent currently supports channel: "telegram" only.
If agent is set and account is omitted, clawchef defaults account to the same value as agent.
channels[].group_policy currently supports channel: "telegram" only and is applied after channels add via openclaw config set so it is not overwritten by add-flow writes.
If channel: "telegram" has token: "" or bot_token: "", clawchef skips that telegram account and does not run channel add/bind.
OpenClaw config patch
Use openclaw.config_patch to apply a deep config patch to active OpenClaw config (same target used by openclaw config set).
Merge behavior:
- objects: merged recursively by setting nested keys
- arrays: replaced as a whole
- scalars: replaced
Applied during cook after channel setup and before gateway start. Not applied in --scope files.
openclaw:
version: "2026.3.2"
config_patch:
channels:
telegram:
accounts:
frontend-dev:
capabilities:
inlineButtons: "all"
groups:
"*":
requireMention: false
enabled: true
actions:
sendMessage: trueWorkspace path behavior
workspaces[].pathis optional.- If omitted, clawchef uses
~/.openclaw/workspace-<workspace-name>. workspaces[].assetsis optional.- If
assetsis set, clawchef recursively copies files from that directory into the workspace root. assetsis resolved relative to the recipe file path (unless absolute path is given).workspaces[].files[]runs after assets copy, so explicit file entries can override copied asset files.- Direct URL recipes do not support
workspaces[].assets(assets must resolve to a local directory). - If provided, relative paths are resolved from the recipe file directory.
- For direct URL recipe files, relative workspace paths are resolved from the current working directory.
- For directory/archive recipe references, relative workspace paths are resolved from the selected recipe file directory.
Example:
workspaces:
- name: "workspace-meeting"
assets: "./meetingbot-assets"OpenClaw root files
openclaw.root.pathis optional.- If omitted, clawchef uses
~/.openclaw. openclaw.root.assetsis optional and recursively copied into the root directory.openclaw.root.files[]runs after assets copy, so explicit file entries can override copied assets.openclaw.root.assetsis resolved relative to the recipe file path (unless absolute path is given).- Direct URL recipes do not support
openclaw.root.assets(assets must resolve to a local directory). openclaw.rootcurrently supportscommandandmockproviders;remoteprovider is not supported.
Example:
openclaw:
version: "2026.2.9"
root:
assets: "./openclaw-root-assets"
files:
- path: "AGENTS.md"
content_from: "./snippets/agents-template.md"File content references
In workspaces[].files[] and openclaw.root.files[], set exactly one of:
content: inline text in recipecontent_from: load text from another file/URL (loaded content supports${var}template rendering)source: copy raw file bytes from another file/URL
content_from and source accept:
- path relative to recipe file location
- absolute filesystem path
- HTTP/HTTPS URL
Useful placeholders when overriding commands:
- common:
${bin},${version},${workspace},${agent},${channel},${channel_q},${account},${account_q},${account_arg} - paths:
${path}/${workspace_path}(shell-quoted),${path_raw}/${workspace_path_raw}(raw) - message:
${content},${content_q},${message_file},${message_file_raw}(${role}is alwaysuser) - run prompt:
${prompt},${prompt_q}
Secret handling
- Do not put plaintext API keys/tokens in recipe files.
- Use
${var}placeholders in recipe and pass values via:--var llm_api_key=...CLAWCHEF_VAR_LLM_API_KEY=...
- Inline secrets in
openclaw.bootstrap.*are rejected by validation.
Conversation message format
conversations[].messages[] uses:
content(required): the user message sent to agentexpect(optional): output assertion for that message
When conversations[].run: true, each message triggers one agent run.
If run is omitted, a message still triggers a run when it has expect.
expect supports:
contains: ["..."]not_contains: ["..."]regex: ["..."]equals: "..."
All configured assertions must pass.
