Markdown for LLMs
Choose an integration pattern
The source Markdown for this article. Copy it into your assistant or download it as a text file.
# 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
| 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
The application opens a pinned canon by name and version and keeps the
handle for the life of the process:
```js
import { open } from '@arxo/law';
const canon = await open('de.bgb.fristen@0.1.0'); // checked against its contentHash
```
Each 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](/agent-engineering/first-agent/).
### 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](/operate/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
`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
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](/agent-engineering/connect-and-discover/) covers this pattern end to end.
## 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, `NEITHER` or a
non-`COMPUTED` status is a stop, not "no" and not zero. The full
reading is in [Read answers](/agent-engineering/handle-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](/agent-engineering/agent-contract/).
## Choose
1. Is the question known when you build the product? If yes, write
domain tools; if the agent must find the question, use MCP.
2. Must every answer be replayable and carry its proof? If yes, use the
SDK or `law serve`; a generated module does not carry them.
3. 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
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](/agent-engineering/first-agent/).
## How to verify
- Open a canon with `@arxo/law` and ask one question; the answer has
`evaluationStatus`, `value`, `proof` and `hashes`.
- Run `law codegen --help` and 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](/agent-engineering/)
Next: [Build your first agent](/agent-engineering/first-agent/)