Claude Code moves from interactive assistant to active team member when you wire it into your automation infrastructure. This module covers CI/CD integration, scheduled tasks, the GitHub Actions integration, and patterns for building reliable multi-step workflows.
CI/CD Integration with Programmatic Runs
The claude -p flag is the foundation of CI/CD integration. It runs Claude non-interactively, sends a prompt, and returns the result to stdout. Combine it with --output-format json for structured parsing, --permission-mode bypassPermissions for fully automated runs (no approval prompts), and --max-turns to cap execution time.
A common pattern is running Claude as part of a PR review process. Configure it as a GitHub Actions step:
- 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
The --from-pr flag opens the session picker filtered to sessions linked to a specific pull request. Sessions are linked automatically when Claude creates the pull request. As of v2.1.119, --from-pr accepts a PR number, a GitHub or GitHub Enterprise PR URL, a GitLab merge request URL, or a Bitbucket pull request URL:
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 disposable automation, Claude can generate tests for new code, update documentation when APIs change, run linters and auto-fix issues, or check for security vulnerabilities. Use --no-session-persistence to avoid saving a session. Use --bare to reduce startup time for CI scripts — it skips auto-discovery of hooks, skills, custom commands, subagents, plugins, MCP servers, auto memory, and CLAUDE.md, so only explicitly-passed flags and settings take effect. The primary benefit is faster, reproducible startup, not cleaner output.
Use prUrlTemplate (new in v2.1.119) to point the footer PR badge at a custom code-review URL instead of the default github.com link — useful for enterprise deployments with internal GitHub instances or custom review tooling:
{
"prUrlTemplate": "https://review.example.internal/pr/{number}"
}
The /install-github-app command sets up the official GitHub integration, which allows Claude to respond to @claude mentions in PR comments and issues.
Mobile Push Notifications
When Remote Control is active, Claude can send push notifications to your phone. Claude decides when to push — typically when a long-running task finishes or when it needs a decision to continue. You can also request one in your prompt: notify me when the tests finish. Setup requires the Claude mobile app (iOS or Android), signed in with the same account, and Push when Claude decides enabled in /config. Beyond the on/off toggle, there is no per-event configuration. Requires Claude Code v2.1.110+.
For autonomous PR monitoring, /autofix-pr spawns a Claude Code on the web session that watches your current branch’s PR. When CI fails or a reviewer leaves a comment, Claude investigates and pushes a fix. Pass a prompt to narrow scope: /autofix-pr only fix lint and type errors. It requires the Claude GitHub App installed on the repository, access to Claude Code on the web, and is not available to organizations with Zero Data Retention enabled.
/ultrareview (added in v2.1.111) runs a comprehensive cloud-based code review using parallel multi-agent analysis and critique. It requires Claude.ai account authentication — if signed in with an API key only, run /login first. It runs on Claude Code on the web infrastructure. Invoke with no arguments to review your current branch, or /ultrareview <PR#> to fetch and review a specific GitHub PR. Pro/Max get 3 free one-time runs (a one-time allotment per account, do not refresh), then each review costs roughly $5–$25 as usage credits. Team/Enterprise have no free runs and are billed as usage credits. Usage credits must be enabled on the account — if disabled, Claude Code blocks the launch; if you can manage billing it links to billing settings, and on Team/Enterprise plans members without billing access send a request from the CLI asking their admin to turn usage credits on. Use /tasks to track running and completed reviews, open detail views, or stop an in-progress review (stopping archives the cloud session; partial findings are not returned). By default a review posts nothing — --no-post is the default. When you review a github.com PR, pass --post (added in v2.1.227) to have Claude post the finished findings to that PR as a single plain comment from your own GitHub account (it ends with a “Generated by Claude Code” note and is not a review or approval). In an interactive run, --post preselects the “post the findings as me” choice and Claude Code still asks before launching; non-interactively, claude ultrareview <PR#> --post posts without asking. Posting only applies to github.com PR targets — branch reviews and GitHub Enterprise Server PRs show the findings in your session only. Check the official docs to confirm /ultrareview availability on your platform.
Since v2.1.309, claude ultrareview needs the folder to be trusted. When it cannot ask you to trust it — such as in CI — it exits with Error: Workspace not trusted. There are two ways to handle that. Pass --trust-workspace to trust the current folder for that run only, without asking, so a script or CI job can review a checkout you haven’t trusted; it takes no value, so put a PR number or base branch before it, as in claude ultrareview 456 --trust-workspace. Or set CLAUDE_CODE_DISABLE_ULTRAREVIEW_TRUST_CHECK=1 so claude ultrareview does not exit with that error when it cannot ask to trust the folder — set it in the environment that launches Claude Code, not in a settings env block, and only where every such run starts in a folder you trust. Runs that can ask still ask. Both require Claude Code v2.1.309 or later.
/ultrareview # review current branch
/ultrareview 456 # review GitHub PR #456
Self-Hosted Runner
claude self-hosted-runner runs Claude Code automation on infrastructure you control rather than the managed cloud. The runner polls for jobs, executes them in a workspace, and reports results back — useful when you want the execution workspace to live on your own hosts. It does not change how Claude itself runs: the model and control plane are still external, and tool results can contain source code or secrets, so this is not a data-residency guarantee.
By default the runner registers with the machine’s hostname as its client label. Use --client-label <label> (or set SELF_HOSTED_RUNNER_CLIENT_LABEL) to override that label, so multiple runners on the same host can be distinguished by role — one for production jobs, another for staging, or per-tenant identities behind a shared hostname:
# Register a runner with a role-specific label
claude self-hosted-runner --client-label prod-runner-01
# Same effect via env var, useful for systemd units or container entrypoints
SELF_HOSTED_RUNNER_CLIENT_LABEL=staging-runner claude self-hosted-runner
Pass --remove-session-state (added in v2.1.268, off by default) to delete each session’s per-session directories under <base-dir>/_sessions/ when that session ends, so a long-lived runner doesn’t accumulate stale session state between jobs. Set SELF_HOSTED_RUNNER_REMOVE_SESSION_STATE for the same effect from a systemd unit or container entrypoint:
# Delete each session's per-session state when the session ends
claude self-hosted-runner --remove-session-state
# Same effect via env var
SELF_HOSTED_RUNNER_REMOVE_SESSION_STATE=1 claude self-hosted-runner
Pass --drain-marker-file <path> (added in v2.1.271) to control how the runner reports its shutdown back to the server: when that file exists at a SIGTERM drain, the runner reports its exit to the server as a host drain (telemetry only). The matching SELF_HOSTED_RUNNER_DRAIN_MARKER_FILE env var lets the same flag be set from a systemd unit or container entrypoint:
# Supervisor creates the marker, then the runner sees it at SIGTERM
touch /var/lib/claude-runner/drain
claude self-hosted-runner --drain-marker-file /var/lib/claude-runner/drain
# Same effect via env var
touch /var/lib/claude-runner/drain
SELF_HOSTED_RUNNER_DRAIN_MARKER_FILE=/var/lib/claude-runner/drain claude self-hosted-runner
Pass --host-config-snapshot disk|memory (added in v2.1.271) to choose where the runner keeps the startup snapshot of host config (settings, skills, plugins, MCP servers) it seeds each session from. The default disk copies the snapshot into a runner-owned directory under --base-dir and verifies every file against an in-memory digest at each session start, so a modified file fails the session and the runner refuses further sessions until you restart it. memory holds the whole snapshot on the heap, capped at 64 MiB — past the cap, sessions start without host config and show a notice — and the runner also falls back to it for a run when it can’t write the disk snapshot. The matching SELF_HOSTED_RUNNER_HOST_CONFIG_SNAPSHOT env var does the same from a systemd unit or container entrypoint:
# Force an in-memory snapshot (no on-disk cache after start)
claude self-hosted-runner --host-config-snapshot memory
# Same effect via env var
SELF_HOSTED_RUNNER_HOST_CONFIG_SNAPSHOT=memory claude self-hosted-runner
Pass --hold-idle-file <path> (added in v2.1.311) to keep an idle session on the runner while the processes it left running finish: your host keeps changing that file, and the runner holds the session instead of releasing it. The path is unset by default. The matching SELF_HOSTED_RUNNER_HOLD_IDLE_FILE env var sets the same path from a systemd unit or container entrypoint:
# The host touches this file while the processes it left are still running
claude self-hosted-runner --hold-idle-file /var/lib/claude-runner/hold-idle
# Same effect via env var
SELF_HOSTED_RUNNER_HOLD_IDLE_FILE=/var/lib/claude-runner/hold-idle claude self-hosted-runner
Pass --max-hold-min <n> (added in v2.1.311) to cap that hold: with --hold-idle-file, the runner releases a held session anyway N minutes after it went idle. A value at or below --release-idle-session-min holds nothing, and 0 turns the hold off. The default is 1440 minutes. The matching SELF_HOSTED_RUNNER_MAX_HOLD_MS env var sets the same cap in milliseconds from a systemd unit or container entrypoint:
# Hold an idle session, but release it at most 4 hours after it went idle
claude self-hosted-runner \
--hold-idle-file /var/lib/claude-runner/hold-idle \
--max-hold-min 240
# Same effect via env vars
SELF_HOSTED_RUNNER_HOLD_IDLE_FILE=/var/lib/claude-runner/hold-idle \
SELF_HOSTED_RUNNER_MAX_HOLD_MS=14400000 \
claude self-hosted-runner
Scheduled Tasks, Routines, and Background Automation
Claude Code supports multiple scheduling layers. /loop creates session-scoped recurring checks while Claude Code is running. Routines are cloud-backed scheduled tasks that persist independently of your local terminal — each run clones your repo fresh, executes autonomously, and can push branches or open PRs.
# 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
Routines
A routine is a saved Claude Code configuration — a prompt, one or more repositories, and a set of connectors — packaged once and run automatically on Anthropic-managed infrastructure. Create and manage them from the web at claude.ai/code/routines, from the Desktop app, or via /schedule in the CLI. Use /schedule list to view all routines, /schedule update to modify one, and /schedule run to trigger one immediately.
When you create or edit a routine that runs in the cloud, pick the model Claude uses on every run from the model selector in the prompt input. For a Claude Code task, if the model offers effort levels, Effort in the same selector shows the current level — select another level to change it. The selector’s Default option offers no levels.
Each routine can have multiple triggers combined:
- Scheduled — recurring cadence (hourly, daily, weekdays, weekly) or a one-off run at a specific time. One-off runs count against the same hourly limit as other scheduled runs (100 scheduled runs per hour, including one-off runs). Custom cron expressions are available via
/schedule update(minimum interval: 1 hour). - API — a per-routine HTTP endpoint. POST with a bearer token to trigger a run, optionally passing context in a
textfield. Wire it into alerting systems, deploy pipelines, or internal tools. - GitHub — reacts to repository events like pull requests or releases. Filters let you narrow by author, title, labels, base/head branch, draft status, and more. Requires the Claude GitHub App installed on the repository.
Routines run as full Claude Code cloud sessions with no permission prompts. They can use your connected MCP connectors (included by default — remove any that aren’t needed) and are scoped by the repositories you select, the cloud environment’s network access, and the connectors you include. By default, Claude pushes to a claude/-prefixed branch unless your prompt directs it elsewhere. To control which branches a run can push to, use branch protection rules or rulesets on GitHub.
Routines are available on Pro, Max, Team, and Enterprise plans with Claude Code on the web enabled. Team and Enterprise Owners can disable scheduled tasks for all members via the Scheduled tasks (Was Routines) toggle at Organization settings > Capabilities > Remote sessions (claude.ai/admin-settings/capabilities). API triggers are configured from the web UI only — you cannot add an API trigger or manage its token from the CLI. GitHub triggers can also be added from the CLI: install the Claude GitHub App from the GitHub App page first, then ask Claude to attach a GitHub trigger to an existing scheduled task (requires Claude Code v2.1.225 or later). /schedule in the CLI creates scheduled routines.
Background Automation
Background subagents with background: true in their frontmatter run without blocking the main conversation. This enables workflows where you kick off a long analysis, continue other work, and get notified when it completes. If you need automation around follow-up work, use the officially documented task and team hook events in their intended contexts: TaskCompleted for task state changes and TeammateIdle for agent teams teammates about to go idle.
{
"hooks": {
"TaskCompleted": [
{
"hooks": [
{
"type": "command",
"command": "curl -X POST $SLACK_WEBHOOK -d '{\"text\": \"Task completed: $TASK_NAME\"}'"
}
]
}
]
}
}
For long-running research that spans multiple sessions, resumable agents and regular memory workflows are the safer mental model: let the agent write findings into memory or project docs, then resume the agent or session later when needed.
Dynamic Workflows
Beyond single-session patterns, Claude Code supports dynamic workflows — a research-preview feature introduced in v2.1.154 that lets you orchestrate dozens to hundreds of subagents from a JavaScript script Claude writes. Unlike /loop or /batch, which run within a single conversation, a workflow moves the plan into a script: the script holds the loop, the branching, and the intermediate results, so Claude’s context keeps only the final answer.
To run a workflow, include the word ultracode anywhere in your prompt (the trigger keyword was renamed from workflow to ultracode in v2.1.160; asking for one in your own words still works), or turn on /effort ultracode to let Claude plan one for every substantial task. Claude writes an orchestration script tailored to your goal, then a runtime executes it in the background while your session stays responsive. Resume works within the same Claude Code session — if you exit Claude Code while a workflow is running, the next session starts the workflow fresh. Dynamic workflows fit codebase-wide audits, large migrations, cross-checked research, and any task that needs more agents than one conversation can coordinate.
The script body is plain JavaScript with top-level await. agent() spawns one subagent, pipeline() runs one per item in a list, and parallel() runs a set of agent tasks at the same time and waits for all of them:
const files = ["src/auth.ts", "src/db.ts"];
const findings = await parallel(
files.map((file) => agent(`Audit ${file} for secrets`))
);
Before v2.1.305, completed agents could also run again when you relaunched an unedited script whose pipeline() items or parallel() tasks ran more than one agent each; they are now served from the run’s journal instead.
The bundled /deep-research <question> workflow automates multi-source research: it fans out web searches across several angles, fetches and cross-checks the sources it finds, votes on each claim, and returns a cited report with claims that didn’t survive cross-checking filtered out. It requires the WebSearch tool to be available:
/deep-research What changed in the Node.js permission model between v20 and v22?
Run /workflows to list running and completed workflows and open a progress view that shows each phase’s agent count, token total, and elapsed time. When a run does what you wanted, select it in the /workflows view and press s to save its script as a command — it then runs as /<name> in future sessions, alongside the bundled workflows. Reuse pays off for recurring work like a weekly code audit or a release checklist.
/effort ultracode turns on automatic workflow orchestration at whatever effort level the session is already running — Claude decides when a task warrants a workflow and coordinates the agents without being asked, rather than raising the effort level itself. To also start a session at xhigh effort, launch with claude --effort ultracode (requires v2.1.203+). It lasts for the current session; turn it off with /effort ultracode off for routine work.
Dynamic workflows require Claude Code v2.1.154+ and are available on all paid plans (Pro, Max, Team, Enterprise). On Pro, turn them on from the Dynamic workflows row in /config. To disable them, toggle Dynamic workflows off in /config, set "disableWorkflows": true in settings, or set CLAUDE_CODE_DISABLE_WORKFLOWS=1.
Multi-Step Workflow Patterns
The most reliable workflows combine skills, hooks, and subagents into a pipeline where each step has clear inputs, outputs, and error handling.
The “develop and verify” pattern pairs a Stop prompt hook that checks completion criteria against an implementation skill. When Claude stops, the hook evaluates whether all requirements were met. If not, it tells Claude what’s missing and Claude continues:
{
"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 “parallel review” pattern uses Agent Teams (experimental, disabled by default — requires CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1) to have multiple specialists review simultaneously. One agent checks security, another checks performance, another checks test coverage. The team lead synthesizes their findings into a single report. Agent Teams have known limitations around session resumption, task coordination, and shutdown behavior.
For tasks that modify many files across a codebase, /batch <instruction> plans the work, splits it across background agents in isolated git worktrees, and is designed for large-scale refactors or repetitive changes. Depending on the workflow, it can also run verification steps and help open PRs for the results.
Git worktrees (isolation: worktree on subagents) are also useful for experimental work. The agent makes changes in an isolated branch, returns the worktree path when done, and you review or discard without affecting your working tree.