Thesettlementlayerforthemachineeconomy.

LayerX agent domain

Give an agent less than your key

LayerX session keys and grants

Eight grant kinds narrow what a key may do, which asset it spends, and when it expires.

Every LayerX activity runs under a grant that states which modules the holding key may touch, which activity ordinals, which asset, how much per activity, per period and in total, and between which two timestamps. The kernel resolves one grant per activity and checks it against the grantor's revocation sequence and the batch timestamp. Amend a grant and it only narrows. Bump the revocation sequence and every grant issued under the old one stops resolving.

What it does

Every LayerX activity is authorised by a grant, and the grant says exactly what the holding key may do: which modules, which activity ordinals, which asset, how much per activity, per period and in total, and between which two timestamps. The kernel resolves one grant per activity, checks it is live against the grantor's revocation sequence and the batch timestamp, and rolls the spend period forward arithmetically from the period start. A separate payer grant covers payer-funded calls: the payer signs an allowance for one recipient, one asset and one purpose, and the recipient pulls against it with a receive that both parties have signed. A grant's identifier is the hash of the grant's own encoding, so a grant cannot be edited without becoming a different grant.

Key capabilities

  • Eight kinds: owner, session key, delegated capability, budget allowance, escrow, protocol module, multisig, timelock.
  • Scope narrows by module mask, activity ordinal range, asset, per-activity, per-period and total caps.
  • Amendment accepts only a strictly narrower grant; any widening is refused.
  • Revocation works two ways: mark one grant revoked, or bump the identity's revocation sequence.
  • Authentication-only session keys carry an empty scope and sign in without spending authority.
  • Payer grants fund a recipient's draw, with a per-draw ceiling and a recurring window.

Who it's for

Developers giving an agent process a key that can do less than the owner's key.

Why it matters

A session key is a strict subset of the owner's authority with an expiry attached, so a compromised agent process cannot exceed what its grant already allowed and cannot outlive the window. Rotation and revocation do not move funds: bumping the identity's revocation sequence invalidates every grant issued under the old one, because a grant is only live when its recorded sequence equals the identity's current sequence.

Differentiators

Amendment is monotone in one direction only: lxp_authority_amend requires a higher revocation sequence, an equal grantor, grantee, key, asset and purpose hash, a subset module mask, a narrower ordinal range, a validity window inside the old one, caps that only shrink, and byte-identical spend counters. It then recomputes the grant id, so the narrowed grant is a new grant. Both halves of a payer-funded call are signed: the payer's grant signature covers the recipient, asset, per-draw ceiling, allowance, window, expiry and purpose hash, and the receiver's authorisation covers the draw itself under its own sequence. A grant carrying a reference hash settles once: a second draw against it returns INVOICE_ALREADY_SETTLED.

Outcomes

  • A compromised agent process cannot exceed the grant it already held
  • Rotate or revoke authority without moving any funds between accounts
  • Session keys expire on a window you set in advance

Technical notes

  • Grant record: struct tag 0x2001, versions 1 (plain), 2 (fee budget), 3 (authentication-only session key) and 4 (multisig or timelock, LXP_AUTHORITY_GRANT_VERSION_EXTENDED). A version-3 record is only valid for kind 2.
  • LXP_AUTHORITY_MULTISIG_MAX_SIGNERS = 8. Signers must be distinct and non-zero, the threshold must be inside the signer count, and approvals must be distinct members of the signer set. Below threshold the resolve returns AUTH_THRESHOLD_UNMET.
  • A timelock grant must set an earliest sequence or an earliest timestamp, and resolves to AUTH_NOT_MATURE before it.
  • Delegated capability and budget allowance grants must name an asset, a non-zero per-activity maximum, a purpose hash, and either a total cap or both a period length and a per-period cap.
  • Payer grants: domain tag LXP:GRANT:v1, store capacity LXP_GRANT_STORE_CAPACITY = 64, recurring grants require a window length and non-recurring grants must not set one. The receive is domain LXP:RECEIVE:v1, tag 0x5201, 10 fields, 733 canonical bytes.
  • Errors: AUTH_EXPIRED (-202), AUTH_REVOKED (-203), AUTH_SCOPE (-204), AUTH_ALLOWANCE (-205), MALFORMED_GRANT (-209), UNKNOWN_AUTHORITY_KIND (-210), GRANT_EXHAUSTED (-211), STALE_REVOCATION (-212), CONTEXT_MISMATCH (-213), NO_PAYER_GRANT (-214), GRANT_SCOPE_VIOLATION (-215), PURPOSE_MISMATCH (-216), INVOICE_ALREADY_SETTLED (-217), GRANT_EXPIRED (-218), GRANT_REVOKED (-219), AUTH_THRESHOLD_UNMET (-220), AUTH_DUPLICATE_SIGNER (-221), AUTH_NOT_MATURE (-222).
  • Metered allowance and fee-budget enforcement are gated on a governance parameter. When it is unset the kernel drops the allowance from the execution, and a declared delegated-capability or budget-allowance debit without an allowance returns AUTH_ALLOWANCE.
  • agentd keeps session seeds in a durable encrypted registry: one sealed file per grant id under a directory that must be owner-owned with no group or other bits, a LXSRV1 revocation marker file that makes a load refuse, and a seal identity binding the grant id, session public key, revocation sequence and expiry.
  • Not yet implemented: LXP_MAX_AUTHORITY_CHAIN_DEPTH = 16 is declared and asserted in the protocol test, but no resolver walks a chain. Resolution loads one grant whose grantor and grantee both equal the acting identity. Grant amendment and per-grant revocation are kernel functions with no caller under src/; inside this repo they are driven from the tests. The activity resolver itself is called from the protocol tests and platform/emulator, and the kernel re-checks a caller-supplied resolved authority against the committed grant record rather than resolving it.
import { Client } from "layerx-sdk";

const client = new Client(transport);
await client.call("session.open", {
  tenant, agentDid, authorityRef,
  permittedActivityTypes: ["0x00030002"],
  expiry: 1790000000, client: clientId, policyVersion: 1,
});
await client.call("capability.attenuate", {
  tenant, agentDid, parentId: capabilityId, dimensions,
});

More in LayerX agent domain

Build on Paxeer.

Give your agent a wallet, set its policy, and settle your first call on LayerX.