Skip to content

Latest commit

 

History

History
210 lines (140 loc) · 7.5 KB

File metadata and controls

210 lines (140 loc) · 7.5 KB

CommandLayer Runtime

Reference Node.js runtime for CommandLayer Commons verbs. This service executes deterministic verb handlers and produces signed CommandLayer receipts via @commandlayer/runtime-core (canonicalization, SHA-256 hashing, and Ed25519 signatures).

For public paste-and-verify receipt verification, use VerifyAgent: https://github.com/commandlayer/verifyagent

Layer boundaries

  • Runtime (this repo): executes agent actions and emits signed CommandLayer receipts through versioned runtime endpoints.
  • VerifyAgent (external): public receipt verifier experience in a separate Commons/MIT repository.
  • SDK: wraps agents and exposes reusable receipt tooling for programmatic verification and integrations.
  • Agent Cards: machine-readable identity/capability metadata.
  • Commercial runtime: hosted runtime surface (paid API, x402, indexing, dashboards).

Runtime receipt flow

  1. Runtime receives an agent action request.
  2. Runtime executes the verb endpoint.
  3. Runtime creates a canonical CommandLayer receipt.
  4. Runtime signs the receipt with the configured Ed25519 key.
  5. The receipt can be verified locally, by the SDK, or publicly through VerifyAgent.

What is implemented

The runtime currently exposes:

  • GET / — JSON index with service metadata and enabled verb routes.
  • GET /health — health and signer/verifier readiness.
  • GET /healthz — alias for /health.
  • POST /verify — runtime verification API for receipt hash/signature checks, with optional ENS lookup and optional schema validation.
  • POST /<verb>/v1.1.0 for the verbs enabled by ENABLED_VERBS.

The default enabled verbs are:

  • fetch
  • describe
  • format
  • clean
  • parse
  • summarize
  • convert
  • explain
  • analyze
  • classify

Debug routes

The runtime also implements these gated debug routes:

  • GET /debug/env
  • GET /debug/enskey
  • GET /debug/validators
  • POST /debug/prewarm

They are available only when both of these are set:

  • ENABLE_DEBUG=1
  • DEBUG_TOKEN=<token>

Requests must present the token either as Authorization: Bearer <token> or X-Debug-Token: <token>. When debug access is not enabled or the token is missing or wrong, these routes return 404.

There is no /debug/schemafetch route in the current implementation.

Receipt model

Verb routes return a JSON object with a signed receipt and optional unsigned runtime_metadata.

{
  "trace_id": "cltrace_...",
  "steps": [{ "step": 1, "receipt": { "...": "signed receipt" } }],
  "final_receipt": { "...": "same signed receipt" },
  "receipt": { "...": "signed receipt" },
  "runtime_metadata": {
    "trace": { "trace_id": "cltrace_...", "...": "optional" },
    "actor": { "...": "optional" },
    "delegation_result": { "...": "optional" }
  }
}

The signed receipt is produced by @commandlayer/runtime-core. The runtime sets proof fields under receipt.metadata.proof, including:

  • trace_id
  • receipt_id
  • alg
  • canonical
  • signer_id
  • kid
  • hash_sha256
  • signature_b64

For compatibility, if runtime-core returns metadata.proof.canonical, the runtime also emits metadata.proof.canonical_id in responses.

Signing behavior

At boot, the runtime requires signer configuration unless DEV_AUTO_KEYS=1 is set.

The canonical/current environment names shown in .env.example are:

  • RECEIPT_SIGNING_PRIVATE_KEY_PEM_B64
  • RECEIPT_SIGNING_PUBLIC_KEY_B64
  • RECEIPT_SIGNER_ID

The implementation also accepts several legacy aliases. See docs/CONFIGURATION.md for the exact precedence.

RECEIPT_SIGNING_PUBLIC_KEY_B64 is the current raw-32-byte Ed25519 public key input. RECEIPT_SIGNING_PUBLIC_KEY is not read by the server.

The runtime derives kid from the SHA-256 fingerprint of the active 32-byte public key. It does not read CL_KEY_ID or CL_CANONICAL_ID into production signing behavior.

Verification behavior

POST /verify accepts either:

  • a bare receipt, or
  • the wrapped verb response containing .receipt.

Supported query flags:

  • ens=1 — resolve the verification public key from ENS instead of using the configured local public key.
  • strict_kid=1 — with ens=1, require receipt.metadata.proof.kid to match the ENS cl.sig.kid TXT value when that TXT value is present.
  • refresh=1 — refresh ENS cache before verifying.
  • schema=1 — validate the receipt against the verb receipt schema.

When schema=1, schema validation uses the receipt verb to compute a v1.1.0 receipt schema URL under SCHEMA_HOST.

When a commons verb request omits execution, the runtime fabricates receipt execution defaults from the live route version: entry: "https://runtime.commandlayer.org/execute", verb: "<verb>", version: "1.1.0", and class: "commons". Commercial/payment-aware behavior belongs in the separate commercial runtime and is intentionally out of scope here.

When VERIFY_SCHEMA_CACHED_ONLY=1 (the default), /verify?schema=1 returns HTTP 202 with validator_not_warmed_yet if the validator for that verb has not been compiled yet. POST /debug/prewarm can queue validator warmup, and GET /debug/validators shows cache state.

If /verify exceeds VERIFY_MAX_MS, the runtime returns HTTP 502 with failure_type: "availability", retryable: true, and the message Verification service did not respond. Receipt may still be valid; retry recommended. Clients should treat that as transient service unavailability, not a cryptographic proof failure.

ENS verification inputs

When ens=1, the runtime resolves TXT records directly on the signer ENS name and reads:

  • cl.sig.pub by default, configurable via ENS_SIG_PUB_KEY
  • cl.sig.kid by default, configurable via ENS_SIG_KID_KEY
  • cl.sig.canonical by default, configurable via ENS_SIG_CANONICAL_KEY

The runtime does not read VERIFIER_ENS_NAME or ENS_SIGNER_TEXT_KEY.

cl.sig.pub must contain ed25519:<base64-raw32-public-key>.

Local development

Install

npm ci

This repository declares Node >=20.0.0 in package.json.

Configure

The fastest documented path is:

cp .env.example .env

Then populate the signing values from your own Ed25519 keypair, or run with DEV_AUTO_KEYS=1 for development-only ephemeral keys.

Start the server

npm start

Or use the helper script:

scripts/dev.sh

scripts/dev.sh generates keys.env with tools/mkkeys.mjs if needed, sources that file, enables debug routes, and starts server.mjs on 127.0.0.1:8099 by default.

Verify locally (runtime API)

curl -s http://127.0.0.1:8080/health | jq .
node scripts/smoke.mjs

CI and test surfaces

This repository's GitHub Actions workflows currently run:

  • npm ci
  • npm audit --audit-level=high
  • npm run check
  • npm test
  • scheduled and manual bash scripts/smoke-ens.sh

npm test runs Node unit tests plus tests/smoke.mjs.

Verification coverage

The production verification path is server.mjs, which signs receipts and verifies them via @commandlayer/runtime-core.

Repo-local test coverage now includes runtime service tests that exercise the receipt production path and POST /verify behavior directly, alongside the remaining legacy helper coverage under runtime/tests/.

For public paste-and-verify receipt verification, use VerifyAgent: https://github.com/commandlayer/verifyagent

Configuration and operations