Skip to content

Promote the AI agent demo into examples/, delete the duplicates - #20

Merged
leggetter merged 1 commit into
mainfrom
docs/promote-examples
Aug 27, 2026
Merged

Promote the AI agent demo into examples/, delete the duplicates#20
leggetter merged 1 commit into
mainfrom
docs/promote-examples

Conversation

@leggetter

Copy link
Copy Markdown
Contributor

Closes #18.

demo-setup/ had four distinct workflows spread over eight files, three scripts
that only ran on one laptop, and credential ids from one n8n instance. This
promotes the part worth keeping, deletes the duplicates, and leaves one reset
script that runs for someone who is not the person who wrote it.

Promoted

demo-setup/flow2-ingestion-incident.jsonexamples/ai-incident-agent.json.
The only demonstration in the repo of the action node on an AI Agent's ai_tool
port — the capability n8n's verification asks about — and it existed three times
in a directory named after a video. Credential ids stripped (Hookdeck and
Anthropic), webhookId dropped, source renamed n8n-example-hookdeck-issues to
match the convention the other examples use. Node graph otherwise untouched.

demo-setup/issue-opened-payload.jsonexamples/issue-opened-payload.json.
Reference material, not an example: the agent's prompt reads fields out of it and
the payload shape is not documented anywhere else.

Deleted

  • examples/stripe-idempotency.json — the same three nodes as
    process-each-event-once.json with a different dedupe key.
  • demo-setup/video-ai-agent.json, video-flow1-stripe-ingestion.json,
    video-flow2-ingestion-incident.json, video-stripe-idempotency.json
  • demo-setup/flow1-stripe-ingestion.json, flow2-ingestion-incident.json
  • demo-setup/pre-take-reset.sh, restore-node.sh, run-demo.sh

Documented instead

Both dedupe keys, in one section. examples/README.md now has a table for
"retries of one event" (hookdeck.idempotencyKey) versus "the provider sent it
twice" (body.id), and spells out that the second needs the trigger's
Deduplication Window set to 0 — otherwise Hookdeck collapses the repeat at
the edge and Remove Duplicates never sees the thing it is there to catch.

Sync acknowledgement, in the agent example's section. Per the decision on the
issue, it is not a fourth workflow file. It is explained where it is load-bearing:
the agent only runs because a failed run answered 5xx, which failed the attempt,
which opened the issue, which fired the webhook. On Async Retry the delivery
succeeds the moment Hookdeck hands the event over and no issue is ever raised, so
the agent never fires. The trade-off (Hookdeck's retries and issue tracking over
your run, versus unlimited runtime and recovery being your problem) is in prose
next to it.

The resource/operation explanation. Both are noDataExpression: true, so
the agent cannot choose them: one tool node is one operation, and the model fills
id and filters via $fromAI(). That is why there are three tool nodes and not
one, and it is the non-obvious thing about building an agent on this node.

The reset script

One demo-setup/reset-demo.sh, plus a demo-setup/README.md covering what the
demo shows, prerequisites, exactly what gets deleted, and how to re-run. The
script now:

  • resolves the repo root from BASH_SOURCE, so it runs from any checkout and any
    working directory;
  • finds the workflow by its exported name and the delivery issue trigger by type,
    instead of the four hardcoded ids it used to carry;
  • checks every prerequisite before deleting anything — commands, Node version,
    both API keys (exported wins over .env), an authenticated probe of each API
    that distinguishes "not running" from "key rejected", the workflow existing,
    the issue trigger existing — and fails with a sentence about what to fix;
  • parses JSON with node, so there is no jq/python3 dependency;
  • takes --no-listen for an n8n that is publicly reachable, where the trigger
    provisions an HTTP destination and the CLI is not involved.

bash -n passes. I did not run it: it deletes Hookdeck resources.

Judgement calls, rather than instructions followed

  • The script's blast radius is narrower than the original's. reset-demo.sh
    used to delete every connection and destination in the project. It now deletes
    connections on the demo's own source and n8n-* destinations that no connection
    references. Dismissing open issues is still project-wide, because after the
    connection is gone there is nothing left to scope by. All of it is tabulated in
    demo-setup/README.md.
  • Issue-trigger scoping is now "every connection except the agent's own",
    rather than one hardcoded connection id. With the Sync workflow gone there is no
    fixed second workflow to name, and the property that actually matters is that the
    agent's own connection is excluded — otherwise a failure in the agent workflow
    opens an issue that notifies the agent workflow. If the project has no other
    connection the script stops and says so, because the demo would have nothing to
    react to.
  • The root README.md said "Two importable workflows". It now says three and
    has a row for the agent example. Leaving it stale seemed worse than touching a
    file the plan did not mention.
  • No CHANGELOG entry. Per the decision on the issue: this does not ship —
    package.json files is an allowlist of dist/nodes and dist/credentials.
  • The "Observed" wording on the agent example is drawn from the three runs
    recorded in the old demo-setup/README.md, and says so. The verbatim agent
    output still names demo-stripe, the source in the project it ran in; I left
    the names as they were rather than editing a quote, and labelled it.
  • temperature: 0 and the resource-locator model parameter are called out
    as load-bearing if anyone edits the model node. A plain string there fails at
    runtime with Could not get parameter "model.value".

Nothing found that makes the plan wrong.

Verification

Every workflow JSON was checked by script, not by eye — parses, node names and ids
unique, every connections key is a node, every target node exists, target type
matches its port, no credential carries an id, no orphan nodes:

ai-incident-agent.json
  7 nodes, 6 edges, name "Hookdeck — AI incident agent"
catch-events-on-final-attempt.json
  4 nodes, 3 edges, name "Hookdeck — catch events on their final attempt"
issue-opened-payload.json
  (not a workflow, parses OK)
process-each-event-once.json
  3 nodes, 2 edges, name "Hookdeck — process each event once"

All example JSON valid.
$ npm run lint
✖ 2 problems (0 errors, 2 warnings)
      # both pre-existing: icon-prefer-themed-variants on the two node files,
      # which this branch does not touch

$ npm run build
└  ✓ Build successful

$ npm run scan
✅ Passed n8n community package verification checks

$ node scripts/verify-package-load.mjs
✅ Package loads the way n8n loads it (29 checks)
   nodes: hookdeckEventGateway, hookdeckEventGatewayTrigger
   credentials: hookdeckEventGatewayApi

$ node --test "test/unit.test.mjs"
ℹ tests 109
ℹ pass 109
ℹ fail 0

$ bash -n demo-setup/reset-demo.sh
      # clean

$ node --test test/live/**   NOT RUN — creates and deletes real Hookdeck resources
$ ./demo-setup/reset-demo.sh NOT RUN — deletes real Hookdeck resources

No file under nodes/, credentials/ or test/ is touched.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XtT85W8PPr2S8RW2WhCtpi

`demo-setup/` arrived on main as scope creep on an error-rendering fix and was
never reviewed as content. Of the eight workflow files across it and
`examples/`, four were distinct: the AI agent workflow existed three times, the
Stripe ingestion flow twice, and the idempotency shape three times. The `video-*`
duplicates were credential-stripped copies made for recording, which existed
only because the originals carried a credential id minted on one laptop — fix
the credentials and the reason for the copies disappears.

The agent workflow is the valuable one: it is the only demonstration in the repo
of the action node on an AI Agent's `ai_tool` port, which is a capability n8n's
verification asks about specifically, and it was sitting in a directory named
after a video. It moves to `examples/ai-incident-agent.json` with the credential
ids stripped, the `webhookId` dropped and the source renamed to match the
`n8n-example-*` convention the other examples use. The captured `issue.opened`
body its prompt reads moves alongside it, because the payload shape is not in
Hookdeck's API spec anywhere else.

`stripe-idempotency.json` goes. It was `process-each-event-once.json` with a
different dedupe key, and two files with an identical node graph invite "which
one do I import?" when the answer is "either, then change one field". The README
now documents both keys in one place, including that keying on `body.id` needs
the trigger's deduplication window set to 0 — otherwise Hookdeck collapses the
repeat at the edge and the Remove Duplicates node never sees the thing it is
there to catch. Someone importing a second JSON would not have noticed that
setting or known why it mattered, which is the reason this is prose.

Sync acknowledgement is documented rather than shipped as a fourth workflow. The
other examples each teach an expression you would not think to write; Sync is a
labelled dropdown that already carries its own description, so a file whose only
distinguishing feature is one setting earns less than a paragraph does. It is
explained where it is load-bearing: in the agent example's section, because the
agent only ever runs when an upstream failure reaches Hookdeck, and on Async
Retry it never does. The old flow also branched on
`payment_intent.payment_failed` and treated it as a processing failure, which is
wrong — a failed payment is a perfectly successful delivery.

Three of the four scripts go. They automated rehearsing a video, and they
hardcoded one laptop's path and workflow ids minted on one n8n instance.
`reset-demo.sh` stays because the reset it performs is not obvious — Hookdeck
aggregates delivery issues by (webhook_id, error_code, response_status), so
after the first issue exists no further `issue.opened` fires and dismissing the
issue does not reset it; only a new connection id does. It now resolves the repo
root from its own location, finds the workflow by name, discovers the issue
trigger, checks every prerequisite before deleting anything, and scopes its
deletions to the demo's own resources rather than clearing the project.

`restore-node.sh` goes, but what it encoded does not: n8n's Public API will
uninstall a community package and refuses to install one that is not vetted, so
until this package is verified an API uninstall cannot be reversed from the API.
That is a note in CONTRIBUTING.md now rather than a script.

No CHANGELOG entry: nothing here ships. `package.json` `files` is an allowlist
of `dist/nodes` and `dist/credentials`.
@leggetter leggetter added this to the 0.3.0 milestone Aug 27, 2026
@leggetter
leggetter merged commit bbd8bec into main Aug 27, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decide what in demo-setup/ is an example, and remove the duplication with examples/

1 participant