docs: finish dropping the stripped-newline rule from the input docs

The first commit left the old rule standing in places: the gotchas list in
extending-codeman.md still said newlines were stripped and that
"echo A\necho B\r" ran `echo Aecho B`, and so did both READMEs and the
skill's big-input section. Those now describe the paste.

Newlines are only kept on the mux path, so the docs that describe the paste
say "with useMux": without it a multi-line body is not a plain prompt and is
written straight into the pane.

Cron keeps rejecting multi-line prompts, but its docs and the code comments
in cron-service.ts, schemas.ts and respawn-controller.ts gave a reason this
change removes (writeViaMux joining lines, a newline submitting in Ink). The
reason that remains is the submit check, which cannot recognise a
multi-line paste in the composer, and for cron's paste mode the newlines
reaching the CLI as keys.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claudia[bot]andClaude Opus 5.5 committed 2026-10-21 04:11:28 +02:00
1 parent e3de354461
commit fe10cad83f
14 files changed
+58 -48

No files matched your search

+4 -3
View File
@@ -207,9 +207,10 @@ trailing carriage return:
| `typed` | `session.writeViaMux()` — the text as a tmux bracketed paste + Enter (a single character is typed, so a dialog answer selects) | Default; like a human pasting the prompt and pressing Enter. |
| `paste` | `session.write()` — writes directly to the PTY/mux | Bulk paste-style delivery. |
> ⚠️ **Single-line only — enforced.** Like all programmatic input in Codeman,
> multi-line delivery would be silently corrupted (Ink-based TUIs treat a
> newline as submit; typed mode fuses lines). So newlines are **rejected**: the
> ⚠️ **Single-line only — enforced.** A job fires unattended, and the submit
> check that re-presses an ignored Enter cannot recognise a multi-line paste in
> the composer, so a stranded prompt would go unnoticed (in paste mode the
> newlines reach the CLI as keys). So newlines are **rejected**: the
> schema and the form refuse a multi-line `promptText`, and at fire time a
> prompt file whose content is multi-line (after stripping trailing newlines)
> fails the run with a clear `errorMessage`. Put multi-line instructions in a
+12 -10
View File
@@ -294,8 +294,8 @@ if ! jq -e '.data.wait.matched' <<<"$R" >/dev/null; then
fi
# 3. Send the prompt AND register the wait in one call, so the answer cannot be
# the previous turn's idle state. Single line only, ending in \r (otherwise
# Enter is never sent and this wait times out on a turn that never started).
# the previous turn's idle state. It must end in \r (otherwise Enter is never
# sent and this wait times out on a turn that never started).
W=$("${CURL[@]}" -X POST "$API/api/v1/sessions/$SID/input" \
-H 'Content-Type: application/json' \
-d '{"input":"Run the test suite and summarize the failures\r","useMux":true,
@@ -414,14 +414,16 @@ Every one of these has cost somebody real time.
shipped bugs more than once.
- **`text/plain` bodies stay raw.** Auto-parsing them as JSON enabled
simple-request CSRF, so it is deliberate. Send `application/json`.
- **Prompts are single-line and must end with `\r`.** The server splits your text
and Enter into two separate tmux writes (Ink needs them apart), but it sends the
Enter **only when the input contains a carriage return**. Without it your text
sits on the prompt unsubmitted, which is the single most common "the wait
endpoints don't work" report: the wait runs its full timeout on a turn that never
started. Newlines inside the string are stripped rather than rejected, so
`"echo A\necho B\r"` runs the single joined command `echo Aecho B`: send one line
per call.
- **Prompts must end with `\r`.** The server splits your text and Enter into two
separate tmux writes (Ink needs them apart), but it sends the Enter **only when
the input contains a carriage return**. Without it your text sits on the prompt
unsubmitted, which is the single most common "the wait endpoints don't work"
report: the wait runs its full timeout on a turn that never started. With
`useMux`, newlines inside the string are kept: the text goes in as one paste and
the Enter after it submits all of it, so `"echo A\necho B\r"` runs both commands
in a shell. The check that re-presses a stranded Enter cannot reliably recognise
a multi-line paste, so a long multi-line prompt to a just-started agent is still
safer in a file it is told to read.
- **`wait-output`'s `from=now` is not "printed after you asked".** tmux repaints
the visible screen on attach, on resize, and on any TUI redraw, and a repaint
arrives as ordinary output, so text already on screen can satisfy a fresh wait.
+5 -4
View File
@@ -51,10 +51,11 @@ or a server restart shifts later runs slightly. That drift is accepted rather th
## Prompts are single line
This is the rule people trip over. Programmatic input into an agent session is single line
everywhere in Codeman, because the terminal UIs these CLIs use treat a newline as submit. A
multi-line prompt would be silently mangled, so it is **rejected** instead: the form refuses
it, and a prompt file whose contents are multi-line fails the run with a clear message.
This is the rule people trip over. A cron job fires with nobody watching, and the check that
re-presses an Enter the agent ignored cannot recognise a multi-line paste in the composer, so
a multi-line prompt could sit there unsent. In `paste` mode the newlines would reach the agent
as keys. So a multi-line prompt is **rejected**: the form refuses it, and a prompt file whose
contents are multi-line fails the run with a clear message.
For anything longer than a sentence, put the instructions in a file and make the prompt tell
the agent to read it:
+6 -5
View File
@@ -127,11 +127,12 @@ Read these before writing any code. Each one has cost somebody an afternoon.
1. **Input must end with `\r`.** Enter fires only when the payload contains a carriage
return. Without it the text sits unsubmitted on the prompt, the request still succeeds,
and a combined wait burns its full timeout on a turn that never started. Embedded
newlines are kept: the text goes in as one paste and the Enter after it submits all of
it, so `"echo A\necho B\r"` runs both commands in a shell. The check that re-presses a
stranded Enter cannot reliably recognise a multi-line paste, so a long multi-line
prompt to a just-started agent is still safer in a file it is told to read.
and a combined wait burns its full timeout on a turn that never started. With
`useMux`, embedded newlines are kept: the text goes in as one paste and the Enter after
it submits all of it, so `"echo A\necho B\r"` runs both commands in a shell. The check
that re-presses a stranded Enter cannot reliably recognise a multi-line paste, so a
long multi-line prompt to a just-started agent is still safer in a file it is told to
read.
2. **Make input idempotent.** Send a stable `clientId` and a monotonic per-session `seq`. The
server deduplicates, so a retry after a dropped connection cannot double-deliver.
3. **Auth.** With `CODEMAN_PASSWORD` set, use HTTP Basic or the session cookie. A missing
+3 -3
View File
@@ -125,9 +125,9 @@ Sending prompts over the API has one rule that catches everyone: **the payload m
`\r`** or Enter is never sent. The request still succeeds, the text sits unsubmitted in the
composer, and any wait burns its whole timeout on a turn that never started.
Embedded newlines are kept: multi-line input goes in as one paste and the Enter after it
submits all of it, so `"echo A\necho B\r"` runs both commands in a shell. The check that
re-presses a stranded Enter cannot reliably recognise a multi-line paste, so long
With `useMux`, embedded newlines are kept: multi-line input goes in as one paste and the
Enter after it submits all of it, so `"echo A\necho B\r"` runs both commands in a shell. The
check that re-presses a stranded Enter cannot reliably recognise a multi-line paste, so long
multi-line content is still safer in a file the agent is told to read.
See [Driving Codeman From An Agent](Driving-Codeman-From-An-Agent).