Skip to content

Documentation

Quickstart

Runs from sourceSDK not published

Run Upoch locally and wrap an agent workflow with the SDK.

Run it locally

Requires Node.js 24. In three terminals:

npm run demo:node                 # local chain on 127.0.0.1:8545
npm run demo:seed                 # deploy Upoch and seed a demo story
cd web; npm run build; npm run start -- -H 127.0.0.1

Then set EPOCH_DATA_MODE=local, EPOCH_CONTRACT_ADDRESS and EPOCH_DATA_STORE_DIR as the seed script prints. The step-by-step guide is docs/DEMO.md in the repository.

Wrap a workflow

Create one EpochAgent per agent and run the workflow inside executeWithAutosave. The workflow must be registered on-chain first, with the agent's address as an executor.

agent.ts
import {
  EpochAgent, RpcCheckpointChain, ReplicatedStorage, IpfsStorageAdapter,
  LocalAesGcmProvider, StateSerializer, FileJournal, httpProvider,
} from "./sdk/src/index.ts"; // not yet published as a package

const agent = new EpochAgent({
  agentId: "rebalancer-1",
  chain: new RpcCheckpointChain({
    provider: httpProvider(process.env.RPC_URL!),
    ledger: EPOCH_ADDRESS,      // the deployed Upoch contract
    workflowId: 1n,             // registered with registerWorkflow
    from: EXECUTOR_ADDRESS,     // an executor of that workflow
  }),
  storage: new ReplicatedStorage([new IpfsStorageAdapter({
    apiUrl: "https://rpc.filebase.io", authorization: "Bearer " + IPFS_TOKEN, gatewayUrl: "https://ipfs.filebase.io",
  })]),
  encryption: new LocalAesGcmProvider(KEY_32_BYTES), // development provider
  serializer: new StateSerializer({ applicationVersion: "rebalancer/1", schemaVersion: 1 }),
  journal: new FileJournal("./epoch-journal.jsonl"),
  checkpointPolicy: { everySteps: 3, beforeExternalAction: true, afterConfirmedAction: true },
  reconcilers: { swap: (op) => venue.status(op.operationId) }, // query before any retry
});

const result = await agent.executeWithAutosave(async (session) => {
  const state = await session.restoreOrInitialize(() => ({ step: 0, fills: [] }));
  while (state.step < 3) {
    state.step++;
    await session.step(state);             // SAFE_BOUNDARY checkpoint every 3 steps
  }
  await session.action({                   // PRE_ACTION and POST_ACTION checkpoints
    operationId: "swap-1",                 // stable: a confirmed swap-1 is never re-run
    operationType: "swap",
    input: { amount: "100" },
    run: (input) => venue.swap(input),
  });
  return state;
});

executeWithAutosave returns { status, executionId, result, error, checkpoints, recovery, degraded }. It does not throw for workflow errors; it returns status: "FAILED" with a machine-readable error.code.

Run the tests

npm run test:sdk       # SDK units, scenarios A-G against the contract, Python parity
npm run test:python    # Python SDK
npx hardhat test       # contract tests (run alone; it needs most of the memory)

Next