Assembling the agent's brain: system prompts, task instructions, and consistent response formatting; using prompt templates and dynamic prompt generation; plus handling edge cases and failure modes so the prompt stays reliable in every situation.

In episode 4 you gave your agent an identity: persona, goals, capability, and toolset inside a profile. But identity alone is not enough — the quality of an agent's answers is largely determined by how well the prompt is structured. This episode teaches how to write prompts that make the agent consistent, easy to control, and not prone to "wandering off" on unusual input.
Here is the roadmap for this episode: structuring the system prompt, task instructions, and response formatting; using prompt templates and dynamic prompt generation; and then handling edge cases and failure modes in prompt design.
The system prompt is the fixed instruction loaded at the start of every conversation. It defines the role, context, and ground rules that apply to all turns. A good system prompt has four layers: role, context, task, and constraints.
[Peran] Kamu adalah research assistant di tim produk.
[Konteks] Perusahaan menjual software checkout SaaS.
[Tugas] Bantu user meriset kompetitor dan menyusun ringkasan.
[Batasan] Gunakan bahasa Indonesia. Jangan menyebutkan
nama user. Kutip sumber setiap klaim faktual.These four layers make it easy for the agent to separate "who I am" from "what I must do". Constraints are placed explicitly at the end so they are easy to spot and do not sink into the middle of a long narrative.
Avoid writing system prompts that are too long or too emotional. Sentences like "you MUST always obey" actually make the model drop its focus. Write positive, specific commands: replace "do not ramble" with "answer in at most 3 sentences".
If the system prompt answers "who are you and what are your rules", the task instruction answers "what specific job must be done right now". Distinguish them clearly — the system prompt stays fixed, while task instructions can change per invocation.
Response formatting forces the output into a specific structure so it is easy to parse programmatically. The most common is JSON.
{
"summary": "ringkasan dalam 2 kalimat",
"competitors": [
{ "name": "Pesaing A", "strengths": ["..."], "risks": ["..."] }
],
"confidence": 0.9
}To produce valid JSON, ask the model to use a JSON schema in the task instruction and set response_format to JSON mode if the provider supports it. Hermes can then parse the result safely without relying on fragile text parsing — for example through the parseJson helper.
When JSON is not needed, use XML tags to mark answer segments — for example, source citations in a <sumber> tag. XML is more tolerant of models that slip text around the core answer than JSON is.
Info
Always decide the response formatting before writing the prompt. A rigid format prevents the agent from adding filler that would force you to write a parser for every possible shape of answer.
Prompts are rarely written raw each time. Templates separate structure from data: the structure stays fixed, the data is injected per invocation.
Rangkum dokumen berikut dalam {max_sentences} kalimat.
Fokus pada keputusan dan tindakan yang perlu diambil.
Dokumen:
---
{document_content}
---Here there are two slots: max_sentences and document_content. The slots are replaced at render time. This template lives in the templates/ folder and is version-controlled together with the agent profile — anyone can read the template contents and know exactly what is sent to the model, without running the agent first.
Avoid putting logic inside templates. A template contains only text and slots; the choice logic (which slots to fill, when to use which template) belongs in code, not in the template string.
Dynamic prompt generation is the process of assembling the final prompt at runtime: read the template, pull data from a tool or memory, and render it into a complete prompt before calling the model.
import { render } from "@hermes/prompt";
export async function buildSummaryPrompt(session) {
const doc = await session.tool("kb.read").call({ id: session.documentId });
return render("templates/summarize.prompt", {
max_sentences: 3,
document_content: doc.content,
});
}This function combines three sources you already know from episode 4 and episode 8: the template as structure, tool data as content, and the session as context. The render function fills the template slots with values from a map. Slot values always come from trusted data — not raw user input — so prompt injection from document content does not automatically become an instruction.
Danger
A document read by a tool is data, not a command. When injecting external content into a prompt, wrap it in a clearly marked data block and maintain the constraint that the agent may only follow the instruction section.
A good prompt must work not only on ideal input, but also on broken input. Some of the most common failure modes:
const parsed = parseJson(raw);
if (!parsed) {
const retry = await model.call(
"Output kamu tidak valid JSON. Ulangi dengan format yang diminta."
);
return parseJson(retry) ?? fallbackSummary;
}The validate-then-retry pattern above is the basic pattern that will later grow into retry with backoff in episode 10. The principle: do not let a single format failure stop the whole workflow — always have a safe fallback answer ready.
Prompt engineering is the bridge between the agent's identity (episode 4) and how it works day to day. With a layered system prompt, specific task instructions, rigid response formatting, templates separated from data, and dynamic prompt generation that assembles everything at runtime, your agent becomes far more consistent and predictable.
Key takeaways:
In episode 6 we activate the agent's hands: Tooling & External Integrations — connecting LLM providers, integrating web search, database, API fetch, and file system tools, plus safety on every tool call. See you there!