Repeatable Automation: Kill the Manual Task for Good

by Alien Brain Trust AI Learning
Repeatable Automation: Kill the Manual Task for Good

Repeatable Automation: Kill the Manual Task for Good

Every recurring manual task is a liability. Not just a time sink — a liability. In 25 years of enterprise security and IAM work, I’ve seen the same pattern cause real damage: a critical process lives in someone’s head (or their personal runbook), runs on a schedule held together by calendar reminders, and fails silently the one time it actually matters. The task was never automated because it was “only five minutes.” Until it wasn’t.

This post is about a specific repeatable automation pattern I use now in ABT’s tooling — a workflow that eliminated a recurring manual task that was eating time and introducing inconsistency. I’ll walk through the pattern, the implementation, and what I’d do differently. If you’re building AI-native tools or running any kind of automated pipeline, this applies directly.


TL;DR

Manual tasks don’t stay small. Build automation with a trigger, a defined scope, error handling, and an audit trail — then retire the runbook. The pattern works for cron-based scripts, GitHub Actions, or AI agent pipelines. The implementation matters less than the discipline of making it actually repeatable.


The Manual Task That Finally Had to Go

My content pipeline generates draft blog posts through an AI agent. For weeks, after each generation run, I was manually doing three things:

  1. Checking whether the frontmatter fields were complete and valid
  2. Verifying the post wasn’t duplicating a recently covered topic
  3. Moving the file from a staging directory to the correct dated folder structure

Each step took two or three minutes. Three posts a week means roughly 15–20 minutes of friction that produced nothing — just moved files and read frontmatter I’d already read while reviewing the draft. Classic five-minute task that adds up.

The real cost wasn’t the time. It was the inconsistency. When I was tired or context-switching, I’d miss a malformed published field or drop a file in the wrong directory. That breaks the site build. Debugging a broken build because of a misplaced file is not how I want to spend a Wednesday morning.


The Repeatable Automation Pattern

The pattern I use has four components. They’re not novel — this is the same structure I applied to IAM provisioning workflows in enterprise environments. It transfers directly.

1. A deterministic trigger

The automation runs when a specific, observable condition is met — not on a timer, not manually, not “when I remember.” In this case: when a new .md file is committed to the staging/ directory in the blog repo. GitHub Actions watches for this with a push event filtered to that path.

on:
  push:
    paths:
      - 'staging/**.md'

No ambiguity. The trigger is the event, not a human decision.

2. A scoped validation step

Before anything moves, the automation validates. For blog posts, that means:

  • All required frontmatter keys are present (title, description, date, category, tags, author, published, featured_image)
  • published is explicitly false
  • title length is within 50–70 characters
  • date matches the expected format

This runs as a small Python script (validate_frontmatter.py) invoked in the action. If validation fails, the workflow exits with a non-zero code and posts a summary to the PR or commit status. Nothing moves. I get a specific error, not a broken build later.

import frontmatter
import sys

REQUIRED_KEYS = ["title", "description", "date", "category", "tags", "author", "published", "featured_image"]

def validate(filepath):
    post = frontmatter.load(filepath)
    missing = [k for k in REQUIRED_KEYS if k not in post.metadata]
    if missing:
        print(f"FAIL: Missing keys: {missing}")
        sys.exit(1)
    if post.metadata.get("published") is not False:
        print("FAIL: published must be false")
        sys.exit(1)
    if not (50 <= len(post.metadata["title"]) <= 70):
        print(f"FAIL: title length {len(post.metadata['title'])} out of range")
        sys.exit(1)
    print("OK")

validate(sys.argv[1])

3. The action — scoped and reversible

If validation passes, the file moves to the correct destination directory based on the date field in frontmatter. A date of 2026-06-27 means the file goes to src/content/blog/2026/06/. The script creates the directory if it doesn’t exist.

Nothing about this step is destructive. The original file in staging/ is deleted only after the destination write is confirmed. If something fails mid-move, I end up with a file in both places, not zero places.

4. An audit trail

Every run appends a line to a pipeline.log file committed back to the repo:

2026-06-27T14:32:01Z | MOVED | staging/repeatable-automation.md -> src/content/blog/2026/06/ | OK

This is the part most developers skip. Don’t skip it. When something breaks three months from now, you want to know exactly what ran, when, and what it touched. In enterprise IAM this is non-negotiable — access changes get logged. Automation that touches your content or infrastructure should be no different.


What This Automation Pattern Handles That Manual Processes Don’t

Manual processes fail in specific ways that automation prevents:

Inconsistency under load. When I’m running three post drafts in a day, the third validation is sloppier than the first. The script doesn’t have attention fatigue.

Silent failures. A file in the wrong directory fails silently until I notice the site build is broken. The automation surfaces the error at the point of failure, not downstream.

Undocumented exceptions. Manual processes accumulate tribal knowledge. “Oh, for posts in the threats category you need to also update the category index.” Automation encodes that logic. It doesn’t live in my head.

No audit trail. If a post goes missing or a published: true slips through, I have no record of what happened. The log gives me that.


Applying This Pattern Beyond Blog Pipelines

The same four-component structure — deterministic trigger, scoped validation, reversible action, audit trail — applies to any recurring manual task in an AI or security workflow:

  • Secret rotation checks: Trigger on a schedule, validate key age against policy, rotate if expired, log the rotation event
  • Agent output review queues: Trigger when agent writes to an output directory, validate structure and content constraints, route to the correct review bucket
  • Access certification reminders: Trigger on calendar event, validate which reviews are outstanding, generate and send summary, log send status
  • Dependency vulnerability scans: Trigger on dependency file change, run scan, fail the build if critical CVEs are found, log results with CVE IDs

The pattern doesn’t care what the task is. It cares that the task has a clear trigger, bounded scope, a safe action, and a record.


What I’d Do Differently

The validation script started as a quick 20-line check. It’s now 80 lines because I kept adding edge cases. I should have written it as a proper module with unit tests from day one. Right now if the validation logic breaks, I won’t catch it until a malformed post slips through.

I’d also add a notification step — a Telegram message when a file is successfully moved, not just when it fails. Right now I have to check the log to confirm success. That’s a minor friction, but it means I sometimes check manually anyway, which defeats part of the point.


Key Takeaways

  • Every recurring manual task is a consistency risk, not just a time cost
  • Repeatable automation needs four things: a deterministic trigger, scoped validation, a reversible action, and an audit trail
  • Validation should fail loudly and early — don’t let bad inputs travel downstream
  • Log everything that touches files, keys, or infrastructure — you will need it
  • Build the pattern once, apply it everywhere; the structure is the reusable part

The five-minute task you skip automating today is the broken build at 11pm six months from now. Build the pattern once. Retire the runbook.

Tags: #automation#workflows#building-and-learning#implementation#case-study

Comments

Loading comments...