Remote Control & Headless Automation
8 min read
What You Will Learn
Claude Code doesn’t have to live inside your terminal window. This chapter shows you how to access your local session from a phone or browser via remote control, run Claude Code programmatically with the -p flag for scripts and CI/CD pipelines, and set up recurring tasks with cron expressions so work happens even when you’re not watching.
Remote Control
Remote control lets you access your local Claude Code session from any device, whether a phone, tablet, or another computer, using just a web browser. Your machine connects outbound to Anthropic’s relay service over HTTPS, so there’s nothing to configure on the network side. No inbound ports get opened, no firewall rules need changing, and no VPN is required.
To get started, fire up a remote control session from your terminal.
claude remote-controlClaude Code displays a QR code and a URL. Scan the QR code from your phone or open the URL in any browser, and you’re connected to the same session running on your machine.
Already have an active Claude Code session? You can start remote control from within it using the slash command.
/remote-controlGenerates a QR code and URL without starting a new session.
Once you’re connected, everything you type in the remote browser gets sent to your local Claude Code instance and responses appear in real time. Claude Code still runs on your machine, reads your local files, and executes commands in your local environment. The remote connection is really just a display and input relay.
Remote vs Web Sessions
These two might sound similar, but they’re fundamentally different.
Remote control means Claude runs locally on your machine. It has full access to your files, terminal, Git history, and entire development environment. The phone or browser is just a window into that local session. When Claude Code edits a file through remote control, the change hits your disk immediately.
Web sessions at console.anthropic.com run on Anthropic’s cloud infrastructure. Claude operates in a sandboxed cloud environment with no access to your local filesystem. They’re useful for quick questions, exploring ideas, or working when you’re away from your development machine.
Reach for remote control when you need Claude Code to work with your local project: reviewing code from your phone during a commute, pairing with a colleague by sharing the URL, or picking up a task from a different room. Go with web sessions when you don’t need local file access.
Programmatic Usage with -p
The -p flag runs Claude Code with a single prompt and exits when it’s done. This is your entry point for integrating Claude Code into scripts, CI/CD pipelines, and automated workflows.
claude -p "Explain the main function in src/index.ts"Claude Code processes the prompt, writes output to stdout, and exits.
Here’s headless mode in action, running prompts, getting JSON output, and piping results to other tools:
View as text (accessible transcript)
$ claude -p 'List all exported functions in this project'
Functions: isValidEmail, authMiddleware, default router (auth routes)
Interfaces: CreateUserInput, LoginInput, UserPayload, AuthenticatedRequest
$ claude -p 'How many TypeScript files are in src/?' --output-format json | jq .
{ "result": "There are 6 TypeScript files...", "cost": 0.003, ... }
$ claude -p 'Generate a one-line summary of this project' | cat -n
1 A Node.js REST API with JWT authentication built using Express and TypeScript.Output comes back as plain text by default. You can change that with --output-format.
# Plain text (default)claude -p "List all exported functions in src/utils.ts" --output-format text
# Structured JSON with metadataclaude -p "List all exported functions in src/utils.ts" --output-format json
# Streaming JSON (one event per line)claude -p "List all exported functions in src/utils.ts" --output-format stream-jsonThe JSON format gives you a structured response with the result text, token usage, cost, and session metadata, making it easy to parse Claude Code output in scripts.
{ "result": "The file exports three functions: parseConfig, validateInput, formatOutput...", "cost": 0.003, "duration_ms": 2400, "session_id": "abc123", "num_turns": 1}Exact fields may vary. Use this format for programmatic consumption.
With stream-json, you get one JSON object per line as Claude Code processes the prompt. Each line represents an event, such as an assistant message, a tool call, or a tool result. It’s great for real-time monitoring in pipelines where you’d rather see progress as it happens instead of waiting for the final result.
Structured Output with —json-schema
When you need Claude Code to return data in a specific shape, pass a JSON schema with the --json-schema flag. Claude Code will structure its response to match.
claude -p "Analyze src/auth.ts and extract all function signatures" --output-format json --json-schema '{ "type": "object", "properties": { "functions": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "params": { "type": "array", "items": { "type": "string" } }, "returnType": { "type": "string" } }, "required": ["name", "params", "returnType"] } } }, "required": ["functions"]}'The response conforms to whatever schema you provide.
{ "functions": [ { "name": "validateToken", "params": ["token: string", "options?: AuthOptions"], "returnType": "Promise<TokenPayload>" }, { "name": "refreshSession", "params": ["sessionId: string"], "returnType": "Promise<Session>" } ]}This opens up a lot of possibilities for building tooling on top of Claude Code. You can extract code metrics, generate documentation, audit dependencies, or build custom analysis pipelines, all with predictable output shapes that your downstream tools can rely on.
System Prompt Customization
Two flags let you control the system prompt Claude Code uses when running with -p.
--system-prompt replaces the default system prompt entirely. Reach for this when you want Claude Code to behave in a completely different way from its defaults.
claude -p "Review this PR" --system-prompt "You are a strict code reviewer. Focus only on security issues and performance problems. Ignore style."--append-system-prompt adds to the default system prompt instead of replacing it. This is what you’ll want when Claude Code should keep its default capabilities but also follow additional project-specific rules.
claude -p "Add a new API endpoint for user preferences" --append-system-prompt "Always use the repository's existing error handling patterns. Never add new dependencies without justification."In most cases, --append-system-prompt is the safer choice. The default system prompt contains important instructions about tool usage, safety, and output formatting. Replacing it entirely with --system-prompt strips all of that out, which can lead to unexpected behavior.
Auto-Approving Tools in Scripts
When you run Claude Code with the -p flag, every tool invocation that would normally need your approval blocks the process. In a script or CI/CD pipeline, there’s nobody around to click “approve.” You need to explicitly declare which tools Claude Code can use without asking.
The --allowedTools flag handles this. It uses the same permission rule syntax described in Models, Cost Economics & Permissions.
claude -p "Fix the failing tests" --allowedTools "Bash(npm test)" "Bash(npm run lint)" "Edit" "Write"Without --allowedTools, Claude Code will fail on any action requiring permission.
You can be as specific or as broad as the task calls for.
# Allow all bash commands (broad)claude -p "Set up the project" --allowedTools "Bash(*)"
# Allow only specific operations (narrow)claude -p "Run the test suite and fix failures" --allowedTools "Bash(npm test)" "Bash(npx vitest run)" "Edit"
# Allow file operations only (no command execution)claude -p "Refactor the utils module" --allowedTools "Edit" "Write"If you run Claude Code with -p and don’t provide --allowedTools, any action that requires approval causes the process to exit with an error. Always specify the tools your script needs.
Session Management
By default, each claude -p invocation starts a fresh session with no prior context. For multi-step workflows where you want to build on what happened before, use session continuation flags.
--continue picks up from the most recent session.
# Step 1: Analyze the codebaseclaude -p "Analyze the authentication module and identify security issues" --output-format json > analysis.json
# Step 2: Continue the same session to fix the issues foundclaude -p "Fix the security issues you identified" --continue --allowedTools "Edit" "Bash(npm test)"--resume resumes a specific session by ID. This comes in handy when you’re running multiple pipelines in parallel and need to continue a particular session.
# Get the session ID from JSON outputSESSION_ID=$(cat analysis.json | jq -r '.session_id')
# Resume that specific sessionclaude -p "Now write tests for the fixes" --resume "$SESSION_ID" --allowedTools "Write" "Bash(npm test)"Here’s --continue in action. The second prompt picks up context from the first without rereading the codebase:
View as text (accessible transcript)
$ claude -p 'What authentication method does this project use?'
This project uses JWT (JSON Web Token) authentication...
$ claude --continue -p 'What are the security risks with that approach?'
Claude remembers the previous conversation about JWT auth
and discusses risks without needing to re-read the codebase:
- Token theft if not stored securely
- No built-in revocation mechanism
- Secret key management concernsSession continuation preserves the full conversation history, including which files Claude Code read, what changes it made, and any context it accumulated. This keeps multi-step workflows coherent without you having to repeat instructions.
Scheduled Tasks
Claude Code can run tasks on a recurring schedule. The /loop skill lets you create scheduled tasks conversationally. Just describe what you want to happen and when, and Claude Code sets up the automation for you.
Every morning at 9 AM, check for outdated npm dependenciesand create a summary report in reports/deps-check.mdClaude Code parses the schedule and creates the cron job for you.
Behind the scenes, three tools power scheduled task management.
CronCreate registers a new recurring task with a cron expression, a prompt to execute, and optional tool permissions.
CronList shows all your registered scheduled tasks along with their schedules, last run time, and next scheduled run.
CronDelete removes a scheduled task by its ID.
You can interact with these tools directly, but the /loop skill is more natural. Just describe your automation need in plain language and Claude Code translates it into the right cron configuration.
Cron Expressions
Scheduled tasks use standard 5 field cron expressions: minute, hour, day of month, month, and day of week.
# ┌─── minute (0-59)# │ ┌─── hour (0-23)# │ │ ┌─── day of month (1-31)# │ │ │ ┌─── month (1-12)# │ │ │ │ ┌─── day of week (0-6, Sunday=0)# │ │ │ │ │# * * * * *
# Every weekday at 9 AM0 9 * * 1-5
# Every 30 minutes*/30 * * * *
# Every Sunday at midnight0 0 * * 0
# First day of every month at 8 AM0 8 1 * *Scheduled tasks run in your local timezone, not UTC. This is an important detail when you’re scheduling tasks around your work hours.
Critical limitation: tasks expire after 3 days. If Claude Code Desktop isn’t running for 3 days, scheduled tasks created through the CLI expire and won’t resume automatically. This is by design; CLI created cron tasks are meant for short-lived automation, not permanent infrastructure. For something more durable, see the alternatives below.
Durable Scheduling Alternatives
When you need scheduled tasks that survive restarts, machine reboots, or extended offline periods, reach for one of these alternatives instead of CLI cron tasks.
Claude Code Desktop scheduled tasks are persistent. Tasks created through the Desktop app survive restarts and don’t have the 3 day expiry limitation. If your automation needs to keep running reliably for weeks or months, create the schedule through the Desktop app.
GitHub Actions with schedule trigger moves the automation entirely to CI. The task runs on GitHub’s infrastructure regardless of whether your local machine is on.
name: Weekly Dependency Review
on:schedule: - cron: '0 9 * * 1' # Every Monday at 9 AM UTC
jobs:review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Claude Code run: curl -fsSL https://claude.ai/install.sh | bash - name: Run dependency review run: | claude -p "Review package.json for outdated or vulnerable dependencies. Create a report." --output-format text --allowedTools "Bash(npm audit)" "Bash(npm outdated)" "Read" > dependency-report.md env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}Runs in CI with no local machine dependency. Note the cron uses UTC.
So which do you pick? CLI cron works well for quick, temporary automation (checking something for the next few days). Desktop scheduled tasks are your go to for persistent local automation. And GitHub Actions is the right call for durable, team visible automation that runs regardless of any individual machine’s state.
Best Practices
-
Use
-pfor CI/CD integration. It’s the entry point for every automated Claude Code workflow. Pair it with--output-format jsonfor machine readable output and--allowedToolsfor unattended execution. -
Prefer
--append-system-promptover--system-prompt. The default system prompt has safety and formatting instructions you almost always want to keep. Append project-specific rules rather than replacing everything. -
Always specify
--allowedToolsin scripts. Without explicit tool permissions, Claude Code exits with an error on any action that requires approval. Specify the minimum set of tools your script actually needs. -
Use JSON output for programmatic consumption. The structured JSON response includes token usage, cost, and session ID alongside the result, making it straightforward to build dashboards, cost tracking, and audit logs.
-
Test cron schedules with short intervals first. Before setting up a daily cron, try
*/5 * * * *(every 5 minutes) to verify the task works as expected, then switch to the production schedule. -
Prefer Desktop scheduled tasks or GitHub Actions over CLI cron for anything durable. CLI cron tasks expire after 3 days. If the automation matters, use a scheduling mechanism that persists.
-
Use
--continuefor multi-step pipelines. Break complex automated workflows into sequential steps that build on each other’s context, rather than cramming everything into one massive prompt.
Further Reading
- Remote Control: official documentation on remote access setup and security
- Running Claude Code Programmatically: the
-pflag, output formats, and system prompt customization - Scheduled Tasks: cron expressions, task management, and limitations
Up next, learn how to extend Claude Code with external tools and data sources in Model Context Protocol.