Projects & Development · n8n

Automation, up close

Excerpts from the n8n workflows that run my projects on a Raspberry Pi. Each one is redrawn from the live workflow definition: same node names, same connections, trimmed to the part worth explaining. The numbers mark what a node is doing and why it is there.

  • 51active workflows
  • 83workflows in total
  • 1error handler for all of them
  • as of 3 Oct 2026

01 · Human approval gate

Nothing is published without a yes

The Ninth Volume10 of 139 nodes shownRuns every third day, one story at a time

An AI-written script should never reach video without a person reading it. The approval also has to finish: no endless revision loops, and no idea quietly regenerated after it was turned down.

ApproveChangesDeclineApproveDecline···Idea row pickedWrite StoryScript1Script ApprovalGate2Route Decision 13Revise Script4Load ApprovedStoryboardMark Declined (1)5ScriptRe-Approval GateRoute Decision 2Mark Declined (2)Save Script ToLibrary6···Images,narration, render
Redrawn from the live n8n workflow · node names and connections as built
  1. Write Story Script

    Gemini writes the script scene by scene with JSON output switched on, so the next step can check its structure instead of guessing at free text.

  2. Script Approval Gate

    Gmail send-and-wait. The email shows every scene, the estimated runtime (flagged if it's short of target) and a continuity flag, with a form: Approve, Request changes or Decline. It waits up to two days.

  3. Route Decision 1

    A switch on the answer. Only “Approve” leads onwards; there is no default route into production.

  4. Revise Script

    My notes go back to Gemini for one revision. The second form only offers Approve or Decline, so revisions stop after one round.

  5. Mark Declined (1)

    A declined script is marked on the content plan sheet, so the same idea isn't picked up and regenerated on the next run.

  6. Save Script To Library

    The approved script is saved to Drive and logged. If a later stage fails, the next run resumes from this approved copy instead of writing a new one.

Every published story has passed a person. When a render fails downstream, the approval is not lost.

Part of AI content pipelines

02 · Locking and re-checking

Two runs, one poster

RTD Poster Generator (sub)12 of 26 nodes shownCalled by the café's nightly event guard and its daily master workflow

Two workflows can ask for the same event poster at the same moment. Without a lock, both would pay for an AI image and both would save a file. A bad generation must not leave a broken poster behind either.

truefalsetruefalseerrorinvalidAcquire Lock1Check Lock2Won Lock?Drop Own LockRe-check Poster3Still Missing?Gemini: GeneratePosterValidate Poster4Capture Failure5Save Poster toDriveRelease Lock(Failure)Release Lock
Redrawn from the live n8n workflow · node names and connections as built
  1. Acquire Lock

    Every contender writes a lock row to an n8n data table, then reads all the lock rows back.

  2. Check Lock

    The lowest live row id wins. Locks older than 30 minutes are ignored, so a crashed run can't block the event for ever.

  3. Re-check Poster

    After winning, look in Drive again. Another run may have saved the poster between the first look and taking the lock.

  4. Validate Poster

    Rejects anything that isn't an image or is under 20 KB before a single byte reaches Drive.

  5. Capture Failure

    Drive and Gemini errors leave through their error outputs and come here, so the lock is released on failure too.

Check Lock (generated from a tested logic.js, never edited in the canvas)

function wonLock(lockRows, myId, nowMs, ttlMinutes) {
  const ttl = ttlMinutes * 60000;
  const live = lockRows.filter(r => nowMs - Date.parse(r.createdAt) < ttl);
  if (!live.some(r => r.id === myId)) return false;
  return Math.min(...live.map(r => r.id)) === myId;
}

One poster per event date, however many runs ask for it. The Code nodes are built from one JavaScript file with tests, so the logic can change without anyone editing the canvas.

Part of Roll The Dice Café

03 · Failure policy

Alert on what matters, once

Studio: Error Handler9 of 9 nodes shownSet as the error workflow on every live workflow

Fifty workflows can fail in fifty ways. Emailing on every failure trains you to ignore the emails. Staying silent hides real problems. Something has to decide which failures need a person.

trueOn Workflow Error1Failure History2Classify3Log FailureLedger Fail InputProduction LedgerFail4Decide EscalationEscalate?Notify Dan5
Redrawn from the live n8n workflow · node names and connections as built
  1. On Workflow Error

    One error handler for every live workflow, so the rules live in one place.

  2. Failure History

    Asks the studio log how many times this workflow has failed in the last 24 hours.

  3. Classify

    Sorts the error. Timeouts, rate limits and 5xx responses stay quiet until the third in 24 hours. Broken credentials raise one alert per credential, not one per workflow. Anything else escalates straight away.

  4. Production Ledger Fail

    If the failed run owns a production item, that item's retry budget applies. Retries are silent; escalation comes only when they run out.

  5. Notify Dan

    Studio: Notify is the only route to email: the same problem at most once every six hours. The email says what was tried, whether it's rescheduled and exactly what to do.

Classify (excerpt)

const TRANSIENT = /\b(429|500|502|503|504)\b|ETIMEDOUT|ECONNRESET|timed out|rate limit|quota/i;
const AUTH = /OAuth client was deleted|needs to be reconnected|invalid_grant/i;
const auth = AUTH.test(message);
const transient = !auth && TRANSIENT.test(message);

The credential rule was added on 2 October, after one deleted OAuth client failed several workflows at once. The fix was one shared alert that names the credential to reconnect.

Part of Pi Ops

04 · Confirm before marking done

Only a post ID counts as posted

TikTok Daily Auto-Post (17:00 UK)10 of 10 nodes shownDaily at 17:00 UK

A publishing step that marks a row as done before the platform confirms will lose posts without telling anyone. A retry that doesn't check will post the same video twice.

truetruefalseDaily 17:00 UKCompute Day Mod 31Is Volume Day?Random Delay(0-60 min)2Get Next UnpostedShort3Post Short toTikTok via BufferPostedSuccessfully?4Mark Row Posted5Log PublicationBuffer PostFailed - Raise6
Redrawn from the live n8n workflow · node names and connections as built
  1. Compute Day Mod 3

    Two channels share one TikTok account, so posting days follow a fixed rota by day number. No state to drift out of sync.

  2. Random Delay (0-60 min)

    A random wait of up to an hour, so posts don't land at exactly the same minute every day.

  3. Get Next Unposted Short

    Takes the oldest unposted short from an n8n data table.

  4. Posted Successfully?

    Success means Buffer's GraphQL response contains a post ID. A 200 response carrying an error doesn't count.

  5. Mark Row Posted

    The row is only marked once that ID exists. Otherwise it stays unposted, so tomorrow's run retries it automatically.

  6. Buffer Post Failed - Raise

    A failure throws on purpose, so it reaches the error handler instead of being recorded as a green run.

No silent losses and no double posts. This pattern came from finding a pipeline that had reported success for weeks while publishing nothing.

Part of AI content pipelines

05 · Rules over guesswork

An inbox that sorts itself

Inbox Auto-Sort6 of 7 nodes shownEvery hour

Automated pipelines send a lot of email: approvals, alerts, summaries. The approvals must not get buried under newsletters.

trueEvery HourGet UnlabeledInbox Mail1Classify Email2Apply CategoryLabelNewsletter &Currently Unread?Mark As Read3
Redrawn from the live n8n workflow · node names and connections as built
  1. Get Unlabeled Inbox Mail

    Searches “in:inbox has:nouserlabels”, so anything I've filed by hand is never touched again.

  2. Classify Email

    Ordered rules on sender and subject, first match wins. Pipeline mail such as script approvals gets its own label, so it's never buried.

  3. Mark As Read

    Only newsletters and marketing are marked read, and only if they're still unread.

Plain rules in a Code node, because they're predictable, testable and free to run every hour.

Part of ATechStudio