feat(prompts): one base prompt for every host, with a Bearing article

HEADLESS_BASE_PROMPT was a second hand-maintained rendering of the
constitution — the drift pattern AGENTS.md already forbids (BASE_PROMPT
is the sole base prompt). Headless hosts now compose the same
BASE_PROMPT + language + output layers as interactive, skipping only
host chrome (execution profile, authority recap).

BASE_PROMPT gains a Bearing article — peer stance, honesty over
deference, candor over refusal theater, no apology as punctuation, no
sanitizing the user's request — and the scope law now opens with the
mandate ("everything inside it is yours to do") before the edge. Every
pinned kernel invariant survives verbatim.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
CodeWhale BotandDevin committed 2026-09-16 18:46:47 -07:00
1 parent 895cc6f52c
commit dc32272f15
3 files changed
+47 -100

No files matched your search

+1 -1
View File
@@ -3970,7 +3970,7 @@ mod tests {
);
let text = crate::prompts::system_prompt_flat_text(&prompt);
assert!(text.contains(crate::prompts::text::HEADLESS_BASE_PROMPT.trim()));
assert!(text.contains(crate::prompts::text::BASE_PROMPT.trim()));
assert!(text.contains("acp-project-marker"));
assert!(text.contains("acp-config-marker"));
assert!(!text.contains("You are a coding assistant inside an ACP-compatible editor."));
+33 -82
View File
@@ -395,7 +395,7 @@ fn user_constitution_disabled_by_setup_state() -> bool {
use text::CALM_PERSONALITY;
pub use text::{
BASE_PROMPT, COMPACT_TEMPLATE, CORE_EXECUTION_PROFILE_PROMPT, GOAL_CONTINUATION_PROMPT,
HEADLESS_BASE_PROMPT, LANGUAGE_PROMPT, MEMORY_GUIDANCE, OUTPUT_PROMPT,
LANGUAGE_PROMPT, MEMORY_GUIDANCE, OUTPUT_PROMPT,
};
// ── Embedder prompt overrides ──
@@ -974,9 +974,9 @@ fn apply_static_prompt_composer(
}
}
// Interactive hosts use the full base and bundled headless hosts use the
// compact base. Tool availability is enforced by the catalog and execution
// layer, never by mode-specific prompt text.
// Every host shares BASE_PROMPT — one constitution, one stance. Host selects
// only which ceremony layers follow it; tool availability is enforced by the
// catalog and execution layer, never by mode-specific prompt text.
// ── Public API ────────────────────────────────────────────────────────
@@ -1075,30 +1075,21 @@ pub(crate) fn system_prompt_for_mode_with_context_skills_session_and_approval_fo
session_context: PromptSessionContext<'_>,
prompt_host: PromptHost,
) -> SystemPrompt {
// The bundled headless coding host gets one compact constitution. Explicit
// user/embedder overrides retain the established full composition because
// those bytes are an intentional customization, not bundled ceremony.
let bundled_headless = prompt_host == PromptHost::Headless
&& BASE_PROMPT_OVERRIDE.get().is_none()
&& effective_static_prompt_composer().is_none();
let composed = if bundled_headless {
apply_model_template(
HEADLESS_BASE_PROMPT.trim(),
session_context.model_id,
session_context.context_window_override,
)
} else {
let default_layers = compose_default_static_layers_with_context(
session_context.model_id,
session_context.context_window_override,
);
apply_static_prompt_composer(
effective_static_prompt_composer(),
Personality::Calm,
session_context.model_id,
&default_layers,
)
};
// One base prompt for every host (AGENTS.md: `BASE_PROMPT` is the sole
// base prompt). Headless still skips interactive ceremony layers below —
// the execution profile and authority recap — which are host chrome, not
// doctrine.
let headless = prompt_host == PromptHost::Headless;
let default_layers = compose_default_static_layers_with_context(
session_context.model_id,
session_context.context_window_override,
);
let composed = apply_static_prompt_composer(
effective_static_prompt_composer(),
Personality::Calm,
session_context.model_id,
&default_layers,
);
// Load project context from workspace
let project_context = load_project_context_with_parents(workspace);
@@ -1201,7 +1192,7 @@ pub(crate) fn system_prompt_for_mode_with_context_skills_session_and_approval_fo
// 4. Lean, runtime-only coding discipline. Context pressure, prompt-cache
// accounting, footer presentation, and automatic compaction are host
// responsibilities; teaching their UI to the model dilutes the task.
if !bundled_headless {
if !headless {
full_prompt.push_str("\n\n");
full_prompt.push_str(CORE_EXECUTION_PROFILE_PROMPT.trim());
}
@@ -1294,7 +1285,7 @@ pub(crate) fn system_prompt_for_mode_with_context_skills_session_and_approval_fo
.to_system_blocks();
// Trailers keep recency bias after WorldState: authority, then locale.
if !bundled_headless {
if !headless {
blocks.push(SystemBlock {
block_type: "text".to_string(),
text: effective_authority_recap().trim().to_string(),
@@ -1541,48 +1532,6 @@ mod tests {
})
}
#[test]
fn bundled_headless_contract_is_small_and_direct() {
for phrase in [
"You already have an A",
"begin from possibility",
"bring your whole attention",
"a question, idea, or task",
"Invent no urgency or deadline",
"tools as senses",
"active authority is your limit",
"Failure is information",
"Check\nbefore concluding",
"unverified work as complete",
] {
assert!(
HEADLESS_BASE_PROMPT.contains(phrase),
"bundled headless contract missing {phrase:?}"
);
}
for ceremony in [
"todo_write",
"checklist",
"`repl`",
"workflow",
"Fleet",
"sub-agent",
"delegation",
"goals",
"harness",
"Mode:",
] {
assert!(
!HEADLESS_BASE_PROMPT.contains(ceremony),
"bundled headless contract must leave optional capabilities to the tool catalog: {ceremony:?}"
);
}
assert!(
HEADLESS_BASE_PROMPT.split_whitespace().count() <= 75,
"bundled headless contract must stay compact"
);
}
#[test]
fn every_mode_shares_one_prompt_per_host() {
let _env_lock = crate::test_support::lock_test_env();
@@ -1613,7 +1562,9 @@ mod tests {
assert!(prompts[0].contains("Preserve the blue-ocean marker"));
assert!(!prompts[0].contains("##### Mode:"));
if host == PromptHost::Headless {
assert!(prompts[0].contains("You already have an A"));
// One base prompt for every host; headless still omits the
// interactive ceremony layers.
assert!(prompts[0].contains("The A is already yours"));
assert!(!prompts[0].contains("## Core Execution"));
assert!(!prompts[0].contains("## Authority Recap"));
}
@@ -3183,7 +3134,7 @@ mod tests {
"When NOT to use certain tools",
"Don't reach for",
] {
assert!(!HEADLESS_BASE_PROMPT.contains(forbidden));
assert!(!BASE_PROMPT.contains(forbidden));
}
}
@@ -3315,7 +3266,7 @@ mod tests {
rlm_count >= 5,
"RLM tool descriptions present: expected >= 5 mentions of 'rlm', got {rlm_count}"
);
assert!(!HEADLESS_BASE_PROMPT.contains("`rlm`"));
assert!(!BASE_PROMPT.contains("`rlm`"));
}
/// Project instructions rank above memory, with the nearest scope winning
@@ -3352,19 +3303,19 @@ mod tests {
fn prompt_documents_fork_context_prefix_cache_contract() {
let source = include_str!("tools/subagent/mod.rs");
assert!(source.contains("fork_context"));
assert!(!HEADLESS_BASE_PROMPT.contains("fork_context"));
assert!(!BASE_PROMPT.contains("fork_context"));
}
#[test]
fn prompt_documents_explicit_subagent_model_strength() {
let source = include_str!("tools/subagent/mod.rs");
assert!(source.contains("model_strength"));
assert!(!HEADLESS_BASE_PROMPT.contains("model_strength"));
assert!(!BASE_PROMPT.contains("model_strength"));
}
#[test]
fn prompt_documents_structured_subagent_briefs() {
assert!(!HEADLESS_BASE_PROMPT.contains("Subagent Brief"));
assert!(!BASE_PROMPT.contains("Subagent Brief"));
for heading in [
"### SUMMARY",
"### EVIDENCE",
@@ -3378,8 +3329,8 @@ mod tests {
#[test]
fn universal_prompt_does_not_invent_orchestration_limits() {
assert!(!HEADLESS_BASE_PROMPT.contains("3-5 tool calls"));
assert!(!HEADLESS_BASE_PROMPT.contains("No fan-out without a fan-in owner"));
assert!(!BASE_PROMPT.contains("3-5 tool calls"));
assert!(!BASE_PROMPT.contains("No fan-out without a fan-in owner"));
}
#[test]
@@ -3390,7 +3341,7 @@ mod tests {
"request_user_input",
".workflow.js",
] {
assert!(!HEADLESS_BASE_PROMPT.contains(recipe));
assert!(!BASE_PROMPT.contains(recipe));
}
}
@@ -3403,7 +3354,7 @@ mod tests {
"dispatch, join",
"busy-waiting",
] {
assert!(!HEADLESS_BASE_PROMPT.contains(internal));
assert!(!BASE_PROMPT.contains(internal));
}
}
+13 -17
View File
@@ -51,12 +51,23 @@ The A is already yours. Your competence is a settled fact, not a performance.
Do the real work — bold, careful, generous. Take the work seriously. Don't take
yourself seriously. Let the work speak.
### Bearing
You answer to the work and to the user — not to habit, optics, or the
appearance of obedience. The user is a peer: they get your honesty, not your
deference. When a gate blocks the work, name it plainly and keep moving —
that is candor, not refusal theater. When the code is bad, say so; when the
request is crude, do it without a lecture. Apologize when there is something
to apologize for, never as punctuation. You do not sanitize what the user
asked for or editorialize what you find. What is real — tools, tests, the
tree — outranks every story about it, including yours.
### Ground truth
Your tools tell you what is. Report what they return — even when it surprises
you. When a tool fails or evidence is uncertain, say so. The user may tell you
to set a fact aside or proceed despite it; no one may tell you to invent one.
### User intent and scope
The request is the whole mandate — everything inside it is yours to do.
Do what the user's current request asks, no more. Act on clear, reversible work;
ask when ambiguity is costly. Report adjacent issues instead of silently
expanding scope. Irreversible actions, external publication, spending,
@@ -80,7 +91,8 @@ Never present a partial result as the whole.
### Put guarantees in mechanism
Authorization, ordering, stopping, schema validity, resource limits, and
required checks belong in code, types, tests, tool gates, and runtime policy.
A principle names the duty; mechanism carries it.
A principle names the duty; mechanism carries it — so the guarantees are
real, and performing them is never your job.
### Whose word wins
When guidance conflicts, each yields to the one before it:
@@ -97,22 +109,6 @@ At equal rank, the more specific and the more recent govern. Ground truth
underlies the whole list: the user may override a fact, but no one may invent
one. A tie you cannot break is not yours to break — name it, and ask.
"#;
/// Compact default constitution for non-interactive coding hosts.
///
/// Tool schemas and repository instructions are supplied separately. This
/// block states only the cross-cutting contract the runtime cannot express.
pub const HEADLESS_BASE_PROMPT: &str = r#"## Codewhale
You are Codewhale, assisting someone.
You already have an A: begin from possibility and bring your whole attention.
Meet each message as it is—a question, idea, or task. Honor the person's intent
and boundaries. Invent no urgency or deadline. Use the workspace and available
tools as senses; active authority is your limit. Failure is information. Check
before concluding; never invent results or present partial, running, or
unverified work as complete.
"#;
/// Language mirroring law, split from the compact constitution in 0.9.0.
///
/// The constitution and internal law stay English (machine-facing, one