System prompt
codex descompone «lo que se le dice al modelo» en varios fragmentos de texto estático, plantillas y piezas de contexto que se ensamblan. El crate prompts aporta constantes y plantillas; core elige al arranque de la sesión las base instructions del modelo correspondiente y luego apila AGENTS.md, permissions instructions y fragmentos de personality para componer el system prompt final. Esta página explica esa cadena de ensamblado.
Responsabilidades
- Mantener las base instructions por defecto y las plantillas de personality de cada modelo, seleccionando y rellenando según el slug del modelo:
codex-rs/protocol/src/openai_models.rs:478-500 - Exponer constantes de prompt relacionadas con herramientas/aprobación (apply_patch, compaction, review, permissions, realtime):
codex-rs/prompts/src/lib.rs:1-27 - Componer las developer instructions a nivel de proyecto a partir de
AGENTS.mdy de las instrucciones de usuario:codex-rs/core/src/agents_md.rs:53-80 - Renderizar sandbox/approval policy como permissions instructions visibles para el modelo:
codex-rs/prompts/src/permissions_instructions.rs:62-117 - Fijar
base_instructionsal arranque de la sesión y en los cambios de turn, dejándolo disponible para client/compact:codex-rs/core/src/session/mod.rs:615-631
Motivación de diseño
Las base instructions no pueden quedar hardcodeadas en core. Los modelos distintos (gpt-5.1, gpt-5.2-codex, etc.) tienen personalidades por defecto y descripciones de herramienta diferentes; además, un mismo modelo puede cambiar personality (friendly/pragmatic/none). Las plantillas se colocan en models-manager y core/templates/; ModelMessages.instructions_template reemplaza en runtime el placeholder , de modo que añadir un modelo solo exige añadir un markdown nuevo y core no se toca.
Otra motivación es el provenance (trazabilidad de origen). AGENTS.md puede venir de nivel de usuario, raíz de proyecto o subdirectorio; al apilar varias capas, LoadedAgentsMd conserva la fuente de cada entrada y, si es necesario, etiqueta la salida por environment, para que el modelo sepa qué instrucción viene de qué directorio. Las permission instructions funcionan igual: no son una cadena cualquiera, sino un ContextualUserFragment con marker <permissions instructions>, para que el context manager las identifique y separe al compactar o reproducir.
Archivos clave
codex-rs/prompts/src/lib.rs:1-27— entrada del crateprompts, re-exportaAPPLY_PATCH_TOOL_INSTRUCTIONS,SUMMARIZATION_PROMPT,REVIEW_PROMPT,BACKEND_PROMPT, etc.codex-rs/prompts/src/permissions_instructions.rs:62-117—PermissionsInstructionsrenderizaPermissionProfile+Policyen un fragmento developer visible para el modelo.codex-rs/core/src/agents_md.rs:253-345—LoadedAgentsMdylegacy_text()implementan la concatenación ordenada de las instrucciones de proyecto.codex-rs/core/src/session/mod.rs:615-631— fallback de tres niveles para base_instructions: override de config → snapshot del historial → por defecto del modelo.codex-rs/core/src/session/mod.rs:1224-1229—get_base_instructionsse invoca repetidamente al procesar un turn y al compactar.codex-rs/protocol/src/openai_models.rs:478-500—get_model_instructionsprefiere reemplazar el placeholder de personality mediante plantilla.codex-rs/models-manager/src/model_info.rs:17-22— constanteBASE_INSTRUCTIONS, y los header/placeholder de la sección personality.codex-rs/core/src/client.rs:849-864— client, al construir la petición, unía base_instructions y tools en los messages.
El fallback de tres niveles para base_instructions: primero la config del usuario; si no, se recupera del conversation history; por último, el por defecto del modelo.
let base_instructions = config
.base_instructions
.clone()
.or_else(|| conversation_history.get_base_instructions().map(|s| s.text))
.unwrap_or_else(|| model_info.get_model_instructions(config.personality));Reemplazo de plantilla de personality: si el modelo tiene instructions_template, siempre se reemplaza con la plantilla; si no, se retrocede a base_instructions.
pub fn get_model_instructions(&self, personality: Option<Personality>) -> String {
if let Some(model_messages) = &self.model_messages
&& let Some(template) = &model_messages.instructions_template
{
let personality_message = model_messages
.get_personality_message(personality)
.unwrap_or_default();
template.replace(PERSONALITY_PLACEHOLDER, personality_message.as_str())
} else {
// ...
self.base_instructions.clone()
}
}Las permissions instructions no son una cadena cualquiera, sino un ContextualUserFragment con marker, para que el context manager las identifique y separe al compactar o reproducir.
impl ContextualUserFragment for PermissionsInstructions {
fn role(&self) -> &'static str { "developer" }
fn markers(&self) -> (&'static str, &'static str) { Self::type_markers() }
fn type_markers() -> (&'static str, &'static str) {
("<permissions instructions>", "</permissions instructions>")
}
fn body(&self) -> String { PermissionsInstructions::body(self) }
}Flujo de datos
Bordes y fallos
- Si el modelo no tiene
instructions_templatepero se pide personality friendly/pragmatic, se retrocede a base instructions y se deja un log de trace:codex-rs/protocol/src/openai_models.rs:488-498 - Cuando
config.personality == None,with_config_overrideslimpiamodel_messagespara evitar que se inyecte por error un tramo de personality:codex-rs/models-manager/src/model_info.rs:56-70 PermissionsInstructions.from_permission_profileexige una referencia aexecpolicy::Policy; si falta, la explicación de aprobación y el bloqueo real dejarían de coincidir:codex-rs/prompts/src/permissions_instructions.rs:89-117- Al cambiar de turn, si base_instructions coincide con la plantilla de personality por defecto del modelo, se salta la inyección duplicada del mensaje de personality:
codex-rs/core/src/session/mod.rs:3244-3257 - Con varios environments,
LoadedAgentsMd.textva por la ramaenvironment_labeled_texten vez delegacy_text, para evitar que las instrucciones de distintos cwd se fundan en un bloque indistinguible:codex-rs/core/src/agents_md.rs:311-345
Resumen
El system prompt en codex no es una cadena hardcodeada, sino el fallback de tres niveles «por defecto del modelo → override de config → snapshot del historial» más fragmentos con marker como AGENTS.md, permissions instructions y personality. El crate prompts solo aporta constantes y plantillas; el ensamblaje ocurre todo en core, y el BaseInstructions que recibe el llamador ya es una cadena fijada. Entender esta cadena es clave para depurar tanto «por qué el modelo responde así» en Bucle principal del Agent como «qué fragmentos se pelan y se reinyectan al compactar» en Compaction.