Dynamic Instructions
Keep an assistant’s instructions in your own codebase instead of only in the Ragtime dashboard — sending the detail that changes with each screen or step at request time, and carrying reference material fetched by an action across turns.
Why System Instructions are capped at 7,500 characters
Section titled “Why System Instructions are capped at 7,500 characters”The cap is a design signal, not a technical ceiling. A prompt that outgrows it has almost always stopped being a description of behaviour and started carrying content — the specifics of six different screens, a policy document, a product catalogue.
That is a problem before it is a size problem. Everything in System Instructions is sent on every request, whether or not it is relevant to what the user just asked, and when the available space is divided across many topics each one gets a couple of lines. The model does not report a thin section; it fills the gap with whatever is plausible for that kind of screen. The result is an assistant that confidently describes a checkbox or a slider that does not exist.
So when you hit the cap, the fix is not a bigger box. It is to decide which of your text is behaviour and which is content:
| Kind of text | Where it belongs |
|---|---|
| Tone, pacing, prohibitions, escalation rules | System Instructions (dashboard) |
| Detail that changes with the screen or step | instructionOverrides per request, or an Agent Graph node |
| Reference material the user may ask about | A knowledge source (RAG) |
| Data fetched live during the conversation | An action, with persistResult when it must persist |
None of the last three are bound by the 7,500-character limit.
Per-request instructions (instructionOverrides)
Section titled “Per-request instructions (instructionOverrides)”Send instructions with each chat request. The dashboard keeps the durable behaviour; your application appends whatever depends on where the user currently is. Your text lands in the system prompt with full authority — it is not tool output the model may weigh as ordinary data.
Enabling it
Section titled “Enabling it”- Deployment → Allow injection must be on for the project.
- The assistant’s persona must be Custom Persona. A preset persona builds structured prompt sections of its own that would fight the injected text, so injection is refused with a 400.
Sending it
Section titled “Sending it”POST /api/chat/stream{ "projectId": "…", "message": "How do I take this capability out of scope?", "messages": [...], "instructionOverrides": { "customInstructions": { "value": "STAGE: Capabilities.\nControls on this screen: a single relevance threshold that applies to the whole list. There is no per-capability slider and no per-capability checkbox.", "mode": "append" } }}mode: "append"adds your text after the stored instructions — the usual choice, since the dashboard keeps owning tone and prohibitions.mode: "replace"substitutes them entirely.openingInstructionsmay be overridden the same way (cap: 2,000 characters).
The 7,500-character limit applies per request, not in aggregate. One stage’s detail gets the whole budget, so splitting six stages across six requests gives you roughly six times the room — and each request carries only what is relevant.
To pass the same overrides from an embedded chat rather than from your own backend, see Chat Injection.
Both transports honour it
Section titled “Both transports honour it”Text chat and realtime/voice sessions apply the same overrides with the same
gating. For realtime, send instructionOverrides in the
POST /api/realtime/sideband body; it is validated before the session
connects, so a rejected payload never opens a billable session.
Before 2026-07, only the text pipeline honoured instructionOverrides —
realtime silently ignored them. If you built around that, you can remove the
workaround.
Per-step instructions (Agent Graph)
Section titled “Per-step instructions (Agent Graph)”When the conversation moves through a fixed set of steps, an Agent Graph is
usually a better fit than injection. Each node carries its own instructions and
its own subset of tools, and the model moves between them via generated
transfer_to_<node> handoffs.
When your host application owns the step (for example, users move through your own screen flow), the host can switch the active node directly in an embedded chat:
const frame = document.getElementById('ragtime-chat');frame.contentWindow.postMessage( { type: 'ragtime-host', action: 'set-node', nodeId: 'stage-3' }, 'https://<host>');- Text path: the node is applied on the next chat request.
- Realtime path: the node is applied on the open session at a safe boundary, without restarting the connection.
- Unknown node ids are rejected; the conversation stays on the current node.
To confirm which node was actually applied, listen for the
ragtime-event event named agent_node_changed on your host page.
- Node instructions are not length-capped. A graph is precisely how a long prompt is meant to be split up: only one node is active at a time.
- The active node’s instructions are layered on top of the assistant’s base instruction, so identity and prohibitions are never discarded.
- Works in text and realtime alike — a handoff pushes a
session.updatecarrying the new node’s instructions.
Manage a graph from the dashboard, or from code via the Assistant Config API.
Retained action results (persistResult)
Section titled “Retained action results (persistResult)”By default an action’s result is available only for the reply it was fetched for. The chat transport carries user and assistant turns between requests; the tool message is not among them, so the material is gone on the next turn. For a one-off lookup that is correct. For an action that serves reference material it is a trap: the assistant answers correctly once and then, several turns later, goes back to guessing — with nothing in the UI to indicate anything changed.
Enable Keep result for later turns on the action (persistResult: true) and
the result is carried forward:
- The server signs the retained results into an opaque token; the client echoes it back with each request and the server re-injects the verified entries as a system section.
- The token is HMAC-signed and bound to the project. A tampered or foreign token yields nothing.
- Re-running an action replaces its retained entry, so retention always holds the current answer, never a pile of stale ones.
- A failed call is never retained — carrying an error forward would suppress the retry that would have fixed it.
- Budget: up to 8 entries and ~12,000 characters combined, expiring after 24 hours. Oldest entries are shed first.
- Retained material is presented as authoritative, and the model is told not to re-call those actions unless it needs something the data does not cover.
Realtime sessions already keep tool results in the session, so this flag changes nothing there.
Choosing between injection and a retained action
Section titled “Choosing between injection and a retained action”Prefer instructionOverrides when your application already knows what the user
is looking at — it is deterministic, costs no extra round trip, and cannot be
skipped by a model that decides not to call a tool. Reach for a retained action
when only the model knows what is needed, or when the data is genuinely fetched
mid-conversation.
Managing instructions from code
Section titled “Managing instructions from code”Both the stored instructions and the Agent Graph can be read and written over the API, so a prompt can live in your repository and be pushed from CI rather than edited in the dashboard — which also makes it something your tests can assert on. See the Assistant Config API.
Related
Section titled “Related”- Assistant Config API — reading and writing instructions and Agent Graphs.
- Chat Injection — delivering
instructionOverridesfrom an embed. - How Ragtime Works — where instructions sit relative to retrieval.