Our team was working on a feature that required clicking a claude-cli:// link in the browser. We expected Claude Code to open with the prompt already typed in the box. Ours opened cut off mid-word: 1041 characters sent, 683 received.
Clicking the same link again sometimes worked. Same link, same machine, different result. Raise your hand if you love debugging exasperating intermittent issues! No one? Ok, let’s move on.
The prompt passes through a command line. Inspecting the running process showed a command line exactly 1024 bytes long, not 1025 or 1023. And software engineers know that a round number like 1024 points to a full buffer somewhere.
Breaking down the command:
113 bytes program path + flags
911 chars encoded prompt, all remaining data
---------
1024 bytes hard stopThose 911 encoded characters unpack to 683 real ones, matching the truncated prompt character for character.
Hypothesis
A browser click does not start Claude. The browser hands the URL to macOS, macOS hands it to the registered handler, and the handler opens a Terminal window and types a command into the shell, encoded prompt and all, as one long line.
So the prompt has to survive the connection between Terminal and the shell in that window. The same channel your keyboard uses.
That channel was the suspect. Stated plainly, the hypothesis had three parts:
The channel holds about 1024 bytes. Anything beyond that gets dropped, with no error.
The drop only happens when the shell is not reading at that moment. A shell that reads continuously drains the channel and lets any length through, which would explain why the same link succeeds and fails.
Therefore the prompt survives only while
113 + encoded length <= 1022, or 681 characters.
The 681 figure came out of (1022 - 113) / 4 * 3 before any test ran.
Setup
I could have planned many experiments, trying to foresee limitations and potential routes and optimize based on what I thought might be quicker and more robust. But I would always rather go directly into experimentation mode, invest that planning time in finding leads on the ground, and iterate from there.
So I started by manually replicating this intermittent issue. Once I found where Claude got an actual truncated prompt, I asked it (given the relationship we’ve built over the years, it feels weird calling Claude “it”, but for the sake of professionalism I’ll stick to that) “check the parameters/arguments used to open this Claude instance, and figure out why the prompt was only prefiled with this instead of the whole prompt”. From there, I dove into the rabbit hole, scripting the browser’s behavior:
Fire the same URL macOS would receive from a click
Snapshot running processes before and after
Capture the full command line of the launched process
Decode the prompt and compare received text with sent text
Kill only the processes the script started
That script measures two hops: what the handler built, and what the launched program received. If the two differ, the loss happened in the terminal hop.
A second script went after the boundary directly. It built the real command line for prompts of every length, pushed each one through a real channel held in the failing state, and bisected the largest prompt that survived.
About 400 measured runs in total, all on the same machine.
Results
The two hops differed. The handler always built the full 1388-character payload; the program sometimes received less. The loss happens in the terminal hop, as predicted.
1. Is the channel the bottleneck?
I fed some text while the receiving program was not reading, then counted what got through.
The cap holds at 1022 bytes no matter how much gets sent. Retrying the send does not help. Once the buffer is full, it stays full.
2. What makes some runs work?
One condition delivers everything: the receiver has to be actively reading at the same moment. Shifting the start of reading by a few hundred milliseconds flipped otherwise identical runs. Ten arrived full, fourteen truncated.
3. Where exactly is the line?
681 characters, exactly where the formula put it.
What this means
All three parts of the hypothesis held. The channel between Terminal and a shell holds about 1024 bytes. If the shell is reading when the command lands, it drains input continuously and any length gets through. If the shell is busy for a moment, redrawing or running a prompt hook, the buffer fills, the channel drops the overflow, and the shell runs a cut-off command.
No error appears anywhere. The prompt is just shorter than the one you sent.
Timing decides, which is why the bug is rare. Twelve emulated clicks in a row delivered the full prompt. Two clicks four minutes apart in the original session did not.
Two false alarms
Both wrong answers came from broken measurement.
The emulator matched the wrong process ID and decoded with standard base64 when the encoding is base64url, so it reported “truncated” on runs where the full prompt had arrived. Then a timing bug in the second script let the receiver wake 193 ms in, inside the sender’s 200 ms deadline. Everything passed, and the reported limit came out at 1040 characters, which meant nothing.
Problematic, because a test that passes for the wrong reason is worse than one that fails.
The fix
Prompts below 681 characters never hit this. Above 681, success depends on timing, and most clicks still work, which is precisely what makes it hard to diagnose.
For our experimental case (opening prefilled Claude Code prompts from the web) the honest answer is: don’t go this route. 🙂
For CLI scripts, keep long prompts off the command line:
claude "$(cat prompt.txt)"
# or
cat prompt.txt | claude -pBoth skip the terminal channel entirely, so the limit never applies.
TL;DR
Clicking a claude-cli:// link makes macOS open a Terminal window and type a long command into it, prompt encoded inside. That typing channel holds about 1024 bytes. If the shell is not reading at that exact moment, everything past the limit is dropped with no error and Claude opens with a half-finished prompt.
The cutoff is 681 characters. Below that, prompts always arrive. Above it, most clicks still work, which is why the bug looks random.
Don’t prefill long prompts from the browser. In CLI scripts, use claude “$(cat prompt.txt)” or cat prompt.txt | claude -p. Neither goes through the terminal.





