Quickstart
Install Edictum, write a ruleset, and block a dangerous tool call in under a minute.
Right page if: you want to install Edictum, write your first ruleset, and block a tool call in Python, TypeScript, or Go. Wrong page if: you need the full schema reference -- see https://docs.edictum.ai/docs/rulesets/yaml-reference. For ordered process enforcement, see https://docs.edictum.ai/docs/guides/workflow-gates. Gotcha: Python needs `pip install edictum[yaml]` for YAML rulesets. TypeScript and Go ship YAML support by default.
Agents can refuse in text and still call the tool. Edictum gives you rules that block the tool call at the decision-to-action seam.
This page shows the shortest path: install Edictum, write rules.yaml, and see .env access get blocked.
Install
pip install edictum[yaml]npm install @edictum/corego get github.com/edictum-ai/edictum-goWrite A Ruleset
Save this as rules.yaml:
apiVersion: edictum/v1
kind: Ruleset
metadata:
name: my-first-ruleset
defaults:
mode: enforce
rules:
- id: block-dotenv
type: pre
tool: read_file
when:
args.path: { contains: ".env" }
then:
action: block
message: "Read of sensitive file blocked: {args.path}"This is a single check rule. If the agent calls read_file with a path containing .env, the call is blocked before the tool runs.
Dry-Run It
from edictum import Edictum
guard = Edictum.from_yaml("rules.yaml")
result = guard.evaluate("read_file", {"path": ".env"})
print(result.decision) # "block"
print(result.block_reasons[0]) # "Read of sensitive file blocked: .env"import { Edictum } from '@edictum/core'
const guard = Edictum.fromYaml('rules.yaml')
const result = await guard.evaluate('read_file', { path: '.env' })
console.log(result.decision) // "deny"
console.log(result.denyReasons[0]) // "Read of sensitive file blocked: .env"package main
import (
"context"
"fmt"
"github.com/edictum-ai/edictum-go/guard"
)
func main() {
g, _ := guard.FromYAML("rules.yaml")
result := g.Evaluate(context.Background(), "read_file", map[string]any{"path": ".env"})
fmt.Println(result.Decision) // "block"
fmt.Println(result.BlockReasons[0]) // "Read of sensitive file blocked: .env"
}The tool never runs in dry-run mode. You just get the decision and the matching rules.
Run It For Real
import asyncio
from edictum import Edictum, EdictumDenied
guard = Edictum.from_yaml("rules.yaml")
async def read_file(path: str) -> str:
return f"contents of {path}"
async def main() -> None:
print(await guard.run("read_file", {"path": "README.md"}, read_file))
try:
await guard.run("read_file", {"path": ".env"}, read_file)
except EdictumDenied as exc:
print(exc.reason)
asyncio.run(main())import { Edictum, EdictumDenied } from '@edictum/core'
const guard = Edictum.fromYaml('rules.yaml')
async function readFile(args: Record<string, unknown>) {
return `contents of ${args.path}`
}
console.log(await guard.run('read_file', { path: 'README.md' }, readFile))
try {
await guard.run('read_file', { path: '.env' }, readFile)
} catch (error) {
if (error instanceof EdictumDenied) {
console.log(error.reason)
}
}package main
import (
"context"
"errors"
"fmt"
edictum "github.com/edictum-ai/edictum-go"
"github.com/edictum-ai/edictum-go/guard"
)
func main() {
g, _ := guard.FromYAML("rules.yaml")
ctx := context.Background()
readFile := func(args map[string]any) (any, error) {
return fmt.Sprintf("contents of %s", args["path"]), nil
}
_, _ = g.Run(ctx, "read_file", map[string]any{"path": "README.md"}, readFile)
_, err := g.Run(ctx, "read_file", map[string]any{"path": ".env"}, readFile)
var blocked *edictum.DeniedError
if errors.As(err, &blocked) {
fmt.Println(blocked.Reason)
}
}Add More Rules
One rule handles one behavior. Real agents usually need a few layers: input checks, sandbox boundaries, and session limits.
apiVersion: edictum/v1
kind: Ruleset
metadata:
name: agent-safety
defaults:
mode: enforce
rules:
- id: block-dotenv
type: pre
tool: read_file
when:
args.path: { contains: ".env" }
then:
action: block
message: "Read of sensitive file blocked: {args.path}"
- id: workspace-sandbox
type: sandbox
tools: [read_file, write_file]
within:
- /workspace
- /tmp
not_within:
- /workspace/.git
outside: block
message: "File access outside workspace: {args.path}"
- id: session-limits
type: session
limits:
max_tool_calls: 100
max_calls_per_tool:
bash: 20
then:
action: block
message: "Session limit reached. Summarize progress and stop."Observe Before You Enforce
Not ready to block production traffic yet? Change one line:
defaults:
mode: observeCalls that would be blocked are logged to the decision log as observed events, but the tool still runs. That gives you live traffic before you flip back to enforce.
Need Ordered Process Instead Of Single-Call Rules?
Rules answer "should this tool call happen?" Workflow Gates answer "is the agent at the right stage yet?"
Use Workflow Gates when you need:
- required reads before edits
- command evidence like
git diff - exit checks like
exec("pnpm test", exit_code=0) - approval pauses before the next stage
Next Steps
Workflow Gates Runtime
Stage-based enforcement, approvals, and evidence recording
Python SDK
Python quick start, adapters, and server SDK
TypeScript SDK
Full TypeScript quickstart and API reference
Go SDK
Full Go quickstart and API reference
Writing Rules
Turn a requirement into a ruleset
Framework Adapters
Connect to LangChain, OpenAI Agents, ADK, and more
Ruleset Generator
Generate valid YAML with the current schema
Workflow Reference
Exact kind: Workflow fields and validation rules
Last updated on