My Claude Code sessions run on a Linux server, started with claude remote-control, and I steer them from the Claude app on my Android phone. I started a line with ! to run a command myself, and the app answered, twice:
Shell commands are only available in local sessions.The short answer: ! is shell mode, and shell mode only works where you type into Claude Code itself: a terminal. The Claude app and claude.ai/code are windows on a session. They can send it messages, but they canât run a shell command for you. The command didnât run. You can still get it run: ask Claude to run it, or type it in a terminal on the machine where the session lives.
What ! does in Claude Code
In the Claude Code prompt, a line that starts with ! is shell mode:
! git status
! npm testThe command runs directly, without going through Claude. Claude Code adds the command and its output to the conversation, and Claude then responds to that output. Claude doesnât have to interpret or approve the command.
That is handy at the keyboard. But it is a feature of the terminal interface, where the claude process reads your input.
Why the app says no
The Claude app is, in the words of the docs, âa client for Claude Code sessions rather than a place where code runsâ. From the Code tab you reach two kinds of sessions, and neither one is a local session from the appâs point of view:
| Session | Where it runs | Shell mode from the app or claude.ai/code |
|---|---|---|
| Remote Control | On your computer or server; the app is a window on it | No |
| Cloud session | On cloud infrastructure, Anthropic-managed by default | No |
| Claude Code in your terminal | On your machine, and you type into it | Yes |
The message is not printed by Claude Code on the server. I searched the two Claude Code builds installed on my server (v2.1.296 and v2.1.316) for it, and the text isnât there. So it is the app that refuses the line. My session never received it: it didnât run as a command, and it didnât reach Claude as a message.
The Remote Control docs describe a slightly different behavior: a line you send from mobile or web that starts with ! âgoes to Claude as a message and doesnât run in shell mode.â Either way, the result is the same: no shell mode from the app.
This is one of a few terminal-only features. The docs also list local-only commands, such as /plugin and /resume, that donât work from mobile or web. Text-output commands such as /compact, /clear, /context and /usage do work. So do /model and /effort when you pass the value as an argument, for example /model sonnet.
Fix 1: ask Claude to run it
From the app, just say it:
Run git status and show me the output.Claude runs the command with its own shell tool, and the output lands in the conversation, much like ! would. The differences are worth knowing:
- It goes through Claude. Claude decides how to run it. If the exact command matters, give it in backticks.
- Permissions apply. Depending on the sessionâs permission mode, Claude may ask you to approve the command. Shell mode never asks, because you typed it yourself.
- The sandbox applies. If youâve enabled sandboxing, it covers the commands Claude runs. Commands you type in shell mode run outside it, unless your session is one of those listed under strict sandbox mode.
For most things, such as git status, a test run or a log tail, this is all you need.
Fix 2: Remote Control session, use the terminal on that machine
A Remote Control session runs on your own machine, so a terminal there can still do what the app canât. It depends on how you started the session:
- Started in an interactive terminal (
claude --remote-control, or/remote-controlin an open session): go back to that terminal and type the!command there. The terminal and the app share one conversation, so the output shows up on your phone too. If that machine is a server, the docs suggest startingclaudeinsidetmuxorscreen, so you can reattach over SSH and keep the session running when you disconnect. - Started in server mode (
claude remote-control, my case): there is no Claude Code prompt to type into. SSH to the machine and run the command in a normal shell. If Claude needs the output, paste it into the conversation.
The same SSH route is how you get things done that the app canât show. One example from the docs: when a claude.ai connector needs to be authorized again, you run claude mcp login with the connectorâs name in a terminal on that machine, then open the link on your phone.
Fix 3: cloud session, pull it into your terminal
A cloud session has no terminal of yours attached. To get shell mode, continue it locally with teleport:
claude --teleport # pick the session from a list
claude --teleport <session-id> # or resume one directlyRun it from a checkout of the same repository. Teleport asks you to stash uncommitted changes first, and the sessionâs branch must be pushed. Inside the cloud session, /teleport prints the exact command for that session.
The terminal gets its own copy of the session. New work there stays local and doesnât appear in the cloud session. To keep steering it from your phone afterwards, start /remote-control in the local session.
Which one to use
- Quick check while away from the desk: ask Claude to run it (Fix 1).
- The exact command matters, or it needs your own shell: use a terminal on that machine (Fix 2).
- Cloud session you want to take over yourself: teleport it (Fix 3).
If you havenât set up Remote Control yet, or it says itâs disabled by your organizationâs policy, start with Claude Code Remote Control: Enable & Fix Policy Error.