Edictum
TypeScript SDK

Migration from Python

Migrate Edictum contracts and patterns from Python to TypeScript. API comparison, key differences, and common patterns.

AI Assistance

Right page if: you are moving an Edictum Python agent to TypeScript, or maintaining both and need to understand the API differences. Wrong page if: you are starting fresh with TypeScript -- see https://docs.edictum.ai/docs/typescript. For Python-only docs, see https://docs.edictum.ai/docs/quickstart. Gotcha: contracts YAML is identical between Python and TypeScript. Only the host language API changes. `fromYaml()` is synchronous in TypeScript (no `await`), but `evaluate()` and `evaluateBatch()` are async (return Promises).

The TypeScript SDK has full feature parity with the Python library. Your contract YAML files work unchanged -- only the host language API differs. This page maps Python patterns to their TypeScript equivalents.

API Comparison

Guard Construction

PythonTypeScript
Edictum.from_yaml("contracts.yaml")Edictum.fromYaml('contracts.yaml')
Edictum.from_yaml_string(content)Edictum.fromYamlString(content)
Edictum.from_template("file-agent")Not yet available -- use YAML
Edictum.from_server(url=..., api_key=...)createServerGuard({ url, apiKey, agentId })
Edictum(contracts=[...])new Edictum({ contracts: [...] })

Running Tool Calls

PythonTypeScript
await guard.run("tool", args, fn)await guard.run('tool', args, fn)
guard.evaluate("tool", args)await guard.evaluate('tool', args)
guard.evaluate_batch([...])await guard.evaluateBatch([...])

Sync vs async. In Python, evaluate() and evaluate_batch() are synchronous. In TypeScript, they return Promises. fromYaml() is synchronous in both.

Errors

PythonTypeScript
EdictumDeniedEdictumDenied
e.reasone.reason
EdictumToolErrorEdictumToolError
EdictumConfigErrorEdictumConfigError

Contracts

PythonTypeScript
Verdict.fail("reason")Verdict.fail('reason')
Verdict.pass()Verdict.pass()
{"tool": "Bash", "check": fn}{ tool: 'Bash', check: fn }
Postcondition: {"tool": "X", "check": fn} (2-arg check auto-detected){ tool: 'X', contractType: 'post', check: fn }

Postcondition classification. In Python, a 2-argument check function is auto-detected as a postcondition. In TypeScript, you must set contractType: 'post' explicitly. The SDK throws EdictumConfigError if a check function has 2+ parameters without contractType: 'post'.

Adapters

PythonTypeScript
pip install edictum[langchain]pnpm add @edictum/langchain
from edictum.adapters.langchain import LangChainAdapterimport { LangChainAdapter } from '@edictum/langchain'
adapter = LangChainAdapter(guard)const adapter = new LangChainAdapter(guard)
adapter.as_tool_wrapper()adapter.asMiddleware() or adapter.asToolWrapper()
adapter.set_principal(p)adapter.setPrincipal(p)
principal_resolver=fnprincipalResolver: fn

Audit

PythonTypeScript
FileAuditSink("audit.jsonl")new FileAuditSink('audit.jsonl')
RedactionPolicy()new RedactionPolicy()
audit_sink=sinkauditSink: sink

Server

PythonTypeScript
Edictum.from_server(url=..., api_key=...)createServerGuard({ url, apiKey, agentId })
guard.close()close() (from the returned ServerGuard)
verify_signatures=True, signing_public_key="..."verifySignatures: true, signingPublicKey: '...'

What Stays the Same

Contract YAML is identical. The same contracts.yaml file works with both SDKs. Same apiVersion, same operators, same effects, same variable interpolation. No conversion needed.

Pipeline semantics are identical. Preconditions before execution, postconditions after, session limits across turns, sandbox allowlists. Same evaluation order, same fail-closed behavior.

Audit events are identical. Same AuditAction enum values, same event structure. Audit events from TypeScript and Python agents can be mixed in the same Edictum Console instance.

Key Differences

Async Everywhere

TypeScript's evaluate() and evaluateBatch() return Promises (Python's are synchronous):

// TypeScript -- must await
const result = await guard.evaluate('readFile', { path: '.env' })

// Python -- no await
result = guard.evaluate("read_file", {"path": ".env"})

ESM + CJS Dual Build

All packages ship both ESM and CJS builds. If you hit module resolution issues with fromYaml() in an ESM context, use the async variant:

// ESM-safe -- always works
const guard = await Edictum.fromYamlAsync('contracts.yaml')

Server Guard is a Separate Package

In Python, Edictum.from_server() is a class method on the core class. In TypeScript, server functionality lives in @edictum/server to keep @edictum/core at zero runtime dependencies:

// Python
from edictum import Edictum
guard = Edictum.from_server(url="https://...", api_key="ek_...")

// TypeScript
import { createServerGuard } from '@edictum/server'
const { guard, close } = await createServerGuard({
  url: 'https://...',
  apiKey: 'ek_...',
  agentId: 'my-agent',
})

Naming Convention

Python uses snake_case. TypeScript uses camelCase:

PythonTypeScript
from_yaml()fromYaml()
from_yaml_string()fromYamlString()
session_idsessionId
principal_resolverprincipalResolver
audit_sinkauditSink
on_denyonDeny
on_allowonAllow
policy_versionpolicyVersion
set_principal()setPrincipal()

Adapter Package Structure

Python uses extras (pip install edictum[langchain]). TypeScript uses separate npm packages:

Python ExtraTypeScript Package
edictum[langchain]@edictum/langchain
edictum[openai-agents]@edictum/openai-agents
Built-in (no extra)@edictum/vercel-ai
Built-in (no extra)@edictum/claude-sdk
N/A@edictum/openclaw
edictum[server]@edictum/server
edictum[otel]@edictum/otel

Next Steps

Last updated on

On this page