Once Claude Code is no longer sitting in front of you in a terminal but inside your pipeline, a schedule, or a script, the question shifts: not “what can I ask it”, but “what should happen without me”. This module walks the three routes — the one-off call from CI, the scheduled task in the cloud, and the workflow that spreads work across many agents — and closes with patterns that have proven themselves in practice.
Calling Claude Code from CI and scripts
The entry point to any automation is --print, or -p for short. Claude works through the prompt you hand it, writes the answer to stdout, and exits — no prompt, no questions back. Three companions pay off in scripts: --output-format json wraps the answer, the session ID, and metadata so that jq can deal with it, --permission-mode bypassPermissions removes the permission prompts nobody could answer in CI anyway, and --max-turns caps the number of agentic turns. Mind what it means: --max-turns counts turns, not minutes, and exits with an error once the limit is reached.
That is enough to express a PR review as an ordinary step in GitHub Actions: collect the diff, pipe it into claude -p, pass the result on. Piping has a side effect that is easy to miss — Claude needs no Bash permission to get at the diff this way:
- name: Claude Code Review
run: |
DIFF=$(git diff origin/main...HEAD)
REVIEW=$(echo "$DIFF" | claude -p "Review these changes. Output JSON with fields: summary, critical_issues, suggestions" \
--output-format json \
--permission-mode bypassPermissions)
echo "$REVIEW" | jq '.critical_issues[]' >> $GITHUB_STEP_SUMMARY
A related but different tool is --from-pr. It doesn’t start a session from a pull request, it finds one: Claude Code links a session to the PR it creates automatically, and --from-pr opens the session picker filtered to that pull request. The argument can be the PR number or the full URL; since v2.1.119 that includes GitHub Enterprise, GitLab merge requests, and Bitbucket pull requests:
claude --from-pr https://github.com/org/repo/pull/123
claude --from-pr https://gitlab.com/org/repo/-/merge_requests/456
claude --from-pr https://bitbucket.org/org/repo/pull-requests/789
For runs that should leave nothing behind there are two switches with different jobs. --no-session-persistence never writes the session to disk in the first place, so it can’t be resumed afterwards either. --bare aims at something else: it skips auto-discovery of hooks, skills, plugins, MCP servers, auto memory, and CLAUDE.md. That makes the run start faster — but above all it makes the run produce the same result on every machine, because a hook in a colleague’s home directory simply isn’t read. Which is exactly why --bare is the recommended form for scripts and CI.
If your team doesn’t look at pull requests on github.com but in a surface of its own, the PR badge in the footer still points there. The prUrlTemplate setting (since v2.1.119) bends the target to your URL:
{
"prUrlTemplate": "https://review.example.internal/pr/{number}"
}
The other direction — GitHub calling Claude rather than Claude calling GitHub — is what /install-github-app sets up. The command installs the Claude GitHub App on the repository and then asks whether to walk you through the GitHub Actions workflows and the secret for the API key as well; from v2.1.187 you can stop after the app with “Skip for now” and catch the rest up later. You need repository admin rights for both. Once the workflow is in place too, Claude answers @claude mentions in pull requests and issues right in the thread.
Notifications on your phone
While a Remote Control session is running, Claude can send push messages to your phone. It decides when on its own: typically when a long task finishes or a decision is due. You can also ask for one, for example with notify me when the tests finish. What you need is the Claude app for iOS or Android, signed in with the same account and organization, the operating system’s notification permission, and one or both of the two switches in /config: Push when Claude decides for messages Claude sends on its own initiative, Push when actions required for permission prompts and questions. Both require Claude Code v2.1.119 or later, and there is no finer per-event control than that. As long as you are typing in the connected terminal, the push is held back.
When a pull request should keep moving long after you have gone elsewhere, /autofix-pr takes over. The command works out the open PR from your checked-out branch with gh pr view — so the gh CLI is a prerequisite — and starts a Claude Code on the web session that watches it. When a check goes red or a review comment arrives, Claude looks into it: if the fix is clear, it pushes it and explains in the session what it did; if the remark is ambiguous or architecturally significant, it asks you first. A prompt narrows the assignment, for instance /autofix-pr only fix lint and type errors. It needs the Claude GitHub App on the repository and access to Claude Code on the web — which stays closed to organizations with Zero Data Retention enabled.
For the thorough look before merging there is the cloud review. Today it starts as /code-review ultra; /ultrareview is the alias from its introduction in v2.1.111 and still works. In a remote sandbox a whole fleet of agents examines your branch. Against a local review that makes three differences: every finding is independently reproduced before it is reported to you; the larger fleet gets further into the change; and your machine stays free because it all runs remotely. Because it runs on Claude Code on the web infrastructure it needs a claude.ai account; if you are signed in with an API key only, run /login first. With no argument it compares your branch against the default branch including uncommitted changes; with a PR number it reviews a pull request. Pro and Max come with three free runs, a one-time allotment that does not refresh; after that — and on Team and Enterprise from the start — it bills as extra usage, roughly $5 to $25 depending on the size of the change. A run typically takes 5 to 10 minutes; /tasks is where you see it, open the detail view, or stop it — which archives the cloud session, and partial findings do not come back:
/ultrareview # review current branch
/ultrareview 456 # review GitHub PR #456
On a timer: routines and background work
Claude Code can work on a timer at two levels that are worth keeping apart. /loop repeats a prompt for as long as your session is open — when the terminal dies, the loop dies. Routines, by contrast, live in the cloud: every run clones your repository fresh, works autonomously, and can push branches or open pull requests, whether or not your machine is on:
# Check build status every 5 minutes (session-scoped)
/loop 5m check if the build succeeded and summarize any failures
# Create a cloud routine from the CLI
/schedule "run a full security audit at 2am"
/schedule daily PR review at 9am
What a routine is
A routine is a Claude Code configuration saved once: a prompt, one or more repositories, an environment, and a selection of connectors. It runs on Anthropic-managed infrastructure. You create and maintain them on the web at claude.ai/code/routines, in the Desktop app, or with /schedule in the terminal; /schedule list shows them all, /schedule update changes one, /schedule run starts one right away. Because the run can’t ask anyone anything, the prompt carries the whole load: it has to make sense on its own and say how success is recognized.
What starts a routine is set by its triggers — freely combinable, and one routine may carry all three:
- Schedule — a recurring frequency (hourly, daily, weekdays, weekly) or a single run at a future moment. You enter times in your own zone and they are converted for you; a stagger of a few minutes is expected and stays consistent per routine. For a custom cron expression, follow up with
/schedule update— anything shorter than an hour is rejected. - API — an HTTP endpoint of its own per routine. A POST carrying the routine’s bearer token starts a run and hands back the session URL; the optional
textfield carries run-specific context. The token is shown exactly once, so store it somewhere safe right away. - GitHub — reacts to repository events, with pull requests and releases to choose from. Filters narrow down which one counts: author, title, body, base and head branch, labels, draft and merged state, each with an operator from “equals” to “matches this regular expression”. The Claude GitHub App has to be installed on the repository for this.
A run is a full cloud session with no permission prompts: no mode picker, no question back, not even for tools that write. What bounds it is what you give it — the repositories you select, the environment’s network access, and the connectors. All of your claude.ai connectors are included when you create it; anything the routine doesn’t need belongs out. By default Claude may only push to branches carrying the claude/ prefix; if you want more, enable Allow unrestricted branch pushes per repository. And whatever the routine does through your GitHub account or your connectors appears under your name.
Routines are a research preview — behavior, limits, and the API may change. They are available on Pro, Max, Team, and Enterprise as long as Claude Code on the web is enabled for the account, and they belong to your personal claude.ai account, not to the team. Owners on Team and Enterprise can switch them off for every member with the Routines toggle at claude.ai/admin-settings/claude-code; existing routines then stop running, and new ones can no longer be created either. In the terminal /schedule only creates scheduled routines — you add API and GitHub triggers on the web.
Automation in the background
Not every bit of concurrency needs the cloud. Since v2.1.198 subagents run in the background by default anyway; background: true in the frontmatter forces that even when Claude would actually need the result right away. So you kick off a long analysis, keep working, and get its result when it is done. Automation hangs off the transitions the docs provide for it — each one in its own place: TaskCompleted runs when a task is marked as completed, either through the TaskUpdate tool or because a teammate ends its turn with tasks still in progress; TeammateIdle fires just before a teammate goes idle. What you hang off them is up to you — a message into the team channel just as much as a check that refuses the completion: when the hook exits with code 2, the task stays open and its message goes back to the model as feedback:
{
"hooks": {
"TaskCompleted": [
{
"hooks": [
{
"type": "command",
"command": "curl -X POST $SLACK_WEBHOOK -d '{\"text\": \"Task completed: $TASK_NAME\"}'"
}
]
}
]
}
}
Nothing that runs in the background carries across sessions. What does carry is memory: a subagent with memory: user gets a memory directory of its own, writes its findings there, and the first 200 lines or 25 KB of its MEMORY.md are back in its system prompt on the next start. For long research that is the more dependable route than trying to hold a run open.
Dynamic workflows: the script holds the plan
Subagents, skills, and agent teams have one thing in common: Claude decides turn by turn what happens next, and every intermediate result lands in its context window. A dynamic workflow turns that around. Claude writes a JavaScript script and a runtime executes it — the loop, the branching, and the intermediate results sit in the script, and Claude’s context keeps only the answer. That makes dozens to hundreds of agents per run possible, and it turns the orchestration itself into something you can read and run again.
A workflow is triggered by putting the word ultracode anywhere in your prompt; asking for one in your own words counts just as much. Before v2.1.160 the keyword was workflow. What matters is where it works: only in a prompt you type yourself. Through -p, from a scheduled task, from a webhook, or from a relayed PR comment it starts no workflow. Depending on your permission mode Claude Code then shows the planned phases for approval — in auto mode only on the first run and not at all with ultracode on, and under bypassPermissions, with -p, and in the Agent SDK never. The run then works in the background while your session stays usable. If you interrupt it, resuming takes the finished agents’ results from the cache — but only within the same session: quit Claude Code and the workflow starts over next time.
Claude Code brings one finished workflow with it. /deep-research <question> fans web searches out across several angles, fetches the sources it finds, checks them against each other, votes on every claim, and returns a report with citations from which everything that didn’t survive the cross-check has dropped out. Anything the verifiers couldn’t judge at all, after a rate limit for instance, has been listed as unverified rather than refuted since v2.1.196. It needs the WebSearch tool:
/deep-research What changed in the Node.js permission model between v20 and v22?
What is running right now is shown by /workflows. From the list you open the progress view with agent count, token total, and elapsed time per phase, and descend all the way to a single agent to read its prompt, tool calls, and result; p pauses, x stops. When a run has done what you wanted, press s and file its script as a command — in the project under .claude/workflows/ for everyone who clones the repository, or under ~/.claude/workflows/ for you alone. After that it is available as /<name> in every further session; through args it can still take input at invocation time.
If you would rather not decide anew for every task, there is /effort ultracode: it combines xhigh reasoning with automatic orchestration, and Claude plans a workflow for every substantive task on its own — sometimes several in a row, one to understand, one to change, one to verify. That costs noticeably more time and tokens. The setting lasts for the current session; /effort high brings you back.
Dynamic workflows need Claude Code v2.1.154 or later and are available on all paid plans, with Anthropic API access, and on Amazon Bedrock, Google Cloud’s Agent Platform, and Microsoft Foundry. On Pro you turn them on from the Dynamic workflows row in /config. Turning them off works in three places: the same toggle in /config, "disableWorkflows": true in settings, or CLAUDE_CODE_DISABLE_WORKFLOWS=1 in the environment, which is read at startup and therefore applies wherever you set it. With workflows off the bundled workflow commands disappear, the keyword triggers nothing, and ultracode is missing from the /effort menu.
Patterns that carry several steps
Durable automations rarely consist of one tool. They assemble skills, hooks, and subagents into a chain in which every step knows what it receives, what it delivers, and what should happen on an error. Three of those chains keep coming up.
The first pattern is the completion check. A Stop hook of type prompt is handed a list of questions when the turn ends: were all files from the spec touched, do the tests pass, is the implementation complete? If the answer comes back negative, it returns to Claude as feedback and the work continues instead of stopping:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Check: 1) Were all files in the spec modified? 2) Do tests pass? 3) Is the implementation complete per the requirements? If anything is incomplete, explain what remains.",
"timeout": 30
}
]
}
]
}
}
The second pattern is review from several angles. With agent teams — experimental and off by default, enabled through CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 — one teammate looks at security, a second at performance, a third at test coverage. Unlike subagents they talk to each other directly and work through a shared task list; the session acting as lead pulls the findings together. The price is high: every teammate is a separate Claude instance, and there are known limitations around session resumption, task coordination, and shutdown behavior.
The third pattern is the bulk change. /batch <instruction> first reads its way into the codebase, decomposes the work into 5 to 30 independent units, and presents you the plan. Once you approve, each unit gets a background subagent in a git worktree of its own that implements it, runs the tests, and opens a pull request. A git repository is a prerequisite.
You can have the isolation behind that on its own too: isolation: worktree in a subagent’s frontmatter gives it a working copy of its own, branched by default from the default branch rather than from your session’s current state. Its cd and its commands stay inside that copy; a command that would end up in your main checkout after all fails with an error. If the agent changed nothing, Claude Code clears the worktree away again — what is left with changes stays until you have looked at it.