Edictum
Guides

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.

AI Assistance

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 init

The 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-code

Supported assistants:

AssistantHook locationFormat
Claude Code~/.claude/settings.jsonPreToolUse
Cursor~/.cursor/hooks.jsonpreToolUse
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/Deny

4. Review the Audit Trail

edictum gate audit

Shows a table of recent tool calls with timestamps, verdicts, tools, and contract matches. Filter by tool or verdict:

edictum gate audit --tool Bash --verdict deny

Observe 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: enforce

Now 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:

CategoryWhat it catches
Secret protection.env, .pem, .key, credentials files, SSH/AWS/GCloud configs
Destructive commandsrm -rf /, mkfs, dd, chmod 777, fork bombs
Git safetygit push --force, git reset --hard, git clean -f, git branch -D
System commandssudo, systemctl, launchctl, system directory access
Package installspip install, npm install, brew install, cargo install
Environment dumpsprintenv, 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_id
  • tool_name, tool_args (redacted)
  • action: call_allowed, call_denied, or call_would_deny
  • decision_name (contract ID), reason
  • assistant, user, cwd
  • contracts_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_here

Gate verifies the connection and validates your API key during init. Events auto-sync every 30 seconds. Manual flush:

edictum gate sync

What 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

CommandDescription
edictum gate initSet 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 statusShow config, contract count, installed assistants
edictum gate auditView recent audit events
edictum gate syncFlush audit events to Console
edictum gate checkEvaluate 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.yaml

Configuration 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: false

Troubleshooting

Gate blocks its own updates

Gate prevents the governed assistant from running pip install or modifying Gate config. To update Gate:

  1. Run in your terminal (not the assistant): edictum gate uninstall claude-code
  2. Update: pip install --upgrade edictum[gate]
  3. 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 cursor

Recovery 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

On this page