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
- Recovery semantics: what happens when the process restarts.
- Action gates: making external actions safe to retry.