Chapter 11: IDE Integration & Multi-device Workflows
Learning Objectives
- The full VS Code extension workflow: inline diffs, @-mentions, parallel conversations
- Remote Control: start a task at your workstation, continue monitoring from your phone
- Desktop App: set up automated daily PR review digests
- Teleport: pull a cloud conversation into your local terminal
- When to use each surface and how they complement each other
Appendix links: A15 Claude Code Internals explains the harness loop, session management, and compaction mechanics that power all five surfaces. See also A04 Agent Architecture for the ReAct pattern underlying tool-calling across surfaces.
The Claude Code Ecosystem
Claude Code is not just a terminal tool. It runs across five surfaces, and each has strengths that the others lack:
Surface Strengths Best For
----------- ------------------------- -------------------------
Terminal CLI Full power, scriptable Heavy development, CI/CD
VS Code Inline diffs, file tree Refactoring, code review
JetBrains Language-aware refactoring Java/Kotlin/Python projects
Desktop App Visual review, scheduling Monitoring, daily digests
Mobile (Remote) Monitoring, approvals On-the-go reviewSession Mobility
Sessions are not locked to a single device. Three mechanisms move them:
| Mechanism | Direction | How |
|---|---|---|
| Remote Control | Local terminal to mobile/web | /remote-control in session, scan QR code |
| Teleport | Cloud (claude.ai) to local terminal | /teleport pulls the session down |
| /desktop | Terminal to Desktop app | Hands off for visual review |
Demo 28: VS Code Refactoring Workflow
Scenario
You have a 2,000-line Express API where all route handlers are defined inline in server.ts. You need to extract them into separate controller files, add proper TypeScript types, and update all imports. This is exactly the kind of task where VS Code's inline diff view shines.
Step 1: Open the Project and Start Claude
Open your project in VS Code with the Claude Code extension installed. Open the Claude Code panel (Cmd+Shift+P, then "Claude Code: Open Panel" or click the Claude icon in the sidebar).
What you see when the panel opens:
╭─────────────────────────────────────────────────────╮
│ Claude Code (VS Code Extension) │
│ Model: claude-sonnet-4-6 │
│ Project: my-express-api │
│ Files: 47 TypeScript files detected │
│ │
│ Type a message or use @ to reference files... │
╰─────────────────────────────────────────────────────╯Step 2: Reference Files with @-mentions
In the Claude Code panel, type your prompt using @-mentions to give Claude precise context:
Look at @server.ts -- it has all route handlers inline. I need you to:
1. Create a controllers/ directory
2. Extract each route group into its own controller file:
- controllers/users.controller.ts (all /api/users/* handlers)
- controllers/orders.controller.ts (all /api/orders/* handlers)
- controllers/products.controller.ts (all /api/products/* handlers)
3. Each controller should export typed handler functions using Express.RequestHandler
4. Update server.ts to import and use the new controllers
5. Make sure @tsconfig.json paths are compatible
Do NOT change any business logic. This is a pure structural refactor.Step 3: Review with Inline Diffs
Claude will propose changes. In VS Code, you see them as inline diffs -- green for additions, red for deletions -- directly in the editor tabs. This is fundamentally different from reviewing changes in the terminal:
EDITOR TAB: server.ts (modified)
─────────────────────────────────────
Line 1 import express from 'express';
- Line 2 import { Pool } from 'pg';
- Line 3 import bcrypt from 'bcrypt';
+ Line 2 import { usersRouter } from './controllers/users.controller';
+ Line 3 import { ordersRouter } from './controllers/orders.controller';
+ Line 4 import { productsRouter } from './controllers/products.controller';
...
- Line 45 app.get('/api/users', async (req, res) => {
- Line 46 const users = await pool.query('SELECT * FROM users');
- Line 47 res.json(users.rows);
- Line 48 });
...
+ Line 12 app.use('/api/users', usersRouter);
+ Line 13 app.use('/api/orders', ordersRouter);
+ Line 14 app.use('/api/products', productsRouter);
NEW FILE: controllers/users.controller.ts
─────────────────────────────────────
+ Line 1 import { Router, RequestHandler } from 'express';
+ Line 2 import { Pool } from 'pg';
+ Line 3
+ Line 4 const router = Router();
+ Line 5
+ Line 6 const getUsers: RequestHandler = async (req, res) => {
+ Line 7 const pool = req.app.locals.pool as Pool;
+ Line 8 const users = await pool.query('SELECT * FROM users');
+ Line 9 res.json(users.rows);
+ Line 10 };
...- You can see the full file context around each change
- You can accept or reject individual hunks
- The file tree shows which files were created or modified
- TypeScript errors update in real time as changes are applied
Accept/reject workflow:
- Click the checkmark to accept a change
- Click the X to reject it
- If you reject a hunk, tell Claude why in the chat: "The users controller is missing the auth middleware import"
Claude Code Panel:
─────────────────────────────────────
You rejected the change to controllers/users.controller.ts.
Tell Claude why:
> The users controller is missing the auth middleware import.
> All /api/users/* routes need authMiddleware applied.
Claude: Got it. I'll add the auth middleware import and apply it to
all user routes. Let me update the controller...
[Proposing changes to controllers/users.controller.ts]
+ Line 2 import { authMiddleware } from '../middleware/auth';
+ Line 7 router.use(authMiddleware);Step 4: Run Parallel Conversations
While Claude is working on the controller extraction, open a second conversation panel (click the + icon) and ask it to work on something independent:
@package.json -- add @types/express if it's not already there, and update
the "scripts" section to include a "typecheck" script that runs tsc --noEmitBoth conversations run simultaneously. Each has its own context and does not interfere with the other.
What Just Happened?
What Makes This Better Than Terminal
| Capability | Terminal | VS Code |
|---|---|---|
| See full file context around changes | No, you see diffs only | Yes, inline in editor |
| Accept/reject individual hunks | /accept or /reject the whole thing | Per-hunk control |
| Real-time type checking | Need to run tsc manually | Automatic |
| Multiple parallel conversations | Need claude --session-id per terminal | Click + to add |
| File tree awareness | You describe paths in text | Click @-mention |
Demo 29: Remote Control -- Start at Work, Monitor From Your Phone
Scenario
It is 5:45 PM. You have a large migration task -- converting 80 React class components to functional components with hooks. You kick it off on your workstation before leaving, then monitor progress and approve decisions from your phone during the commute.
Step 1: Start the Task on Your Workstation
claude --permission-mode acceptEdits
# In the session:
> I need to convert all React class components in src/components/ to functional
> components using hooks. There are about 80 files. Rules:
>
> 1. Convert componentDidMount to useEffect
> 2. Convert componentDidUpdate to useEffect with dependencies
> 3. Convert componentWillUnmount to useEffect cleanup
> 4. Convert this.state/this.setState to useState
> 5. Preserve all existing prop types
> 6. Run npm test after every 10 files and stop if tests fail
>
> Start with the smallest files first to build confidence.What you see as Claude starts working:
> [Your prompt above]
I'll start converting the smallest components first. Let me find all
class components and sort them by file size.
[Auto-approved] Grep "extends React.Component" in src/components/**
Found 82 class components
[Auto-approved] Read src/components/Spinner.tsx (12 lines)
[Auto-approved] Edit src/components/Spinner.tsx
Converted: class Spinner -> function Spinner with useState
[Auto-approved] Read src/components/Badge.tsx (18 lines)
[Auto-approved] Edit src/components/Badge.tsx
Converted: class Badge -> function Badge (stateless, simplified)
[Auto-approved] Read src/components/Toggle.tsx (24 lines)
[Auto-approved] Edit src/components/Toggle.tsx
Converted: class Toggle -> function Toggle with useState
Progress: 3/82 components converted...Step 2: Enable Remote Control
While Claude is working, type:
/remote-controlClaude displays a QR code and a URL:
> /remote-control
╭───────────────────────────────────────────────────────╮
│ │
│ Remote Control Enabled │
│ │
│ Scan the QR code or visit: │
│ https://claude.ai/remote/sess_abc123xyz │
│ │
│ [QR CODE DISPLAYED HERE] │
│ │
│ This session will remain active on your machine. │
│ You can monitor and send messages from any device. │
│ │
╰───────────────────────────────────────────────────────╯Step 3: Open on Your Phone
Scan the QR code or type the URL on your phone. You now see:
- Claude's real-time output as it converts files
- Any permission prompts waiting for approval (in
acceptEditsmode, these are only shell commands that are not in the allow list) - The ability to type messages to redirect Claude
Step 4: Monitor and Intervene
From your phone, you see Claude has converted 30 files and hit a test failure:
[Auto-approved] Edit src/components/UserProfile.tsx
Converting class UserProfile to function...
[Auto-approved] Bash npm test
FAIL tests/components/UserProfile.test.tsx
TypeError: Cannot read properties of undefined (reading 'context')
at UserProfile (src/components/UserProfile.tsx:15:22)
at renderWithProviders (tests/helpers.tsx:8:5)
12 tests failed
Tests failed after converting UserProfile.tsx.
The error is: Cannot read properties of undefined (reading context)
This component uses legacy context API (this.context).
Should I:
1. Convert it to useContext() hook
2. Skip this file and continue with others
3. Convert it but add a TODO for manual reviewYou respond from your phone:
Option 1. Use useContext. If the context provider doesn't exist as a
separate component yet, create one.Claude continues on your workstation:
Got it. I'll convert the legacy context usage to useContext.
[Auto-approved] Read src/components/UserProfile.tsx
[Auto-approved] Grep "createContext" in src/**
Found ThemeContext in src/contexts/theme.ts but no UserContext
[Auto-approved] Write src/contexts/user-context.tsx
Created UserContext with provider component
[Auto-approved] Edit src/components/UserProfile.tsx
Replaced this.context with useContext(UserContext)
[Auto-approved] Bash npm test
PASS tests/components/UserProfile.test.tsx
All 12 tests passed
Continuing with remaining components. Progress: 31/82...Claude continues working. You close your phone and check back 20 minutes later to see the progress summary.
What Just Happened?
What Is Actually Happening
Your workstation (still running)
+-- Claude Code process
|-- Local file access (reads/writes your actual files)
|-- Local tool execution (npm test runs on your machine)
+-- WebSocket connection to claude.ai
Your phone (browser)
+-- claude.ai/remote/sess_abc123xyz
|-- Streams Claude output via WebSocket
|-- Sends your messages back to the local process
+-- Renders permission prompts for approvalKey point: the files and tools never leave your workstation. Your phone is a remote display and input device, not a second execution environment.
Demo 30: Desktop App -- Automated Daily PR Review Digest
Scenario
You are a tech lead. Every morning, you spend 30 minutes checking what PRs landed overnight, what is still open, and whether anything needs urgent attention. You want Claude to prepare a digest before you arrive.
Step 1: Create the Review Agent
In the Desktop App, create a new scheduled task with this configuration:
Schedule: Every weekday at 7:00 AM (cron: 0 7 * * 1-5)
Prompt:
Review all open pull requests in our repository. For each PR:
1. Read the PR description and all changed files
2. Categorize as: needs-review, changes-requested, approved-waiting-merge, or blocked
3. Flag any PRs that have been open more than 3 days without review
4. Flag any PRs with failing CI checks
Produce a digest in this format:
URGENT (needs action today):
- PR #123: "Add payment retry logic" - CI failing on integration tests since yesterday
NEEDS REVIEW (no reviewer assigned):
- PR #145: "Migrate user table to new schema" - opened 2 days ago by @alice
IN PROGRESS (has reviewer, waiting on changes):
- PR #130: "Update API rate limits" - @bob requested changes 1 day ago
READY TO MERGE (approved, CI passing):
- PR #128: "Fix timezone bug in reports" - approved by @carol, all checks pass
STATS:
- Total open PRs: 12
- Average age: 2.3 days
- Oldest: PR #110 (5 days, blocked on design review)Step 2: Configure MCP for GitHub Access
The Desktop App needs access to your GitHub repository. Configure the GitHub MCP server:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@anthropic-ai/mcp-server-github"],
"env": {
"GITHUB_TOKEN": "ghp_your_token_here"
}
}
}
}Step 3: What You See Each Morning
When you open the Desktop App at 8:30 AM, the digest is already waiting:
Claude Desktop -- Scheduled Report (ran at 7:02 AM)
════════════════════════════════════════════════════
URGENT (needs action today):
- PR #201: "Hotfix: connection pool exhaustion" - @dave opened at 2AM,
CI passing, no reviewer yet. Fixes the connection leak we saw in prod.
3 files changed, looks correct. Recommend fast-track merge.
NEEDS REVIEW:
- PR #198: "Add WebSocket support for real-time notifications" - @eve
opened 2 days ago, 47 files changed. Large PR, suggest splitting
into transport layer + handler layer.
IN PROGRESS:
- PR #195: "Refactor auth middleware" - @frank requested changes from
@grace 1 day ago. 2 comments unresolved.
READY TO MERGE:
- PR #192: "Fix timezone bug in weekly reports" - approved by @carol,
all 3 CI checks pass. Last activity 6 hours ago.
- PR #190: "Add retry logic to payment webhook" - approved by @dave,
squash-ready.
STATS:
- Total open PRs: 11
- Average age: 2.8 days
- Oldest: PR #185 (6 days, blocked on design review from @henry)
- PRs merged yesterday: 4What Just Happened?
Step 4: Act on It
Click any PR reference to open it directly. The Desktop App can also let you respond:
Assign me as reviewer on PR #201 and approve it. For PR #198, leave a
comment asking @eve to split it into two PRs: one for the WebSocket
transport layer and one for the notification handlers.What Claude does:
Done. Two actions taken:
1. PR #201 "Hotfix: connection pool exhaustion"
- Assigned you as reviewer
- Submitted approving review with comment: "LGTM. Connection pool
fix looks correct. Fast-track merge approved."
2. PR #198 "Add WebSocket support"
- Posted comment: "@eve This PR covers both the WebSocket transport
layer and the notification handlers (47 files). Could you split
this into two PRs? Suggested split:
- PR A: WebSocket transport (src/transport/*)
- PR B: Notification handlers (src/handlers/notifications/*)
This will make review faster and reduce merge conflict risk."Combining Surfaces
A typical day might use three surfaces:
7:00 AM Desktop App runs the PR digest automatically
8:30 AM You read the digest on Desktop, approve urgent PRs
9:00 AM Terminal CLI for deep feature work
12:00 PM VS Code for reviewing and refactoring a specific module
5:30 PM Remote Control from phone to monitor a long-running migrationTeleport: Cloud to Local
Teleport handles the reverse direction -- you started a conversation on claude.ai (web) and want to continue in your local terminal where Claude has access to your actual files.
# In your terminal:
/teleport
# Claude shows a code to enter on claude.ai, or you paste the session URL:
/teleport https://claude.ai/chat/abc123What the teleport process looks like:
$ claude
> /teleport https://claude.ai/chat/abc123
Connecting to cloud session...
Downloading conversation history (23 messages, 4,200 tokens)...
Session teleported successfully.
Context imported:
- 23 messages from cloud conversation
- Topic: "Design a caching layer for the user service"
- Key decisions: Redis for hot data, PostgreSQL for cold data
- Pending: Implementation plan needs local file access
You can now continue this conversation with full local file access.
> implement the caching plan we discussed -- start with the Redis layerThe conversation history transfers to your local session. Claude now has access to your local filesystem and tools, while keeping the context from the web conversation.
When to use Teleport: You were brainstorming an approach on the web, and now want to implement it. Instead of re-explaining everything, teleport the session and say "implement the plan we just discussed."
When Things Go Wrong
IDE Extension Version Mismatch
Symptom: The VS Code Claude Code panel shows errors, fails to connect, or features are missing.
Claude Code Panel (VS Code):
─────────────────────────────────
Error: Extension version 1.2.0 is not compatible with CLI version 1.5.0.
Some features may not work correctly.
Please update the VS Code extension to match your CLI version.Root cause: The VS Code extension and the CLI tool have different version numbers. Some features (like parallel conversations or inline diff improvements) require matching versions.
Fix:
# Check your CLI version
claude --version
# Update the VS Code extension:
# 1. Open VS Code
# 2. Go to Extensions (Ctrl+Shift+X)
# 3. Search "Claude Code"
# 4. Click "Update" if available
# Or update via command line:
code --install-extension anthropic.claude-code --force
# Update CLI to match if needed:
npm update -g @anthropic-ai/claude-codePrevention: Enable auto-update for the VS Code extension in VS Code settings. When you update the CLI, always check the extension version too.
Remote Control Connection Issues
Symptom: You scan the QR code on your phone but the remote session does not load, or it loads but then disconnects.
Phone browser:
─────────────────────────────────
Connecting to remote session...
Error: Session not found or expired.
The remote session may have ended or the connection timed out.Common causes and fixes:
Session ended on workstation: If the Claude process on your workstation exited (crashed, terminal closed, machine went to sleep), the remote session is gone. Restart Claude and run
/remote-controlagain.Network changed: Your phone switched from WiFi to cellular, breaking the WebSocket. Refresh the browser page to reconnect.
Firewall blocking WebSocket: Corporate networks sometimes block WebSocket connections to external services. Try using your phone's cellular data instead of corporate WiFi.
Session timeout: Remote control sessions time out after extended inactivity (typically 30 minutes of no messages). Re-run
/remote-controlon your workstation to get a new session URL.
# On your workstation, check if the session is still alive:
> /remote-control
Remote control is already active for this session.
Session URL: https://claude.ai/remote/sess_def456uvw
If your device cannot connect, try refreshing the page or
scanning the QR code again.Desktop App Scheduled Task Not Running
Symptom: Your 7 AM PR digest does not appear.
Checklist:
# 1. Is the Desktop App running?
# The scheduled agent requires the Desktop App process to be active.
# Check your system tray / menu bar for the Claude icon.
# 2. Is the MCP server configured?
# Open Desktop App settings and verify the GitHub MCP config.
# The GITHUB_TOKEN must have repo and read:org scopes.
# 3. Check the agent logs:
# Desktop App > Settings > Scheduled Tasks > View Logs
Agent log (2026-05-27 07:00:01):
Error: MCP server github failed to start.
Reason: GITHUB_TOKEN environment variable not set.
# Fix: Update the MCP config with a valid tokenKnowledge Check
Chapter Summary
- VS Code extension provides inline diffs with per-hunk accept/reject, @-mentions for precise file references, and parallel conversations
- Remote Control lets you monitor and steer a long-running local session from any device -- files and tools stay on your workstation
- Desktop App scheduling automates recurring tasks like daily PR digests
- Teleport pulls web conversations into your local terminal for implementation
- Use the right surface for the right task: terminal for heavy work, IDE for refactoring, mobile for monitoring
- When the IDE extension misbehaves, check version compatibility between CLI and extension
- Remote Control sessions require your workstation to stay active -- if the process dies, the remote session is gone
Further reading: A15 Claude Code Internals explains how session state is managed across surfaces, including the compaction and serialization mechanisms that make Teleport and Remote Control possible.