Skip to content

Stamp CLAUDE_CODE_ENTRYPOINT so phone-started sessions appear in the resume pickers - #108

Open
jankarres wants to merge 1 commit into
shellular-org:mainfrom
jankarres:jan/claude-session-visibility
Open

Stamp CLAUDE_CODE_ENTRYPOINT so phone-started sessions appear in the resume pickers#108
jankarres wants to merge 1 commit into
shellular-org:mainfrom
jankarres:jan/claude-session-visibility

Conversation

@jankarres

@jankarres jankarres commented Aug 19, 2026

Copy link
Copy Markdown

Sessions started from the app are written to ~/.claude/projects like any other, and then neither /resume nor the VS Code session list will show them, because the Agent SDK stamps them sdk-ts and both pickers filter that out. This sets CLAUDE_CODE_ENTRYPOINT=shellular when the host spawns the Claude Code adapter, which is all it takes. Closes #107.

ClaudeCode overrides spawnEnvOverride(), the hook ACP already provides for exactly this, and returns the value only when the operator has not exported one of their own. That is deliberate rather than lazy: spawnAgentProcess merges the descriptor env over process.env, so putting it in BUILTIN_AGENT_DESCRIPTORS would silently beat anyone who sets it themselves. The SDK defaults its own value the same way.

The value is not arbitrary. cli is rewritten to sdk-cli under the SDK and lands back on the filter list; anything else outside sdk-cli, sdk-ts and sdk-py works, and shellular also labels the transcript with where the session came from.

How I checked it

Built the CLI, pointed it at a local central and relay, paired the app and opened the agent's session list, since that is what makes the host spawn the adapter in the first place. Then read the environment out of /proc rather than trusting the code.

With nothing exported, the host process has no CLAUDE_CODE_ENTRYPOINT and the adapter underneath it comes up with shellular. Restart the same host with CLAUDE_CODE_ENTRYPOINT=operator-choice and the adapter comes up with operator-choice, so exporting your own still wins.

tsc --noEmit and biome check are clean, and there are no tests in the package to add to. CI here only checks that cli/schema.sql is in sync; nothing in this change touches a migration, and regenerating it leaves the file untouched.

Before you merge

shellular as the value is the part I would expect an opinion on, since it is what ends up in every transcript record. Any string outside the three filtered ones does the job.

If anything here should be different, tell me and I will take care of it.

@biraj21

biraj21 commented Aug 22, 2026

Copy link
Copy Markdown
Member

hey @jankarres.

this looks valid today, but i’m hesitant to rely on an undocumented internal variable. bannthropic could start rejecting or filtering unknown values like shellular. and what if changing the entrypoint tomorrow starts affecting auth or cause sessions to use API billing instead of the user’s Claude subscription?

@jankarres
jankarres force-pushed the jan/claude-session-visibility branch from d287216 to 0704871 Compare August 23, 2026 09:09
Claude Code records an entrypoint on every transcript record, and both of its
resume pickers drop the ones that look machine-driven: /resume in the CLI and
the session list in the VS Code extension each filter sdk-cli, sdk-ts and
sdk-py. The Agent SDK that the ACP adapter runs on stamps sdk-ts unless the
variable is already set, so a session started from the phone is written to
~/.claude/projects like any other and is then invisible at the desk, which is
where you would want to pick it up.

Set CLAUDE_CODE_ENTRYPOINT=shellular at spawn time, and only when the operator
has not set one, the way the SDK itself does it. Baking it into the descriptor
would win over an inherited value, since spawnAgentProcess merges the
descriptor env over process.env.

The value matters: cli is rewritten to sdk-cli when Claude Code runs under the
SDK and is filtered again. Anything outside that set works, and shellular also
labels the transcript by where it came from.
@jankarres
jankarres force-pushed the jan/claude-session-visibility branch from 0704871 to 4f6fad3 Compare August 23, 2026 09:14
@jankarres

Copy link
Copy Markdown
Author

Honestly, that one nagged at me too while I was writing it. So I went and looked at what the current CLI and SDK actually do with the value I changed in this PR.

Undocumented: you're right, it is. What settled it for me is that Anthropic's own VS Code extension sets this same variable, to claude-vscode, before it starts Claude Code. So it isn't a hidden debug flag, it's how their own front ends identify themselves. And whether you come in through the extension or through plain Claude Code, both end up in the same code, which has a defined path for a name it doesn't recognise.

Unknown values: everywhere the CLI reads the entrypoint, it checks for one specific known name and falls through to that default otherwise. Leave the variable unset entirely and it just reports the value as "unknown". Which is also why I'd rather make up a name than borrow a real one. The real ones bring behaviour with them, remote for example is tied into a whole session token flow, and that's the version of this change I'd expect to bite us eventually.

Auth and billing: token billing only happens if an API credential is configured in the first place, so ANTHROPIC_API_KEY, an apiKeyHelper, or ANTHROPIC_AUTH_TOKEN. With none of those around, Claude Code runs on the OAuth login and bills against the subscription, exactly as it does at the desk, and the entrypoint isn't part of that decision anywhere. shellular takes the same path as sdk-ts and as plain cli there, the only values that touch auth at all are the claude-desktop ones and local-agent, and those widen subscription use rather than narrowing it. And if the surface ever did start to matter, what these sessions carry today, without this PR, is sdk-ts. That's the label I'd be nervous about, a neutral one much less so. The one thing I don't want to hand to the user is the decision itself. Anyone who wants the old behaviour can set the variable and we leave it alone, but nobody should have to know any of the above just to find their session again the next morning.

Stepping back for a moment on why I think this belongs in the CLI at all: the discovery already works in one direction. The session watcher picks up whatever I start at the desk, a terminal session or one from the VS Code extension, and surfaces it in the app. What's missing is the way back, and this variable is the only lever for it, since the pickers hard-code the filter and there's no setting anywhere near it. With this in, both sides finally see each other's sessions instead of one side seeing the other's.


If you'd rather not carry it, that's fair, and it stays solvable, just not by default. We ran it exactly that way in our own setup before I opened this PR. The shellular process passes its own environment down to the agent it spawns, and the SDK only stamps sdk-ts when the variable isn't already set, so whatever sits in the CLI's environment survives all the way into the session. If you run it as a systemd unit, that's one line in the unit:

[Service]
Environment=CLAUDE_CODE_ENTRYPOINT=shellular

And if you start it by hand instead:

export CLAUDE_CODE_ENTRYPOINT=shellular
shellular

Just not cli. That's the one value Claude Code rewrites to sdk-cli in SDK mode, and then it's filtered all the same. I'd still rather have it in the CLI, because "export an undocumented environment variable" isn't an answer most people are ever going to find.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show Claude Code sessions started from the phone in /resume and the VS Code session list

2 participants