[codex] allow disabling prompt instruction blocks (#16735)

This PR adds root and profile config switches to omit the generated
`<permissions instructions>` and `<apps_instructions>` prompt blocks
while keeping both enabled by default, and it gates both the initial
developer-context injection and later permissions diff injection so
turning the permissions block off stays effective across turn-context
overrides.

Also added a prompt debug tool that can be used as `codex debug
prompt-input "hello"` and dumps the constructed items list.
This commit is contained in:
Thibault Sottiaux
2026-04-03 23:47:56 +00:00
committed by GitHub
parent f263607c60
commit 8d19646861
11 changed files with 531 additions and 120 deletions
+34
View File
@@ -4493,6 +4493,8 @@ fn test_precedence_fixture_with_o3_profile() -> std::io::Result<()> {
base_instructions: None,
developer_instructions: None,
guardian_developer_instructions: None,
include_permissions_instructions: true,
include_apps_instructions: true,
compact_prompt: None,
commit_attribution: None,
forced_chatgpt_workspace_id: None,
@@ -4635,6 +4637,8 @@ fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> {
base_instructions: None,
developer_instructions: None,
guardian_developer_instructions: None,
include_permissions_instructions: true,
include_apps_instructions: true,
compact_prompt: None,
commit_attribution: None,
forced_chatgpt_workspace_id: None,
@@ -4775,6 +4779,8 @@ fn test_precedence_fixture_with_zdr_profile() -> std::io::Result<()> {
base_instructions: None,
developer_instructions: None,
guardian_developer_instructions: None,
include_permissions_instructions: true,
include_apps_instructions: true,
compact_prompt: None,
commit_attribution: None,
forced_chatgpt_workspace_id: None,
@@ -4901,6 +4907,8 @@ fn test_precedence_fixture_with_gpt5_profile() -> std::io::Result<()> {
base_instructions: None,
developer_instructions: None,
guardian_developer_instructions: None,
include_permissions_instructions: true,
include_apps_instructions: true,
compact_prompt: None,
commit_attribution: None,
forced_chatgpt_workspace_id: None,
@@ -5783,6 +5791,32 @@ async fn approvals_reviewer_defaults_to_manual_only_without_guardian_feature() -
Ok(())
}
#[tokio::test]
async fn prompt_instruction_blocks_can_be_disabled_from_config_and_profiles() -> std::io::Result<()>
{
let codex_home = TempDir::new()?;
std::fs::write(
codex_home.path().join(CONFIG_TOML_FILE),
r#"include_permissions_instructions = false
include_apps_instructions = false
profile = "chatty"
[profiles.chatty]
include_permissions_instructions = true
"#,
)?;
let config = ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.fallback_cwd(Some(codex_home.path().to_path_buf()))
.build()
.await?;
assert!(config.include_permissions_instructions);
assert!(!config.include_apps_instructions);
Ok(())
}
#[tokio::test]
async fn approvals_reviewer_stays_manual_only_when_guardian_feature_is_enabled()
-> std::io::Result<()> {
+22
View File
@@ -280,6 +280,12 @@ pub struct Config {
/// Guardian-specific developer instructions override from requirements.toml.
pub guardian_developer_instructions: Option<String>,
/// Whether to inject the `<permissions instructions>` developer block.
pub include_permissions_instructions: bool,
/// Whether to inject the `<apps_instructions>` developer block.
pub include_apps_instructions: bool,
/// Compact prompt override.
pub compact_prompt: Option<String>,
@@ -1183,6 +1189,12 @@ pub struct ConfigToml {
#[serde(default)]
pub developer_instructions: Option<String>,
/// Whether to inject the `<permissions instructions>` developer block.
pub include_permissions_instructions: Option<bool>,
/// Whether to inject the `<apps_instructions>` developer block.
pub include_apps_instructions: Option<bool>,
/// Optional path to a file containing model instructions that will override
/// the built-in instructions for the selected model. Users are STRONGLY
/// DISCOURAGED from using this field, as deviating from the instructions
@@ -2452,6 +2464,14 @@ impl Config {
Self::try_read_non_empty_file(model_instructions_path, "model instructions file")?;
let base_instructions = base_instructions.or(file_base_instructions);
let developer_instructions = developer_instructions.or(cfg.developer_instructions);
let include_permissions_instructions = config_profile
.include_permissions_instructions
.or(cfg.include_permissions_instructions)
.unwrap_or(true);
let include_apps_instructions = config_profile
.include_apps_instructions
.or(cfg.include_apps_instructions)
.unwrap_or(true);
let guardian_developer_instructions = guardian_developer_instructions_from_requirements(
config_layer_stack.requirements_toml(),
);
@@ -2618,6 +2638,8 @@ impl Config {
developer_instructions,
compact_prompt,
commit_attribution,
include_permissions_instructions,
include_apps_instructions,
// The config.toml omits "_mode" because it's a config file. However, "_mode"
// is important in code to differentiate the mode from the store implementation.
cli_auth_credentials_store_mode: cfg.cli_auth_credentials_store.unwrap_or_default(),
+2
View File
@@ -49,6 +49,8 @@ pub struct ConfigProfile {
pub experimental_instructions_file: Option<AbsolutePathBuf>,
pub experimental_compact_prompt_file: Option<AbsolutePathBuf>,
pub include_apply_patch_tool: Option<bool>,
pub include_permissions_instructions: Option<bool>,
pub include_apps_instructions: Option<bool>,
pub experimental_use_unified_exec_tool: Option<bool>,
pub experimental_use_freeform_apply_patch: Option<bool>,
pub tools_view_image: Option<bool>,