AI prompts
Every prompt layer the product injects, which lane receives which, and where to edit each one.
Every system prompt is a stack of six layers, each gated on a condition. The injected strings live in packages/config/src/ai/prompts.ts (@repo/config/ai/prompts); the persona lives with the agent; the desktop persona is one config value.
The layers
| Layer | Says | Edit at |
|---|---|---|
| Persona | The assistant's character | packages/api/src/mastra/agents/assistant/config.ts |
| Identity line | Which product and that the session runs in its desktop app | Automatic (from your product name) - not a string to edit |
| Desktop instructions | Your desktop persona | config.desktop.agents.instructions in desktop.mjs |
terminalPreamble | One sentence: "you are in a terminal session here" | aiPrompts |
capability | "Act through your tools; discover with list_* first" | aiPrompts |
webResearch | "Search rather than guess; cite real URLs" | aiPrompts |
Who gets what
✓ always · ◐ on its condition · - never
| Layer | Chat (web + desktop cloud) | Cloud automation | Dispatched runner run | Paired runner terminal | Desktop CLI chat | Desktop Terminal tab |
|---|---|---|---|---|---|---|
| Persona | ✓ | ✓ | ✓ | - | - | - |
| Identity line | - | - | - | - | ✓ | ✓ |
| Desktop instructions | - | - | - | - | ◐ | ◐ |
terminalPreamble | - | - | - | ✓ | - | ◐ |
capability | ◐ | ◐ | ◐ | ✓ | ◐ | ◐ |
webResearch | ◐ | ◐ | - | - | - | - |
| Condition | Gates |
|---|---|
| The run's toolset is non-empty | capability on every lane |
The turn registered the app's own web_search | webResearch (never on provider-native search or extract-only deployments) |
| The app's tools are mounted (user signed in) | capability + terminalPreamble on the desktop local lanes |
You set config.desktop.agents.instructions | Desktop instructions |
Layers always compose in the table's top-to-bottom order. An automation's own prompt is the user message, never a system layer - see Built-in automations.
One voice everywhere
capability is the same string on every lane - the desktop stages it into the on-device runtime config - so one edit re-voices web, cloud, runner, and desktop together. terminalPreamble is shared by both terminal kinds the same way.
Utility prompts
Three keys in the same file never enter a conversation:
| Key | Used by |
|---|---|
chatTitle | The run that names a conversation from its first exchange, on every naming lane - built-in, BYOK, and desktop CLI |
compactionSummary | Conversation compaction runs |
mcpInstructions | What the outward MCP server advertises to a connecting external agent |
Gate a new layer on its capability. One that ships on every request tells a model to do things this deployment may have no tools for, and bills those tokens every turn. Cut before you add: a line a current model already follows naturally ("answer clearly", "never invent facts") buys nothing and costs context on every run.