Introducing smarter-sh/automation, the GitHub Actions Cron Jobs That Look After Every Smarter Repository

smarter-sh/automation is a new repository that holds The Smarter Project’s scheduled GitHub Actions workflows. It has no application code. Each workflow checks out another smarter-sh repository, tests it, checks it or tidies it, and posts one message to the project’s Slack when it’s done.

The Smarter Project is now 29 active repositories. There is the Django platform, a command-line tool, SDKs for Python, Node.js and Go, a VS Code extension, a chat widget on npm, and plugins for WordPress, Drupal, Shopify and Google Tag Manager that load it. Each one depends on another one staying current, and until now nothing checked that except me, when I remembered to. Three cron jobs did exist, but they lived in the platform repository, next to its build and deploy pipeline, where they didn’t belong. They have moved, and eight new jobs have joined them.

JobWhenWhat it does
Repository TestsDailyRuns the test suite of every repository on its default branch and reports which passed.
Pod Log ReviewDailyHas Claude Code read the production pods’ logs and keep the platform’s GitHub issues current with what it finds.
Did You Know?DailyPosts the web console’s fact of the day.
API Contract SyncMondaysOpens a pull request in each SDK, the CLI and the VS Code extension whose copy of the API contract is behind.
Repository Security ReviewMonday nightsReports drift in branch protection, secret scanning, Dependabot and Actions token settings.
Embed Version SyncTuesdaysOpens a pull request in each CMS plugin that doesn’t load the latest Smarter Chat from npm.
Workflow Security ReviewTuesday nightsFlags unpinned actions, missing token permissions and jobs without timeouts in every workflow.
Dependabot MergeWednesdaysMerges the Dependabot pull requests that pass, and closes the ones with conflicts.
Published Package Health CheckWednesday nightsChecks that what’s on npm, PyPI and the Go module proxy matches the GitHub releases, and that it installs.
Stale Items ReportThursday nightsLists pull requests and issues open for more than a month.
Secrets Age ReviewFridaysLists GitHub Actions secrets older than six months, by name and date, never by value.

Every job can run by hand with a dry-run input that writes nothing to GitHub and posts nothing to Slack.


Keeping the clients in step with the platform

Smarter publishes its API as a contract, a set of JSON Schemas for its manifests plus one OpenAPI document. The Python, Node.js and Go SDKs, the CLI and the VS Code extension each carry a copy and generate code from it. When the platform releases and a client’s copy falls behind, that client starts to reject valid manifests or miss new routes.

API Contract Sync runs every Monday. It finds the platform’s latest stable release, and for each client it runs the tests, updates the copy of the contract, regenerates the generated code and runs the tests again. When the copy was out of date, it opens one issue and one pull request into that repository’s alpha branch. The pull request is a draft when the tests fail after the sync, so a breaking change shows up as a red draft rather than a broken release. Once the copy is current, the job closes both.

Embed Version Sync does the same for the chat widget. The WordPress, Drupal, Shopify, Google Tag Manager and docs-site integrations each pin an exact version of @smarter.sh/ui-chat, and nothing told them when a new one was published. Every Tuesday the job updates each pin with that repository’s own command, and opens or updates a pull request into alpha when it changed. It also reports a repository whose alpha is current but whose latest release isn’t, as waiting for a release.

📖 API contract documentation


Dependabot, merged weekly

Dependabot opens pull requests in every repository, every week. Most of them pass and need nothing more than a click, but 29 repositories make for a lot of clicks.

Dependabot Merge goes through every open Dependabot pull request in the organization, oldest first, and re-reads each one before it acts.

  • Passing pull requests are merged, by squash where the repository allows it.
  • Still running ones are set to auto-merge.
  • Conflicted ones are closed, with a comment that says how to get them back. A conflict that the run’s own merges caused is left for Dependabot to rebase.
  • Failing ones, drafts, and ones whose state GitHub hasn’t worked out yet are left open and listed in Slack for a person to look at.

It never merges with admin rights, so branch protection and required checks hold.


A nightly test run of everything

A repository that nobody has touched in a month can still break, because a dependency or a registry changed underneath it. Repository Tests starts the test workflow of every active repository on its default branch each night, waits up to 75 minutes for the runs, and posts one message that lists which passed and which failed, with links. A repository whose test workflow can’t be started by hand is reported as not started, rather than silently skipped.


Claude Code reads the production logs

Pod Log Review is the one job that runs an AI agent. Every morning it downloads the logs of the production platform’s pods (the app server, the Celery workers and Celery Beat) and removes credentials and personal data from them. It then removes the cluster credentials from the runner and starts Claude Code in a checkout of the platform repository, with its full history and its Agent Skills.

Claude diagnoses each problem against the code. It opens an issue for a new problem, comments on an existing issue only when it has new evidence, closes an issue that a merged pull request resolved, and may propose a small fix as a draft pull request into alpha. It does all of that through the Smarter Project MCP server, which holds the GitHub token, so the agent itself never sees one. A run that finds nothing posts a clean bill of health. How the daily pod log review works tells the whole story.

📖 Smarter Project MCP server documentation


Weekly organization audits

Four reports run on weeknights, and a fifth on Fridays. They read and report, and none of them changes anything.

  • Repository Security Review compares every repository’s GitHub Actions token defaults, default-branch protection, secret scanning and Dependabot security settings against what they should be, and reports the ones that drifted.
  • Workflow Security Review reads every repository’s workflows and flags third-party actions not pinned to a full commit SHA, workflows without explicit token permissions, write permissions, and jobs without a timeout.
  • Published Package Health Check finds every package the project publishes to npm, PyPI and the Go module proxy, compares each registry’s latest stable version with the latest GitHub release, and installs or downloads it to prove it works.
  • Stale Items Report lists pull requests and issues that have been open for more than a calendar month.
  • Secrets Age Review lists organization, repository and environment secrets older than six months, by name and last-updated date. It never reads a secret’s value.

The details go to Slack. The public run summaries on GitHub contain counts only, since the repository is public.


How the jobs reach other repositories

The token that GitHub gives a workflow run can write only to its own repository. Everything a job does elsewhere goes through a personal access token, and shows its owner’s name. So the jobs follow a few rules.

  • A job never pushes to main, and never force-pushes a branch it doesn’t own.
  • Changes go through pull requests into each repository’s alpha branch, which start that repository’s own tests like any other pull request.
  • Anything a job writes, whether a commit, issue, comment or pull request, links back to the run that wrote it.
  • The audit jobs use a separate read-only token.

The logic lives in Python scripts that use only the standard library, with 180 tests, none of which reaches GitHub, Slack, npm or AWS. Every pull request runs those tests and the repository’s pre-commit hooks, including actionlint, which type-checks the workflows and runs ShellCheck on every shell step.


Three quirks of GitHub Actions cron

If you run scheduled workflows in a repository of their own, three of GitHub’s habits are worth knowing.

  • New schedules didn’t start until a maintainer disabled and re-enabled the workflow. That makes the maintainer the schedule’s owner. I now do it after every new workflow and every changed cron: line.
  • Schedules stop after 60 days without a commit in a public repository, and GitHub only sends an email. A repository of cron jobs can easily go that quiet. Here, Dependabot Merge merging Dependabot’s own updates to this repository keeps it active.
  • Schedules run late, by an hour or more at busy times, and most of all on the hour. The jobs start at odd minutes (08:13, 13:47) and none depends on another finishing at a set time.

Running a job yourself

Each job runs from the repository’s Actions tab, or with the GitHub CLI.

gh workflow run embedVersionSync.yml --repo smarter-sh/automation -f dry-run=true
gh run list --repo smarter-sh/automation --workflow embedVersionSync.yml --limit 1
gh run watch <run id> --repo smarter-sh/automation

The secrets each job needs, and what it does without the optional ones, are in the header comment of its workflow file and in the README. Like the platform repository, this one has a CLAUDE.md and its own Agent Skills, so a coding agent can add a job the same way the existing ones were built. Claude Code wrote most of this first release, and I reviewed and merged it.


What’s next

Now that the jobs have a home, adding one is a small change. The next ones will most likely be more of the checks I still do by hand before a release.