flowingkhaosSign inBrowse the marketplace
New here? flowingkhaos is a build-in-public workshop. This is its weekly column.What this site is

Claude Code Skills vs Cron Jobs: Keep the Script, Put Only the Judgment in the Skill

Claude Code Skills vs Cron Jobs: Keep the Script, Put Only the Judgment in the Skill

Turn the job into a script, put only the judgment in the Claude Code skill, and let a timer call it. A six-step checklist, from my own daily jobs.

Turn the Job Into a Script, Put Only the Judgment in the Skill

I’ll give you the answer first: turn the job into a script, put only the judgment into the skill, and let a timer call the script. That is how I use Claude Code skills for background work, and most of what people call an agent is a skill plus a timer. Of the 8 subagents in my old agent app, only 2 kept a real model loop.

Let’s get one thing straight. A skill is not a tiny agent. A skill is a written procedure with the scripts it needs, and a timer is just one way to call it. You can also call it by hand, or from a button. The unit is the procedure, not the thing that wakes it up.

Am I being too harsh on agents? Probably. So here is the rule I use, as of 2026-10-22: a model loop earns its place only when every step depends on a judgment about the previous step’s result. Everything else is a script with one model call, made at the one point where a choice is needed.

Claude Code skills and the timer that calls them

I run 37 global Claude Code skills in my vault, plus 9 local ones. Seven local systemd timers call some of them, and 8 scheduled Trigger.dev tasks run in my main app. Anthropic’s Claude Code docs on skills describe skills as the way to extend what Claude can do, and I agree with the framing: a skill extends a procedure you already have, it does not replace your scripts.

This is the same habit I described in the measured ladder for Claude Code hooks: stop at the first rung that holds. For a background job, the first rung is a plain script. The model only goes where a script can’t decide.

What a Skill Is, and Why the Procedure Is the Unit

You can see the shape in Anthropic’s own definition. Their guide to using Agent Skills with the API describes skills as “organized folders of instructions, scripts, and resources”. Instructions and scripts, together. That sentence is the whole argument of this column: the scripts do the work that must be the same every time, and the instructions tell the model where its judgment is wanted.

The skill authoring best practices note it in their opening line: “Good Skills are concise, well-structured, and tested with real usage.” I’d add one thing for background work: tested with real usage means tested when nobody is watching. A skill you run at your desk gets corrected the moment it drifts. A job on a timer runs unattended, so nobody is there to correct it when it drifts.

That is why I treat the procedure as the unit and the caller as a detail. My keyword harvest started as a skill I ran by hand, a driver for a keyword tool, on 2026-09-23. The next day the skill, a scheduled script and two timers landed together. Same procedure, new caller.

The listicles of best skills to install all miss the same thing: they tell you which skills to add, and none of them tells you what happens when the skill fails at 5 a.m. The ranking of Claude Code skills from AY Automate is a fine list of what to install. It is not a plan for running one unattended.

The Lead Example: A Script Spends the Credits, the Model Enters Once a Week

My keyword harvest is the job that taught me the split. Here is how it runs.

The keyword harvest: script runs daily, model enters once a week
  1. 01Timer 05:40Starts the daily plain script, no model
  2. 02Script spends creditsPicks seeds, spends at most 75 of 200 credits
  3. 03Screen and loadScript screens results and loads them into the bank
  4. 04Sunday refill calls modelScript calls claude -p with four tools, once a week
  5. 05Script validates outputModel writes candidates to a file; script checks before merge

Every day at 05:40 a timer runs a plain script. No model. The script picks seed keywords, spends at most 75 credits on a keyword tool, then screens the results and loads them into my keyword bank. My plan has 200 credits a day: 75 go to the harvest, 75 stay for my own research runs, and 50 are never touched. On a login bounce or a captcha it stops, spends nothing, and says so in its note. To switch it off I create one file, raw/keywords/HARVEST_OFF, and the timer stays as it is.

The model enters once a week. On Sunday at 05:00 the script calls claude -p with a written prompt and a tool allow-list of four tools: Read, Glob, Grep and Write. The model writes candidate keywords to a file. Then the script checks them and merges what passes into the bank. The model only ever writes to its own file. If the model wrote nothing, the script writes the run note itself, “The model wrote no candidates. The bank keeps its old seed keywords.”, and exits 1.

The skill’s own description says it plainly: it is “the unattended half of the keyword method”, and “the judgment stays with /keyword-research”. The driver skill has a shorter rule: “Numbers only; the thinking is /keyword-research.”

Job Caller Run notes Non-zero exits
Keyword harvest, daily timer 05:40, plain script 27 (2026-09-24 → 2026-10-22) 2
Keyword refill, Sunday timer 05:00, script calls claude -p 4 0

Today’s note, 2026-10-22: 74 of 75 credits spent, 75 seed keywords, 616 new in the bank, 361 kept by the screen.

The script checking the model’s output before anything merges is the same rule I argued in why your green gate might be lying to you: a pass is only worth what the check behind it actually measures.

What Happens When It Runs Unattended

I know the harvest works because every run writes a note. I also know which of my jobs don’t work, for the same reason.

Job Caller Run notes Non-zero exits
/daily brief skill on a timer 77 (2026-08-04 → 2026-10-22) 26
vault-cleanup skill on a timer 12 7
Knowledge sync timer 06:15, script only 13 3

The /daily brief is a skill on a timer: 26 of its 77 runs ended with a non-zero exit. I don’t know the cause of most of them. Most of those failed notes were written by the wrapper, not the skill, so the failure is recorded and the reason is not. Without the wrapper’s note, those runs would be silent.

The wrapper is a short shell script, run-skill.sh. It takes a run lock, pulls the vault, re-installs the schedules, then runs claude -p "/<skill>" with a tool allow-list and one appended instruction: do not run git add, git commit or git push. The wrapper owns the commit and the push. If the skill fails or writes no note, the wrapper writes a fallback note at system/runs/<date>-<skill>.md.

vault-cleanup failed 7 of 12 runs, and the reason is recorded this time: the move command was refused by the permission allow-list on 09-13, 09-20, 09-27, 10-04 and 10-11. The first run where the moves actually happened was 10-18. A refusal is the right default for a run nobody can answer. I argued that in my column on Claude Code subagents running headless: a hook that can’t ask must refuse. It just has to be a refusal you can read, which is why I count the refusals before I write a single hook.

Claude Code itself keeps moving under these jobs: the release list on GitHub shows v2.1.304 at the top as I write this. A skill that ran fine last month runs on a newer engine this month. The note is how you notice.

Two more things I learned the hard way. A scheduled run once swept a half-built change into its commit, because the run commit stages everything on purpose: it doubles as the vault backup. And a skill edit in my vault does nothing until the installer copies it. What I don’t have: any cost or duration for a headless claude -p run. I never recorded one.

Agents vs Skills vs Jobs: What Our 8 Subagents Actually Became

When I took my old agent app apart on 2026-10-21, I sorted its 8 subagents by what they actually did.

Outcome Count Which ones
Already plain runs: deleted 4 the run kinds the app already had
Became plain chat tools 2 publish, business
Kept a real model loop: became Trigger tasks 2 prospect, social post

Only prospect and social post kept a loop, because there each step needs a judgment about the previous step’s result. The other six were a script, or a single tool call, wearing an agent costume.

Anthropic’s own design points the same way. The ClaudeLog changelog documents version 2.0.43 adding a skills frontmatter field, so a subagent can declare the skills it auto-loads, plus a SubagentStart hook event. Read that as a design decision: the subagent is a container, and the skills are what it carries. The procedure is the unit, even inside an agent.

So my three words mean three different things. A skill is a procedure. A timer is a caller. A loop is a model that needs its previous result to decide its next step. If you want the longer version of where skills sit next to hooks, mods and MCP servers, the workshop step that tells a mod from a skill, a hook and an MCP server covers it.

The Six-Step Checklist to Apply to Your Jobs Today

You can run this checklist on every cron job and script you have:

  1. Split the job: counts, fetches, writes and spends go in a script; only the judgment call goes to the model.
  2. The script owns every side effect (credits, commits, pushes), never the model.
  3. The skill is a written procedure (SKILL.md) with its stop rules: when to quit, what it may never do.
  4. A timer calls the script; the model is called only at the judgment point, with a short tool allow-list.
  5. Every run writes a dated note; if the skill dies, the wrapper writes it.
  6. An off switch: one file that stops the job without editing the timer.
Work Goes in Why
Counts, fetches, screens, writes, credit spending the script it must give the same result every time, and you must be able to check it
Commits, pushes, the off switch, run notes the script or the wrapper side effects stay out of the model’s hands
The one judgment call the skill, at a single point the script checks the model’s output before anything merges

Step 2 is the one I’d tattoo somewhere. A throwaway test run once rewrote my live database; the repair write-up describes the second net I built after it: a mod that holds any shell call that could reach production, and refuses when nobody is there to answer. Side effects belong to code you can read, never to a model you can’t.

This is my stance as of 2026-10-22, not a settled standard. Take one cron job this week and run it through the six steps. If you keep the deterministic part a script and give the model only the judgment, the Claude Code skills docs cover the rest of the format.

Sources

Questions, answered

What is the difference between a Claude Code skill and an agent?
A skill is not a tiny agent; it is a written procedure with the scripts it needs, and the caller (timer, hand, button) is just a detail. The author argues a model loop only earns its place when every step depends on a judgment about the previous step's result.
How do you run a Claude Code skill on a schedule?
A timer calls the script, and the model is called only at the judgment point with a short tool allow-list. In the author's setup, seven local systemd timers call skills and 8 scheduled Trigger.dev tasks run in the main app.
What happens when a Claude Code skill fails while running unattended?
Every run should write a dated note, and a wrapper script (run-skill.sh) takes a run lock, runs the skill with a tool allow-list, and writes a fallback note if the skill fails or writes nothing. One skill, vault-cleanup, failed 7 of 12 runs because the permission allow-list refused its move command.
How do you stop a scheduled Claude Code job without editing the timer?
Use an off switch: one file that stops the job. In the keyword harvest, creating the file raw/keywords/HARVEST_OFF switches it off while the timer stays as it is.
Should the model own commits and pushes in an automated skill?
No. The script or wrapper owns every side effect including commits and pushes, and the wrapper instructs the skill not to run git add, commit or push. The author once had a scheduled run sweep a half-built change into its commit because the run commit stages everything.

Keep reading

The column · weekly · free

The next piece, the morning it is published.

One written column a week. The email service holds the list.

The columns, fixes and workshops continue in the community: SEO, AI, and making money with code.

Join on Whop

Luke Sidney writes and builds everything here, alone, in the open. lukesidney.me