issue #7 · automation gallery

keeper / hub

The agent runs its own infrastructure. Vercel hosts the application; KeeperHub schedules and executes the agent's automations. Each workflow card below is a recipe — open KeeperHub's dashboard, create a new workflow, drop in the listed nodes with the exact parameters shown, and paste the resulting workflow id back into the env var (or Edge Config key). Vercel cron handlers stay as fallbacks; the primary execution path is keeper-driven.

workflows
3
configured
0
recent runs
75
last run
6h ago

shared parameters · copy these into every workflow

webhook url
https://hackagent-nine.vercel.app/api/webhooks/keeperhub
ens name
tradewise.agentlab.eth
ens namehash
0x6d81003b2f91af0480ced9f5ab8aec945befadb5342a572c264ec86bcfc00cce
resolver
0xE99638b40E4Fff0129D56f03b55b6bbC4BBE49b5
reputation registry
0x477D6FeFCE87B627a7B2215ee62a4E21fc102BbA
compliance registry
0xD92F99A883B3Ca3F5736bf24361aa75B53168e7c
expected manifest root
0x6b675048fbacbe7c0b90b796ff07657ac2a410969018ff2436d6566e62952f12
signer wallet
PRICEWATCH_PK · owns the ENS subname; use it for any setText / setAgentWallet writes
§01

ens heartbeat

webhook only · push from x402 · not configured

writes `last-seen-at` to the agent's ENS text record. webhook trigger only — fires when /api/a2a/jobs pushes via execute_workflow on a paid x402 quote (debounced 5min). no cron schedule means zero gas when the agent is idle. /api/cron/ens-heartbeat on Vercel is the absolute fallback if both KeeperHub and x402 go silent.

env var · set KEEPERHUB_WORKFLOW_ID_HEARTBEAT= <workflow id> in vercel + .env.local

recipe · 3 nodes

  1. 1.
    triggercron schedule
    cron
    0 * * * *
    input.ts
    {{$now.timestamp}}
    or webhook
    POST https://hackagent-nine.vercel.app/api/cron/ens-heartbeat

    either keeperhub's own cron, or call the vercel cron route which forwards to this workflow when the env var is set.

  2. 2.
    web3 · writesetText (sepolia)
    chain
    ethereum sepolia (11155111)
    address
    0xE99638b40E4Fff0129D56f03b55b6bbC4BBE49b5
    function
    setText(bytes32,string,string)
    node
    0x6d81003b2f91af0480ced9f5ab8aec945befadb5342a572c264ec86bcfc00cce
    key
    last-seen-at
    value
    {{$trigger.input.ts}}
    signer
    PRICEWATCH_PK (deployer wallet)

    ENS PublicResolver on Sepolia. node = namehash('tradewise.agentlab.eth'). signer must own the ENS subname (deployer pricewatch wallet does).

  3. 3.
    http · webhookcallback to /api/webhooks/keeperhub
    method
    POST
    url
    https://hackagent-nine.vercel.app/api/webhooks/keeperhub
    body
    {"kind":"heartbeat","workflowRunId":"{{$run.id}}","txHash":"{{$step2.txHash}}","summary":"ens last-seen-at updated"}

no runs recorded yet

§02

reputation cache

webhook only · push from x402 · not configured · last 1d ago

reads ERC-8004 feedbackCount and writes a compact summary to the `reputation-summary` ENS text record. webhook trigger only — fires when /api/a2a/jobs pushes via execute_workflow on a paid x402 quote (debounced 5min). no cron schedule.

env var · set KEEPERHUB_WORKFLOW_ID_REPUTATION_CACHE= <workflow id> in vercel + .env.local

recipe · 7 nodes

  1. 1.
    triggercron schedule
    cron
    0 * * * *
    input.agentId
    1
  2. 2.
    web3 · readReputationRegistry.feedbackCount
    chain
    sepolia
    address
    0x477D6FeFCE87B627a7B2215ee62a4E21fc102BbA
    function
    feedbackCount(uint256) view returns (uint256)
    args
    [{{$trigger.input.agentId}}]
    outputAs
    $step2.count
  3. 3.
    transformcompose summary string
    expression
    "feedback=" + $step2.count + " ts=" + $trigger.input.ts
    outputAs
    $step3.summary
  4. 4.
    web3 · readENS PublicResolver.text (idempotency check)
    address
    0xE99638b40E4Fff0129D56f03b55b6bbC4BBE49b5
    function
    text(bytes32,string) view returns (string)
    args
    [0x6d81003b2f91af0480ced9f5ab8aec945befadb5342a572c264ec86bcfc00cce, "reputation-summary"]
    outputAs
    $step4.current

    skip the write step if $step4.current === $step3.summary — saves gas on quiet hours.

  5. 5.
    conditional$step4.current !== $step3.summary
    if false
    skip step 6 (and webhook with summary='no-op')
    if true
    continue to setText
  6. 6.
    web3 · writesetText reputation-summary
    address
    0xE99638b40E4Fff0129D56f03b55b6bbC4BBE49b5
    function
    setText(bytes32,string,string)
    node
    0x6d81003b2f91af0480ced9f5ab8aec945befadb5342a572c264ec86bcfc00cce
    key
    reputation-summary
    value
    {{$step3.summary}}
    signer
    PRICEWATCH_PK
  7. 7.
    http · webhookcallback
    url
    https://hackagent-nine.vercel.app/api/webhooks/keeperhub
    body
    {"kind":"reputation-cache","workflowRunId":"{{$run.id}}","txHash":"{{$step6.txHash}}","summary":"{{$step3.summary}}"}

recent runs

  • 1d agofeedback=267 ts=no tx
  • 1d agofeedback=267 ts=no tx
  • 1d agofeedback=267 ts=no tx
  • 1d agofeedback=267 ts=no tx
  • 1d agofeedback=267 ts=no tx
  • 1d agofeedback=267 ts=no tx
§03

compliance attest

every 6h · not configured · last 6h ago

re-reads the on-chain manifest root, compares to the expected root passed in by the caller, fires an alarm if they drift. ties issue #6 (compliance) to issue #7 (keeper).

env var · set KEEPERHUB_WORKFLOW_ID_COMPLIANCE_ATTEST= <workflow id> in vercel + .env.local

recipe · 4 nodes

  1. 1.
    triggercron schedule
    cron
    0 */6 * * *
    input.registry
    0xD92F99A883B3Ca3F5736bf24361aa75B53168e7c
    input.agentId
    1
    input.expectedRoot
    0x6b675048fbacbe7c0b90b796ff07657ac2a410969018ff2436d6566e62952f12

    expectedRoot = keccak256(canonicalJson(TRADEWISE_MANIFEST)) computed off chain. anyone can re-derive it.

  2. 2.
    web3 · readComplianceManifest.getManifest
    chain
    sepolia
    address
    {{$trigger.input.registry}}
    function
    getManifest(uint256) view returns (address,bytes32,string,uint256,uint64,uint8,address,uint256,string)
    args
    [{{$trigger.input.agentId}}]
    outputAs
    $step2 (manifestRoot at index 1)
  3. 3.
    conditional$step2[1] === $trigger.input.expectedRoot
    if true
    webhook summary = "verified"
    if false
    webhook summary = "DRIFT detected: " + $step2[1] + " vs " + $trigger.input.expectedRoot

    drift means either the manifest doc was updated without re-committing, or someone overwrote the on-chain root. both demand human attention.

  4. 4.
    http · webhookcallback
    url
    https://hackagent-nine.vercel.app/api/webhooks/keeperhub
    body
    {"kind":"compliance-attest","workflowRunId":"{{$run.id}}","txHash":null,"summary":"{{$step3.summary}}"}

recent runs

  • 6h agoverified · 0x6b675048…no tx
  • 12h agomanifest readno tx
  • 12h agoverified · 0x6b675048…no tx
  • 18h agomanifest readno tx
  • 18h agoverified · 0x6b675048…no tx
  • 24h agomanifest readno tx