Privilege Boundaries
WASP uses a 5-level capability system to classify skills by operational risk. This system provides metadata for auditing, rate limiting, and risk assessment — it does not disable skills.
CapabilityLevel Enum
class CapabilityLevel(str, Enum):
SAFE = "safe" # Pure computation, no side effects
MONITORED = "monitored" # Read-only external access
CONTROLLED = "controlled" # Scoped writes, bounded impact
RESTRICTED = "restricted" # Arbitrary operations
PRIVILEGED = "privileged" # System-level / infrastructure
Level Definitions
SAFE
Examples: calculate, datetime
- Pure computation, no external calls
- No side effects
- Not audited (no log entry written)
- No risk assessment
- Unlimited usage
MONITORED
Examples: web_search, fetch_url, browser, scrape
- Read-only external access
- Can see internet but cannot modify anything
- Not audited (high volume, low risk)
- No risk assessment
- Unlimited usage
CONTROLLED
Examples: gmail, create_reminder, task_manager, subscribe, memory, agent_manager, integration
- Writes with bounded, reversible impact
- Creates data but doesn't modify infrastructure
- Audited — every call logged to
audit_log - No risk assessment
- Unlimited usage
RESTRICTED
Examples: shell, python_exec, http_request, read_file, write_file
- Arbitrary operations — can do anything the agent user can do
- Network access without SSRF filtering (http_request has explicit protection)
- Audited — every call logged
- Risk assessed —
RiskAssessorevaluates before execution - Anticipatory simulation runs before execution
- Unlimited usage (monitored carefully)
PRIVILEGED
Examples: broker commands (Docker operations), self_improve
- System-level / infrastructure operations
- Can affect the container, Docker, or running code
- Audited
- Risk assessed
- Anticipatory simulation runs before execution
- Rate limited: 20 calls/hour
Policy Enforcement
@dataclass(frozen=True)
class CapabilityPolicy:
level: CapabilityLevel
max_per_hour: int # 0 = unlimited
requires_audit: bool
risk_assess: bool
description: str
The executor checks policy before each execution:
policy = capability_registry.get_policy(skill_name)
if policy.risk_assess:
risk = await risk_assessor.evaluate(call)
# In Sovereign Mode: warn-only (never blocks)
# In normal mode: blocks HIGH risk without explicit confirmation
if policy.requires_audit:
await write_audit_log(call, result)
if policy.max_per_hour > 0:
await check_rate_limit(skill_name, policy.max_per_hour)
Sovereign Mode Impact
When SOVEREIGN_MODE=true:
- Risk assessment results are warn-only — HIGH risk calls execute anyway
- This is intentional for power-user scenarios
- All calls are still audited (no bypass)
Skill Registration
Skills self-register their capability level:
# In register_builtin_skills()
cap_reg.register("web_search", CapabilityLevel.MONITORED)
cap_reg.register("shell", CapabilityLevel.RESTRICTED)
cap_reg.register("self_improve", CapabilityLevel.PRIVILEGED)
Custom skills default to CONTROLLED if not registered.
Querying Capability Levels
# View all registered capability levels
docker exec agent-core python3 -c "
from src.skills.capability import capability_registry
for name, level in sorted(capability_registry.summary().items()):
print(f'{level:12} {name}')
" 2>/dev/null
Risk Levels (RESTRICTED+)
For RESTRICTED and PRIVILEGED skills, the RiskAssessor assigns risk:
| Risk Level | Description | Action (Normal) | Action (Sovereign) |
|---|---|---|---|
low | Minimal impact | Execute | Execute |
medium | Moderate impact | Execute + warn | Execute |
high | Significant impact | Block + confirm | Execute + warn |
critical | Catastrophic potential | Block always | Block + warn |
Audit Query by Capability
# Count calls by capability level (last 7 days)
docker exec agent-postgres psql -U agent -d agent -c "
SELECT
capability_level,
COUNT(*) as calls,
SUM(CASE WHEN success THEN 1 ELSE 0 END) as successes
FROM audit_log
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY capability_level
ORDER BY calls DESC;
"