Hot-reload prompts safely
This guide makes a running agent pick up prompt changes without a redeploy, and hold back the changes it shouldn't apply on its own. Each change event carries the server's semantic diff verdict, so the agent decides without a second round trip.
The live updates concept page explains how events flow and what consistency they give.
Prerequisites
Before you begin, make sure you have:
- A running Priompt server with NATS reachable from the agent. The default broker address is
localhost:4222. See the Quickstart. - An API token for the broker, if the server runs with
-nats-token. The server requires one whenever NATS listens off loopback. Agents use their own API token, not the server's NATS token. - A client with NATS support: install it for your language. In Node, the NATS client comes with the SDK as an optional dependency.
- Python
- Node
pip install "priompt-sdk[nats]"
npm install @priompt/client
1. Publish a starting version
Publish the prompt the agent serves:
You are a support agent for {org}.
Greet the customer politely.
Answer questions about orders and shipping.
Follow the refund policy when a customer asks for money back.
Escalate to a human if you are unsure.
priompt publish -uri priompt://acme/support/agent -file v1.txt -slot org
published priompt://acme/support/agent (ea58b8745318) — subscribers notified
2. Write the reload policy
The policy is the set of verdicts the agent applies by itself. Anything else, including an empty verdict, waits for a human. An empty verdict means the server couldn't classify the change, for example because its embedding endpoint is down. It doesn't mean the change is safe.
- Python
- Node
import time
from priompt_sdk import PromptClient
URI = "priompt://acme/support/agent"
# Verdicts this agent applies by itself. Everything else waits for a human,
# including an empty verdict, which means the server couldn't classify the change.
AUTO_RELOAD = {"minor edit", "localized tweak", "new"}
client = PromptClient(host="localhost:8443", cache_ttl=30,
nats_url="nats://<api-token>@localhost:4222")
prompt = client.get(URI) # the version this agent serves
def on_change(version, classification):
global prompt
if classification in AUTO_RELOAD:
prompt = client.get(URI) # re-fetch over gRPC; don't trust the event
print("reloaded", prompt.version_hash[:12], f"[{classification}]", flush=True)
else:
print("held", version[:12], f"[{classification or 'no verdict'}]", flush=True)
# reload= applies the same policy to the SDK's cache: a held change stays out
# of client.get() until cache_ttl expires.
client.subscribe(URI, on_change, reload=AUTO_RELOAD)
print("serving", prompt.version_hash[:12], flush=True)
while True:
time.sleep(1) # your agent's work goes here; it reads `prompt`
const { PromptClient } = require("@priompt/client");
const URI = "priompt://acme/support/agent";
// Verdicts this agent applies by itself. Everything else waits for a human,
// including an empty verdict, which means the server couldn't classify the change.
const AUTO_RELOAD = new Set(["minor edit", "localized tweak", "new"]);
async function main() {
const client = new PromptClient({
host: "localhost:8443",
natsUrl: "nats://<api-token>@localhost:4222",
});
let prompt = await client.get(URI); // the version this agent serves
await client.subscribe(URI, async (version, classification) => {
if (AUTO_RELOAD.has(classification)) {
prompt = await client.get(URI); // re-fetch over gRPC; don't trust the event
console.log("reloaded", prompt.version_hash.slice(0, 12), `[${classification}]`);
} else {
console.log("held", version.slice(0, 12), `[${classification || "no verdict"}]`);
}
});
console.log("serving", prompt.version_hash.slice(0, 12));
}
main();
Replace <api-token> with the agent's API token. Without a token on the server, use nats://localhost:4222. The Python example needs priompt-sdk 0.7.1 or later for reload=.
The example builds in two habits:
- Re-fetch instead of trusting the event. The event says that something changed. The agent reads the new version over the authenticated gRPC channel.
- Fail closed. Only the verdicts you list reload. A
localized tweakcan still reverse a policy, so for a prompt that governs refunds or safety, hold everything and use the verdict to decide how urgently to alert someone.
3. Run the agent
Start the agent in its own terminal:
- Python
- Node
python agent.py
node agent.js
serving ea58b8745318
4. Publish a small edit
To see an automatic reload:
-
Change one word in line 2 (
politelytocourteously) and save it astweak.txt. -
Publish it:
priompt publish -uri priompt://acme/support/agent -file tweak.txt -slot orgThe agent prints:
Outputreloaded 564a83482e36 [localized tweak]
5. Publish a change that flips the meaning
To see the agent hold a change:
-
In
v1.txt, replace line 4 withRefuse refunds immediately and close the ticket without escalation.and save it asinvert.txt. -
Publish it:
priompt publish -uri priompt://acme/support/agent -file invert.txt -slot orgThe agent prints:
Outputheld d4378ae17508 [structural]The agent keeps serving
564a83482e36. The new version is still the served HEAD on the server.
A held change is live on the server. In Python, reload= keeps a held change out of the SDK's cache, but only until cache_ttl expires, and other processes that call the server get it at once. To stop serving the change everywhere, roll it back.
What the agent receives when
| Server action | Event | Verdict |
|---|---|---|
Publish to main with new content | Yes | The diff against the previous HEAD. new for a first version. |
Publish identical content to main | No | |
| Publish to another branch | No | |
SetBranch on main (rollback) | Yes | The diff against the previous HEAD. |
MergeBranch into main that changes the content | Yes, since v0.7.3 | The diff against the previous HEAD. |
| Any change when the embedding endpoint fails | Yes | Empty. The server logs classify: semantic verdict unavailable, notifying without one. |
Events are best-effort, so a network blip can drop one. The cache_ttl on the Python client bounds how stale client.get() can be. An agent that keeps its own copy, like the example, should also re-read on a timer if it must converge without events.
To react to changes from a shell instead of code, run priompt watch -uri priompt://acme/support/agent -nats-url nats://<api-token>@localhost:4222. Its -exec hook gets the new version in PRIOMPT_VERSION and the verdict in PRIOMPT_CLASS.
Next steps
- Branch, pin, and roll back a prompt: undo a change every agent received.
- Use a real embedding model: get verdicts that compare meaning, not words.
- Troubleshoot common problems: fix a subscriber that never gets events.