Choose an integration pattern
An agent can stand on an Arxo canon in four ways. They differ in two things: what the model sees, and what the answer carries back. Pick the pattern before you write instructions or tools, because it decides who pins the canon, who asks for the date of law, and whether every answer can be replayed.
In three of the four patterns the model never sees Arxo at all. It calls tools named after your domain — “end of a period”, “check the claim documents” — and your application answers them with the engine. The user sees your product; the canon is the foundation underneath.
The four patterns
Section titled “The four patterns”| Pattern | What the model sees | Where the canon runs | What an answer carries | Use it when |
|---|---|---|---|---|
| Domain tools over the local SDK | your tools, e.g. period_end | in your process, @arxo/law with the engine in WebAssembly, offline after install | status, values, proof, sources, three hashes, the canonical document | you ship a product on one or a few canons |
Domain tools over your own law serve | your tools | a long-running HTTP service you host, with journals | the same answer, plus the exact embedded document bytes | several applications or languages share one pinned deployment |
| Domain tools over a generated module | your tools | code printed from the canon by law codegen (TypeScript, Python, Go); no engine at run time | truth status, evaluation status, issues, judgment requests — no proof, no hashes | the engine cannot ship with the product and replay is not required |
| The agent explores the canon over MCP | Arxo tools: law_search, law_rules, law_ask and the rest | the public Arxo host or your own MCP server | the host’s answer projection | research assistants and open questions across many canons |
The first agent of this section uses the first pattern; example A (one labour-law question) uses the fourth.
Domain tools over the local SDK
Section titled “Domain tools over the local SDK”The application opens a pinned canon by name and version and keeps the handle for the life of the process:
import { open } from '@arxo/law';const canon = await open('de.bgb.fristen@0.1.0'); // checked against its contentHashEach domain tool is a small function: it maps the tool’s arguments to
typed facts, asks one question, and returns the status, the values and
the grounds in the application’s own words. The SDK rejects a fact
that does not fit the canon — an unknown relation, a wrong arity or
type — with FactError before the engine runs, so a model that invents
a field cannot reach a result.
Status: ran locally (@arxo/law 0.3.3, de.bgb.fristen@0.1.0); the
complete tool is in Build your first agent.
Domain tools over your own law serve
Section titled “Domain tools over your own law serve”The same tools, but the application asks a service instead of an
in-process engine: open(name, { serve: { endpoint, token } }). The
service is a journaled HTTP deployment with /v1/... routes that you
run and upgrade yourself; see Private HTTP
service. Choose it when the pinned
world must be one shared deployment rather than a copy inside each
application.
Domain tools over a generated module
Section titled “Domain tools over a generated module”law codegen prints an installable TypeScript, Python or Go package
from a canon installed in a project. The module evaluates without the
engine and returns one answer envelope per question: truth status,
evaluation status, issues and judgment requests, under the same status
names. It carries no proof graph and no hashes, so an answer cannot be
replayed or audited byte for byte, and a canon construct outside the
generator’s coverage is refused when the module is generated, not at
run time.
Status: NOT RUN in this section — there is no agent example on a
generated module yet. The command accepts the targets py, ts and
go; to try it, install a canon into a project and run
law codegen <package> --target ts --name <npm-name> --version 0.1.0 --out lib-ts.
The agent explores the canon over MCP
Section titled “The agent explores the canon over MCP”The model itself searches for a question, reads the rules’ input
contract (law_rules with contract: true), collects facts and calls
law_ask. This is the right pattern when the question is not known in
advance. An MCP profile narrows the tool surface and the packages a
server exposes; it restricts what the agent can reach, it is not a
different way of computing. Connect and
discover covers this pattern end to end.
What stays the same in every pattern
Section titled “What stays the same in every pattern”- The engine decides. Neither the model nor your application computes, rounds, compares against a threshold or fills a missing value. A domain tool returns what the engine returned.
- The date of law comes from a person. A tool takes it as an argument; the agent asks for it and never defaults it to today.
- Statuses survive the translation. A domain tool must pass the
evaluation status through. An empty collection,
NEITHERor a non-COMPUTEDstatus is a stop, not “no” and not zero. The full reading is in Read answers. - The contract applies to the whole system. When the model cannot see a field, the obligation moves into your application code; see The agent contract.
Choose
Section titled “Choose”- Is the question known when you build the product? If yes, write domain tools; if the agent must find the question, use MCP.
- Must every answer be replayable and carry its proof? If yes, use the
SDK or
law serve; a generated module does not carry them. - One process or a shared deployment? One process: the SDK. Several
applications on one pinned world:
law serve.
Failure case: the tool that drops the status
Section titled “Failure case: the tool that drops the status”A domain tool returns only end_dates[0]. On a case where the user
did not give the period’s length, the engine completes the evaluation
with an empty collection; the tool returns undefined, and the model
fills the gap with a date it counted itself. The fix is structural:
return the status, the full value list and the grounds every time, and
say in the tool result that an empty list is not an answer. The first
agent’s tool does exactly that.
Status: labeled illustration; the empty-collection behavior itself ran locally and is recorded in Build your first agent.
How to verify
Section titled “How to verify”- Open a canon with
@arxo/lawand ask one question; the answer hasevaluationStatus,value,proofandhashes. - Run
law codegen --helpand read the target list. - Connect to an MCP server and read
tools/list; it is the authority on which tools exist.
Previous: Agent Engineering with Arxo Next: Build your first agent
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.