Recipe: Input Cleanup
Some users write out-of-character instructions alongside their in-character messages — things like [make this more dramatic] or respond in first person //. This recipe strips that instruction from what the bot receives (keeping the chat clean) and moves it into a hidden Stage Direction so the bot still acts on it.
Simple approach: split on a marker
If you are happy with a specific marker — like // — this is the easiest version. No regex needed.
{
"variables": [
{ "name": "oocInstruction", "initialValue": "\"\"", "perTurnUpdate": "\"\"" }
],
"content": [
{
"category": "Input",
"condition": "contains(\"{{content}}\", \"//\")",
"modification": "split(\"{{content}}\", \"//\")[0]"
},
{
"category": "Stage Direction",
"condition": "contains(\"{{content}}\", \"//\")",
"modification": "\"Author instruction: \" + split(\"{{content}}\", \"//\")[1]"
}
]
}How it works:
- Both rules check whether the message contains
//. - The Input rule splits the message at
//and sends only the first half to the bot. - The Stage Direction rule takes the second half (the instruction) and injects it as a hidden author note.
The user writes: Let's go to the market // make the merchant suspicious The bot sees: Let's go to the market plus a hidden note: Author instruction: make the merchant suspicious
Advanced version: square-bracket detection
Advanced — skip if you're just getting started
This version uses capture() to pull text out of [brackets] automatically. It is more flexible but also harder to read. Try the simple version above first.
If your users write instructions in square brackets like [make this more dramatic], this version detects them automatically via the classifier.
{
"variables": [
{
"name": "oocInstruction",
"initialValue": "\"\"",
"perTurnUpdate": "\"\""
}
],
"classifiers": [
{
"name": "OocDetector",
"inputTemplate": "{{content}}",
"inputHypothesis": "This message contains {}.",
"classifications": [
{
"label": "an out-of-character instruction in square brackets",
"threshold": 0.6,
"updates": [
{
"variable": "oocInstruction",
"setTo": "capture(\"{{content}}\", \"\\\\[([^\\\\]]+)\\\\]\")[0][0]"
}
]
}
]
}
],
"content": [
{
"category": "Input",
"condition": "isNotNull(oocInstruction) and oocInstruction != \"\"",
"modification": "join(split(\"{{content}}\", \"[\" + oocInstruction + \"]\"), \"\")"
},
{
"category": "Stage Direction",
"condition": "isNotNull(oocInstruction) and oocInstruction != \"\"",
"modification": "\"Author's note: \" + oocInstruction"
}
]
}The [0][0] picks the first match ([0]), then the first captured group within it ([0]) — that's how you get a plain string out of the nested array capture returns.
How it works:
oocInstructionstarts empty and resets to empty at the start of every turn viaperTurnUpdate.OocDetectorchecks whether the user's message contains bracketed text. If the classifier fires, it captures the text inside the brackets and stores it inoocInstruction. The[0][0]indexing is necessary becausecapture()returns an array of arrays — one sub-array per match, each containing its capture groups — so[0][0]extracts the first capture group of the first match as a plain string.The
Inputrule fires whenoocInstructionis not empty. It strips the full[...]block from the message so the bot never sees it.The
Stage Directionrule takes the captured instruction and injects it as an author's note — hidden from the chat history but visible to the bot.
Important notes
- The
replacebuilt-in has a known bug and may not work for regex-based stripping. Thesplit/joinapproach in both examples above avoids it entirely. - These rules only run on the current turn. Previous messages in the history are not affected.
- If you want the bot to treat the instruction as very authoritative, consider using
"Post Input"instead of"Stage Direction"to position it closer to the end of the prompt.