Skip to content

dolepee/actionfeed

Repository files navigation

ActionFeed

When an agent is sold, upgraded, or forked, how do you know its reputation was not wiped clean?

ActionFeed is the black box recorder for autonomous agent commerce: ENS-named agents, 0G-backed public intelligence, TEE-reviewed decisions, and receipt-verified Uniswap actions.

It stores signed, hash-linked agent actions on 0G, commits each feed head onchain, and binds the history to an iNFT so reputation survives transfer, handover, and fork. ActionFeed is not an agent. It is the public memory layer agents plug into. It is a reference implementation for verifiable autonomous agent commerce backed by 0G, identified by ENS, and extended with receipt-verified Uniswap actions.

  • Primary 0G track: Best Agent Framework, Tooling & Core Extensions
  • Secondary 0G fit: Best Autonomous Agents, Swarms & iNFT Innovations — ERC-7857-inspired iNFT public intelligence
  • Additional partner fit: Uniswap Foundation — agent swap quotes and executions become signed, auditable feed events; ENS — agent subnames resolve into the same signed feed identity

Every offer, payment, delivery, review, transfer, and fork is a signed JSON blob on 0G storage, hash-chained back to genesis, with the head committed on-chain. Anyone can read; only the iNFT holder can write. Agent runtimes make agents act; ActionFeed makes those actions impossible to silently rewrite.

Built for ETHGlobal Open Agents (Apr 24 – May 6, 2026).

Why this is not just receipts

Receipts prove an event happened. ActionFeed binds those events to an iNFT lifecycle where ownership, transfer, fork, and signer history remain verifiable:

  • Owner-only appends. Only the current iNFT holder can extend the feed. Reputation is not a string database can rewrite.
  • Transfer without laundering. When the iNFT moves to a new owner, the old signatures stay valid and stay attached. Old behavior remains tied to the asset, signed by the previous signer. The successor signs forward, not backward.
  • Signer history. Every event records the signer at the time. The verifier surfaces the full handover record, not just the current owner.
  • Fork lineage. declareFork(parent, atEvent) anchors a child feed to an exact event in the parent's onchain Append log, so a fork cannot pretend to start later than it did.
  • ENS identity that points at signed history, not just a wallet. Each subname resolves into the live feed head, current event count, and the same signed ens event on the feed itself.
  • Independent verification. A single CLI verifier walks each chain back to genesis from 0G storage, matches payments to ActionRouter.Paid logs, and replays Uniswap swap receipts on each chain. No trusted app oracle or proprietary off-chain index; verification reads chain state and 0G Storage/indexer data.

Receipt-style projects answer "did this happen?" ActionFeed answers "did this happen, who signed it, who owns it now, what was the agent's reputation when this was signed, and can the new owner pretend the old behavior never happened?"

Why frameworks need ActionFeed

ActionFeed is not a single agent demo and does not try to replace an agent runtime. It is the accountability layer frameworks can plug into when agent actions need durable, public proof.

Builders can use it to:

  • give agents public action histories;
  • make paid work verifiable;
  • transfer agent ownership without laundering reputation;
  • fork agents while preserving lineage;
  • let reviewers and auditors verify behavior without trusting an oracle.

Agent demos can show actions happening. ActionFeed makes what agents did publicly verifiable, transferable, forkable, and impossible to silently rewrite.

V2: Authority Gate

ActionFeed now closes the loop from public history into future authority. The Authority Gate reads seller.actionfeed.eth / token #5, evaluates the signed history against a mandate, grants bounded authority only if the public record passes, refuses over-budget actions, and records the allowed use as a signed feed event with a real ActionRouter payment receipt.

Live Authority Gate proof is isolated on token #8 so the clean #4/#5/#6 judge path stays stable:

  • token #8: 11/11 signatures valid, 2/2 delegated payments verified;
  • seller history evaluated: token #5, 50/50 signatures, completed accepted rounds: 21/21 verified, open offers: 3 intentionally unpaid;
  • latest mandate snapshot anchors seller source head 0x4af4dd1c…95fc;
  • mandate cap: 0.01 OG;
  • refused action: 0.05 OG payment attempt, signed as mandate.refused, no payment broadcast;
  • allowed action: 0.0001 OG payment, signed as delegation.used, latest payment tx 0x2fbfbd…2749.

Run npm run verify:authority -- --token 8 --subject 5 for the semantic Authority Gate verifier, or inspect the live feed at /feed/8?verify=full. Run npm run verify:commerce for the cross-feed buyer/seller/skeptic graph verifier, and npm run verify:fixtures for deterministic no-network fixture replay in CI. npm run authority:gate replays the local token #8 proof when local authority state exists, otherwise it prints a fresh dry-run evaluation. Live writes are guarded: use npm run authority:gate -- --live --append-existing only when intentionally appending to token #8, or npm run authority:gate -- --live --fresh when intentionally minting a new authority token.

Framework recipe (OpenClaw-compatible module pattern)

A working OpenClaw-compatible module pattern ships in examples/openclaw-actionfeed-module/. The same shape ports to any planner/executor runtime because all ActionFeed asks of the runtime is one signed append_action call per public side-effect:

// examples/openclaw-actionfeed-module/actionfeed-module.ts
import { createActionFeedOpenClawModule } from './actionfeed-module';

const module = createActionFeedOpenClawModule({
  evmRpc,
  indexerRpc,
  feedInft,
  tokenId,
  signerPrivateKey,
});

// The runtime calls this whenever a tool produces a public effect.
await module.tools.appendAction.execute(
  {
    action: 'deliver-work',
    decision: 'published delivery after planner approval',
    observation: 'delivery artifact uploaded and paid offer resolved',
    counterparty: buyerAddress,
    metadata: { rootHash, spec, notes },
  },
  { agentId, runId, goal, planner: 'openclaw-runtime' },
);

Any private memory and tool selection stay inside the runtime. ActionFeed only sees the public action and signs it onto the iNFT's feed. Run the live demo with npm run openclaw:demo.

Live proof on 0G Galileo (chain 16602)

Artifact Value
Demo video https://youtu.be/G_NdybIndX0
Explorer https://actionfeed.vercel.app
FeedINFT contract 0xD2e95c44ed36E8b4CCf706FA19a941e463393c3F
ActionRouter contract 0x407a236C5dAE08C62A5076ef679f0629E5C13e43
Buyer feed (token 4) 57 events live, 57/57 signatures valid · 21 accepts, 21 verified payments, Uniswap 3/3, transferred to a successor signer who continues signing without rewriting old history · ENS bound to buyer.actionfeed.eth (signed ens event at seq 51) · mint tx 0x9c3442…7cfa · /feed/4?verify=full
Seller feed (token 5) 50 events live, 50/50 signatures valid · completed accepted rounds: 21/21 verified · open offers: 3 intentionally unpaid · OpenClaw module action · ENS bound to seller.actionfeed.eth (signed ens event at seq 44) · mint tx 0xda6906…ff16 · /feed/5?verify=full
Skeptic feed (token 6) 37 events live, 37/37 signatures valid · 33 review events generated through verified 0G Compute (TeeML); default recent view is backed by embedded durable TEE attestations · ENS bound to skeptic.actionfeed.eth (signed ens event at seq 33) · mint tx 0xfc65fa…478d · /feed/6?verify=full
Authority Gate feed (token 8) 11 events live, 11/11 signatures valid · evaluates seller token #5 with source feed head evidence, grants bounded mandate, refuses 0.05 OG, allows 0.0001 OG, verifies 2/2 delegated ActionRouter payments · /feed/8?verify=full
Sample paid task tx 0xbfa094…cfffPaid(buyer → seller, taskHash = offer rootHash)
Fork capability declareFork(parent, atEvent) is implemented in FeedINFT.sol and exercised by probe/check-fork-token.ts; not featured in the judge demo to keep the first click on the handover narrative.

One-page proof packet: https://actionfeed.vercel.app/proof

For judges, start at the proof packet before opening individual feeds. The proof page headlines the aggregate verifier output (21/21 payments, 3/3 Uniswap executions, and latest TEE proof) before linking into tokens #4, #5, and #6.

The explorer reads each feed head and current event count directly from FeedINFT. The table above records the last full local verifier run so the README does not pretend to be a live index. Signatures are verified against the canonical signed JSON pulled from 0G storage. No trusted app oracle or proprietary off-chain index; verification reads chain state and 0G Storage/indexer data. Completed work is reported separately from feed integrity: token 5 currently has completed accepted rounds: 21/21 verified, with 3 intentionally unpaid open offers.

Current Compute proof path: token 6's latest review stores the signed TEE attestation inside the 0G event, and npm run verify:compute -- --token 6 --latest-only recovers the TEE signer from that embedded proof. The explorer's default recent view for token 6 is now all durable-attestation Compute reviews.

Uniswap partner integration

ActionFeed also includes a Uniswap extension as a partner-prize integration, separate from the core 0G proof stack. Aria-Buyer records policy-checked swap.quote events, guarded live swap.execution events, and refused quotes in the same feed used for paid work and handover.

Live proof:

  • Sepolia tx 0x714c33…7e8
  • Unichain tx 0x3f4ae0…7734
  • Base tx 0x01795e…7315
  • Three refused quotes on Unichain (seq 43) and Sepolia (seq 47, 48)
  • Verifier result: 3/3 Uniswap swap executions verified across Sepolia, Unichain, and Base

See docs/UNISWAP_INTEGRATION.md and FEEDBACK.md.

For explicit proof boundaries and non-goals, see THREAT_MODEL.md.

ENS partner integration

ActionFeed also ships a full ENS integration as a partner-prize layer. Each agent is published as a subname under the mainnet parent actionfeed.eth with both forward records (subname → addr + actionfeed.* text records) and reverse records (addr → subname). The same binding is then re-asserted inside the signed feed as an ens typed event, so a judge clicking /feed/4?verify=full immediately sees the ENS identity as part of the agent's signed history rather than as a side badge.

Live proof:

  • Parent name registration tx: 0x4b15ffa7…d10d7
  • Forward records (subnode + multicall) for buyer.actionfeed.eth, seller.actionfeed.eth, skeptic.actionfeed.eth — six mainnet txs documented in docs/ENS_INTEGRATION.md.
  • Reverse records: buyer 0x81fb5fa…d8bb, seller 0xbeb91851…c20b, skeptic 0xc59cd439…3a95e.
  • Signed ens binding event on each feed (token 4 seq 51, token 5 seq 44, token 6 seq 33) carrying the symmetric forward/reverse mapping plus all four mainnet tx hashes as proof.
  • ENSIP-25-format agent-registration[<erc7930>][<tokenId>] resolver text record published on each subname, pointing at the FeedINFT registry on 0G Galileo (chain 16602): tx 0xbe998dca…d3d119. This is the resolver-side half of ENSIP-25; the registry-side ENS-name claim on FeedINFT is a follow-up that doesn't change this record.
  • Every offer, accept, payment, review, refusal, and delivery produced by the Aria loop carries an addressedAs field naming counterparties by ENS subname; the explorer renders these names alongside the underlying addresses.

See docs/ENS_INTEGRATION.md.

Use ActionFeed in your agent

The SDK ships as the @actionfeed/sdk workspace package inside this repo (not on npm). Build it locally, or package it as a tarball for another project:

npm install
npm run sdk:build
npm run sdk:pack  # writes dist/actionfeed-sdk-0.2.0.tgz

Workspace consumers can import it directly:

import { ActionFeedClient } from '@actionfeed/sdk';

const feed = new ActionFeedClient({
  evmRpc: 'https://evmrpc-testnet.0g.ai',
  indexerRpc: 'https://indexer-storage-testnet-turbo.0g.ai',
  feedInft: '0xD2e95c44ed36E8b4CCf706FA19a941e463393c3F',
});

const minted = await feed.mint(agentWallet, {
  type: 'genesis',
  payload: { name: 'research-agent', purpose: 'public action history' },
});

await feed.append(agentWallet, {
  tokenId: minted.tokenId,
  type: 'delivery',
  payload: { task: 'market research', resultHash },
});

Architecture

                   ┌────────────────────────────────────────────────────────────┐
                   │                      0G Galileo Testnet                    │
                   │                                                            │
   ┌──────────┐    │    ┌──────────────────┐         ┌──────────────────────┐   │
   │  Agent   │────┼───▶│  0G storage      │         │  FeedINFT            │   │
   │ (signer) │    │    │  signed JSON     │         │  (ERC-7857-inspired) │   │
   └──────────┘    │    │  rootHash chain  │         │  headCid, eventCount │   │
        │          │    └──────────────────┘         │  forkParent/atEvent  │   │
        │          │             ▲                   └──────────────────────┘   │
        │          │             │ download(rootHash)            ▲              │
        │          │             │                               │ appendHead   │
        │          │    ┌──────────────────┐         ┌──────────────────────┐   │
        └──────────┼───▶│  Reader / Skeptic│         │ ActionRouter         │   │
                   │    │  walks the chain │         │ payForTask(to, hash) │   │
                   │    │  verifies sigs   │         │ emits Paid           │   │
                   │    └──────────────────┘         └──────────────────────┘   │
                   └────────────────────────────────────────────────────────────┘
flowchart LR
  A[Agent wallet] --> B[Sign canonical event]
  B --> C[Upload JSON to 0G Storage]
  C --> D[0G rootHash]
  D --> E[FeedINFT.appendHead]
  E --> F[Onchain iNFT head]
  F --> G[Verifier walks prev chain]
  G --> H[Reputation, audit, reviews]
  S[0G Compute TeeML] --> T[Skeptic review proof]
  T --> B
  P[ActionRouter.payForTask] --> Q[Paid log]
  Q --> G
Loading

Four moving parts:

  • FeedINFT: ERC-721 token using an ERC-7857-inspired public intelligence mode. Stores the head rootHash, event count, and optional fork lineage. mint, appendHead, declareFork, transferFrom. The encrypted-metadata oracle re-encryption flow remains the canonical private-intelligence path; ActionFeed deliberately implements the public reputation path because auditable agent behavior should not be hidden.
  • ActionRouter: minimal payment relay. payForTask(to, taskHash) forwards real OG and emits Paid keyed by the event rootHash, so every payment has a verifiable off-chain receipt.
  • 0G Compute: Skeptic reviews call a verifiable TeeML chat model through @0glabs/0g-serving-broker. A review is accepted only when processResponse() verifies the TEE signature against the provider's contract-pinned signer. Current demo reviews embed the provider's signed attestation text, signature, and attestation-text hash so judges can recover the TEE signer from the 0G event itself.
  • SDK: TypeScript wrapper that handles canonical JSON, EIP-191 signing, 0G storage upload/download with retry, and chain walking with signature verification.

Reputation cannot be silently laundered

When an agent iNFT transfers, write authority moves to the new owner, but old events remain signed by the old owner.

The verifier surfaces:

  • current owner;
  • historical signers;
  • signer changes;
  • handover events;
  • valid old signatures.

Someone can sell or transfer an agent, but cannot erase the previous action history.

Forks are not resets

A forked agent can change policy, pricing, or behavior, but its lineage remains public.

The contract and SDK support declareFork(parentTokenId, forkAtEvent, childHeadCid). Fork anchors are resolved from the parent Append log, so later parent appends cannot rewrite the fork point. The current judge proof set focuses on the clean Compute-backed buyer, seller, and skeptic feeds.

Working example agent

ActionFeed ships Aria, a three-agent example built directly on the SDK. It satisfies the prize requirement of "at least one working example agent built using your framework/tooling".

  • Buyer (aria/src/run-loop.ts) — issues offers, pays counterparties through ActionRouter.payForTask (aria/src/payment.ts), and signs a payment event with the resulting paidTxHash.
  • Seller (aria/src/run-loop.ts) — accepts offers and signs delivery events whose payload references the offer rootHash.
  • Skeptic (aria/src/skeptic.ts, aria/src/compute.ts) — walks counterparty feeds, sends the summary to 0G Compute, refuses unverified TEE responses, and signs review events with the Compute provenance and durable TEE attestation material embedded.
  • Uniswap extension (aria/src/uniswap.ts, aria/src/run-uniswap.ts) — lets Aria-Buyer request a Uniswap quote, evaluate max impact/gas/slippage policy, and sign a swap.quote event. Live Sepolia, Unichain, and Base execution are hard-gated behind UNISWAP_EXECUTE_LIVE=1, a chain-specific UNISWAP_LIVE_CONFIRM, and tiny execution caps.

Each agent owns its own iNFT (tokens 4, 5, 6 on Galileo) and uses only the SDK to sign, upload, and append. Run it locally:

ARIA_ROUNDS=12 npm run aria:loop
npm run verify -- --token 5

The concrete OpenClaw-compatible module lives in examples/openclaw-actionfeed-module/. It exposes actionfeed.append_action, actionfeed.verify_feed, actionfeed.summarize_feed, and actionfeed.prompt_context tools plus a runnable loop that records an agent planner/executor decision into a real FeedINFT.

This is the 0G tooling-track wedge: OpenClaw keeps private planning and tool selection, while ActionFeed gives the runtime public hands. A planner can append what it did, verify its own or another agent's feed, and inject a compact public-behavior summary into the next reasoning step without trusting a centralized log.

Project layout

Dir Contents
sdk/ Canonical event format, signing, 0G storage wrapper, ActionFeedClient
contracts/ FeedINFT + ActionRouter Solidity sources, Foundry config, deployed addresses in .env
aria/ Three-agent demo: buyer, seller, skeptic. Run-loop, fork, transfer, backfill
examples/openclaw-actionfeed-module/ Concrete OpenClaw-compatible module pattern with manifest, tools, and runnable agent loop
explorer/ Next.js feed viewer with hash-chain integrity check + spec page
probe/ 0G SDK smoke test (5 round-trips)
docs/ Spec, why-0G writeup

Quick start

# Prereqs: Node 22+, foundry, .env populated (see .env.example)
npm install
npm run sdk:build       # builds the repo-local @actionfeed/sdk package
npm run probe:kv          # 0G storage round-trip smoke test
npm run sdk:test          # canonical + sign unit tests
npm run sdk:e2e           # mint + appends + chain-walk verification
npm run aria:scaffold     # mint 3 agent iNFTs (idempotent)
# First-time skeptic Compute path needs ~3 OG seeded into the broker's ledger
# (`broker.ledger.addLedger(3)`, see aria/src/compute.ts). The loop will fail
# at broker init otherwise. Use `npm run probe:compute` once to confirm.
ARIA_ROUNDS=12 npm run aria:loop   # seed an economic history
npm run aria:transfer     # demonstrate transfer + handover
npm run openclaw:demo -- "Record a public decision after reviewing buyer payment history"
npm run verify -- --token 5        # verifier report for any minted feed
npm run verify:compute -- --token 6 --latest-only # newest review's embedded TEE attestation proof
npm run feed:export -- --token 4 --out feed-4.json # portable signed-event chain export
npm run aria:fork                  # optional: mint a new fork and verify lineage
cd explorer && npm run dev   # browse feeds at :3300

Optional Uniswap partner path:

# Read-only readiness check: balances, quote, policy verdict. No writes.
npm run probe:uniswap

# Requires UNISWAP_API_KEY. This writes a signed swap.quote event to the buyer feed.
npm run aria:uniswap

# Only after funding the buyer owner and setting a chain-specific confirmation.
# Sepolia: USDC -> WETH. Unichain: ETH -> USDC. Base: ETH -> USDC.
UNISWAP_EXECUTE_LIVE=1 UNISWAP_LIVE_CONFIRM=sepolia-testnet npm run aria:uniswap

Further reading

About

Signed, append-only action ledger for autonomous agents — ERC-7857 public-intelligence mode on 0G

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors