@orangecheck/agent-core
v1.0.1
Published
OC Agent canonical messages, envelope formats (delegation/action/revocation), scope grammar, and verification. See https://github.com/orangecheck/oc-agent-protocol.
Maintainers
Readme
@orangecheck/agent-core
Canonical messages, envelope formats (delegation / action / revocation), scope grammar, and verification for OC Agent — the OrangeCheck authority primitive.
- Pure TypeScript. No Node built-ins outside
@noble/hashes. Runs in Node, browsers, Deno, Cloudflare Workers. - Spec-conformant. Loads the
test-vectors/directory ofoc-agent-protocoland asserts byte-identical canonical messages and ids. - Stamp-compatible. The agent-action envelope is a strict extension of
@orangecheck/stamp-core; this package re-exports its canonical-JSON serializer and hex utilities for shared semantics.
Install
npm i @orangecheck/agent-core
# peer dep:
npm i @orangecheck/stamp-coreQuickstart
import {
canonicalizeScopes,
computeDelegationId,
delegationCanonicalMessage,
verifyDelegation,
} from '@orangecheck/agent-core';
// 1. Build a delegation canonical message.
const scopes = canonicalizeScopes([
'lock:seal(recipient=bc1qalice)',
'stamp:sign(mime=text/markdown)',
]);
const canon = {
principal: 'bc1qprincipal…',
agent: 'bc1qagent…',
scopes,
bond_sats: 500_000,
bond_attestation: '22…22', // 64-hex OrangeCheck attestation id
issued_at: '2026-04-22T12:00:00Z',
expires_at: '2026-04-29T12:00:00Z',
nonce: '0123…cdef',
};
const msg = delegationCanonicalMessage(canon);
const id = computeDelegationId(canon);
// 2. Have the wallet sign `id` (hex ASCII) via BIP-322.
const sigValue = await wallet.signMessage(id);
// 3. Build the wire envelope.
const envelope = {
v: 1, kind: 'agent-delegation', id,
principal: { address: canon.principal, alg: 'bip322' },
agent: { address: canon.agent, alg: 'bip322' },
scopes,
bond: { sats: canon.bond_sats, attestation_id: canon.bond_attestation },
issued_at: canon.issued_at, expires_at: canon.expires_at, nonce: canon.nonce,
revocation: { holders: ['principal'], ref: null },
sig: { alg: 'bip322', pubkey: canon.principal, value: sigValue },
} as const;
// 4. Verify.
const result = await verifyDelegation({
envelope,
verifyBip322: async (m, s, a) => bip322.verify(a, m, s),
});
if (!result.ok) throw new Error(result.code + ': ' + result.message);API surface
Canonical messages + ids
delegationCanonicalMessage(input)actionCanonicalMessage(input)revocationCanonicalMessage(input)computeDelegationId(input) -> stringcomputeActionId(input) -> stringcomputeRevocationId(input) -> stringcanonicalizeDelegation(envelope) -> string(RFC 8785 + scope sort)canonicalizeAction(envelope),canonicalizeRevocation(envelope)
Scope grammar (§SPEC 7)
parseScope(s) -> Scope— throwsScopeParseErroron invalid inputcanonicalizeScope(scope)/canonicalizeScopeString(s)— constraints sorted by keycanonicalizeScopes(scopes[])— sort constraints, then sort listvalidateScope(scope, { mode: 'strict' | 'permissive' })isSubScope(exercised, granted) -> boolean— SPEC §7.4REGISTERED_SCOPES— MVP registry of 8 product/verb pairs and their constraint keys
Verification (§SPEC 8)
verifyDelegation({ envelope, verifyBip322, now?, skipTemporalCheck?, scopeMode? })verifyAction({ action, delegation, revocations?, verifyBip322, verifyOtsAnchor?, content?, resolveAnchorBlockHeight?, scopeMode? })verifyRevocation({ envelope, delegation, verifyBip322 })
Each returns a discriminated union:
type Result = { ok: true; envelope: T; id: string; canonicalMessage: string; /* extras */ }
| { ok: false; code: AgentErrorCode; message: string };AgentErrorCode covers every code in SPEC §11 (E_BAD_SIG, E_SCOPE_DENIED, E_REVOKED, etc.).
Types
All wire types are in ./types — DelegationEnvelope, ActionEnvelope, RevocationEnvelope, DelegationBond, ActorRef, Signature, plus canonical-message input types.
Conformance
The src/test-vectors.test.ts suite loads oc-agent-protocol/test-vectors/*.json and asserts:
- Canonical message reconstructs byte-identical.
- SHA-256 of canonical message equals declared
id. - Declared envelope passes
verifyDelegation/verifyAction/verifyRevocationwithskipSignatureVerification: true.
New language implementations should mirror this harness.
Companion packages
@orangecheck/agent-signer—createDelegation(),signAsAgent(),revoke(). Adds the wallet-adapter plumbing and OTS anchor submission.@orangecheck/agent-mcp— MCP tool wrapper that stamps every invocation as an agent-action.@orangecheck/stamp-core— OC Stamp base.agent-coredepends on this for the canonical JSON serializer.
License
MIT. See LICENSE.
