# Automating recurring work
The same prompt you run by hand every Monday morning can run itself, generate a competitive brief, and land in your inbox before you finish your coffee. The gap between a one-off Claude task and a hands-off pipelinepipelineAll active sales opportunities across the stages of the sales process, together with their combined potential value and probability of closing.Voir la définition complète → is smaller than it looks, and this lesson closes it.
You already know how to get a great result from Claude once. Now we make it repeatable, scheduled, and safe.
There are three rungs on the automation ladder, and you climb them based on how much control and infrastructure you want.
Rung 1: Inside the Claude apps. Projects, Connectors, and Skills let you do a lot without touching code. A Connector plugs Claude into an external system (Gmail, Google Drive, Linear, a database) using MCP, the Model Context Protocol, which is the open standard that lets a model call external tools and data sources. This is the no-code rung.
Rung 2: Claude Code and scheduled agents. Claude Code can run unattended in a terminal or container. Pair it with cron (the standard Unix job scheduler) and you have a recurring agent on your own machine or a small server.
Rung 3: CI like GitHub Actions. Your automation lives in a repo, runs on Anthropic's or GitHub's infrastructure, has logs, and triggers on a schedule or an event. This is the most auditable and the most "production."
We will build the Monday brief on rung 3, but I will show you where rungs 1 and 2 fit.
A schedule is just a trigger. The work itself is a normal Claude agent: a prompt, some tools, and a model call. The new ingredient is that *nobody is watching when it runs*. That changes how you design it.
When you are in the chat window, you are the guardrail. You see a bad answer and rerun it. An unattended pipelinepipelineAll active sales opportunities across the stages of the sales process, together with their combined potential value and probability of closing.Voir la définition complète → has no human in that loop, so the guardrails have to be written into the pipelinepipelineAll active sales opportunities across the stages of the sales process, together with their combined potential value and probability of closing.Voir la définition complète → itself. Hold that thought; it drives every design decision below.
Here is the goal. Every Monday at 7am, Claude:
1. Pulls recent news and pricing pages for three competitors.
2. Compares them against last week's brief.
3. Writes a one-page brief highlighting what changed.
4. Emails it to the team, but only after a cost and sanity check passes.
Never automate something you have not run manually first. Build it as a Claude Code session or a Project until the output is genuinely good. This is your spec.
Capture the winning instructions as a reusable asset. A Skill is a packaged set of instructions and resources Claude loads on demand, like a competitive-analysis playbook with your brief template, tone rules, and source list. A Skill makes the same behavior portable from your desktop session into the automated one.
For a scheduled job, the Claude Agent SDK (formerly the Claude Code SDK) is the right tool. It gives you Claude Code's agent loop (planning, tool calls, file edits) as a programmable library, so your scheduled run behaves like the interactive session you already tuned.
Here is the core of the job. It is deliberately small: the intelligence lives in the prompt and the Skill, not in the Python.
import os
from claude_agent_sdk import query, ClaudeAgentOptions
async def generate_brief() -> str:
options = ClaudeAgentOptions(
system_prompt="You are a competitive intelligence analyst. "
"Use the competitive-brief skill. Be concise and cite sources.",
allowed_tools=["WebFetch", "Read", "Write"],
permission_mode="acceptEdits",
max_turns=20,
)
prompt = (
"Generate this week's competitive brief comparing Acme, Globex, and Initech. "
"Compare against last_week.md. Output a one-page brief to brief.md. "
"Flag only what materially changed."
)
result = []
async for message in query(prompt=prompt, options=options):
result.append(message)
return open("brief.md").read()Two things to notice. allowed_tools is a whitelist: the agent can fetch web pages and read and write files, and nothing else. max_turns caps how long the agent loop can run. Both are guardrails, and we are only getting started.
On your own machine or server, cron is enough. A crontab entry is five time fields plus a command. This runs the job every Monday at 7am:
# m h dom mon dow command
0 7 * * 1 cd /opt/briefs && /usr/bin/python run_brief.py >> brief.log 2>&1The 1 in the fifth field is Monday. The redirect at the end keeps a log, which you will want the first time something breaks at 7am while you are asleep.
Cron is great for a personal server, but it dies when your laptop sleeps and it has no audit trail beyond a text file. For anything a team depends on, move to CI.
GitHub Actions runs your job on a schedule using the same cron syntax, but in a clean cloud container with logs, secrets management, and history. The official Claude GitHub integration is built for this.
name: weekly-competitive-brief
on:
schedule:
- cron: "0 7 * * 1" # Mondays 07:00 UTC
workflow_dispatch: # lets you trigger a manual run too
jobs:
brief:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install claude-agent-sdk
- name: Generate brief
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: python run_brief.pyYour APIAPIApplication Programming Interface: a standardised interface that lets applications communicate and exchange data without knowing each other's internal workings.Voir la définition complète → key lives in GitHub's encrypted secrets, never in the code. workflow_dispatch is a small but important addition: it lets you run the pipelinepipelineAll active sales opportunities across the stages of the sales process, together with their combined potential value and probability of closing.Voir la définition complète → on demand to test it, instead of waiting for Monday.
This is the part people skip, and it is the part that matters. An unattended agent with a credit card and an email button is a liability until you constrain it.
Set a hard budget at the account level in the Anthropic Console, using usage limits and spend alerts on the APIAPIApplication Programming Interface: a standardised interface that lets applications communicate and exchange data without knowing each other's internal workings.Voir la définition complète → key this pipelinepipelineAll active sales opportunities across the stages of the sales process, together with their combined potential value and probability of closing.Voir la définition complète → uses. Give the automation its own key so a runaway loop cannot drain your whole budget. The max_turns cap in the SDK is your second layer: it bounds a single run even if the prompt sends the agent in circles.
Pick the right model for the job, too. A weekly brief does not need your most expensive model for every sub-task. Cheaper models for fetching and summarizing, a stronger model for the final synthesis, keeps cost predictable.
Sending email is irreversible. So split the pipelinepipelineAll active sales opportunities across the stages of the sales process, together with their combined potential value and probability of closing.Voir la définition complète →: generate runs unattended, but send waits for a human nod, at least until you trust it.
The cleanest pattern in GitHub Actions is to post the draft brief as output and require a manual approval (an environment protection rule) before the send step runs. You get the email drafted automatically and a one-click "ship it."
Vérification des acquis
1. What does MCP (Model Context Protocol) provide in the context of Claude automation?
2. According to the lesson, which rung of the automation ladder is described as the most auditable and the most 'production'?
3. In a normal Claude chat session, what plays the role that an unattended pipeline must replace with built-in safeguards?
4. Select ALL correct answers about what distinguishes a scheduled Claude agent from an interactive chat session.
Sélectionnez toutes les réponses correctes.
5. Select ALL correct answers about the three rungs of the automation ladder described in the lesson.
Sélectionnez toutes les réponses correctes.
A job that "succeeds" can still produce garbage. Add a cheap validation gate before the send step: does brief.md exist, is it under a sane length, does it contain the three competitor names, does it cite at least one source URL? If any check fails, stop and alert instead of emailing nonsense.
def validate(brief: str) -> None:
assert 500 < len(brief) < 8000, "brief length looks wrong"
for name in ("Acme", "Globex", "Initech"):
assert name in brief, f"missing competitor: {name}"
assert "http" in brief, "no sources cited"This is dumb code on purpose. Deterministic checks catch the failures that a model-based review might rationalize away.
Notice we never gave the agent a "send email" tool inside the SDK call. The send happens in a separate, dumb script *after* approval. Keep destructive or external-facing actions out of the agent's tool list and in plain code you control. The agent writes a file; your pipelinepipelineAll active sales opportunities across the stages of the sales process, together with their combined potential value and probability of closing.Voir la définition complète → decides what to do with it.
Building Agents with the Claude Agent SDK
You do not always need a repo. If your recurring task is "summarize this week's Linear issues into a Slack post," a Connector plus a scheduled trigger inside an automation tool may be all you need, with no Python at all. The connector marketplace is growing fast, so check whether your data source already has one before you build a custom MCP server.
The decision rule: stay no-code while the task is simple and the blast radius is small. Move to the SDK and CI when you need version control, real logging, cost controls, and review gates. The Monday brief sits on the line, which is why it is a good teaching example.
One last concept that separates a toy from a pipelinepipelineAll active sales opportunities across the stages of the sales process, together with their combined potential value and probability of closing.Voir la définition complète →. Idempotency means running the job twice produces one correct result, not two messes. If GitHub retries a run, or you trigger it manually to test, you do not want two emails or a corrupted history file.
Make the run safe to repeat: write to a dated file (brief-2026-01-19.md), check whether this week's brief already exists before sending, and treat "already done" as success. Cheap to add, painful to retrofit after the day you get two briefs and a confused team.
max_turns, whitelist tools, and run deterministic validation before any irreversible action.