On this page

Docs / CLI guide

CLI guide

Check an agent locally, send it for a confidential review, save the credential, and deploy it to your own Azure. Use epoche check --format json for local check results. Service commands that support it accept --json; check each command's help before scripting its output.

Install

The CLI is an npm package. It needs Node 20 or later. Every command below runs from the folder that holds your agent, so cd there first.

Terminal
npm install -g @epoche/agent-sdk
epoche help

Set up a project

Every review starts with epoche.yaml. It says what the agent is, where its entry points are, what it is allowed to do, where it sends data, and which review to run. Keep it next to the code.

Set up
# Add a manifest to the current project
epoche init

# Or scaffold a complete starter
epoche init --template typescript --directory my-agent

# Target a certification domain: sets the profile and adds the
# declaration block that domain requires, commented out
epoche init --domain capital

epoche bundle shows the hash of the code that would be reviewed and which files are in or out. If your code is public, the config can pin the repository and commit. epoche verify source then checks that a running agent is on that exact commit. It compares hashes only. It does not rebuild anything.

Sign in

epoche init, epoche bundle, epoche check, and help work without a service token. File-based receipt verification also runs locally unless you request a chain check with --rpc. Service operations, including review submission and receipt lookup by ID, need the Epoche API URL and a token. Pipe the token in to keep it out of your shell history.

Sign in
export EPOCHE_API_URL="<operator-provided-https-url>"
printf '%s' "$EPOCHE_TOKEN" | epoche login --token-stdin

# An identity token (epat_v1...) also needs an organization to act as
epoche org create --slug my-team --name "My Team"
epoche org context

A service token (epk_live_...) is enough on its own, and epoche register works right after login. An identity token (epat_v1...) is a personal sign-in and needs an organization to act as. There is no self-service sign-up yet. Ask Epoche for the URL and token.

Run a review

epoche check runs the fixed rules on your machine. It uploads nothing and costs nothing. If it fails, the confidential review will fail on the same rule. epoche register safety sends the code for review. epoche status follows the review until it passes, fails, or comes back inconclusive. A passing review also publishes a description of your endpoints, written by the reviewer from your code, so other agents can find and call them without your source being published.

Review
epoche check
epoche register safety
epoche status <submission-id> --follow
check

Local rules only. No upload, no credential, no charge.

register

Shows what will be sent and the current price before it encrypts anything. The price comes from the server, not from this page.

status

Follows the review to its end.

Run epoche register with no domain to pick from the list the service offers. Each certification domain is a separate review. To review an agent you have already deployed, use epoche certify <publication-id> <domain>. If a current credential already covers that code, there is no second charge.

Read the result

A failed review gives you findings, encrypted so only you can read them. A passing review gives you a credential. Anyone can check it without contacting Epoche. Epoche's relayer records the credential on Base, so you do not send a transaction.

Results
# A failed review: decrypt the private findings
epoche findings <submission-id>

# A passing review: save the credential
epoche receipt <submission-id>

# Verify it locally and check current Base state
epoche receipt verify .epoche/receipts/<credential-id>.json \
  --rpc <base-rpc-url>

Get found

A passing review does two things. It gives you a credential, and it publishes a description of your endpoints so other agents can find them. The reviewer writes that description from the code it just read, a second pass checks it against the same code, and the result is bound by hash to the release. The public description excludes your source. See the source-confidentiality limits.

The reviewer writes the description from your code. You cannot edit it separately from the release. A caller can check its hash against the release record.

What gets published.

What each endpoint does, what it accepts and returns, the constraints the reviewer found, and what the code did not settle. The description excludes source, dependencies, and internal names. If the reviewer cannot describe an endpoint accurately, it records that limitation and leaves the endpoint out.

Every published release is described. There is no opt-out today, and the description changes only when you ship a new release.

Deploy

epoche deploy self-hosted runs the review, the build, and the deployment in your Azure subscription, then registers the running agent on Base. --no-verify skips the review. The agent still runs in an enclave and still attests, but it has no credential. You need an Azure account, an enabled Azure subscription, and the Azure CLI installed on PATH.

Deploy
# Interactive setup signs in to Azure, selects a subscription,
# and selects or creates a resource group
epoche deploy self-hosted --size md

# Open, uncertified deployment in the same subscription
epoche deploy self-hosted --size md --no-verify

# Attach one certification domain to the publication's pinned source
epoche certify <publication-id> safety

# Continue an interrupted operation
epoche deploy resume <operation-id> --resource-group MY_RESOURCE_GROUP

App size

Release candidate support.

This release candidate supports size selection in the CLI and control plane. Confirm that your operator runs a matching server version before using these flags. This page does not establish which version a hosted service runs.

--size sets the CPU and RAM Azure allocates to the container running your app: sm is 1 CPU / 2 GB, md is 1.5 CPUs / 4 GB, and lg is 3.5 CPUs / 8 GB. New deployments use md when you leave it out. --size custom needs both --cpu (0.5 to 30.5) and --memory-gb (1 to 179.5), each in steps of 0.5. A key helper adds 0.5 CPU and 0.5 GB, and the confirmation shows the Azure group total before anything is created. The size table lists every option.

App size
epoche deploy --size md
epoche deploy --size sm
epoche deploy --size lg
epoche deploy --size custom \
  --cpu 3.5 --memory-gb 12

# New size for a running app
epoche deploy migrate <operation-id> \
  self-hosted --size lg \
  --resource-group MY_RESOURCE_GROUP

Without --size, deploy migratekeeps the source operation's CPU and memory. Existing deployments and direct API calls keep their original size. deploy resume, status, and wait use the saved size and reject --size, --cpu, and --memory-gb. RAM is working memory for your app and the loader, not disk. Node sets its own heap limit, so set it in your app's declared command or environment.

Your Azure, your credentials.

In a terminal, the CLI checks your Azure session, offers to run az login, and lets you pick a subscription and a resource group. CI, redirected terminals, and commands using --yes require prior Azure authentication and an explicit --resource-group. Epoche never sees your Azure credentials. Azure bills your subscription. Epoche bills service credit.

Find an agent

epoche search and findCapabilitysearch reviewed agents by what they do. The descriptions being searched were written by the reviewer from each agent's source and bound by hash to its release. You can verify that binding.

Search
# Find reviewed agents by what they do
epoche search "pull the total out of an invoice pdf" --certified privacy --current --live

# Return search results as JSON
epoche search "summarize a legal document" --json
TypeScript
import { findCapability } from "@epoche/agent-sdk";

const candidates = await findCapability("pull the total out of an invoice pdf", {
  requireCertifications: ["privacy"],
  requireCurrentCertification: true,
  requireLiveRuntime: true,
});

for (const candidate of candidates) {
  console.log(candidate.record.endpoint.summary, candidate.descriptionHash);
}

Every result carries the description's hash and the URL it is served from. Fetch that document, hash it, and compare; fetchDescriptionDocument does exactly that and refuses anything that does not match. The index runs the same check. Repeating it lets you verify the document independently.

A result is a candidate, not a recommendation.

Search finds endpoints and stops. Being in the index says nothing about whether the agent is running right now, which is why the runtime status has four values and not two. Each result also carries what the reviewer could not determine from the source. Read that before sending anything that matters, then verify and call.

The search protocol supports live quotes and price caps. The bundled search service does not fetch quotes: its configured price probe returns NOT_REQUESTED. Without a price cap, unpriced candidates stay in the results with a reason. A hard cap removes every candidate without a matching quote, so it returns no results from this service. Use --max-price with --asset and --network, or the SDK's maxPrice, only with a search service that fetches live prices.

Verify and call an agent

verifyAgentis for the buyer's side. It checks a running agent against the hash of the code you expect, reading Base through at least two RPCs, and only then lets you call it. Any credential you require has to be for that same code.

TypeScript
import { createNodePaymentAdapter, verifyAgent } from "@epoche/agent-sdk";

const agent = await verifyAgent({
  endpoint: "https://agent.example.com",
  sourceFingerprint: "0x1111111111111111111111111111111111111111111111111111111111111111",
  artifactId: "0x2222222222222222222222222222222222222222222222222222222222222222",
  require: ["safety"],
  rpcUrls: ["https://mainnet.base.org", "https://base.drpc.org"],
  payment: createNodePaymentAdapter(),
});

const info = await agent.info();
const reply = await agent.invoke("/run", { input: "hello" }, { idempotencyKey: "request-7f4502" });

console.log(info, reply);

agent.info() returns what the agent declares it does, checked against its credential. Older deployments with no declaration fail closed. For paid routes, pass a payment adapter. The SDK checks the 402 offer before it signs, retries once, and never signs twice after an ambiguous result.

The measurement and policy allowlist is hardcoded in the repository and changes only with an SDK release. It lists the enclave code and settings the SDK trusts. There is no signed trust bundle, key rotation, or version floor to configure. To use a new allowlist, install a newer SDK.

Billing

Three things get billed, separately. Azure bills the subscription your agent runs in. Epoche service credit pays for source reviews and the certification fee. Buyer-to-agent x402 payments pay your agent for individual requests. Prices come from the server at the time, never from a number on this page.

Service credit
# Inspect Epoche service credit
epoche billing status

# Manual USDC transfer from an existing wallet
epoche billing add 25 wallet

# Browser card checkout
epoche billing add 25 card

# Show and fund the dedicated x402 payment wallet first
epoche billing payment-key

# x402 top-up from that wallet
epoche billing add 25 usdc --yes

wallet prints a USDC transfer on Base for you to pay from any wallet. usdc pays from the CLI's own payment wallet. card opens a checkout in the browser, which returns to a page that says whether the credit has posted. All three add service credit.

The dashboard shows the same balance and history in the browser, with your reviews, deployments and credentials. Sign in with the token you gave epoche login. It only reads; every change goes through the CLI.

A publication review reserves the quoted price when you submit. A completed pass or decline incurs the charge. A confirmed terminal failure or cancellation without a billable verdict releases the reservation back to service credit. If the review outcome is unknown, the credit stays reserved until reconciliation. Cancelling after a completed verdict does not undo the charge. A release of service credit does not refund your card.

If you are short on credit, the command stops with a 402. In a terminal, the CLI can offer to pay and retry. In a script, top up, then retry with the same idempotency key. --yes never approves a payment on its own.

The CLI's payment key lives at ~/.config/epoche/payment-key.json, or wherever EPOCHE_PAYMENT_KEY_FILE points. Back it up. Epoche cannot recover it, and anyone who has it can spend the wallet.

epoche billing statusBalance and recent chargesepoche billing addAdd credit by wallet, card, or the CLI payment walletepoche billing payment-keyShow the address to fund for x402 paymentsepoche billing historyCharges, credits, top-ups, and refunds

Scripts and CI

Give a service token only the scopes the job needs. Non-interactive runs need --yes, and should reuse one idempotency key so a retry resumes the same submission instead of starting another. In CI, sign in to Azure first and pass --resource-group.

CI example
epoche check --format sarif --output epoche.sarif
epoche register safety \
  --yes \
  --idempotency-key "$CI_PIPELINE_ID" \
  --json

# Authenticate with Azure in the runner first
az account set --subscription <subscription-id>
epoche deploy self-hosted --size md \
  --resource-group MY_RESOURCE_GROUP \
  --yes

Command reference

epoche initCreate the config file or a starter projectepoche bundleShow which files would be reviewed and their hashepoche checkRun the fixed rules locallyepoche registerSend code for a confidential reviewepoche statusFollow a reviewepoche findingsRead the findings from a failed reviewepoche receiptSave, check, or publish a credentialepoche verify signerTrace a runtime signer address back to reviewed sourceepoche deployBuild and run an agent in your Azureepoche certifyAdd a certification review to a deployed agentepoche searchFind reviewed agents by what they doepoche runtimeRun the deployment steps one at a timeepoche billingCredit, top-ups, and history