All articles Day 11 · Automating it

Run it without you.
Keep the guardrails.

By Kowshik Kesavarapu 5 min quick start + 25 min full guide Oct 22, 2026

Beyond the roadmap: Claude Code without you in the room. Days 1 to 10 were about working with Claude Code in a conversation. Today it runs on its own: from a script, from a build, or on GitHub when someone comments on a pull request. Same tools, same rules from Day 5, no chat window. The big rule of the day is simple: the less you watch, the tighter the guardrails must be.

01The big picture: from conversation to command

What. Until now you typed to Claude Code and read its answers. Headless mode (also called print mode) turns it into an ordinary command: you give it a prompt, it does the work, prints the result and exits. That makes it something a script, a scheduled job or a build server can call, just like git or npm.

Why it matters. Plenty of useful work does not need you watching: explain this failing build log, check my diff for typos, review every pull request, write a daily summary of what changed. Doing these by hand is easy to forget. Automating them means they happen every time, for every teammate.

Part 1: ScriptsSections 02 to 11. The claude -p command: input, permissions, output you can parse, reproducible runs, conversations, and cost limits.
Part 2: GitHub ActionsSections 12 to 16. Let Claude answer @claude in issues and pull requests, review PRs automatically, and run on a schedule.
Part 3: Use it safelySections 17 to 23. Costs, safety, VS Code, troubleshooting, a cheat sheet, questions and exercises.

02What headless mode is, in plain words

What. Think of two ways to use a calculator. You can press buttons and watch the screen (interactive), or you can hand someone a slip of paper with the sum and get a slip back (headless). The flag -p (short for --print) means "take this one prompt, print the answer, stop." There is no back and forth, so nobody can answer a question or click Approve halfway through.

Why that last point matters. In a normal session, when Claude wants to run a command you have not allowed, it asks you. In a headless run nobody is there to ask. So you decide in advance what Claude may do, using the permission ideas from Day 5. Most of this article is about making that decision well.

03Your first claude -p

How. Open a terminal in a project (in VS Code, Ctrl+`) and run:

>_PowerShell — a one-shot question
—☐✕
claude -p "What does the auth module do?"

# let it edit files too: name the tools it may use
claude -p "Find and fix the bug in auth.py" --allowedTools "Read,Edit,Bash"

# did it work? 0 means success, anything else means failure
echo $LASTEXITCODE

Claude Code exits with code 0 on success and a non-zero code when the run fails, so a script can branch on it ($LASTEXITCODE in PowerShell, $? in bash). If you pass an invalid flag you get an error on stderr before anything runs. Some failures happen inside the run, such as missing sign-in: those are printed as the result on stdout, so read the output as well as the exit code in your scripts.

Use the quotes your shell expects. The examples use double quotes, which work in PowerShell, cmd and bash. Inside a double-quoted PowerShell string, a $ starts a variable, so put prompts that contain $ in single quotes.

04Pipe data in, redirect the answer out

What and why. A headless run reads standard input, so you can feed it a log, a diff or a file the same way you would feed grep. This is often better than letting Claude go and fetch the data itself: it needs fewer permissions, and you control exactly what it sees. How:

>_PowerShell and bash
—☐✕
# bash / macOS / Linux
cat build-error.txt | claude -p 'concisely explain the root cause of this build error' > output.txt

# PowerShell
Get-Content build-error.txt | claude -p "concisely explain the root cause of this build error" | Set-Content output.txt

# the diff of your branch against main
git diff main | claude -p "list any typos, one per line as file:line then the issue"

Piped input is capped at 10 MB. Beyond that Claude Code exits with a clear error and a non-zero code. For bigger inputs, write the data to a file and mention the path in the prompt. Piping a diff also means Claude needs no permission to run git itself.

05Letting it act: permissions when nobody is watching

What. By default a headless run starts in Manual mode: anything that would need your approval is simply denied, because nobody can click yes. Reading files in the project and the usual read-only commands still work. To let it do more, you grant permission up front. You have three levers, all from Day 5:

--allowedToolsA list of tools or command patterns that run without asking. "Read,Edit" allows reading and editing. For shell commands use a pattern: "Bash(git diff *)" allows any command that starts with git diff. The space before the star matters: without it, git diff* would also match git diff-index.
--permission-modeacceptEdits: file edits and common filesystem commands (mkdir, mv, cp) go through. dontAsk: anything that would prompt is denied, the safest choice for locked-down CI. auto: a classifier reviews most actions for you.
--permission-prompts noneFor unattended jobs: anything that would prompt is denied and Claude is told nobody can approve it, so it stops retrying. Needs a recent Claude Code (v2.1.259 or later).

Why this is the heart of automation. Every allowed tool is something a robot can do at 3 a.m. with nobody watching. The rule of thumb: start with the smallest list that completes the job, run it, see what was denied, and add only that. In stream-json output, denials show up as permission_denied messages, and the final result lists them in permission_denials, so you can see exactly what to consider adding.

>_PowerShell — a small, specific permission list
—☐✕
# write a commit message and commit, and nothing else
claude -p "Look at my staged changes and create an appropriate commit" `
  --allowedTools "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)"

# apply lint fixes; file edits allowed, shell still restricted
claude -p "Apply the lint fixes" --permission-mode acceptEdits

# locked-down unattended run
claude -p "Update the dependency pins and run the tests" `
  --permission-mode auto --permission-prompts none

The backtick ` at the end of a line continues the command in PowerShell. In bash use a backslash \ instead.

06Output a program can read

What. By default you get plain text, which is great for people and awkward for programs. --output-format changes that. text is the default. json returns one JSON object with the answer in a result field plus the session id and usage details. stream-json sends one JSON event per line as it works, for live progress.

Why. A script that has to parse a paragraph of prose will break. A script that reads a field will not. With JSON you can pull out the answer, check the cost, or continue the same conversation later.

>_PowerShell and bash
—☐✕
# bash with jq: just the answer text
claude -p "Summarize this project" --output-format json | jq -r '.result'

# PowerShell, no extra tools needed
$out = claude -p "Summarize this project" --output-format json | ConvertFrom-Json
$out.result
$out.total_cost_usd      # estimated spend for this run

Force an exact shape. Add --json-schema with a JSON Schema and the reply is checked against it, with the structured data in a structured_output field. Always check that the field exists before using it: if Claude declined the request, it is missing.

>_Structured output
—☐✕
claude -p "Extract the main function names from auth.py" `
  --output-format json `
  --json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}' `
  | jq '.structured_output'
# result: the list of function names

For live output use --output-format stream-json --verbose --include-partial-messages. The last line of the stream is a result message with the final text, cost and session details. The cost numbers are client-side estimates and can differ from your bill.

07Reproducible runs: --bare

What. A normal claude -p loads the same things an interactive session would: your CLAUDE.md, hooks, skills, subagents, plugins, MCP servers and memory. --bare skips all of that auto-discovery and starts faster. Claude then has just the Bash, file read and file edit tools.

Why it matters. A script that behaves differently on every laptop is a bug factory. A hook in one teammate's home folder or an MCP server in a project's .mcp.json can change what a run does. --bare makes the run depend only on what you pass in the command. It is the recommended mode for scripted calls and is expected to become the default for -p in a future release. One more reason: without it, a -p run in a repository you have never opened runs that project's hooks and connects its MCP servers with no trust prompt, so be careful pointing it at code you did not write.

How. Bare mode never reads your sign-in, so set an API key. Pass anything you do want with flags:

>_PowerShell
—☐✕
$env:ANTHROPIC_API_KEY = "sk-ant-..."     # create a key in the Claude Console
claude --bare -p "Summarize README.md" --allowedTools "Read"

# bring back only what you need
claude --bare -p "Review this change" `
  --append-system-prompt "You are a strict reviewer." `
  --mcp-config .\ci-mcp.json --plugin-dir .\team-standards
System prompt--append-system-prompt or --append-system-prompt-file.
Settings--settings <file-or-json>.
MCP servers--mcp-config <file-or-json>. Only servers named here connect.
Agents and plugins--agents, --plugin-dir (the Day 10 plugin flag works here too), --plugin-url.

Never type a real key into a file you commit. Keep it in an environment variable, and in CI in the platform's secret store.

08Multi-step runs: continue and resume

What and why. Each claude -p is a fresh start unless you tell it otherwise. For a review that needs follow-up questions, continue the earlier conversation so Claude keeps its context (Day 5). How:

>_PowerShell and bash
—☐✕
# continue the most recent conversation
claude -p "Review this codebase for performance issues"
claude -p "Now focus on the database queries" --continue

# several conversations at once: capture the session id
# bash
session_id=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$session_id"

# PowerShell
$id = (claude -p "Start a review" --output-format json | ConvertFrom-Json).session_id
claude -p "Continue that review" --resume $id

You can run the two commands from different folders, because Claude Code finds a session by its id across projects on this machine.

09Skills, commands and system prompts in headless runs

What and why. Everything you built earlier still works headless, which is what makes automation powerful. Your Day 8 skill becomes a one-line job. How:

Run a skillPut /skill-name in the prompt, for example claude -p "/review". Claude Code expands it before running. From a plugin: /team-standards:review.
Add instructions--append-system-prompt "You are a security engineer" adds your rules on top of the defaults. --system-prompt replaces the defaults entirely, which also drops the git status snapshot.
What does not workCommands that only make sense in the terminal interface, like /login, are not available. A few take a value as an argument, such as /model sonnet. To change a setting, pass /config key=value.

10Four small recipes you can use today

What and why. Automation pays off in small, boring jobs. Each recipe below is a few lines. How:

>_Recipe 1: a typo linter in package.json
—☐✕
{
  "scripts": {
    "lint:claude": "git diff main | claude -p \"you are a typo linter. for each typo in this diff, report filename:line on one line and the issue on the next. return nothing else.\""
  }
}

Run it with npm run lint:claude. The escaped double quotes keep it working on Windows.

>_Recipe 2: a security review of a pull request (review.sh)
—☐✕
gh pr diff "$1" | claude -p \
  --append-system-prompt "You are a security engineer. Review for vulnerabilities." \
  --output-format json | jq -r '.result'
# run with: bash review.sh 123
>_Recipe 3: explain a failed build (PowerShell)
—☐✕
npm run build 2>&1 | Tee-Object build.log
if ($LASTEXITCODE -ne 0) {
  Get-Content build.log | claude -p "explain the root cause in 3 lines and the fix" | Set-Content why.txt
}
>_Recipe 4: gate a script on a yes or no
—☐✕
$r = claude --bare -p "Does this diff change a public API? Answer only with the word YES or NO." `
  --allowedTools "Read" < diff.txt
if ($r -match "YES") { Write-Host "needs an API review" }

Recipe 4 uses Claude as a judge in a pipeline. Treat the answer as a hint that routes work to a human, not as a decision that ships code.

11Limits: budget, turns and stopping a run

What and why. An unattended run that goes in circles costs money and time with nobody noticing. Put a ceiling on every automated run. How:

--max-budget-usdStops the run when its spend reaches the amount. When the cap is hit, remaining background work is stopped too.
--max-turnsLimits how many back-and-forth steps Claude may take. The GitHub Action uses the same flag inside claude_args.
Check the costWith --output-format json the reply includes total_cost_usd and a per-model breakdown, so a script can log spend. It is an estimate, not your bill.
Stopping itSIGTERM ends a run with exit code 143 and records no result for the unfinished turn. SIGINT ends the turn first. Background tasks Claude started make the run wait, up to 10 minutes of idle waiting by default.

Wrap scripted runs in your platform's own timeout as well (a CI job timeout, or the Windows Task Scheduler stop setting), so a hung run cannot hold a machine forever.

12What GitHub Actions is, in plain words

What. GitHub Actions is a robot that lives in your repository. You write a workflow, a YAML file in .github/workflows/, that says "when this happens (a comment, a new pull request, 9 a.m.), start a fresh computer, check out the code and run these steps." The Claude Code GitHub Action (anthropics/claude-code-action) is one of those steps: it runs Claude Code inside that fresh computer.

Why it matters. It moves Claude Code from your laptop to where the team already works. Anyone can mention @claude on an issue and get a pull request back. Every pull request can get a first review before a human opens it. It also means Claude runs on GitHub's machines using your repository secrets, so Part 3 on guardrails applies double.

Interactive modeThe workflow has no prompt. Claude waits for the trigger phrase (@claude by default) in an issue, a PR comment or a PR review, then answers in a comment and updates it as it works.
Automation modeThe workflow has a prompt. Claude runs on any GitHub event, including a schedule, with no mention needed. By default results go to the workflow run log unless the prompt tells it to post and it has a tool that can.

13Set it up: quick and manual

What and why. Setup does three things: installs the Claude GitHub App on the repository, stores your credential as a repository secret, and adds a workflow file. You need admin access to the repository. How, the quick way:

>_Quick setup (terminal or the VS Code integrated terminal)
—☐✕
# prerequisites: GitHub CLI installed and signed in
gh auth login

# then, in a Claude Code session inside your repository
> /install-github-app

Follow the prompts. Claude Code installs the app, saves the secret (ANTHROPIC_API_KEY for an API key, or CLAUDE_CODE_OAUTH_TOKEN for a subscription token), pushes a branch with the workflow files you select, and opens GitHub with a pull request ready to create. Create and merge that PR and @claude works. This works for github.com repositories only. For GitLab there is a separate GitLab CI/CD integration.

The manual way, when the command fails or you want full control:

1. Install the appInstall the Claude GitHub App on the repository. The action relies on three of its permissions: Contents, Issues and Pull requests, each read and write.
2. Add a secretIn the repository settings add ANTHROPIC_API_KEY (a key from the Claude Console) or CLAUDE_CODE_OAUTH_TOKEN (run claude setup-token locally; available on Pro, Max, Team and Enterprise plans). Never commit a key into the repository.
3. Add the workflowCopy examples/claude.yml from the anthropics/claude-code-action repository into .github/workflows/. If you use the OAuth token, change the anthropic_api_key line to claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}.
4. TestComment @claude on an issue or pull request.

Installing the app grants its full permission set (it is shared with other Claude features such as Code Review). If your organisation wants only what the Action uses, create a custom GitHub App as the setup guide describes.

14@claude in issues and pull requests

What and why. This is the friendliest first workflow: nobody has to learn a command. Someone writes @claude fix the TypeError in the dashboard on an issue, and Claude reads the code, makes the change and opens a pull request. How: this workflow runs in interactive mode:

>_.github/workflows/claude.yml
—☐✕
name: Claude Code
on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]
jobs:
  claude:
    if: contains(github.event.comment.body, '@claude')
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
      issues: write
      id-token: write
      actions: read
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 1
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
on:The events that start the job: a new comment on an issue or pull request, or on a line of a PR review.
if: contains(...)Skips starting a computer for comments that do not mention @claude, which saves minutes.
permissions:What the workflow's GitHub token may do. id-token: write is needed for the default GitHub App sign-in, and actions: read lets Claude read CI results on PRs.
actions/checkoutGives Claude a copy of the code to work in.
uses: anthropics/claude-code-action@v1The step that runs Claude. Pin the major version as shown. If an old workflow says @beta, migrate: change it to @v1, replace direct_prompt with prompt and move options like model into claude_args.

Try requests like @claude implement this feature based on the issue description or @claude how should I implement user authentication for this endpoint?. Claude answers in the same thread. Put your standards in a CLAUDE.md at the repository root (Day 2): Claude follows it on every run, and keeping it short saves tokens.

Who can trigger it. Two checks run before Claude starts. The person commenting must have write access to the repository, so a stranger cannot spend your money from a public issue. And bot accounts are rejected unless you list them in allowed_bots, which stops bots from triggering each other in a loop.

15Automatic review of every pull request

What and why. A review at the moment a PR opens catches the obvious problems before a teammate spends time on it. Here Day 10 pays off: the review logic comes from the official code-review plugin, installed inside the workflow. How:

>_.github/workflows/code-review.yml
—☐✕
name: Code Review
on:
  pull_request:
    types: [opened, synchronize, ready_for_review, reopened]
jobs:
  review:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: read
      issues: read
      id-token: write
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 1
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          plugin_marketplaces: "https://github.com/anthropics/claude-code.git"
          plugins: "code-review@claude-code-plugins"
          prompt: "/code-review:code-review --comment ${{ github.repository }}/pull/${{ github.event.pull_request.number }}"
          claude_args: '--allowedTools "mcp__github_inline_comment__create_inline_comment"'
plugin_marketplaces and pluginsThe Day 10 ideas in YAML: add a marketplace by its Git URL, then install plugin@marketplace-name. The marketplace name comes from the marketplace's own file, not its URL.
promptA skill call with the namespaced /plugin-name:skill-name form from Day 10.
--commentClaude posts the review on the pull request: an inline comment per issue, or one summary when it finds none. Without it nothing is posted and you read the findings in the run log.
claude_argsKeep this line. The server that posts inline comments only starts when --allowedTools names it here.

Claude skips draft and closed pull requests, ones it judges not to need review (automated or trivial) and ones it already commented on. On public repositories GitHub withholds secrets from fork pull requests, so this review runs only for branches in the same repository. If you want automatic reviews without maintaining a workflow, Anthropic also offers a separate Code Review feature.

16Run on a schedule

What and why. A cron trigger lets Claude do a recurring job: a morning summary, a weekly dependency check, a stale-issue sweep. How: give the workflow a prompt and a schedule. For a plain-text prompt Claude has no shell or GitHub access until you grant the tools it needs, so name them:

>_.github/workflows/daily-report.yml
—☐✕
name: Daily Report
on:
  schedule:
    - cron: "0 9 * * *"        # 09:00 UTC every day
jobs:
  report:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      issues: read
      id-token: write
    steps:
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          prompt: "Generate a summary of yesterday's commits and open issues"
          claude_args: |
            --model claude-sonnet-5-5
            --max-turns 8
            --allowedTools "mcp__github__list_commits,mcp__github__list_issues"

Three details to know. GitHub runs scheduled workflows only from the default branch. In public repositories GitHub turns the schedule off after 60 days without repository activity. And a scheduled run is attributed to the person who last changed the cron line, so if that is a bot, add it to allowed_bots. In this example the report goes to the workflow run log, which is the default. Cron times are in UTC: 09:00 UTC is 14:30 in India.

17Costs and guardrails in CI

What. Every automated run spends two things: GitHub Actions minutes on GitHub's machines, and tokens on the model (or your subscription, if you authenticate with an OAuth token). Why it matters. A loop or a very busy repository can multiply both quietly. How to keep control:

Cap the workSet --max-turns in claude_args, add a job timeout-minutes, and use GitHub concurrency controls so a burst of pushes does not start ten reviews at once.
Be specificClear @claude requests and issue templates mean fewer turns. A short CLAUDE.md is read on every run.
Least privilegeGive each workflow only the permissions: it needs. The review job above is read-only apart from comments.
Protect secretsKeys live in repository or organisation secrets, never in files. For a secret shared across repositories use an API key, not an OAuth token, because the token belongs to the person who generated it. For no long-lived secret at all, the Action supports workload identity federation.
Review before mergeClaude's pull request is a suggestion. A human reads it and CI runs on it like any other. Do not auto-merge unreviewed AI changes.
Watch spendTrack usage on the Claude Console and your organisation analytics. JSON output from scripts includes an estimated cost for each run.

18Safety: the rules for unattended code

What and why. A chat session is supervised by you. A headless run or a workflow is not, so the safety work moves into the setup. The list below is the habits that matter most.

Allow narrowlyPrefer Bash(git diff *) to bare Bash. Add tools only after you see what was denied.
Run it where mistakes are cheapA fresh CI runner or a throwaway clone, not the folder with your only copy of the work.
Use --bare in scriptsSo a surprise hook or MCP server on one machine cannot change a run.
Treat input as untrustedA pull request from a stranger can contain text meant to steer Claude (a "prompt injection"). Keep permissions small enough that a steered Claude still cannot do harm, and require write access to trigger runs.
Never auto-approve everythingDo not reach for a flag that skips every permission check. A precise allow list does the same job with far less risk.
Keep a human in the loopClaude opens the pull request, you merge it.

19In VS Code

What and why. Headless mode and Actions are terminal and GitHub features, not extension screens, but you still do most of the work from VS Code. The Claude panel is for conversation. The pieces below are what you use around it.

Run itOpen the integrated terminal (Ctrl+`) and run claude -p there. Pipes and redirects work the same in PowerShell, bash and zsh.
Write the workflowsCreate .github/workflows/claude.yml from the Explorer with New File. YAML is indentation sensitive, so use spaces, and let VS Code show you the indent guides. Ask the Claude panel to check your YAML or explain a failed run.
Set it upRun /install-github-app in a Claude session inside the repository. In the panel or the terminal, it needs the GitHub CLI signed in first.
Test locally firstRun the same claude -p command in the terminal before putting it in a workflow. If it works there with your --allowedTools list, it will behave the same in CI. Add --bare to match the clean CI environment.

20When it does not work

Claude does not answer @claudeCheck the GitHub App is installed on the repository, workflows are enabled, the secret exists, the comment has @claude as a whole word (not /claude or @claude-bot), and the commenter has write access.
CI does not run on Claude's commitsGitHub does not trigger workflows for commits made with the default GITHUB_TOKEN. Remove a github_token: ${{ secrets.GITHUB_TOKEN }} line so Claude pushes as the GitHub App, and check your CI triggers include push or pull_request.
Authentication errorsTest the key or token locally with claude first. Bare mode ignores your login, so it needs ANTHROPIC_API_KEY.
A run is denied everythingThat is Manual mode doing its job. Add the specific tools to --allowedTools, or read the permission_denials in the output.
Review posts nothingAdd --comment and the claude_args line with the inline-comment tool. Without them the findings stay in the run log.
Output will not parseUse --output-format json, read the result field, and check structured_output exists. Do not parse the plain-text answer.
The scheduled run never firesIt runs only from the default branch, and the schedule pauses after 60 days of no repository activity in public repos.
It hangsAdd --max-turns and a CI timeout. Background tasks make a headless run wait, up to 10 idle minutes by default.

21Cheat sheet: I want this, so use that

"Ask one question"claude -p "question"
"Feed it a file or diff"git diff main | claude -p "..."
"Let it edit files"--permission-mode acceptEdits or --allowedTools "Read,Edit"
"Allow one kind of command"--allowedTools "Bash(git commit *)"
"Never wait for a prompt"--permission-prompts none with --permission-mode dontAsk or auto
"Get data back"--output-format json, read .result
"Force a shape"--json-schema, read .structured_output
"Same result everywhere"--bare plus ANTHROPIC_API_KEY
"Follow up"--continue, or --resume <session_id>
"Cap the spend"--max-budget-usd and --max-turns
"Run my skill"claude -p "/skill-name"
"Set up GitHub"/install-github-app (needs gh auth login)
"Review every PR"The code-review plugin workflow with --comment
"Run daily"on: schedule plus a prompt in the workflow

22Questions beginners ask

Do I need an API key?For scripts you run on your own machine while signed in, your login works. For --bare runs and CI you set ANTHROPIC_API_KEY (a key from the Claude Console), or in GitHub a subscription token made with claude setup-token.
Is headless mode different from the Agent SDK?Same engine. claude -p is the command-line form. The Python and TypeScript SDK packages give you more control inside a program, such as approval callbacks and structured message objects.
Can Claude push to main from a workflow?Only if you grant write permissions and nothing blocks it. Keep branch protection on, and let Claude open pull requests instead.
Will it cost a lot?It depends on prompt size, task difficulty and codebase size. Use --max-turns, job timeouts and concurrency limits, and watch your first week of runs before scaling up.
Does it work with GitLab or other clouds?There is a GitLab CI/CD integration, and the GitHub Action can send requests through Amazon Bedrock, Google Cloud's Agent Platform or Microsoft Foundry with OIDC instead of a stored key.
Is it safe on a public repository?It can be, if only people with write access can trigger it, permissions are minimal and a human merges. GitHub also withholds secrets from fork pull requests.
Can I schedule it on my own computer?Yes. Put the claude -p command in a script and run it from cron on Linux and macOS, or from Task Scheduler on Windows. Use --bare, a budget cap, and a key from an environment variable.

23Try this today

One-shotRun claude -p "summarize this repository in 5 bullets" in a project and check the exit code.
PipePipe your last build log or git diff main into claude -p and ask for the root cause or typos.
ParseRun it with --output-format json and print only the result and total_cost_usd.
Lock it downMake a commit-message command with a four-pattern --allowedTools list and confirm it cannot do anything else.
Go to GitHubIn a practice repository run /install-github-app, merge the setup pull request and comment @claude on an issue.

You now have the full ladder: talk to Claude Code, extend it, package it, and let it work on its own, with limits at every step.

Follow along

A new article lands every day. I post the short version on LinkedIn.