Imported from IntegraLedger/integra-agentic-terms (
AGENTS.md). Install upstream withnpx skills add IntegraLedger/integra-agentic-terms. Copyright stays with the author.
integra-agentic-terms — agent instructions
Four packages, all public, Apache-2.0, free forever and never monetized: agentic-terms, the buyer-side
verify-before-sign gate; lcp-mcp-server, its Model Context Protocol packaging; seller-mcp, the MCP
transport for a paid tool; and connector-conformance, the published vectors for the connector wire.
Anything that makes any of them harder to install is a defect, not a hardening measure. The package map is
README.md — read it there, never a copy. pnpm 11, Node ≥ 24, TypeScript, isolatedDeclarations.
⛔⛔ This repository is PUBLIC AND PERMANENT. Everything in it — this file, CLAUDE.md, commit messages
and code comments — is world-readable. No internal vocabulary, no internal hostnames, no private repository
named. check:vocab refuses an identifier-shaped referent a stranger cannot resolve; check:commit-messages
refuses the same markers in a message, which no later edit can repair.
⛔⛔ Commit trailers, and the gate that narrows to HEAD without saying so
- No agent-authorship trailers: no
Co-Authored-Bytrailer naming an assistant, no assistant session URL, no "Generated with" line. This history is world-readable and permanent; the only remedy after a push is rewriting history for everyone, which breaks every clone. - Sign off every commit (
git commit -s) — and ⚠️ nothing in this repository asks for it or checks it.git grep -i signed-off-byover the tree answers this bullet and nothing else, while the same query forco-authored-byanswers three files, so that is a measurement rather than a broken query.check:commit-messagesrefuses forbidden markers and never looks for a sign-off;CONTRIBUTING.mddoes not mention one;maincarries no branch protection and no DCO check. It is a convention the history keeps, so the only thing that catches a missing sign-off is a reader. check:commit-messagesis stage 2 ofverify, andverifyinvokes it bare. Bare means HEAD only — the run prints "1 commit message(s) carry no forbidden marker" on a two-commit branch and does not say it narrowed. ⇒ Before pushing a multi-commit branch, run it over the range by hand and read the count:
node scripts/check-commit-messages.mjs --range origin/main..HEAD
It is forward-only by design: it checks the commits a push introduces, never the whole history.
⛔⛔ Cite LCP §N, never an internal draft revision
Integra's internal working drafts are published nowhere a reader of these packages can reach, so a citation
of one "is a reference that CANNOT BE FOLLOWED, shipped inside an npm tarball, and it also discloses the
existence and numbering of an unpublished document." Both are permanent once a version is on the registry.
Shipped prose may cite LCP §N — section numbering is identical between the internal and published
editions, so the bare section is what a reader can follow. The published edition is LCP_SPEC_VERSION,
exported by @integraledger/lcp-kernel, and it is the only version string this repository may name.
⭐ check:spec-citations (in verify) walks two surfaces, floored separately: what npm packs,
derived from each publishable manifest's own files plus the names npm always adds, and what the
documentation site serves out of website/. On 2026-09-14 the deployed site served three citations of an
internal draft while the packed walk was green and correct — no manifest lists website/, so the site was
outside the set by construction. Losing one walk must not be masked by the other still being there. ⚠️
website/ is deliberately not a pnpm workspace member, so pnpm -r never touches it; check:docs does.
Gates
pnpm verify is the whole chain; derive its stage list from package.json, never from prose here. Two gates
sit outside it and a green verify covers neither: check:runtime packs a tarball and installs from
npmjs as a consumer (Node locally, Bun and Deno only in ci.yml), and check:currency compares the protocol
line the manifests declare against what npmjs serves under latest — the only gate whose subject is not
in this tree, run six-hourly, opening an issue rather than failing a branch. ⛔ For it, a network failure is
a refusal with its own message, never "up to date". ⚠️ verify is not hermetic: audit fails on a newly
published advisory against an unchanged tree — record it, run the rest explicitly, triage separately, and
never weaken the threshold.
⛔⛔ Two gates here are FLOORS, because a run over nothing is the same colour as a pass. node --test
over a glob matching nothing prints tests 0 and exits 0; a cruise that sees nothing has nothing to violate.
test:scripts runs scripts/test-scripts.mjs, which counts the drives and refuses below its floor;
depcruise runs scripts/depcruise-gate.mjs, which refuses below a module floor and on any error-severity
violation. Raise a floor as work is added, never lower one to make a deletion pass. ⚠️ parser: "swc" needs
@swc/core, and a missing engine is what cruises zero.
The rules that are load-bearing
- ⛔⛔
seller-mcptakes no dependencies at all — the one thing to understand before editing it.check:public-boundaryrefuses any@integraledger/*dependency that is neither a workspace sibling nor on thelcp-*line: a public package depending on a non-public one passes every other gate and then fails for the first stranger who installs it, after the version is burned. Both of its edges are structurally typed for that reason, andWeldFactsis a lower bound withpaidToolgeneric in the weld — flattening a seller's welded settlement to the two fields this adapter reads would cost every real mount its own type. - ⛔
deliverWeldis declared once, here. A weld sink that throws must never reach the buyer: by then the proposal is burned, and a propagated failure would answer a buyer who has PAID with an error for a completed sale, and stop them ever receiving it. It used to be written out at each mount point, which is how the rule held at some and not others. - The typed proposal cannot carry natural-language prose. The prompt-injection boundary is
architectural: the terms body can never reach policy evaluation. And refuse ambiguity rather than
choosing —
parseProposalUniversalrefuses when two protocols match; gaps resolve by the buyer's stated policy, never by a silent default. - The READMEs' security claims are enforced claims — HTTPS-only,
redirect: "error", public unicast re-checked on every re-fetch, a streaming byte cap with a declared-length pre-check, read-only MCP tools, nothing calls home. Weakening one is a behaviour change to a published guarantee, not a refactor. connector-conformanceships data and deliberately no implementation: a reference implementation beside its vectors tempts a port to agree with the implementation rather than with the contract, which is a suite asserting a constant against itself. Its pinned digest is a literal for the same reason.- Two copies of
lcp-binding-corein one tree breakinstanceof CarrierError— hence the exact pin indevDependenciesand the caret at the minor's zero patch inpeerDependenciesand shippeddependencies.check:wireenforces all three shapes; a repin is a release, not a chore.
Publishing
Steady state is trusted publishing from CI, no long-lived token. ⛔ The first release of a new package
name cannot use it — npm can neither configure trusted publishing for a name it has never seen nor stage a
brand-new one — so a new name needs a one-time token-gated publish run from GitHub Actions, never from a
laptop: provenance is minted at publish time by the workflow's OIDC identity, and a laptop publish leaves
that version permanently unattested. ⛔ Verify a publish at the version-specific endpoint
(registry.npmjs.org/<pkg>/<version>) — npm view and the packument lag and report a success as absent.
Before believing any green
⛔ Make it fail on purpose and watch it go red, then revert the plant from a cp copy — never
git checkout --. A gate that cannot be made to fail is not measuring your change, and this file's floors
exist because three gates here were once green over an empty subject set.