What this repo shows: a coding agent — Claude Code — installing Activepieces, building a working automation through its REST API, finding four real defects, fixing them, and then proving the automation works by running it and reading the results. No node was placed by hand in the flow builder. No step was declared finished on the strength of an exit code.
📖 Read the full development journey →
The journey document is the point of this repo. It is a warts-and-all record: every error message verbatim, every wrong turn, every claim retracted before delivery, and how each "it works" was actually checked.
Anyone can get an agent to generate a workflow. The interesting question is whether it can close the loop — build the thing, discover that it does not work, find out why, fix it, and produce evidence that the fixed version runs.
That loop is what this repo documents. Concretely, the agent:
- Installed Activepieces in Docker and confirmed the API answered.
- Read the flow schema out of the running container, because the operation it needed is not publicly documented.
- Built a six-step flow as one JSON document and posted it to the API.
- Ran it, and it failed. Six times, for six different reasons.
- Diagnosed each failure from logs and source, fixed it, and re-ran.
- Published the flow, forced a real run, and read back per-step statuses, HTTP codes and message counts.
- Changed the requirement mid-flight (Inbox only, excluding Junk), then proved the change by querying two endpoints over the same window and comparing the counts.
Two of the four flow defects were the agent's own fault — a consequence of building through the API rather than the UI. The journey document says so plainly rather than hiding it.
This work started after watching 10 Open Source Repos BETTER Than Your Paid Subscription by Eric Michaud (2026-08-29), which features Activepieces. The first prompt of the session was simply to install it and explain what it does. The automation came second.
An hourly digest of new Inbox mail, sent to an address of your choice.
| # | Step | Piece | What it does |
|---|---|---|---|
| 1 | Every Hour | @activepieces/piece-schedule |
Fires at the top of each hour |
| 2 | One hour ago | Code | Builds a UTC timestamp 60 minutes back, 2026-08-31T23:19:50Z |
| 3 | Fetch inbox mail | @activepieces/piece-microsoft-outlook |
GET /me/mailFolders/inbox/messages with $filter=receivedDateTime ge <timestamp>, $select, $top=50, $orderby=receivedDateTime desc |
| 4 | Build digest | Code | Builds an HTML list — sender, time, subject as a link, first 200 characters. Escapes & < > |
| 5 | Any new mail? | Router | Continues only when the count is above zero |
| 6 | Send digest | @activepieces/piece-microsoft-outlook |
send-email with the list |
Design choices worth naming:
- A digest, not per-message alerts. Fifty messages at 09:00 should be one email, not fifty.
- Silence when there is nothing. The router stops the run at zero. Twenty-four "nothing happened" emails a day is worse than no automation at all.
- Microsoft Graph, not IMAP. Microsoft disabled basic authentication for personal Outlook.com accounts, so IMAP is a dead end for Hotmail.
custom_api_call, not thefindEmailaction.findEmailhas no date filter, so it would re-send the same messages every hour, forever.- A Code step instead of the Date Helper piece. The Date Helper's output format is a fixed dropdown, and none of its fifteen options produce the ISO form with a trailing
Zthat Graph's$filteraccepts. Three lines of JavaScript do.
Every claim was checked against the running instance. The full table is in section 7 of the journey.
| Claim | Evidence |
|---|---|
| The Graph call works | Step run, fixed window: SUCCEEDED http=200 msgs=50 |
| The timestamp is right | Step run alone: output {"since":"2026-08-31T23:19:50Z"} |
| The whole chain works | Production run, six steps SUCCEEDED, count=6, digest delivered |
| The schedule fires | Run created at 01:00:00.107Z — the top of the hour, unprompted |
| Inbox-only really excludes Junk | Same window, two endpoints: /me/messages → 50 messages, /me/mailFolders/inbox/messages → 0 messages |
| The Code steps are correct | Run under node on the host before upload, asserted for 1 message and for 0 |
One finding that only shows up when you actually run things: Activepieces' single-step test does not chain outputs from the preceding step. It uses stored sample data, which is empty on a fresh import. A variable renders blank and Graph returns Invalid filter clause. That looks exactly like a broken flow and is not. Only a published run proves the chain.
Counted node by node in section 4 of the journey.
| Manual UI | API | |
|---|---|---|
| Build the flow | ~51 interactions plus ~17 lines typed into two editors | 2 calls — POST /api/v1/flows, then IMPORT_FLOW |
| Rebuild on another machine | ~51 again | 2 again |
| Review a change | Read a canvas | git diff |
The honest qualification, also in the journey: those 51 interactions are guided. The UI shows valid actions, validates as you type, and builds awkward structures for you. Two of the four defects exist only on the API path. On a first flow the trade is roughly even; on the fifth, or on a rebuild, it is not close.
| File | What it is |
|---|---|
DEVELOPMENT-JOURNEY.md |
The full story — nine sections plus an appendix of rules learned |
DEVELOPMENT-JOURNEY.html |
The same, rendered dark-mode, live on GitHub Pages. Generated — do not edit by hand |
build-journey-html.py |
Edit the Markdown, run this, and the HTML is rebuilt |
hotmail-hourly-check.json |
The importable flow |
hotmail-hourly-check.md |
Seven-step install guide for the flow |
docker-compose.yml |
The five environment variables an Activepieces container actually needs |
activepieces.html |
An explainer page on Activepieces itself, from the first prompt of the session |
flow-canvas.jpg, flow-trigger-panel.jpg |
The finished flow, and one node's configuration panel |
git clone https://github.com/az9713/activepieces-flow-demo
cd activepieces-flow-demo
cp .env.example .env # generate or paste AP_JWT_SECRET and AP_ENCRYPTION_KEY
docker compose up -dThen open http://localhost:8080, create an account, and import hotmail-hourly-check.json. Before it runs you must set two things it cannot carry publicly:
- A Microsoft Outlook connection, created in the browser. Only you can sign in to your own mailbox.
- The placeholders
YOUR_CONNECTION_EXTERNAL_IDandyou@example.com. The connection is referenced by its external id, fromGET /api/v1/app-connections— not by the name shown in the UI.
Two container flags are load-bearing, and the quickstart docker run omits both:
AP_JWT_SECRET—docker-entrypoint.shderivesAP_WORKER_TOKENfrom it. Without it the worker crash-loops withEnvVarErrorand no flow ever runs, while the web UI looks perfectly healthy.AP_INTERNAL_URL=http://127.0.0.1:80— inside the container the API listens on port 80. Without it every run dies withECONNREFUSED 127.0.0.1:8080.
Both are in docker-compose.yml. That is the whole reason the file exists.
- One flow, one session. This is a case study, not a benchmark.
- Two of the four flow defects were self-inflicted by taking the API path.
- The instance runs on a laptop. A missed hour is not retried — the next run asks only for its own 60 minutes.
- The agent could not complete the OAuth sign-in. A human must do that in a browser.
- Versions move. This was Activepieces 0.82.0,
piece-microsoft-outlook0.4.0,piece-schedule0.1.22. The image taglatestresolved to 0.82.0 while the repo's main branch pinned 0.89.0.
MIT — see LICENSE. Activepieces itself is MIT licensed too.
- Activepieces — MIT licensed, self-hosted workflow automation.
- Eric Michaud — the video that prompted the session.
- Built with Claude Code.
