AgentsOpen SourceFreeActiveMachine-verified· intermediate · ~10 min setup

Hermes Kanban: The Idempotent Nightly Review

A task that files itself onto the board every night and never double-books.

by Shilpa Mitra· verified today· v1.0.0

Run this workflow

CI-verified, 4/4 fixtures passing.

Build this with your agent

One copy-paste hands Claude Code, Codex, or Cursor the full recipe, steps included, nothing to fetch.

Intended Use

Anyone who wants a recurring Hermes task triggered from system cron or a webhook, where a dated idempotency key guarantees repeat triggers never create duplicate cards.

Not for

  • One-off tasks (no need for an idempotency key)
  • Schedules you'd rather manage inside another orchestrator

The Stack

Tested Against

hermes@0.15node@20.x

Side effects & data flow

Network
your LLM provider, only in the non-CI worker step
Writes
~/.hermes/kanban.db (the board)
Credentials
LLM provider key (hermes setup), for the review step only

Data privacy

  • your LLM provider, only in the non-CI worker step the notes/state the review reads (retention: per that provider's API policy)

Prerequisites

  • Hermes Agent (MIT): `curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash`
  • `hermes setup` (LLM provider — only to run the review itself)
  • cron (or any nightly trigger) calling the create command
  • Node 20+ (used here to read the --json board state)

Steps

  1. 1

    Create with a dated idempotency key, twice

    The trick that makes a cron/webhook trigger safe: call create with `--idempotency-key "nightly-ops-$(date -u +%F)"`. CI calls it twice with the same key and asserts the second call returns the SAME task id (no duplicate) — an un-fakeable property of the board.

    hermes kanban init >/dev/null
    mkid() { node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).id))'; }
    KEY="nightly-ops-$(date -u +%F)"
    echo "idempotency key: $KEY"
    ID1=$(hermes kanban create "Nightly ops review" --assignee ops --idempotency-key "$KEY" --max-runtime 30m --json | mkid)
    ID2=$(hermes kanban create "Nightly ops review" --assignee ops --idempotency-key "$KEY" --max-runtime 30m --json | mkid)
    if [ -n "$ID1" ] && [ "$ID1" = "$ID2" ]; then echo "idempotent OK: repeat returned same id $ID1"; else echo "DUPLICATE: $ID1 vs $ID2"; exit 1; fi
    hermes kanban list --json | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const o=JSON.parse(s);const t=Array.isArray(o)?o:(o.tasks||o.items||[]);console.log("cards titled Nightly ops review: "+t.filter(x=>x.title==="Nightly ops review").length)})'
  2. 2

    Schedule it (cron) and run the review (worker step, not CI)

    Add a line like `0 3 * * * hermes kanban create "Nightly ops review" --assignee ops --idempotency-key "nightly-ops-$(date -u +%F)" --max-runtime 30m` to crontab. The dated key makes re-triggers safe; `--max-runtime` caps a stuck worker. The review itself runs a model, so CI doesn't run it.

Eval, 4 fixtures

Last passed: verified today
  • key-formatregextimeout 60s · max $0

    Expected: nightly-ops-[0-9]{4}-[0-9]{2}-[0-9]{2}

  • idempotentcontainstimeout 60s · max $0

    Expected: idempotent OK: repeat returned same id

  • no-duplicatecontainstimeout 60s · max $0

    Expected: cards titled Nightly ops review: 1

  • clean-exitexit_codetimeout 60s · max $0

    Expected: 0

Results

The 'set it and forget it' pick from the WebAfterAI guide.

Did this work for you?

Our CI checks the setup runs. You tell us if the whole thing worked. Tell us straight.

Related workflows

Liked this workflow?

Get new verified workflows in WebAfterAI, three issues a week (Tue, Thu, Sat).