mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-11 01:51:34 -10:00
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:
1 parent
895cc6f52c
commit
dc32272f15
3 files changed
+47
-100
No files matched your search
@@ -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
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user