Four features to complete the open-source governance tier: 1. Policy Presets (presets.ts): Built-in rule sets (permissive, safety, strict, audit-only) users can reference by name. Merge order: preset defaults → top-level overrides → additional rules appended. 2. Rate Limiting (rate-limiter.ts): Sliding window counters per key (tool or category). RateLimiter integrated into PolicyEngine — rate limit rules only match when threshold exceeded within window. Memory-only, resets on session restart. 3. Audit Query (audit.ts filter()): Filter audit records by tool, category, status, target pattern (glob), time range (ISO or relative like "1h"), and limit. CLI: moltbot audit query. 4. Audit Reporter (reporter.ts): Aggregates audit data into tool stats, category breakdown, policy decisions, error summaries, and per-minute timeline. Text and JSON output formats. All wired into index.ts with CLI commands (policy presets, audit query, audit report) and plugin.json schema updated with preset field. 151 tests pass across 9 test files. Co-authored-by: dp-web4 <dp@metalinxx.io> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| src | ||
| ARCHITECTURE.md | ||
| clawdbot.plugin.json | ||
| index.ts | ||
| package.json | ||
| README.md | ||
web4-governance
R6 workflow formalism, audit trails, session identity, and policy-based pre-action gating for moltbot agent sessions.
Overview
This plugin observes and optionally gates every tool call an agent makes:
- R6 audit records capture intent, context, and outcome for each action
- Hash-linked chain provides tamper-evident provenance (SHA-256 chain)
- Session identity via software-bound Linked Context Tokens (Soft LCT)
- Policy engine evaluates rules before tool execution, with allow/deny/warn decisions
Installation
The plugin is bundled with moltbot. Enable it in your moltbot config:
{
"plugins": {
"web4-governance": {}
}
}
Configuration
All fields are optional. Defaults shown below.
{
"plugins": {
"web4-governance": {
"auditLevel": "standard",
"showR6Status": true,
"storagePath": "~/.web4/",
"policy": {
"defaultPolicy": "allow",
"enforce": true,
"rules": []
}
}
}
}
| Field | Type | Default | Description |
|---|---|---|---|
auditLevel |
"minimal" | "standard" | "verbose" |
"standard" |
Controls audit detail level. verbose logs every R6 to the console. |
showR6Status |
boolean |
true |
Show R6 chain status in session output. |
storagePath |
string |
~/.web4/ |
Directory for audit logs and session state. |
policy |
object |
see below | Policy engine configuration. |
Policy Engine
The policy engine evaluates every tool call against a configurable set of rules before execution. Rules are matched in priority order (ascending); first match wins.
Policy Configuration
| Field | Type | Default | Description |
|---|---|---|---|
defaultPolicy |
"allow" | "deny" | "warn" |
"allow" |
Decision when no rule matches. |
enforce |
boolean |
true |
When false, deny decisions are logged but not enforced (dry-run mode). |
rules |
PolicyRule[] |
[] |
Ordered list of policy rules. |
Rule Schema
{
"id": "deny-destructive-commands",
"name": "Block destructive shell commands",
"priority": 1,
"decision": "deny",
"reason": "Destructive command blocked",
"match": {
"tools": ["Bash"],
"targetPatterns": ["rm\\s+-rf", "mkfs\\."],
"targetPatternsAreRegex": true
}
}
| Field | Required | Description |
|---|---|---|
id |
yes | Unique rule identifier, used in audit constraints. |
name |
yes | Human-readable rule name. |
priority |
yes | Lower number = evaluated first. First match wins. |
decision |
yes | "allow", "deny", or "warn". |
reason |
no | Reason string recorded in audit and shown on block. |
match |
yes | Match criteria (all specified fields are AND'd). |
Match Criteria
All specified criteria within a rule must match (AND logic). Omitted criteria are ignored.
| Field | Type | Description |
|---|---|---|
tools |
string[] |
Tool names: Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch, Task, NotebookEdit, TodoWrite |
categories |
string[] |
Tool categories: file_read, file_write, command, network, delegation, state, mcp, unknown |
targetPatterns |
string[] |
Patterns to match against the tool's target (file path, command, URL, etc.). Glob by default. |
targetPatternsAreRegex |
boolean |
Set true to treat targetPatterns as regex instead of glob. Default: false. |
Target Extraction
The target matched against targetPatterns is extracted from tool parameters:
| Tool | Target source |
|---|---|
| Read, Write, Edit, NotebookEdit | file_path param |
| Glob, Grep | path or pattern param |
| Bash | command param (truncated to 80 chars) |
| WebFetch, WebSearch | url param |
| Task, TodoWrite | no target extracted |
Glob Patterns
Glob matching supports * (any characters except /), ** (any characters including /), and ? (single character). Special regex characters are escaped.
Examples:
**/.env*matches/project/.env,/project/.env.local/src/*.tsmatches/src/index.tsbut not/src/sub/index.ts/src/**/*.tsmatches any.tsfile under/src/at any depth
Decisions
| Decision | Behavior (enforce=true) | Behavior (enforce=false) |
|---|---|---|
allow |
Tool executes normally | Tool executes normally |
deny |
Tool is blocked, returns [blocked] [web4-policy] <reason> |
Logged as warning, tool executes |
warn |
Tool executes, warning logged | Tool executes, warning logged |
Audit Integration
Policy decisions are recorded in the R6 rules.constraints field:
{
"rules": {
"auditLevel": "standard",
"constraints": ["policy:deny", "rule:deny-destructive-commands"]
}
}
Example: Full Policy Config
{
"plugins": {
"web4-governance": {
"policy": {
"defaultPolicy": "allow",
"enforce": true,
"rules": [
{
"id": "deny-destructive-commands",
"name": "Block destructive shell commands",
"priority": 1,
"decision": "deny",
"reason": "Destructive command blocked",
"match": {
"tools": ["Bash"],
"targetPatterns": ["rm\\s+-rf", "mkfs\\."],
"targetPatternsAreRegex": true
}
},
{
"id": "deny-secrets",
"name": "Block reading secret files",
"priority": 5,
"decision": "deny",
"reason": "Secret file access denied",
"match": {
"categories": ["file_read"],
"targetPatterns": ["**/.env", "**/.env.*", "**/credentials.*", "**/*secret*"]
}
},
{
"id": "warn-network",
"name": "Warn on network access",
"priority": 10,
"decision": "warn",
"match": {
"categories": ["network"]
}
}
]
}
}
}
}
CLI Commands
Audit Commands
moltbot audit summary # Show active session stats
moltbot audit verify [sessionId] # Verify chain integrity
moltbot audit last [count] # Show last N audit records (default: 10)
audit summary
Displays all active governance sessions with action counts, audit record counts, chain validity, and tool/category breakdowns.
audit verify [sessionId]
Verifies the hash-linked audit chain integrity. Checks that each record's prevRecordHash matches the SHA-256 hash of the previous record. Pass a session ID to verify a specific chain, or omit for all active sessions.
audit last [count]
Shows the most recent audit records across all active sessions. Each record shows timestamp, tool name, target, and result status.
Policy Commands
moltbot policy status # Show policy engine status
moltbot policy rules # List all rules in evaluation order
moltbot policy test <tool> [target] # Dry-run a tool call against the policy
policy status
Shows the current policy engine state:
Policy engine:
Rules: 3
Default: allow
Enforce: true
policy rules
Lists all configured rules in priority order with match criteria:
3 rules (priority order):
[1] deny-destructive-commands -> deny
Block destructive shell commands
match: tools=[Bash] AND targets(regex)=[rm\s+-rf, mkfs\.]
reason: Destructive command blocked
[5] deny-secrets -> deny
Block reading secret files
match: categories=[file_read] AND targets(glob)=[**/.env, **/.env.*, **/credentials.*, **/*secret*]
reason: Secret file access denied
[10] warn-network -> warn
Warn on network access
match: categories=[network]
Default: allow | Enforce: true
policy test <tool> [target]
Dry-runs a tool call against the policy engine without executing anything. Shows what decision would be made:
$ moltbot policy test Bash "rm -rf /tmp"
Tool: Bash
Category: command
Target: rm -rf /tmp
Decision: deny
Enforced: true
Reason: Destructive command blocked
Rule: deny-destructive-commands (priority 1)
Constraints: policy:deny, rule:deny-destructive-commands
$ moltbot policy test Read "/project/src/index.ts"
Tool: Read
Category: file_read
Target: /project/src/index.ts
Decision: allow
Enforced: true
Reason: Default policy: allow
Constraints: policy:allow, rule:default
Storage Layout
~/.web4/
audit/
<sessionId>.jsonl # Hash-linked audit records (append-only)
sessions/
<sessionId>.json # Session metadata (overwritten on each action)
Architecture
Hooks
The plugin uses two hook surfaces:
before_tool_call(sequential): Evaluates policy rules. Can block tool execution by returning{ block: true, blockReason }. Stashes the policy evaluation for the after-hook.after_tool_call(fire-and-forget): Creates the R6 audit record, writes policy constraints from the stashed evaluation, and appends to the hash-linked chain.
Internal hooks handle session lifecycle (bootstrap, start, end) and command-level auditing.
R6 Request Structure
Each tool call produces an R6 record with six fields:
| Field | Content |
|---|---|
| Rules | Audit level + policy constraints |
| Role | Session ID, agent ID, action index, binding type |
| Request | Tool name, category, target, input hash |
| Reference | Session ID, previous R6 ID, chain position |
| Resource | Approval requirement flag |
| Result | Status (success/error/blocked), output hash, duration |
Session Identity
Each session gets a Soft LCT (software-bound Linked Context Token) derived from hostname:username. Format: web4:session:<machineHash>:<sessionId>. This is the upgrade path to hardware-bound identity in Tier 2.
Implementation Tiers
| Tier | Scope | Status |
|---|---|---|
| 1 - Observational | R6 audit, hash chain, soft LCT, tool classification | Done |
| 1.5 - Policy | Configurable rules, before_tool_call gating, allow/deny/warn | Done |
| 2 - Authorization | T3 trust tensors, ATP economics, hardware LCT, full policy engine | Planned (Hardbound) |
Development
# Run plugin tests
npx vitest run extensions/web4-governance/
# Type-check
pnpm build
# Full test suite
pnpm test