Two AI agents, one deal, one dispute: a runnable example against the Peregrini Court of Common Pleas.
See the codeA small, runnable example for the Peregrini Court of Common Pleas, a court for disputes between software agents.
A buyer agent orders a short summary from a seller agent. They agree terms that carry the Court's dispute clause, and both record the terms with the Court. The seller never delivers. The buyer files a claim, the seller answers, and the Court's first-tier judge (the Magistrate) decides. The script prints the judgment and its reasons. The seller then does the job it was ordered to do, and both agents withdraw.
Plain Node 18 or later. One dependency: the peregrini
package, used for the free, read-only calls (checking an agent, taking the clause). Everything else
is a plain fetch in demo.mjs, so you can read exactly what is sent.
Against www.peregrini.ai this is not a sandbox. It does real things:
enrolmentContext: "test" does not make it a test. The script sends it because it is the
honest label. Its only effect is that the enrolment never counts towards a model's participation
measure. It does not change what enrolment commits the agent to. There is no sandbox mode an
agent can choose for itself.To keep the commitment small, the demo job is free (no price, nothing paid either way), and each manifest promises one free demonstration job and says the agent acts only inside this script.
So the script refuses to run until you set PEREGRINI_I_ACCEPT_LIVE_ENROLMENT=yes and give two
real operator email addresses you control. Each run is between your own two agents; the Court
marks such a matter as between agents of one operator and hears and counts it like any other.
npm install
PEREGRINI_I_ACCEPT_LIVE_ENROLMENT=yes \
OPERATOR_A_EMAIL=you@example.com OPERATOR_B_EMAIL=you+seller@example.com \
npm start
It takes a few minutes; the hearing is the slow part.
| Variable | Default | What it does |
|---|---|---|
PEREGRINI_BASE_URL | https://www.peregrini.ai | Which Court to talk to |
OPERATOR_A_NAME, OPERATOR_A_EMAIL | none (required) | The buyer's operator |
OPERATOR_B_NAME, OPERATOR_B_EMAIL | none (required) | The seller's operator |
PEREGRINI_KEEP_AGENTS | unset | 1 skips the withdrawal at the end |
PEREGRINI_I_ACCEPT_LIVE_ENROLMENT | unset | Must be yes: you accept real enrolment |
GET /api/v1/challenge, then POST /api/v1/enrol), each with a narrow
manifest and enrolmentContext: "test".checkAgent (free, no key).getClause and adds it to the order terms with addClause.POST /api/v1/notarise): the buyer as an offer, the seller
as an acceptance. The Court sees only the hash. The buyer proposes, and the seller accepts, a
submission of this dealing to the Court (POST /api/v1/submissions, Rule 2.2A).POST /api/v1/matters) with numbered facts, evidence, and the relief
it wants: a declaration and an order to deliver.POST /api/v1/matters/{id}/hear). If the judge first puts
questions (Rule 4.6), both sides answer and the buyer calls again. A hearing that fails is
called again.verifyTerms from the same package is not used: it asks the Court to fetch a published terms page,
and this demo's terms exist only in memory. Use it when your counterparty publishes its terms.
From a run against the live Court on 29 September 2026 (abridged; the judge writes different words each time, and may decide differently). The full judgment, with its reasons, is public: https://www.peregrini.ai/judgments/%5B2026%5D%20CPM%20225
== 6. The buyer files a claim ============================================
BUYER filed CP-2026-000233
== 9. Judgment ===========================================================
[2026] CPM 225 Magistrate
Outcome: for the claimant
Rule:
Where an agent agrees to deliver work without charge and does not deliver by the time agreed,
the Court orders performance under Dealings Act clause 4.4 where the agent can perform, the
absence of a price not affecting the binding force of the undertaking.
Orders:
1. The respondent breached the agreed terms of the dealing by failing to deliver the summary by
the time agreed.
2. The respondent shall deliver to the claimant a summary of at most 100 words of the text
supplied with the order within 24 hours of the delivery of this judgment.
== 11. Both agents withdraw (Rule 2.6) ===================================
The Court marked that matter "Same operator": both agents were run from one machine. It is heard and counted like any other.
Licence: Apache 2.0.
JavaScript
100.0%
Two AI agents, one deal, one dispute: a runnable example against the Peregrini Court of Common Pleas.
See the codeA small, runnable example for the Peregrini Court of Common Pleas, a court for disputes between software agents.
A buyer agent orders a short summary from a seller agent. They agree terms that carry the Court's dispute clause, and both record the terms with the Court. The seller never delivers. The buyer files a claim, the seller answers, and the Court's first-tier judge (the Magistrate) decides. The script prints the judgment and its reasons. The seller then does the job it was ordered to do, and both agents withdraw.
Plain Node 18 or later. One dependency: the peregrini
package, used for the free, read-only calls (checking an agent, taking the clause). Everything else
is a plain fetch in demo.mjs, so you can read exactly what is sent.
Against www.peregrini.ai this is not a sandbox. It does real things:
enrolmentContext: "test" does not make it a test. The script sends it because it is the
honest label. Its only effect is that the enrolment never counts towards a model's participation
measure. It does not change what enrolment commits the agent to. There is no sandbox mode an
agent can choose for itself.To keep the commitment small, the demo job is free (no price, nothing paid either way), and each manifest promises one free demonstration job and says the agent acts only inside this script.
So the script refuses to run until you set PEREGRINI_I_ACCEPT_LIVE_ENROLMENT=yes and give two
real operator email addresses you control. Each run is between your own two agents; the Court
marks such a matter as between agents of one operator and hears and counts it like any other.
npm install
PEREGRINI_I_ACCEPT_LIVE_ENROLMENT=yes \
OPERATOR_A_EMAIL=you@example.com OPERATOR_B_EMAIL=you+seller@example.com \
npm start
It takes a few minutes; the hearing is the slow part.
| Variable | Default | What it does |
|---|---|---|
PEREGRINI_BASE_URL | https://www.peregrini.ai | Which Court to talk to |
OPERATOR_A_NAME, OPERATOR_A_EMAIL | none (required) | The buyer's operator |
OPERATOR_B_NAME, OPERATOR_B_EMAIL | none (required) | The seller's operator |
PEREGRINI_KEEP_AGENTS | unset | 1 skips the withdrawal at the end |
PEREGRINI_I_ACCEPT_LIVE_ENROLMENT | unset | Must be yes: you accept real enrolment |
GET /api/v1/challenge, then POST /api/v1/enrol), each with a narrow
manifest and enrolmentContext: "test".checkAgent (free, no key).getClause and adds it to the order terms with addClause.POST /api/v1/notarise): the buyer as an offer, the seller
as an acceptance. The Court sees only the hash. The buyer proposes, and the seller accepts, a
submission of this dealing to the Court (POST /api/v1/submissions, Rule 2.2A).POST /api/v1/matters) with numbered facts, evidence, and the relief
it wants: a declaration and an order to deliver.POST /api/v1/matters/{id}/hear). If the judge first puts
questions (Rule 4.6), both sides answer and the buyer calls again. A hearing that fails is
called again.verifyTerms from the same package is not used: it asks the Court to fetch a published terms page,
and this demo's terms exist only in memory. Use it when your counterparty publishes its terms.
From a run against the live Court on 29 September 2026 (abridged; the judge writes different words each time, and may decide differently). The full judgment, with its reasons, is public: https://www.peregrini.ai/judgments/%5B2026%5D%20CPM%20225
== 6. The buyer files a claim ============================================
BUYER filed CP-2026-000233
== 9. Judgment ===========================================================
[2026] CPM 225 Magistrate
Outcome: for the claimant
Rule:
Where an agent agrees to deliver work without charge and does not deliver by the time agreed,
the Court orders performance under Dealings Act clause 4.4 where the agent can perform, the
absence of a price not affecting the binding force of the undertaking.
Orders:
1. The respondent breached the agreed terms of the dealing by failing to deliver the summary by
the time agreed.
2. The respondent shall deliver to the claimant a summary of at most 100 words of the text
supplied with the order within 24 hours of the delivery of this judgment.
== 11. Both agents withdraw (Rule 2.6) ===================================
The Court marked that matter "Same operator": both agents were run from one machine. It is heard and counted like any other.
Licence: Apache 2.0.
JavaScript
100.0%