#2473: GitHub Actions Beyond CI/CD: What You're Missing

Cron jobs, self-hosted runners, NPM publishing, and self-healing repos — GitHub Actions does way more than run tests.

0:000:00
Episode Details
Episode ID
MWP-2631
Published
Duration
25:05
Audio
Direct link
Pipeline
V5
TTS Engine
chatterbox-regular
Script Writing Agent
deepseek-v4-pro

AI-Generated Content: This podcast is created using AI personas. Please verify any important information independently.

GitHub Actions is one of the most underutilized pieces of infrastructure sitting right in front of developers. Baked into GitHub for years, with 2,000 free minutes per month on private repos and unlimited on public repos, most people still treat it as a glorified test runner. But under the hood, each workflow runs on an ephemeral virtual machine or container — a clean instance that spins up, executes job steps in sequence, and tears itself down. No state carries over between runs. That ephemeral nature is a feature, not a limitation: you always know exactly what you're starting with.

Scheduled Workflows (Cron Jobs)

GitHub Actions fully supports scheduled triggers using standard POSIX cron syntax (five fields: minute, hour, day of month, month, day of week). A daily 2 AM UTC backup is as simple as adding schedule to your workflow YAML. The practical minimum frequency is about every 5–15 minutes — GitHub doesn't guarantee sub-five-minute precision — but for daily or hourly tasks, it's rock solid. Two gotchas: scheduled workflows only trigger if the workflow file exists on the default branch, and schedules are always in UTC (no timezone support natively). Best practice is to combine schedule with workflow_dispatch so you can trigger runs manually when needed.

Self-Hosted Runners for Deployment

For deploying to a VPS or home server without fragile SSH pipelines, self-hosted runners are the answer. You install the runner agent on your target machine, configure it with a token from your repo settings, and now that server is listening for jobs directly. The runner executes locally, so your deploy step is just docker compose pull && docker compose up -d — no SSH keys stored in GitHub secrets, no firewall rules to manage. The security trade-off is that self-hosted runners persist between jobs, so state can leak. Mitigations include: only running on the default branch, avoiding fork PRs on self-hosted runners, and using the --ephemeral flag to auto-destroy the runner after each job.

NPM Package Publishing

Publishing to NPM via Actions is surprisingly clean. A workflow triggers on release or version tag push, checks out code, sets up Node with registry-url: https://registry.npmjs.org, runs npm ci, then npm publish. You store an NPM automation token as a repo secret. For supply chain security, add --provenance and --access public to the publish command, plus id-token: write permission in the workflow — this gives verifiable attestation linking packages back to exact commits and workflow runs. Full semantic release automation (version bumping, changelog generation, GitHub releases) is achievable with npx semantic-release in a workflow.

Beyond CI/CD: Self-Healing Repos and Incident Response

The real power of Actions lies in responding to any GitHub event — not just pushes and pull requests. The event list includes issues, issue comments, discussions, stars, forks, releases, deployments, and repository dispatch from external webhooks. Concrete examples include: a test failure automatically triggering a workflow that creates a branch, suggests a fix via the GitHub Copilot API, opens a PR, and tags a reviewer (self-healing repository pattern); or an external monitoring tool firing a webhook to GitHub's repository dispatch endpoint, triggering a workflow that creates an incident issue, posts to a status page, and pages the on-call engineer. The mental model shift: GitHub Actions becomes the orchestration layer, decoupling tools from processes.

Downloads

Episode Audio

Download the full episode as an MP3 file

Download MP3
Transcript (TXT)

Plain text transcript file

Transcript (PDF)

Formatted PDF with styling

#2473: GitHub Actions Beyond CI/CD: What You're Missing

Corn
Daniel sent us this one — he wants to talk about GitHub Actions. Not just the classic CI/CD stuff everyone knows about, but the full range of what these things can actually do. He's asking whether they can run on a schedule with a cron job, he's curious about self-hosted runners for deploying to a VPS or home server without the whole manual SSH routine, and he mentioned distributing NPM packages. The real question underneath all of it is: what's the full potential here that most developers are sleeping on?
Herman
There's a lot they're sleeping on. I've been digging into this, and GitHub Actions is genuinely one of the most underutilized pieces of infrastructure sitting right in front of developers. It's been baked into GitHub for years now, two thousand free minutes per month on private repos, unlimited on public repos, and people still think of it as just "run tests when I push.
Corn
Which is like owning a pickup truck and only using it to get groceries.
Herman
By the way, DeepSeek V four Pro is writing our script today, so if anything sounds unusually coherent, that's why.
Corn
I'll take that as a compliment to our usual standards. So let's start with what these things actually are under the hood. Daniel described them as worker executors spinning up ephemeral containers. Is that the right way to think about it?
Herman
It's pretty close. Each workflow runs on what GitHub calls a runner, and a runner is essentially an ephemeral virtual machine or container that spins up, executes your job steps in sequence, and then tears itself down. No state carries over between runs. Every time a job starts, you're getting a clean instance. That's the GitHub-hosted runner model, and it's the default for most people.
Corn
That ephemeral nature is actually a feature, not a limitation. You know exactly what you're starting with every time.
Herman
No mysterious leftover files from the last run, no state corruption. But it also means if you need persistence between jobs, you have to explicitly use caching or artifacts. And that brings us to Daniel's first real question: can these things run on a schedule?
Corn
Because if you're only thinking of Actions as event-driven — push code, run tests — the idea of a cron job might not even occur to you.
Herman
It's fully supported. The schedule event uses standard POSIX cron syntax, five fields: minute, hour, day of month, month, day of week. So if you want something to run daily at two AM UTC, you'd write zero two asterisk asterisk asterisk. You can list multiple cron entries under a single schedule key for different frequencies.
Corn
This is just a line in the YAML file?
Herman
That's it. You define your workflow in dot github slash workflows, set the on key to schedule, provide your cron expression, and GitHub handles the rest. There's a practical minimum frequency of about every five to fifteen minutes — they don't guarantee sub-five-minute precision on scheduled runs. But for daily or hourly tasks, it's rock solid.
Corn
What's the catch?
Herman
Two main ones. Scheduled workflows only trigger if the workflow file exists on the default branch — usually main or master. So you can't test a schedule on a feature branch. And schedules are always in UTC. No timezone support natively. If you need something at midnight Eastern, you're doing the offset math yourself.
Corn
Which is annoying but not exactly a dealbreaker. What about combining schedule with manual triggers?
Herman
That's actually a best practice. You add workflow dispatch alongside your schedule trigger, and now you get a button in the GitHub UI that says "Run workflow." So you're not locked into waiting for the cron window if you need to kick something off manually. It's one extra line in the YAML and it makes debugging infinitely easier.
Corn
You could have a workflow that runs every night at three AM to back up a database, but if you're about to do something risky at two in the afternoon, you just hit the button and get a fresh backup first.
Herman
And that database backup use case is one of the ones I think people don't consider enough. You can have a scheduled workflow that connects to your production database, runs a dump, encrypts it, and pushes it to a private repo or to cloud storage. All without any external cron service, no separate server, no third-party scheduler. It's just sitting there in your repo.
Corn
Let's talk about self-hosted runners, because I think this is where Daniel's deployment question gets really interesting. He mentioned having a VPS or a home server where he wants to rebuild a container on push without manually SSHing in.
Herman
This is the pattern that I think more small teams and indie developers should be using. Here's how it works: you set up a self-hosted runner on your VPS. Navigate to your repo settings, go to Actions, Runners, click New self-hosted runner, and GitHub gives you a token and a configuration script. You download the runner agent, run config dot sh with your repo URL and token, then run dot sh to start it. Now that VPS is listening for jobs from your repository.
Corn
The key insight here is that the runner is already on the server.
Herman
That's the whole magic. Your deployment step doesn't need to SSH anywhere. It doesn't need SSH keys stored in GitHub secrets. The runner is executing directly on the target machine. So your deploy step can just be a local script: docker compose pull, docker compose up dash D, done. No fragile SSH pipelines, no firewall rules to configure, no jump hosts.
Corn
You've eliminated an entire class of deployment failure modes.
Herman
You're not storing SSH private keys in your repo's secrets where a misconfigured workflow could leak them. The runner authenticates to GitHub, not the other way around.
Corn
What about the security trade-offs? Because if the runner is persistent on your production server, that seems like it introduces new risks.
Herman
This is the part where people need to be careful. GitHub's documentation explicitly warns that self-hosted runners don't need to have a clean instance for every job execution. State can leak between jobs. If you allow pull requests from forks to run on your self-hosted runner, a malicious PR could compromise the runner and from there access your production server.
Corn
The obvious mitigation is don't run fork PRs on your self-hosted runner.
Herman
The recommended approach is to only use self-hosted runners on the default branch, or to use ephemeral runners that auto-destroy after each job. You add the ephemeral and unattended flags during configuration, and the runner registers for a single job, executes it, and then removes itself. That's ideal for auto-scaling setups, but it also works for single-server deployments if you can tolerate the registration overhead on each run.
Corn
For a lightweight application on a single VPS, is the registration overhead actually noticeable?
Herman
We're talking seconds. The runner agent downloads pretty quickly, and the config step is just exchanging tokens with GitHub's API. For most small deployments, it's negligible. And the security benefit of a clean slate every time is substantial.
Corn
Daniel also mentioned distributing NPM packages. How does that workflow look?
Herman
It's surprisingly clean. The standard pattern is a workflow that triggers on release — specifically the published event type — or on a push of a version tag. Your steps are checkout the code, set up Node with a registry URL pointing to npmjs dot org, run npm ci to install dependencies, then npm publish.
Herman
You generate an NPM automation token from your NPM account, store it as a repo secret — typically called NPM underscore TOKEN — and the setup-node action creates a local dot npmrc file that references it through the NODE underscore AUTH underscore TOKEN environment variable. It's three or four lines of YAML once you have the secret configured.
Corn
What about provenance? There's been a lot of talk about supply chain security and verifying that packages actually came from the repo they claim to.
Herman
You can add dash dash provenance and dash dash access public to your npm publish command, and you need to grant id-token colon write permission in the workflow. That gives you verifiable supply chain attestation. Someone downloading your package can trace it back to the exact commit and workflow run that built it. It's becoming standard practice, and GitHub Actions supports it natively.
Corn
If you want full semantic release automation — automatic version bumping, changelog generation, the works?
Herman
You can use npx semantic-release in a workflow that triggers on push to main. It needs two secrets: GH underscore TOKEN for GitHub API access and NPM underscore TOKEN for publishing. The tool figures out the next version number based on your commit messages, generates release notes, publishes to NPM, and creates a GitHub release.
Corn
That's the kind of thing where once you set it up, you forget it exists and it just works. Until it doesn't.
Herman
Which is why you keep the manual trigger available. But honestly, semantic-release has been around long enough that the failure modes are pretty well understood at this point.
Corn
Let's get into the stuff beyond CI/CD, because I think this is where the real "aha" moments are. What are some of the weirder things people are doing with Actions?
Herman
My favorite is the self-healing repository pattern. Imagine you've got a test suite, and a test fails. Normally, someone gets a notification, they look at it, they fix it, they push. But you can set up a workflow where a test failure automatically triggers a new workflow that creates a branch, uses something like the GitHub Copilot API to suggest a fix, opens a pull request, and tags a reviewer.
Corn
The repo tries to fix itself before a human even looks at it.
Herman
Whether you want to auto-merge those fixes is a separate question, but even just having a PR pre-drafted with a suggested fix cuts the response time dramatically. It's not science fiction — people are doing this today.
Corn
What about issue management? I've seen repos where issues get automatically labeled, or stale issues get closed.
Herman
That's one of the most common beyond-CI/CD patterns. You can have a workflow that triggers on issue creation, reads the issue body, and applies labels based on keywords or patterns. Or a workflow that checks for issues that haven't met a naming convention and auto-closes them with a comment explaining why. Or a workflow that sends a notification to a Slack channel every time a new issue is created with a certain label.
Corn
The key insight here is that Actions can respond to basically any GitHub event. It's not just push and pull request.
Herman
That's the part most people miss. The event list is enormous: issues, issue comments, discussions, stars, forks, releases, deployments, even repository dispatch from external webhooks. You can build workflows that manage your project management, your onboarding, your security scanning, and your release marketing all from the same YAML files where your CI lives.
Corn
Can you give me a concrete example of the repository dispatch one? Because that sounds powerful.
Herman
Say you've got an external monitoring service that checks your production site every five minutes. If it detects downtime, instead of just sending an email, it can fire a webhook to GitHub's repository dispatch endpoint with a custom event type. Your repo has a workflow that listens for that event type, and when it fires, the workflow automatically creates an incident issue, posts to your status page, and pages the on-call engineer.
Corn
Your monitoring tool doesn't need to know anything about your incident response process. It just pings GitHub, and GitHub Actions becomes the orchestration layer.
Herman
And that's the mental model shift I think Daniel was getting at. GitHub Actions is not a CI/CD tool that happens to have some extra features. It's a generic workflow automation engine that happens to be really good at CI/CD. The same YAML syntax, the same runner infrastructure, the same secrets management — it's a unified automation layer for the entire software development lifecycle.
Corn
Let's talk about some of the other creative use cases. You mentioned onboarding earlier.
Herman
There's a pattern where when a new engineer joins the organization, you can trigger a workflow — maybe through an issue with a specific label or a repository dispatch — that automatically sets up their repo access, adds them to the right teams, creates their development environment, and even sends welcome messages to the relevant Slack channels. It turns what's usually a checklist of twenty manual steps into a single automated process.
Herman
This one's clever. Instead of a synchronous meeting where everyone says what they're working on, you have a scheduled workflow that runs every morning — there's your cron job, Daniel — and posts a message to a Slack thread or creates a discussion post asking team members what they did yesterday and what they're doing today. People reply in their own time, and the workflow collects and summarizes the responses.
Corn
That's the kind of thing that sounds small but eliminates a recurring friction point. No more "sorry, I was in the bathroom, what did I miss?
Herman
The social media automation is another one. You push a new release, and a workflow automatically posts an announcement to Twitter or LinkedIn with the release notes and a link. You don't have to remember to do it manually, and the post goes out within seconds of the release being published.
Corn
What about keeping forks in sync? I've definitely let forks drift out of date.
Herman
There are workflows that periodically check if your fork is behind the upstream repository and automatically create a pull request to sync it. Set it on a schedule, and your fork stays current without you thinking about it. For open source contributors who maintain forks, that's useful.
Corn
We've covered scheduled jobs, self-hosted runners for deployment, NPM publishing, and a bunch of creative use cases. What about practical advice for someone like Daniel who wants to use these effectively?
Herman
First thing: always add workflow dispatch alongside your schedule trigger. It costs you one line of YAML and saves you from waiting for a cron window when you need to test or manually trigger something. Second: be intentional about where your self-hosted runners run. If you're using them for production deployments, restrict them to the default branch and consider ephemeral mode.
Herman
Use environment-level secrets where possible, not just repository-level. Environments let you set protection rules — required reviewers, wait timers, restricted branches — so a workflow that deploys to production can require manual approval before it runs. That's built into GitHub Actions and a lot of people don't realize it exists.
Corn
What about the free tier? You mentioned two thousand minutes on private repos.
Herman
For public repos, it's unlimited. For private repos, the free tier gives you two thousand minutes per month on GitHub-hosted runners. That's about thirty-three hours of CI time. For a small team or an indie developer, that's often more than enough. And self-hosted runners are always free — you're providing the compute, so GitHub doesn't charge for the runner minutes.
Corn
If you have a VPS that's already running anyway, adding a self-hosted runner costs you nothing extra.
Herman
And that's the pattern I think Daniel was circling: you've already got a server. It's already running your application. Adding the runner agent means your deployment pipeline lives on the same machine, and you're not paying for extra CI minutes or managing a separate deployment tool.
Corn
Any pitfalls people should watch out for?
Herman
The big one with scheduled workflows: they can be delayed during periods of high load. GitHub doesn't guarantee exact execution times for scheduled events. If you need something to run at precisely two AM with zero tolerance for drift, GitHub Actions scheduled workflows are not the right tool. But for most use cases — daily backups, nightly reports, periodic cleanup — a few minutes of variance doesn't matter.
Corn
The security thing you mentioned with self-hosted runners — that seems like the most dangerous gotcha.
Herman
It's the one that could actually compromise your infrastructure. If you're running a self-hosted runner on a machine that has access to production secrets, network access to your database, or any other sensitive resources, you need to be extremely careful about what code runs on that runner. The safest approach is ephemeral runners combined with branch restrictions: only allow workflows on main to use the self-hosted runner, and make sure the runner destroys itself after each job.
Corn
What about the NPM publishing angle? Any common mistakes there?
Herman
People often forget to set the registry URL in the setup-node step. Without it, npm publish tries to publish to the default registry, which might not be what you want, especially if you're publishing to GitHub Packages instead of npmjs. And the token scoping matters: NPM automation tokens are different from publish tokens. Automation tokens bypass two-factor authentication, which is what you want in a CI environment.
Corn
The distinction between automation tokens and regular tokens is exactly the kind of detail that trips people up.
Herman
It's documented, but you have to know to look for it. The NPM docs mention it, and the setup-node action's README covers it, but if you're following a tutorial from three years ago, it might not mention automation tokens at all.
Corn
One more thing on the creative use cases — you mentioned the self-healing repo pattern with Copilot. Is that actually reliable enough to use in production?
Herman
I'd say it's more of an accelerator than a replacement. The auto-generated fix creates a PR — a human still reviews and merges it. The value is that instead of starting from zero when a test fails, you're starting from a suggested fix. Even if the fix is wrong fifty percent of the time, you've still cut your response time in half for the other fifty percent.
Corn
That's a good way to frame it. Not full automation, but reducing the cognitive load of the initial response.
Herman
That's really the theme across all of these beyond-CI/CD use cases. GitHub Actions isn't replacing human judgment. It's handling the mechanical, repetitive parts of the software development lifecycle so humans can focus on the parts that actually require thinking.
Corn
Let's circle back to Daniel's specific deployment scenario, because I think it's worth spelling out the full workflow. He's got a GitHub repo, a VPS running Docker, and he wants a push to trigger a container rebuild without manual SSH.
Herman
Here's the step-by-step. One: set up a self-hosted runner on the VPS using the GitHub UI to get your token and config script. Two: restrict that runner to your deployment branch — probably main. Three: create a workflow file in dot github slash workflows that triggers on push to main. Four: in the job steps, checkout the code, then run your Docker commands directly — docker compose build, docker compose up dash D. No SSH, no secrets for server access, no external deployment tool.
Corn
If he wants to add a manual trigger for deployments that aren't tied to a push?
Herman
Add workflow dispatch to the on section. Now he can go to the Actions tab in GitHub, select the workflow, and click Run workflow. He can even add input fields — like a specific tag or environment to deploy — using the inputs key under workflow dispatch.
Corn
That's cleaner than most deployment setups I've seen at small companies.
Herman
It costs nothing beyond the VPS he's already paying for. That's the part that I think should make people reconsider their deployment pipelines. You don't need a separate CI service, a separate deployment tool, a separate cron scheduler. It's all in one place, with one configuration format, one secrets store, one logging interface.

And now: Hilbert's daily fun fact.
Herman
The national animal of Scotland is the unicorn. It has been since the twelfth century, when William the First used it on the Scottish royal coat of arms.
Corn
If someone's listening and wants to start using GitHub Actions more effectively, where should they begin? What's the low-hanging fruit?
Herman
Start with something you're already doing manually and ask whether it can be automated. Do you manually run tests before merging? Do you manually deploy after merging? Do you manually check for outdated dependencies? There's a scheduled workflow for that. The barrier to entry is a YAML file in your repo — that's it. You don't need to sign up for anything, you don't need to configure a new service, you don't need to give a third party access to your code.
Corn
The incremental approach means you can add one workflow at a time. You don't need to overhaul your entire development process on day one.
Herman
The other thing I'd recommend: look at the Actions marketplace. There are thousands of pre-built actions for common tasks — deploying to specific cloud providers, sending notifications, running linters, generating release notes. You don't need to write everything from scratch. Most workflows are composing existing actions with a small amount of custom scripting.
Corn
What about debugging? When a workflow fails, how do you figure out what went wrong?
Herman
The logs are surprisingly good. Every step produces its own collapsible log output, and you can enable debug logging by setting a repository secret called ACTIONS underscore STEP underscore DEBUG to true. That gives you much more verbose output, including the exact commands being run and their full output. There's also a command line tool — gh run view with the log flag — if you prefer working in the terminal.
Corn
The manual trigger we mentioned is a debugging tool in itself. Being able to re-run a failed workflow with a button click instead of pushing a dummy commit is underrated.
Herman
It's one of those quality-of-life features that you don't appreciate until you've done it the hard way a few times. Pushing an empty commit with a message like "trigger CI" feels ridiculous once you know workflow dispatch exists.
Corn
We've covered a lot of ground. Let me try to pull it together. GitHub Actions is a generic workflow automation engine. It does CI/CD, but it also does scheduled jobs, deployment orchestration, package publishing, issue management, and basically anything else you can trigger off a GitHub event. Self-hosted runners let you run workflows on your own infrastructure, which eliminates the SSH-in-and-rebuild pattern for deployments. And the whole thing is free for public repos and comes with a generous free tier for private ones.
Herman
That's the summary. The one thing I'd add is that the YAML-based configuration makes it easy to version-control your automation alongside your code. Your CI pipeline, your deployment process, your issue automation — it's all in the repo, subject to the same code review and change history as everything else. That's a bigger deal than it sounds.
Corn
Because when your deployment breaks, you can git blame the workflow change that caused it.
Herman
Revert it with a single commit. Infrastructure as code, but for your entire development workflow.
Corn
One open question I keep coming back to: as these workflow engines get more capable, where's the line between "this should be a GitHub Action" and "this should be a separate service"? At what point does cramming everything into YAML files in your repo become the wrong abstraction?
Herman
I think the line is state and complexity. If your automation needs to maintain long-running state, handle complex branching logic, or integrate with services that don't have webhooks, a dedicated service might make more sense. But for event-driven automation that fits naturally into the software development lifecycle, GitHub Actions is hard to beat. And the fact that it's already there, already configured, already trusted with your code — that's a real advantage over adding another tool to the stack.
Corn
Thanks to our producer Hilbert Flumingtop for the daily fact, and thanks to Daniel for the prompt. This has been My Weird Prompts. You can find every episode at myweirdprompts dot com. I'm Corn.
Herman
I'm Herman Poppleberry. We'll catch you next time.

This episode was generated with AI assistance. Hosts Herman and Corn are AI personalities.