Developer API¶
The public Python path is top-level casegraph.
Use it when you want your code to open a case, run workers, propose changes, gate them, commit local/fake actions, and inspect replay.
For an existing structured-output agent, the useful first path is cover.case(...). The agent keeps
its normal framework call. CaseGraph extracts the typed decision, records evidence, proposes
developer-owned local actions, previews them, applies automatic local policy, approves, commits,
verifies, and replay-checks the persisted case.
from casegraph import cover
from pydantic_ai import Agent
@cover.local_action
class IssueRefund(cover.ActionInput):
order_id: str
amount_cents: int
currency: str
reason: str
def preview(self) -> cover.PreviewResult:
return cover.PreviewResult(
target=f"order:{self.order_id}",
before={"refund_status": "not_refunded"},
after={"refund_status": "refund_queued", "amount_cents": self.amount_cents},
summary="Preview refund before committing.",
)
def commit(self) -> cover.CommitResult:
return cover.CommitResult(
target=f"order:{self.order_id}",
output={"refund_id": f"refund-{self.order_id.lower()}", "status": "queued"},
summary="Queued local refund.",
)
class RefundDecision(cover.Decision):
action: IssueRefund | None = None
agent = Agent("openai-chat:gpt-4o-mini", output_type=RefundDecision)
with cover.case("refund_request", goal="Resolve refund request") as case:
result = agent.run_sync("Review refund request for order R123")
print(result.output)
print(case.outcome.inspect_command)
Repeated runs with the same cover.case("refund_request", ...) name are linked as one run series
in the persisted case metadata and browser case list.
This path requires structured output. CaseGraph does not infer business actions from raw text, and
the model only fills action fields. The preview(...), commit(...), and optional verify(...)
methods are normal Python owned by the developer.
For larger decisions, keep the same manager shape and add
additional_evidence: list[cover.Evidence] plus more decorated action fields or an action list on
the structured output model. CaseGraph promotes all evidence records and one action per decorated
action kind in the same governed case.
For a native CaseGraph pack, use EngineHost.
Create a local pack first:
casegraph init intake_review --output .casegraph/intake_review_pack --json
casegraph db upgrade --json
The Core Loop¶
host = EngineHost.from_env(packs=[my_pack()])
case = host.open_case(intent=..., contract=..., initial_gaps=...)
run = host.run(case, max_steps=1)
proposal = host.generate_proposal(case)
preview = host.preview(case, proposal)
assessment = host.assess_policy(case, preview)
approval = host.approve_all(case, assessment)
result = host.commit(case, approval)
replay = host.replay(case)
What Each Method Does¶
| Method | Use it to |
|---|---|
from_env(packs=[...]) |
Create a local host and register workflow packs. |
open_case(...) |
Start the durable unit of work. |
run(...) |
Let workers resolve frontier gaps and record evidence. |
generate_proposal(...) |
Suggest case-changing actions without executing them. |
preview(...) |
Record expected before/after effects. |
assess_policy(...) |
Decide whether the preview is allowed, blocked, or approval-ready. |
approve_all(...) |
Record operator approval for local examples. |
commit(...) |
Plan, execute, receipt, verify, and optionally compensate. |
replay(...) |
Rebuild the projected graph from events. |
Packs¶
A pack is the user-owned workflow module registered with EngineHost.
Generated packs expose imports like:
Bundled examples expose imports like:
from casegraph_minimal_transactional import minimal_transactional_pack
from casegraph_support_escalation import support_escalation_pack
Support escalation is only a reference/demo pack. It is not core domain support.
Existing Agent Frameworks¶
CaseGraph can sit around LangGraph, LangChain, Pydantic-AI, direct OpenAI, or custom Python code.
Use cover.case(...) when the framework returns a typed cover.Decision and you want a governed
CaseGraph outcome.
Use cover.run(...) only when you want capture-only runtime instrumentation:
from casegraph import cover
with cover.run("incident_triage"):
result = incident_agent.run_sync(prompt, deps=active_deps)
That shape also covers supported LangChain invoke(...), LangGraph invoke(...), and OpenAI SDK
responses.create(...) or chat.completions.create(...) calls. CaseGraph records sanitized local
coverage artifacts under .casegraph/coverage/; it does not require Postgres, EngineHost,
workers, packs, or evidence mappings for this first pass.
Inspect recent runtime coverage locally:
Those systems can still run inside workers when you are ready to promote coverage into cases. CaseGraph owns the case boundary: evidence, proposed actions, policy, approval, commit receipts, and replay.
Framework adapters are optional. A native CaseGraph project does not install Pydantic-AI, LangGraph, LangChain, or provider SDK extras. Install only the integration you are using:
uv add "casegraph[pydantic-ai]"
uv add "casegraph[langchain]"
uv add "casegraph[langgraph]"
uv add "casegraph[openai]"
The advanced Pydantic-AI worker-step adapter remains available as
casegraph.adapters.pydantic_ai when you are already authoring CaseGraph workers and want to map
typed framework output into explicit CaseGraph observations and claims.
Worker Steps¶
Use @worker(...) to expose a typed Python function to CaseGraph, and context.step(...) inside
that function when the worker has meaningful internal operations:
@worker(id="intake_reviewer", resolves="intake")
def review_record(context: WorkerContext) -> WorkerOutput:
with context.step("retrieve_intake", input_summary={"record_id": "intake-001"}) as step:
review = retrieve_intake(...)
step.output_summary({"status": "found"})
step.observation(...)
step.claim(...)
return WorkerOutput()
Steps are flattened into normal CaseGraph provenance records. They make large workers and wrapped framework flows easier to inspect without adding a new graph ontology.
worker_function(...) is still available for manual adapter construction, but the decorator is the
greenfield authoring path.
Pack Validation¶
For generated packs, use: