Skip to content

sysprompt: remind claude of the output style on every turn - #1

Merged
tdwd merged 2 commits into
mainfrom
sysprompt-turn-reminder
Sep 7, 2026
Merged

sysprompt: remind claude of the output style on every turn#1
tdwd merged 2 commits into
mainfrom
sysprompt-turn-reminder

Conversation

@tdwd

@tdwd tdwd commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Why

/sysprompt delivered the user's standing instructions but did not change the replies. Delivery was never the problem: the style text is visible in claude's system prompt, and the system/init line names the style it resolved. Adherence was.

claude's harness appends its own response-shaping sections after the output style. The style stops holding the last word, and the built-in guidance wins on length and format.

What

The system prompt is fixed at launch, but every turn is composed here. sendTurn now appends a two-line reminder after the user's text, where recency favours it.

  • Tagged, not in the user's mouth. The reminder rides in <cathode-reminder>. The transcript shows the typed text, and replay.go strips a trailing block back out on resume.
  • Never on a slash command. A forwarded slash command is an argument list. Appending prose to /compact rewrites its arguments. Load-bearing, not defensive: pickerkeys.go and mcp.go both send commands through sendTurn.
  • Says which rules govern, not what to write. cathode does not know which of the user's rules matter, and the failure is precedence, not memory. A prompt needing other wording marks its own block with <!-- reminder --><!-- /reminder -->.

One owner for "is a style loaded"

Adding a second consumer surfaced a latent split. sysPromptArgs wrote the style file and composed the flag; newModel re-derived the same fact by reading the prompt file from the setting. Those answer different questions and part company when writing the style file fails: main starts without the flag, yet sysPromptSeen was still set.

Harmless while the only consumer was the edited-file check. Not harmless once a reminder fires every turn about a style claude never loaded. sysPromptArgs now returns the text its flag selects and main hands it to newModel.

Tests

remind_test.go covers the gate, the slash-command skip, the marked-block override with both malformed cases, the strip round trip, and text that quotes the tag. TestSysPromptArgsReportsNothingAppliedWhenTheStyleFileFails pins the invariant above. Full suite green, go vet clean.

Not verified

Unit-tested only. I have not watched the reminder work in a live session — that needs a rebuilt binary and a fresh instance.

tdwd added 2 commits August 31, 2026 17:21
bubbles' textarea caps content at MaxHeight (default 99) and truncates a
longer paste in silence. newPromptArea already cleared CharLimit but left
MaxHeight, so a paste over 99 lines lost its tail with no message.

The display height is computed separately by syncPromptHeight and capped
at maxPromptRows, so the content cap buys nothing. Clear it.
The output style delivers the user's standing instructions and the delivery
was never in doubt: the text is visible in claude's system prompt and the init
line names the resolved style. Adherence was the part that failed. claude's
harness appends its own response-shaping sections after the output style, so
the style stops holding the last word and the built-in guidance wins on length
and format.

Take the last word back with the one lever that is ours at runtime. The system
prompt is fixed at launch, but every turn is composed here, so sendTurn now
appends a two-line reminder after the prompt, where recency favours it.

The reminder is not the user's words, so it rides in a <cathode-reminder> tag:
the transcript shows the typed text, and replay strips a trailing block back
out on resume. It is skipped for anything starting with "/", because a
forwarded slash command is an argument list and appending prose to /compact
rewrites its arguments. The default says nothing about what to write, only
which instructions govern, because that is the actual failure and cathode does
not know which of the user's rules matter. A prompt needing other wording
marks its own block with <!-- reminder --> … <!-- /reminder -->.

Give "is a style loaded" one owner while adding its second consumer.
sysPromptArgs already wrote the style file and composed the flag, but newModel
re-derived the same fact by reading the prompt file from the setting. Those
answer different questions and part company when writing the style file fails:
main starts without the flag, yet sysPromptSeen was still set. Harmless while
the only consumer was the edited-file check, not harmless once a reminder
fires every turn about a style claude never loaded. sysPromptArgs now returns
the text its flag selects and main hands it to newModel.
@tdwd
tdwd merged commit 0b827d2 into main Sep 7, 2026
1 check passed
@tdwd
tdwd deleted the sysprompt-turn-reminder branch September 7, 2026 10:15
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.

1 participant