<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Automate Repeat Work |</title><link>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/02-automate-repeat-work/</link><atom:link href="https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/02-automate-repeat-work/index.xml" rel="self" type="application/rss+xml"/><description>Automate Repeat Work</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>en</language><lastBuildDate>Sat, 03 Oct 2026 00:00:00 +0000</lastBuildDate><image><url>https://haobin-tan.netlify.app/media/icon_hu_eee4a95885829ab2.png</url><title>Automate Repeat Work</title><link>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/02-automate-repeat-work/</link></image><item><title>Routines and Headless</title><link>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/02-automate-repeat-work/routines_and_headless/</link><pubDate>Sat, 03 Oct 2026 00:00:00 +0000</pubDate><guid>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/02-automate-repeat-work/routines_and_headless/</guid><description>
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;Note&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;h3 id="tldr"&gt;TL;DR&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Routines&lt;/strong&gt; are the default for repeat work. They run on Anthropic&amp;rsquo;s infrastructure with nothing for you to host.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Headless mode with &lt;code&gt;-p&lt;/code&gt;&lt;/strong&gt; is for when the job needs your pipeline and you want to pipe data through a script.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--bare&lt;/code&gt;&lt;/strong&gt; is for when CI needs the same results every single run.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Agent SDK&lt;/strong&gt; is for when the work belongs inside your own product.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="routines"&gt;Routines&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;routine&lt;/strong&gt; is the most direct way to automate a task. There&amp;rsquo;s no script and no server.&lt;/p&gt;
&lt;p&gt;It bundles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a prompt&lt;/li&gt;
&lt;li&gt;the repository it works on&lt;/li&gt;
&lt;li&gt;any connectors it needs&lt;/li&gt;
&lt;li&gt;a schedule&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then it runs that bundle in the cloud whenever it&amp;rsquo;s triggered.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The infrastructure is &lt;strong&gt;Anthropic&amp;rsquo;s&lt;/strong&gt; (i.e., in the cloud). There&amp;rsquo;s no machine of yours staying on overnight, and there&amp;rsquo;s no workflow file for you to maintain. You describe the job once and it just runs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A routine can fire on a few kinds of triggers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A cron schedule, like every morning at 9am.&lt;/li&gt;
&lt;li&gt;An HTTP POST to its API endpoint, so your own code can kick it off.&lt;/li&gt;
&lt;li&gt;A GitHub event, like a new pull request landing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;-&amp;gt; Anything that&amp;rsquo;s the same prompt on a recurring trigger is a good fit&lt;/p&gt;
&lt;h2 id="creating-a-routine"&gt;Creating a Routine&lt;/h2&gt;
&lt;p&gt;Two ways to create a routine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create one from the web at &lt;code&gt;claude.ai/code/routines&lt;/code&gt;. You give it a name, write the instructions describing what Claude should do in each session, pick a repository, and choose a trigger.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;create one from inside Claude Code: Run the &lt;code&gt;/schedule&lt;/code&gt; command and describe what you want in plain language&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/schedule daily dependency audit at 9am
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="three-things-to-know-before-you-rely-on-routines"&gt;Three Things to Know Before You Rely on Routines&lt;/h2&gt;
&lt;p&gt;Before you lean on routines for anything important, keep these three limits in mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Routines are a research preview.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Behavior and limits will keep moving, so don&amp;rsquo;t be surprised if things change.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A recurring schedule runs at most &lt;em&gt;hourly&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you need something more frequent, routines aren&amp;rsquo;t the tool.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Runs start from a fresh clone of your default branch, push to &lt;code&gt;claude/&lt;/code&gt; branches freely, and get checked before pushing anywhere else.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="headless-mode"&gt;Headless Mode&lt;/h2&gt;
&lt;p&gt;Sometimes the job needs your environment, or logic wrapped around the run. That&amp;rsquo;s when you drop to &lt;strong&gt;headless&lt;/strong&gt; mode.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Headless&amp;rdquo; means &lt;strong&gt;running without the interactive interface&lt;/strong&gt; (the &amp;ldquo;head&amp;rdquo;).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Normally you open Claude Code, type prompts, watch it work, and approve things.&lt;/li&gt;
&lt;li&gt;In headless mode you run one command, Claude does the job, prints the result to standard output, and exits (Just like executing a shell command).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;-p&lt;/code&gt;&lt;/strong&gt; flag (short for &lt;code&gt;--print&lt;/code&gt;) turns it on: It runs Claude Code as a one-shot command with no interactive UI. It reads standard in and writes standard out, so it pipes like any other shell tool.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;claude -p &lt;span class="s2"&gt;&amp;#34;summarize the changes in this diff&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-red-100 dark:bg-red-900 border-red-500"
data-callout="caution"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-red-600 dark:text-red-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0zM12 15.75h.007v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;Caution&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;p&gt;&lt;code&gt;-p&lt;/code&gt; skips auto-discovery of hooks, skills, plugins, MCP servers, and the CLAUDE.md file. You get Claude plus the tools you allow explicitly, and nothing the local environment happens to load.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- Raw HTML instead of the card shortcode: the shortcode only opens http(s) URLs in a new tab --&gt;
&lt;div class="hb-cards mt-4 grid gap-4 not-prose" style="--hb-cols: 1;"&gt;
&lt;a class="hb-card group" href="https://haobin-tan.netlify.app/uploads/claude-code-in-action/interactive_vs_headless_claude_code.html" target="_blank" rel="noopener"&gt;
&lt;span class="hb-card-title p-4"&gt;&lt;svg style="height: 1em; width: 1em;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"/&gt;&lt;/svg&gt;Interactive example: Interactive vs. headless Claude Code&lt;/span&gt;
&lt;/a&gt;
&lt;/div&gt;
&lt;!-- text: required trigger text; content is inserted from clipboard --&gt;
&lt;h3 id="getting-structured-output-back"&gt;Getting structured output back&lt;/h3&gt;
&lt;p&gt;When using headless mode, you can pair a JSON schema with the JSON output format, and Claude will constrain its output to match your schema. The object that matches your schema lands in the &lt;code&gt;structured_output&lt;/code&gt; field of the JSON response.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;claude -p &lt;span class="s2"&gt;&amp;#34;Extract the exported function names from src/core/style.js&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output-format json &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --json-schema &lt;span class="s1"&gt;&amp;#39;{&amp;#34;type&amp;#34;:&amp;#34;object&amp;#34;,&amp;#34;properties&amp;#34;:{&amp;#34;functions&amp;#34;:{&amp;#34;type&amp;#34;:&amp;#34;array&amp;#34;,&amp;#34;items&amp;#34;:{&amp;#34;type&amp;#34;:&amp;#34;string&amp;#34;}}},&amp;#34;required&amp;#34;:[&amp;#34;functions&amp;#34;]}&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq &lt;span class="s1"&gt;&amp;#39;.structured_output.functions&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="when-to-use-and-not-use-headless"&gt;When to use and not use headless&lt;/h3&gt;
&lt;details class="spoiler " id="spoiler-0"&gt;
&lt;summary class="cursor-pointer"&gt;When to use headless&lt;/summary&gt;
&lt;div class="rounded-lg bg-neutral-50 dark:bg-neutral-800 p-2"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You need your own environment.&lt;/strong&gt; For example, the job needs local data, GPUs, or internal tools that a cloud routine can&amp;rsquo;t reach.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You want to pipe data through a script.&lt;/strong&gt; For example: &lt;code&gt;git diff | claude -p &amp;quot;review this&amp;quot; | tee review.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You need structured output.&lt;/strong&gt; Pair &lt;code&gt;--output-format json&lt;/code&gt; with &lt;code&gt;--json-schema&lt;/code&gt; and read &lt;code&gt;structured_output&lt;/code&gt; in your code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You&amp;rsquo;re batch-processing.&lt;/strong&gt; Loop over files or tickets and call &lt;code&gt;claude -p&lt;/code&gt; once per item.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You&amp;rsquo;re running in CI.&lt;/strong&gt; Add &lt;code&gt;--bare&lt;/code&gt; when you need the same results every run.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You want multi-step automation.&lt;/strong&gt; Capture the &lt;code&gt;session_id&lt;/code&gt; from the JSON, then &lt;code&gt;claude --resume&lt;/code&gt; it in a later step (plan first, execute later).&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;!-- text: required trigger text; content is inserted from clipboard --&gt;
&lt;details class="spoiler " id="spoiler-1"&gt;
&lt;summary class="cursor-pointer"&gt;When not to use headless&lt;/summary&gt;
&lt;div class="rounded-lg bg-neutral-50 dark:bg-neutral-800 p-2"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Exploring or debugging&lt;/strong&gt; something you don&amp;rsquo;t understand yet. Use the interactive mode, where you can steer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A simple recurring prompt on a repo&lt;/strong&gt; (e.g. a morning dependency audit). A routine is simpler, and you host nothing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Work that belongs inside your product.&lt;/strong&gt; That&amp;rsquo;s what the Agent SDK is for.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2 id="multi-step-automation-with-sessions"&gt;Multi-Step Automation with Sessions&lt;/h2&gt;
&lt;p&gt;For work that happens across multiple steps, you don&amp;rsquo;t have to cram everything into one command. Capture the session&amp;rsquo;s ID from the JSON output and resume it later:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;claude --resume &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;jq -r .session_id /tmp/plan.json&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One script kicks off the work. Another resumes it later with full context. This is handy when the first pass produces a plan and a second pass carries it out.&lt;/p&gt;
&lt;h2 id="deterministic-runs-for-ci"&gt;Deterministic Runs for CI&lt;/h2&gt;
&lt;p&gt;When CI needs the same results every single run, use the &lt;code&gt;--bare&lt;/code&gt; flag, which gives you deterministic mode.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s the right choice when you&amp;rsquo;re running Claude Code inside a pipeline and you want repeatable, predictable output rather than anything that varies run to run.&lt;/p&gt;
&lt;h2 id="the-agent-sdk"&gt;The Agent SDK&lt;/h2&gt;
&lt;p&gt;The Agent SDK gets you a library that embeds Claude Code inside your own TypeScript or Python applications.&lt;/p&gt;
&lt;p&gt;Both languages expose a &lt;code&gt;query&lt;/code&gt; function and the same primitives as the CLI. You pass a prompt plus options, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;allowedTools&lt;/code&gt; to control what Claude can do,&lt;/li&gt;
&lt;li&gt;a system prompt,&lt;/li&gt;
&lt;li&gt;and a permission mode.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then you iterate over the messages Claude streams back and handle them however your app needs. It&amp;rsquo;s the same engine as the CLI, just callable from inside your product.&lt;/p&gt;</description></item><item><title>GitHub Actions and Code Review</title><link>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/02-automate-repeat-work/github_actions_and_code_review/</link><pubDate>Sat, 03 Oct 2026 00:00:00 +0000</pubDate><guid>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/02-automate-repeat-work/github_actions_and_code_review/</guid><description>&lt;!-- card params: title (required), url (optional), icon (Hero Icons), subtitle (Markdown supported) --&gt;
&lt;div class="hb-cards mt-4 grid gap-4 not-prose" style="--hb-cols: 1;"&gt;
&lt;a
class="hb-card group"href="https://academy.claude.com/courses/claude-code-in-action/github-actions-and-code-review" target="_blank" rel="noreferrer"&gt;
&lt;span class="hb-card-title p-4"&gt;
&lt;svg style="height: 1em; width: 1em;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"/&gt;&lt;/svg&gt;GitHub Actions and Code Review&lt;/span&gt;&lt;/a&gt;
&lt;/div&gt;</description></item></channel></rss>