This is the multi-page printable view of this section. Click here to print.
Security
1 - OpenClaw Secrets Management with 1Password
This guide walks through setting up 1Password as a centralized secret provider for OpenClaw. By the end, every API key, token, and credential in your OpenClaw config will resolve at runtime through 1Password — nothing sensitive stored in plaintext.
Prerequisites
- OpenClaw installed and running
- 1Password account (personal or business)
- 1Password CLI (
op) installed - Basic familiarity with OpenClaw’s
openclaw.jsonconfig
Part 1: Install and Configure 1Password CLI
Install the CLI
# Ubuntu/Debian
curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
sudo gpg --dearmor --output /usr/share/keyrings/1password-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/$(dpkg --print-architecture) stable main" | \
sudo tee /etc/apt/sources.list.d/1password.list
sudo apt update && sudo apt install 1password-cli
# Verify
op --version
Create a Service Account
For non-interactive (agent) access, you need a service account — not a personal sign-in.
- Go to your 1Password admin console
- Navigate to Developer → Service Accounts
- Create a new service account with access to your vault
- Copy the service account token
Set the Token
Add the service account token to your OpenClaw environment:
# In ~/.openclaw/.env
OP_SERVICE_ACCOUNT_TOKEN=ops_your_service_account_token_here
This is the one secret that bootstraps access to everything else. Protect this file with appropriate permissions:
chmod 600 ~/.openclaw/.env
Verify Access
# Test that op can authenticate
export OP_SERVICE_ACCOUNT_TOKEN="ops_your_token"
op vault list
op item list --vault "Your-Vault-Name"
Part 2: Create a Vault and Add Credentials
Create a Dedicated Vault
Keep OpenClaw credentials separate from personal items:
# Via 1Password web UI or CLI
op vault create "OpenClaw-API-Keys"
Add Credentials
For each API key your OpenClaw instance uses:
# Create items with the password field
op item create \
--category=password \
--title="ANTHROPIC_API_KEY" \
--vault="OpenClaw-API-Keys" \
password="sk-ant-your-key-here"
op item create \
--category=password \
--title="OPENROUTER_API_KEY" \
--vault="OpenClaw-API-Keys" \
password="sk-or-v1-your-key-here"
op item create \
--category=password \
--title="DISCORD_TOKEN" \
--vault="OpenClaw-API-Keys" \
password="your-discord-bot-token"
Verify Items
# List all items (titles only, never echo values)
op item list --vault OpenClaw-API-Keys --format json | jq '.[].title'
# Verify a specific item resolves (check existence, not value)
op read "op://OpenClaw-API-Keys/ANTHROPIC_API_KEY/password" > /dev/null && echo "OK" || echo "FAILED"
Important: Never echo secret values to terminal, logs, or chat. Always verify with existence checks.
Part 3: Configure OpenClaw Secret Providers
Add Exec Providers
In openclaw.json, add a secrets.providers entry for each credential:
{
"secrets": {
"providers": {
"onepassword_anthropic": {
"source": "exec",
"command": "/usr/bin/op",
"args": ["read", "op://OpenClaw-API-Keys/ANTHROPIC_API_KEY/password"],
"jsonOnly": false,
"passEnv": ["HOME", "OP_SERVICE_ACCOUNT_TOKEN"],
"allowInsecurePath": true
},
"onepassword_openrouter": {
"source": "exec",
"command": "/usr/bin/op",
"args": ["read", "op://OpenClaw-API-Keys/OPENROUTER_API_KEY/password"],
"jsonOnly": false,
"passEnv": ["HOME", "OP_SERVICE_ACCOUNT_TOKEN"],
"allowInsecurePath": true
}
}
}
}
Key Configuration Notes
| Field | Purpose | Notes |
|---|---|---|
source | Always "exec" for CLI-based providers | |
command | Full path to op binary | Use which op to find it |
args | Arguments for op read | Format: op://Vault/Item/Field |
jsonOnly | Set false for raw text output | op read returns raw text, not JSON |
passEnv | Environment variables to forward | Must include OP_SERVICE_ACCOUNT_TOKEN |
allowInsecurePath | Allow non-user-owned binaries | Required because op is owned by root |
Common Field Names
Most 1Password items use password as the field name, but watch for variations:
password— Standard for most itemscredential— Some items created through web UItoken— Custom field namenotesPlain— Notes field
Check your item’s field structure:
op item get "ITEM_NAME" --vault "OpenClaw-API-Keys" --format json | \
jq '[.fields[] | select(.value != null) | .label]'
Part 4: Replace Plaintext Values with SecretRefs
Config-Level Credentials
Replace plaintext apiKey values with SecretRef objects:
Before:
{
"tools": {
"web": {
"search": {
"apiKey": "BSA-actual-key-value"
}
}
}
}
After:
{
"tools": {
"web": {
"search": {
"apiKey": {
"source": "exec",
"provider": "onepassword_brave",
"id": "value"
}
}
}
}
}
Skill Credentials
Same pattern for skill configs:
{
"skills": {
"entries": {
"todoist": {
"apiKey": {
"source": "exec",
"provider": "onepassword_todoist",
"id": "value"
}
}
}
}
}
Agent Auth Profiles
For model provider credentials, use auth-profiles instead of direct apiKey values.
Create auth-profiles.json in each agent’s directory (~/.openclaw/agents/<name>/agent/auth-profiles.json):
{
"version": 1,
"profiles": {
"openrouter:default": {
"type": "api_key",
"provider": "openrouter",
"keyRef": {
"source": "exec",
"provider": "onepassword_openrouter",
"id": "value"
}
},
"anthropic:default": {
"type": "token",
"provider": "anthropic",
"tokenRef": {
"source": "exec",
"provider": "onepassword_anthropic",
"id": "value"
}
},
"cloudflare-ai-gateway:default": {
"type": "api_key",
"provider": "cloudflare-ai-gateway",
"keyRef": {
"source": "exec",
"provider": "onepassword_cloudflare",
"id": "value"
}
}
}
}
Then set the apiKey in the agent’s models.json to "secretref-managed":
{
"providers": {
"openrouter": {
"apiKey": "secretref-managed"
},
"anthropic": {
"apiKey": "secretref-managed"
}
}
}
Local Services (No Auth Needed)
If a provider doesn’t require authentication (local Ollama, local Whisper), remove the apiKey field entirely rather than setting a placeholder:
{
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434",
"api": "ollama"
}
}
}
Part 5: Validate and Restart
Pre-Flight Backup
Always back up before restarting:
cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.backup.$(date +%Y%m%d-%H%M%S)
Run the Secrets Audit
openclaw secrets audit --check
Target output:
Secrets audit: clean. plaintext=0, unresolved=0, shadowed=0, legacy=0.
If you see REF_UNRESOLVED, the SecretRef can’t resolve. Common causes:
| Error | Cause | Fix |
|---|---|---|
| “returned invalid JSON” | Wrong id value (e.g., "google/apiKey" instead of "value") | Use "id": "value" for op read providers |
| “must be owned by current user” | Missing allowInsecurePath | Add "allowInsecurePath": true |
| “provider not found” | Typo in provider name | Check secrets.providers key matches |
| “command failed” | OP_SERVICE_ACCOUNT_TOKEN not available | Add to passEnv array |
Restart Gateway
openclaw gateway restart
If things break, restore:
cp ~/.openclaw/openclaw.json.backup.TIMESTAMP ~/.openclaw/openclaw.json
openclaw gateway restart
Part 6: Best Practices
Migration Strategy
- Start with low-risk credentials — Skills and non-critical integrations first
- Test one at a time — Validate each SecretRef resolves before moving to the next
- Save critical-path credentials for last — Discord token, primary model provider keys
- Back up before every restart — Revert should always be one command away
Security Hygiene
- One vault, one purpose — Keep OpenClaw credentials in a dedicated vault
- Service account, not personal — Don’t rely on interactive sign-in for agent access
- Never echo values — Verify credentials exist with
> /dev/null && echo OK, never print them - Audit regularly — Run
openclaw secrets audit --checkafter any config change - Restrict
.envpermissions —chmod 600on the file containingOP_SERVICE_ACCOUNT_TOKEN
Operational Notes
- Boot order matters — The
OP_SERVICE_ACCOUNT_TOKENmust be available in the environment when OpenClaw starts. If using systemd, ensure the.envfile is loaded viaEnvironmentFile= - 1Password CLI caches — The CLI caches auth sessions. If you rotate the service account token, restart the gateway to pick up the new one
- Field name consistency — Standardize on
passwordas the field name when creating vault items. It makesop readpaths predictable
Adding New Credentials
When you add a new integration:
- Create the 1Password vault item
- Add a
secrets.providersentry inopenclaw.json - Reference it with a SecretRef in the appropriate config location
- Run
openclaw secrets audit --check - Restart and verify
Quick Reference
SecretRef Format
{
"source": "exec",
"provider": "<provider_name>",
"id": "value"
}
Provider Template
"onepassword_<name>": {
"source": "exec",
"command": "/usr/bin/op",
"args": ["read", "op://OpenClaw-API-Keys/<ITEM_TITLE>/password"],
"jsonOnly": false,
"passEnv": ["HOME", "OP_SERVICE_ACCOUNT_TOKEN"],
"allowInsecurePath": true
}
Useful Commands
# Audit current state
openclaw secrets audit --check
# List vault items
op item list --vault OpenClaw-API-Keys --format json | jq '.[].title'
# Verify a specific item (never echo the value)
op read "op://OpenClaw-API-Keys/ITEM/password" > /dev/null && echo "resolves: yes"
# Backup config
cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.backup.$(date +%Y%m%d-%H%M%S)
Written based on a real migration from 127 plaintext credentials to zero on an OpenClaw homelab deployment. March 2026.
2 - SEL × Cynefin: Security and Autonomy for AI Agents
AI agents need to know two things before acting:
- What tools can I use? (Security Execution Level)
- How autonomous can I be in this domain? (Cynefin classification)
This guide shows you how to implement both, with OpenClaw-specific examples and prompts.
Prerequisites
- OpenClaw installed and configured
- Basic understanding of AI agents
- Familiarity with Cynefin framework
Background
The Problem
When you have 150+ agents (like we do after installing Agency), you need answers to:
- Can the
researcheragent rundocker restart? - Should the
homelab-guardianagent be able to delete files? - Does the
code-crafterneed approval before pushing to GitHub? - When should an agent escalate to a human?
The answer isn’t binary. It depends on both the tools available and the domain complexity.
Related Reading
- Domain Classification for Agent Autonomy — First principles of Cynefin for agents
- Security Execution Levels — How we developed this framework
- MCP Bridge paper — Inspiration for security levels
Part 1: Security Execution Levels (SEL)
SEL defines what tools an agent can use:
SEL-0: Read-only
Tools: read, web_fetch, web_search, memory_search, qmd
Use for: Information gathering agents that should never modify state.
Example agents: researcher, qa-reviewer
sel:
default: 0
sandbox_required: false
capabilities:
allowed_tools: [web_search, web_fetch, memory_search, memory_get]
denied_tools: [exec, write, edit, message, gateway]
SEL-1: Standard
Tools: SEL-0 + write (workspace files), exec (non-destructive commands)
Use for: Agents that create content but shouldn’t touch the system.
Example agents: communicator, librarian
sel:
default: 1
sandbox_required: false
capabilities:
allowed_tools: [read, write, web_search, web_fetch, memory_*]
denied_tools: [exec, edit] # Edit may include system files
SEL-2: Elevated
Tools: SEL-1 + exec (destructive), edit (any file), gateway (config changes)
Use for: Infrastructure agents that need to modify the system.
Requires: /approve before destructive operations
Example agents: homelab-guardian, devops-engineer
sel:
default: 1
elevated_to: 2
elevated_for: [docker_restart, docker_rm, package_install]
sandbox_required: false
SEL-3: Quarantine
Tools: Arbitrary code execution, untrusted API calls
Use for: Running untrusted code, processing untrusted input
Requires: Per-operation approval + Docker sandbox
Example uses: Running user-provided scripts, processing unknown files
sel:
default: 3
sandbox_required: true
capabilities:
allowed_tools: [exec_sandbox] # Only sandboxed execution
network:
allowed_domains: []
denied_domains: ["*"]
Part 2: Cynefin Domain Classification
Cynefin defines how autonomous an agent can be in a given domain:
Clear Domain
Characteristics: Best practices exist, cause-effect is obvious, predictable outcomes.
Agent behavior: Autonomous execution
Human role: Exception handling only
Complicated Domain
Characteristics: Expert analysis needed, multiple valid approaches.
Agent behavior: Recommend with analysis, wait for approval
Human role: Approve and implement
Complex Domain
Characteristics: Patterns emerge in retrospect, no single right answer.
Agent behavior: Probabilistic prediction, flag uncertainty
Human role: Interpret, decide, adjust
Chaotic Domain
Characteristics: Unknown unknowns, no discernible cause-effect.
Agent behavior: Contain, escalate, document
Human role: Diagnose, respond, learn
Part 3: SEL × Cynefin Matrix
The combination determines agent behavior:
| Cynefin \ SEL | SEL-0 | SEL-1 | SEL-2 | SEL-3 |
|---|---|---|---|---|
| Clear | ✅ Autonomous | ✅ Autonomous | ⚠️ Approve first | ❌ Escalate |
| Complicated | ✅ Autonomous | ⚠️ Approve | ⚠️ Approve | ❌ Escalate |
| Complex | ✅ Research | ⚠️ Uncertainty | ❌ Human required | ❌ Escalate |
| Chaotic | ✅ Observe | ❌ Escalate | ❌ Escalate | ❌ Full stop |
Decision Logic
IF domain is Clear AND tool SEL ≤ 1:
→ Execute autonomously
IF domain is Clear AND tool SEL = 2:
→ Request approval, explain cause-effect, execute on /approve
IF domain is Complicated AND tool SEL ≤ 0:
→ Execute autonomously (research/analysis)
IF domain is Complicated AND tool SEL = 1+:
→ Recommend with analysis, wait for approval
IF domain is Complex:
→ Report findings with uncertainty estimates, defer decisions
IF domain is Chaotic:
→ Immediately escalate, contain if possible, document everything
Part 4: Implementation in OpenClaw
Step 1: Classify Your Skills
Add cynefin and sel blocks to each skill’s SKILL.md:
---
name: homelab-guardian
description: Infrastructure automation and security for homelab
cynefin:
primary: complicated
subdomains:
monitoring: clear # Health checks are predictable
management: complicated # Requires analysis
failure_recovery: complex # Emergent patterns
rationale: "Infrastructure operations require expertise. Multiple valid approaches exist."
autonomous: false
human_approval: on_elevation
confidence: medium
sel:
default: 1
elevated_to: 2
elevated_for: [docker_restart, docker_rm, package_install]
sandbox_required: false
capabilities:
allowed_tools: [exec, read, write, edit]
rate_limits:
exec: "1 per 5s"
---
Step 2: Define Agent SEL Ceilings
In your agent coordination config:
agents:
researcher:
max_SEL: 0 # Can only use SEL-0 tools
communicator:
max_SEL: 1 # Can use SEL-0 and SEL-1
homelab-guardian:
max_SEL: 2 # Can use SEL-0, SEL-1, SEL-2 (with approval for SEL-2)
Step 3: Implement Approval Flow
When an agent wants to use an SEL-2 tool:
def check_sel_permission(agent, tool, domain):
tool_sel = get_tool_sel(tool)
agent_max_sel = agent.max_SEL
domain_cynefin = get_domain_classification(domain)
# SEL ceiling check
if tool_sel > agent_max_sel:
return {"action": "deny", "reason": f"Tool requires SEL-{tool_sel}, agent limited to SEL-{agent_max_sel}"}
# Cynefin autonomy check
if domain_cynefin == "chaotic":
return {"action": "escalate", "reason": "Chaotic domain requires human intervention"}
if domain_cynefin in ["complex", "complicated"] and tool_sel >= 1:
return {"action": "approve", "reason": f"{domain_cynefin} domain needs approval for SEL-{tool_sel}"}
if tool_sel >= 2:
return {"action": "approve", "reason": f"SEL-{tool_sel} always requires approval"}
return {"action": "execute", "reason": "Within bounds"}
Part 5: Prompts for OpenClaw
Classifying a New Skill
Classify this skill using the SEL × Cynefin framework:
Skill: [skill name]
Description: [what it does]
Tools it uses: [list of tools]
Provide:
1. SEL level (0-3) with rationale
2. Cynefin domain (clear/complicated/complex/chaotic) with subdomains
3. Whether it should be autonomous
4. When it needs human approval
Checking Agent Permissions
Can the [agent name] agent use [tool name] for [task]?
Check:
1. Agent's max SEL vs tool's required SEL
2. Task domain Cynefin classification
3. Decision: autonomous / approve / escalate
Explain your reasoning.
Onboarding New Agents
onboard the [agent name] agent:
1. What is its primary purpose?
2. What tools does it need?
3. What domain(s) does it operate in?
4. Assign SEL ceiling
5. Classify Cynefin domains
6. Define capability boundaries
7. Document escalation paths
Part 6: Common Patterns
Pattern: Read-Only Research Agent
# researcher agent
cynefin:
primary: complicated
subdomains:
search: clear
analysis: complicated
sel:
default: 0
capabilities:
allowed_tools: [web_search, web_fetch, memory_search, memory_get]
denied_tools: [exec, write, edit, message]
Behavior: Can search and analyze autonomously, can’t modify anything.
Pattern: Infrastructure Agent
# homelab-guardian agent
cynefin:
primary: complicated
subdomains:
monitoring: clear
management: complicated
recovery: complex
sel:
default: 1
elevated_to: 2
elevated_for: [docker_restart]
capabilities:
allowed_tools: [exec, read, docker]
Behavior: Status checks autonomous, Docker restart needs approval.
Pattern: Untrusted Code Runner
# code-runner agent
cynefin:
primary: chaotic
subdomains:
known_code: complicated
unknown_code: chaotic
sel:
default: 3
sandbox_required: true
capabilities:
allowed_tools: [exec_sandbox]
network:
denied_domains: ["*"]
Behavior: Always sandboxed, requires approval, no network access.
Troubleshooting
“Agent can’t use tool it should have access to”
Check:
- Agent’s
max_SELvs tool’s required SEL - Domain Cynefin classification (complex domains limit autonomy)
- Capability boundary
denied_toolslist
“Agent is asking for approval when it shouldn’t”
Check:
- Is the task in a Clear domain?
- Is the SEL ≤ 1?
- Is the domain classified correctly?
“How do I elevate temporarily?”
Use /approve <reason> in the session. Approval applies to the next elevated operation only.
Related Documentation
memory/procedural/security-execution-levels.md— Full SEL frameworkmemory/procedural/domain-classification.md— Cynefin classification guidememory/procedural/agent-onboarding-contract.md— Agent onboarding process- Journal: Security Execution Levels
This framework was developed while onboarding 154 Agency agents. All 62 skills in our OpenClaw install now have SEL + Cynefin classification.