SDK tutorial · 5 of 10
Customize agent behavior
Keep durable product guidance in system context, keep capability instructions beside their host extension, and reserve user-prompt formatting for request-specific framing.
Customization depth
Level 3 · Input and capability policy
Hosting depth
Quickstart or conversation engine
Documentation status
Supported SDK boundary
Assumptions
- The product has stable behavioral guidance that should apply across turns.
- Some guidance belongs to a particular capability rather than the whole agent.
- Credentials and private user data remain outside prompts and system context.
- Compose engine and host-extension context deterministically before a turn.
- Apply the selected tool profile and Heddle's runtime-owned domain context.
- Persist conversation behavior without requiring the host to rebuild history.
- Write product-specific goals, boundaries, terminology, and capability instructions.
- Choose the model, reasoning effort, visible tools, and memory-maintenance policy.
- Keep request data, secrets, and authorization decisions in the appropriate product layer.
Use system context for stable product guidance
import {
createConversationEngine,
defineHostExtension,
} from '@roackb2/heddle'
const recordsExtension = defineHostExtension({
id: 'records',
tools: [findRecord, updateRecord],
systemContext: [
'Use record tools only when the request concerns a product record.',
'After a mutation, report the record ID and validation status.',
].join('\n'),
})
const engine = createConversationEngine({
workspaceRoot,
stateRoot,
model,
systemContext: [
'You are an assistant embedded in the Acme product.',
'Use concise product terminology and state uncertainty explicitly.',
].join('\n'),
hostExtensions: [recordsExtension],
})Engine-level systemContext is stable host guidance. It augments Heddle's runtime-owned context; it does not replace the entire runtime system prompt.
Host-extension context should explain when and how to use that extension. Multiple extensions compose in declaration order after the engine context. Keep each extension focused so it can be added or removed without rewriting one global prompt.
Format user prompts only when the quickstart owns the loop
import { runQuickstartConversationCli } from '@roackb2/heddle'
await runQuickstartConversationCli({
formatPrompt: (prompt) => [
prompt,
'',
'Response requirements:',
'- Mention validation status.',
'- Link every saved artifact by ID.',
].join('\n'),
})formatPrompt transforms each submitted quickstart prompt. It is not system context and is not an option on engine.turns.submit. Once your product owns the engine, build the user message in your application layer and keep stable instructions in engine or extension context.
Control which tools the model can see
const engine = createConversationEngine({
workspaceRoot,
stateRoot,
model,
toolProfile: {
preset: 'default',
memoryMode: 'none',
},
})toolProfile controls model-visible tool policy. It is separate from memoryMaintenanceMode:
toolProfile.memoryModecontrols whether memory tools are visible to the model.memoryMaintenanceModecontrols post-turn memory-maintenance scheduling.
If a turn selects a coding-agent profile, that profile's tool policy can override the engine default for that turn. Product authorization must still be enforced inside tools and host policy.
Prepare extensions with resolved defaults
If an extension needs the quickstart's resolved stateRoot or model before startup, call resolveQuickstartConversationCliDefaults, prepare the extension, then pass both to the runner. Do not duplicate Heddle's fallback order in product code.
Prompt hygiene
- Keep credentials, access tokens, private keys, and raw provider errors out of every prompt layer.
- Prefer short, testable behavioral rules over a large product manual.
- Put authoritative domain data behind tools instead of freezing it into system context.
- Verify behavior with representative tool and failure cases; prompt prose alone is not a policy boundary.