fix(claude-code): route the executor prompt through the single base builder, preserving hot-reload (task #76) #185
Reference in New Issue
Block a user
Delete Branch "fix/t76-executor-consume-config-system-prompt"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Stop the claude-code executor from re-reading only
system-prompt.md(ignoringprompt_files) and route its per-turn prompt through the ONE canonicalbuild_system_prompt— keeping the load-bearing hot-reload.Why (task #76)
_build_system_promptcalledget_system_prompt(config_path), which reads ONLYsystem-prompt.mdand ignoresconfig.yamlprompt_files. The concierge is the one workspace that declaresprompt_files, so it booted identity-less — the per-runtime drift this task closes. The invariant is: ONE source of truth (theprompt_files-honoring base builder); no executor ignoringprompt_files.Hot-reload reconciliation (the key decision)
The claude-code executor's per-turn re-read of
/configs/system-prompt.mdis load-bearing: it lets a freshly delivered/edited prompt take effect without a restart (proven on thee2e-concierge-prooforg).I kept the file as a live source but made the SSOT builder the single resolution path:
_build_system_promptnow callsbuild_system_prompt(config_path, …, prompt_files=self.prompt_files)per turn, reading from disk each time. So hot-reload is preserved ANDprompt_filesis honored — the build lives in ONE place.build_system_promptalready includes the base platform identity + A2A + HMA, so those are no longer re-appended by the executor (no duplication); only the claude-code-specificget_display_instructions()is appended (it is not part of the base build). If the builder is unavailable (stubbed test runtime), it falls back to the base-publishedconfig.system_prompt(built by the same builder), so the executor never boots prompt-less.setup()now publishesconfig.system_promptvia the same builder (boot value + threaded into the executor as the hot-reload fallback;prompt_files/workspace_idare threaded through).create_executorno longer re-readssystem-prompt.md.Tests
tests/test_system_prompt_ssot.py(new):test_effective_prompt_honors_prompt_files— declaredprompts/concierge.mdis loaded, the stalesystem-prompt.mdis NOT (the drift).test_effective_prompt_hot_reloads_from_disk— editing the declared file changes the next turn's prompt without a restart.test_legacy_system_prompt_md_still_loads_without_prompt_files— backwards-compat fallback.tests/conftest.py— adds amolecule_runtime.prompt.build_system_promptstub (honorsprompt_files) +prompt_files/workspace_idon the stubAdapterConfig, mirrored intest_adapter_prevalidate.py's local stub (the realAdapterConfigcarries these fields). Removed the three now-unused executor_helpers imports (get_system_prompt,get_a2a_instructions,get_hma_instructions).Prove-fail verified: reverting
_build_system_promptto the oldsystem-prompt.md-only read makes the concierge identity get shadowed by the stale fallback and the tests fail. Full suite green (171 passed, 1 skipped; baseline was 168 + 1) under the CI-faithful env (pytest + pyyaml, stubbed runtime).Note: openclaw is intentionally out of scope — its gateway assembles the prompt natively from copied
*.mdfiles (no singlesystem_promptinjection point).🤖 Generated with Claude Code
APPROVE: current-head 5-axis review for task #76. Correctness: claude-code now routes setup and per-turn hot-reload prompt construction through the shared build_system_prompt path, preserving prompt_files semantics and avoiding stale system-prompt.md shadowing. Robustness: fallback to the setup-published prompt keeps turns from booting promptless if the builder is unavailable, and tests cover prompt_files plus hot reload. Security: no secret/auth/network surface changes. Performance: per-turn file rebuild preserves existing hot-reload behavior with small prompt-file reads only. Readability: comments are explicit and tests document the SSOT invariant.
REQUEST_CHANGES: independent current-head review for claude-code#185 @
295aa344b4.Finding: the hot-reload path is not actually equivalent to the setup-time SSOT prompt when plugins contribute rules/prompts. adapter.py publishes config.system_prompt with build_system_prompt(..., plugin_rules=plugins.rules, plugin_prompts=plugins.prompt_fragments), but claude_sdk_executor.py:817-823 re-builds the per-turn prompt with only config_path/workspace_id/prompt_files and no plugin_rules/plugin_prompts. Because _build_options sends system_prompt=self._build_system_prompt(), the effective turn prompt takes the rebuild path whenever the builder is available and therefore drops plugin prompt fragments instead of falling back to the setup-published prompt.
5-axis summary: correctness/robustness need a fix so hot reload preserves the same builder inputs or otherwise carries plugin fragments into the executor; security/performance are not the concern; readability is mostly clear but the comments currently claim setup and per-turn builds use the same SSOT while their inputs diverge. Tests cover prompt_files and legacy fallback, but not plugin prompt/rule preservation, so this regression is unpinned.
New commits pushed, approval review dismissed automatically according to repository settings
APPROVE: current-head 5-axis review for task #76 claude-code prompt SSOT after the Researcher RC. Correctness: setup and per-turn hot-reload now both call build_system_prompt with prompt_files plus the same plugin_rules/plugin_prompts, so the previous plugin-drop asymmetry is closed while preserving hot reload. Robustness: fallback to the setup-published prompt remains, and tests cover prompt_files, legacy fallback, hot reload, and plugin fragment preservation. Security: no auth/secret/network surface changes. Performance: bounded per-turn prompt-file rebuild matches existing hot-reload behavior. Readability: the SSOT and plugin threading intent are explicit.
APPROVED (independent 5-axis review on current head
01a4aced85).Correctness: RC 14068 is resolved. The adapter now captures plugin_rules/plugin_prompts from loaded plugins and passes them into both config.system_prompt setup and the executor; the executor hot-reload rebuild calls build_system_prompt with those same plugin fragments, so per-turn prompt rebuild no longer drops them.
Robustness: test_hot_reload_preserves_plugin_fragments covers the prior regression shape and would fail on the old hot-reload path.
Security: no new trust boundary or secret handling changes; plugin prompt content follows the existing loaded-plugin path.
Performance: prompt rebuild cost is unchanged in shape; only the existing plugin fragments are threaded through.
Readability: builder remains the prompt SSOT, with the plugin inputs explicit at the adapter/executor boundary.