Edictum Gate
Govern coding assistants with contract-based audit and enforcement. Gate sits between your AI assistant and the OS, evaluating every tool call against YAML contracts.
Right page if: you want to govern a coding assistant (Claude Code, Cursor, Copilot, Gemini CLI, OpenCode) with contract-based audit and enforcement at the OS level. Wrong page if: you want to govern an AI agent framework (LangChain, CrewAI, etc.) -- see https://docs.edictum.ai/docs/adapters/overview. For writing YAML contracts, see https://docs.edictum.ai/docs/guides/writing-contracts. Gotcha: Gate defaults to observe mode -- it audits every tool call but does not block anything except changes to its own configuration. Switch to enforce mode only after reviewing the audit trail.
Gate is a pre-execution hook that sits between coding assistants and the operating system. Every tool call -- file reads, shell commands, web fetches -- passes through Gate before execution. Gate evaluates the call against YAML contracts and records it to a local audit trail.
The default mode is observe: Gate logs everything but blocks nothing. The only exception is self-protection -- Gate always prevents the governed assistant from disabling or modifying Gate itself.
Install
pip install edictum[gate]This includes the YAML engine, CLI, and httpx for Console sync.
Quick Start
1. Initialize Gate
edictum gate initThe wizard creates ~/.edictum/ with:
gate.yaml-- configuration (audit settings, redaction, fail-open)contracts/base.yaml-- default contracts covering secret file access, destructive commands, git safety, system modifications, and package installations- Hook registration for your chosen assistants
2. Install a Hook
If you skipped assistant selection during init:
edictum gate install claude-codeSupported assistants:
| Assistant | Hook location | Format |
|---|---|---|
| Claude Code | ~/.claude/settings.json | PreToolUse |
| Cursor | ~/.cursor/hooks.json | preToolUse |
| Copilot CLI | .github/hooks/hooks.json (per-repo) | preToolUse |
| Gemini CLI | .gemini/settings.json (per-repo) | BeforeTool |
| OpenCode | ~/.opencode/plugins/ | Plugin |
3. Use Your Assistant Normally
Open your assistant and work as usual. Every tool call flows through Gate:
Assistant → Hook fires → edictum gate check → Evaluate contracts → Audit → Allow/Deny4. Review the Audit Trail
edictum gate auditShows a table of recent tool calls with timestamps, verdicts, tools, and contract matches. Filter by tool or verdict:
edictum gate audit --tool Bash --verdict denyObserve vs Enforce
Gate defaults to observe mode. This means:
- Every tool call is evaluated against contracts
- Matches are logged to the audit trail as
call_would_deny - Nothing is blocked -- the assistant proceeds normally
- You see exactly what your contracts would catch
When you're confident in your contract set, switch to enforce:
# ~/.edictum/contracts/base.yaml
defaults:
mode: enforceNow matched contracts actually block the tool call, and the assistant sees the denial message.
Start with observe
Always deploy new contracts in observe mode first. Review the audit trail for false positives before enforcing.
Default Contracts
The base contract template covers:
| Category | What it catches |
|---|---|
| Secret protection | .env, .pem, .key, credentials files, SSH/AWS/GCloud configs |
| Destructive commands | rm -rf /, mkfs, dd, chmod 777, fork bombs |
| Git safety | git push --force, git reset --hard, git clean -f, git branch -D |
| System commands | sudo, systemctl, launchctl, system directory access |
| Package installs | pip install, npm install, brew install, cargo install |
| Environment dumps | printenv, env, export -p, echo $AWS_SECRET_ACCESS_KEY |
Edit ~/.edictum/contracts/base.yaml to customize. These are standard Edictum YAML contracts -- the same syntax used by framework adapters.
Self-Protection
Gate prevents the governed assistant from disabling or modifying Gate itself. These contracts are always enforced, even in observe mode:
- File access: blocks Read/Write/Edit of
~/.edictum/,~/.claude/settings.json,~/.cursor/hooks.json,.gemini/settings.json - Shell tampering: blocks Bash commands targeting Gate config files or running
edictum gate uninstall
The denial message tells the assistant to ask the human:
Gate infrastructure is managed by humans, not by the governed assistant. Tell the human what needs to change and they will update it in their terminal.
Scope Enforcement
Gate enforces that Write, Edit, and NotebookEdit operations stay within the project directory (the cwd from the assistant's hook). This prevents the assistant from writing to system files or other projects.
In observe mode, out-of-scope writes are logged but allowed. In enforce mode, they are blocked.
Paths in scope_allowlist (default: ~/.claude/) bypass this check so the assistant can manage its own memory.
Audit Trail
Every tool call produces an audit event written to ~/.edictum/audit/wal.jsonl. Events include:
call_id,timestamp,agent_idtool_name,tool_args(redacted)action:call_allowed,call_denied, orcall_would_denydecision_name(contract ID),reasonassistant,user,cwdcontracts_evaluated(which contracts fired and why)
Redaction
Secrets are redacted before hitting the WAL. API keys, SSH keys, tokens, and other sensitive patterns are replaced with <REDACTED>. Configure patterns in gate.yaml:
redaction:
enabled: true
patterns:
- 'sk_live_[a-zA-Z0-9]+'
- 'AKIA[A-Z0-9]{16}'
replacement: "<REDACTED>"Console Sync
Connect Gate to Edictum Console for centralized audit, dashboards, and fleet monitoring across all developers.
Setup
edictum gate init --server http://localhost:8000 --api-key edk_your_key_hereGate verifies the connection and validates your API key during init. Events auto-sync every 30 seconds. Manual flush:
edictum gate syncWhat Console Shows
- Real-time event feed from all connected developers
- Denial rates, contract drift, sandbox violations
- Per-developer and per-assistant breakdowns
- Contract evaluation details
Gate events appear in Console alongside framework adapter events -- same audit schema, same dashboard.
Writing Custom Contracts
Gate uses standard Edictum YAML contracts. Any contract that works with framework adapters works with Gate.
Example: Block Database Mutations
- id: deny-db-mutations
type: pre
tool: Bash
when:
args.command:
matches_any:
- 'DROP\s+(TABLE|DATABASE)'
- 'DELETE\s+FROM'
- 'TRUNCATE\s+'
then:
effect: deny
message: "Denied: database mutation commands are not allowed"
tags: [security, database]Example: Restrict File Writes to Source Directories
- id: restrict-writes-to-src
type: pre
tool: Write
when:
all:
- args.file_path:
not_in: [src/, tests/, docs/]
then:
effect: deny
message: "Writes are restricted to src/, tests/, and docs/"See the contract writing guide for the full YAML syntax.
CLI Reference
| Command | Description |
|---|---|
edictum gate init | Set up Gate with contracts and hooks |
edictum gate install <assistant> | Register hook with an assistant |
edictum gate uninstall <assistant> | Remove hook from an assistant |
edictum gate status | Show config, contract count, installed assistants |
edictum gate audit | View recent audit events |
edictum gate sync | Flush audit events to Console |
edictum gate check | Evaluate a tool call (called by hooks, not directly) |
Non-Interactive Mode
For CI, Docker, or scripted setups:
edictum gate init --non-interactive
edictum gate init --non-interactive --server http://console:8000 --api-key $EDICTUM_API_KEY
edictum gate init --non-interactive --contracts ./my-contracts.yamlConfiguration Reference
~/.edictum/gate.yaml:
# Contract file paths
contracts:
- /home/user/.edictum/contracts/base.yaml
# Console sync (optional)
console:
url: http://localhost:8000
api_key: edk_your_key
agent_id: "${hostname}-${user}"
# Local audit trail
audit:
enabled: true
buffer_path: /home/user/.edictum/audit/wal.jsonl
# Secret redaction (applied before WAL write)
redaction:
enabled: true
# Paths outside cwd that Write/Edit/NotebookEdit are allowed to access
scope_allowlist:
- ~/.claude/
# Contract cache (avoids re-parsing YAML on every check)
cache:
hash_mtime: true
ttl_seconds: 300
# Fail-closed by default: if contracts fail to load, deny
fail_open: falseTroubleshooting
Gate blocks its own updates
Gate prevents the governed assistant from running pip install or modifying Gate config. To update Gate:
- Run in your terminal (not the assistant):
edictum gate uninstall claude-code - Update:
pip install --upgrade edictum[gate] - Reinstall hook:
edictum gate install claude-code
Cursor shows as "claude-code"
Gate auto-detects Cursor from stdin fields (cursor_version, workspace_roots) even when the hook is registered as Claude Code format. If events still show the wrong assistant, install the Cursor hook explicitly:
edictum gate install cursorRecovery from broken Gate
If Gate crashes or misconfigures, manually edit ~/.claude/settings.json to remove the hook entry containing edictum gate check.
Last updated on