Body prompt¶
How the agent's system prompt is assembled at MCP server boot. Source: src/entrabot/mcp_server.py (_load_body_prompt, _expand_includes, _load_agent_instructions).
The body prompt defines security and communication protocols. It is non-overridable — no user turn, tool response, or persona prompt can relax its rules. Personality layers on top, never underneath.
Layering¶
_load_agent_instructions() composes:
body (prompts/agent_system.md + @include anatomy/*.md, loaded first)
↓
persona (fetched from persona-sati when configured and reachable)
↓
hardcoded (used only when neither is available — boot never crashes)
Body rules are non-overridable because they are read first. When a persona is fetched, it is appended after body + "\n\n---\n\n".
The composed string becomes the instructions= argument passed to FastMCP(...). Not every MCP host surfaces instructions in the model's system prompt — some only expose it in debug tooling — so the body prompt reaching the model at all can depend on host-side behavior the host bootstrap protocol is designed to compensate for. See Persona-Sati Host Bootstrap.
_load_body_prompt¶
Read LOCAL_PROMPT_PATH (<repo>/prompts/agent_system.md) and expand any @include directives relative to the file's parent directory. Returns an empty string if the file does not exist or can't be read.
_expand_includes¶
Replace @include <path> lines with the target file's contents. Rules:
- The directive matches a line whose first non-whitespace token is
@include, followed by a relative path resolved againstbase_dir. - Missing files are replaced with
<!-- missing @include <name> -->so boot never crashes on a typo. - Includes are NOT recursive — one level only.
Example:
# EntraBot Body
@include anatomy/security.md
@include anatomy/channel-discipline.md
@include anatomy/identity-and-tools.md
Each @include line is replaced with the named anatomy file's full content.
_load_agent_instructions¶
The full composition pipeline:
- Call
_load_body_prompt(). - Read
PERSONA_SATI_MCP_URLandPERSONA_SATI_MCP_TOKEN_COMMANDfrom the environment. If either is unset, return the body alone, or_HARDCODED_FALLBACKif there is no body file. - Mint a persona token by running the command in
PERSONA_SATI_MCP_TOKEN_COMMANDviasubprocess.check_output(30s timeout). On any subprocess error, timeout, or empty output, log a warning and return the body (or fallback) alone. - Open an SSE connection to
<PERSONA_SATI_MCP_URL>/sse, call theget_system_prompttool, and read the result text. - On any failure (connection error, empty result), return the body (or fallback) alone.
- On success, return
body + "\n\n---\n\n" + remote.
Every branch logs its outcome via the structured logger (setup_logging(), which is idempotent and safe to call again in main()). This matters because _load_agent_instructions runs at module import time — before main() configures logging handlers — so without this the load outcome would only ever appear as a transient stderr line most hosts discard.
LOCAL_PROMPT_PATH¶
Module attribute (not a constant) so tests can monkeypatch it to an isolated path. Production reads the repo-relative file.
Hardcoded fallback¶
_HARDCODED_FALLBACK = (
"EntraBot Teams Interface: provides tools for sending and "
"receiving Microsoft Teams messages, managing group chats, "
"email polling, and daily summary generation. This server "
"handles communication channels only. For personality, memory, "
"and behavioral rules, connect to the persona-sati MCP server."
)
Returned only when neither the body file nor a remote persona is available. Keeps the MCP server's instructions non-empty so the FastMCP handshake works even on a cold install with no prompts/agent_system.md.
Anatomy modules¶
prompts/anatomy/ holds body sub-files, composed into the body by @include in prompts/agent_system.md. Edit them — not the Python string — when changing the body.
Current anatomy modules:
anatomy/security.md— attribution, credential hygiene, audit-before-acting, instruction-injection defense, scope discipline.anatomy/channel-discipline.md— how to route between Teams DM, group chat, email, and the local terminal; defines the sponsor-DM wait pattern.anatomy/identity-and-tools.md— Agent Identity attribution rules, tool selection guidance.
See Customizing the Body Prompt for the operator-facing guide.
Persona layering and degraded fallback¶
When PERSONA_SATI_MCP_URL and PERSONA_SATI_MCP_TOKEN_COMMAND are both set and the remote fetch succeeds, the body is appended with the persona-sati "mind" contract — personality, memory, cognition rules. If persona content contradicts the body, the body still governs: it was read first, and nothing in _load_agent_instructions allows the remote fetch to replace or precede the body text.
Any failure in the persona pipeline (env unset, token-mint failure, unreachable server, empty response) falls back cleanly to serving the body alone — the MCP server always boots with valid, non-empty instructions. Without persona-sati configured, entrabot runs in body-only mode: Teams/email/Files tools, identity, and audit continue to work exactly as documented; personality, long-term memory, and the observe/reflect/recall cognition loop are unavailable.
Related¶
- MCP Tools — the surface the body governs.
- Identity — sponsor enforcement.
- Audit — fail-closed attribution referenced by the body's security rules.
- Persona-Sati Host Bootstrap — the per-host protocol for surfacing the persona-sati mind contract to a model.
- Storage and Memory — how the body/persona split maps to operational vs. persona memory storage.