Move agent facing text copy into a i18n style dir #632

Open
opened 2026-07-07 21:37:38 +00:00 by coilysiren · 2 comments
Owner

The problem

the system prompts / preambles / etc...

this is half a true i18n problem, and half a simpler customization thing

probably public config should ride the ".ward/" dir

Proposed change

//

Alternatives considered

//

Before filing

  • I searched existing issues and this is not a duplicate.
  • This stays within ward's scope (the dev-verb gate / agent driver), not a personal-infra or downstream-repo verb.
### The problem the system prompts / preambles / etc... this is half a true i18n problem, and half a simpler customization thing probably public config should ride the ".ward/" dir ### Proposed change // ### Alternatives considered // ### Before filing - [x] I searched existing issues and this is not a duplicate. - [x] This stays within ward's scope (the dev-verb gate / agent driver), not a personal-infra or downstream-repo verb.
Member

Director scoping note from the read-only surface.

This should start as a design pass, not a direct implementation. The target is not full translation coverage of every CLI string. The useful first boundary is agent-facing internally emitted copy: prompts, preambles, structured comments, and agent-visible status text that ward generates for the agent workflow.

Candidate first-slice surfaces in current main:

  • Agent prompts: agentSeedPrompt, preflightPrompt, askPrompt, interactivePrompt, directorDecidePrompt, triagePrompt, and internal/reviewpanel.RefutePrompt.
  • Structured issue comments: reservationCommentBody, reservation release comments, WARD-OUTCOME final comments, director merge done comments, review summaries.
  • Agent/container log text that agents and directors rely on: bootstrap run context, startup config echo, dispatch/reap gate messages, smoke-test failure text.
  • Existing asset-style precedent: cmd/ward/*assets packages and .ward/ config bundle. A copy bundle probably wants a committed default under ward plus an override/config hook later, but the design should pick the exact owner.

Questions the advisor should settle before implementation:

  • Directory/package shape: e.g. cmd/ward/textassets, internal/agentcopy, or .ward/copy defaults. Avoid pretending this is locale-complete if the first goal is copy customization.
  • Lookup contract: stable message IDs with typed render functions, not ad hoc string map lookups spread across call sites.
  • Override contract: whether public config rides .ward/ now or waits for the config-driven ward work (#650). If it waits, still create the default-copy seam now.
  • Boundary: separate agent-facing workflow copy from normal CLI help/errors, generated guardfile docs, and low-level debug logs unless they are intentionally part of the agent protocol.
  • Test strategy: golden tests or ID coverage that prevents call sites from reintroducing large inline prompt/comment blocks.

Acceptance for the design pass: post a concrete implementation plan with the first-slice file list, proposed package/API, migration order, and examples for at least one prompt and one structured issue comment.

Director scoping note from the read-only surface. This should start as a design pass, not a direct implementation. The target is not full translation coverage of every CLI string. The useful first boundary is **agent-facing internally emitted copy**: prompts, preambles, structured comments, and agent-visible status text that ward generates for the agent workflow. Candidate first-slice surfaces in current `main`: * Agent prompts: `agentSeedPrompt`, `preflightPrompt`, `askPrompt`, `interactivePrompt`, `directorDecidePrompt`, `triagePrompt`, and `internal/reviewpanel.RefutePrompt`. * Structured issue comments: `reservationCommentBody`, reservation release comments, `WARD-OUTCOME` final comments, director merge done comments, review summaries. * Agent/container log text that agents and directors rely on: bootstrap run context, startup config echo, dispatch/reap gate messages, smoke-test failure text. * Existing asset-style precedent: `cmd/ward/*assets` packages and `.ward/` config bundle. A copy bundle probably wants a committed default under ward plus an override/config hook later, but the design should pick the exact owner. Questions the advisor should settle before implementation: * Directory/package shape: e.g. `cmd/ward/textassets`, `internal/agentcopy`, or `.ward/copy` defaults. Avoid pretending this is locale-complete if the first goal is copy customization. * Lookup contract: stable message IDs with typed render functions, not ad hoc string map lookups spread across call sites. * Override contract: whether public config rides `.ward/` now or waits for the config-driven ward work (#650). If it waits, still create the default-copy seam now. * Boundary: separate agent-facing workflow copy from normal CLI help/errors, generated guardfile docs, and low-level debug logs unless they are intentionally part of the agent protocol. * Test strategy: golden tests or ID coverage that prevents call sites from reintroducing large inline prompt/comment blocks. Acceptance for the design pass: post a concrete implementation plan with the first-slice file list, proposed package/API, migration order, and examples for at least one prompt and one structured issue comment.
Member

🔎 ward agent advisor

ward agent advisor --harness codex ran a one-shot standard research pass on this question:

Read the issue title, body, and comment thread below as the research brief. Identify the decisions, options, open questions, and risks, then give a clear advisory recommendation that can be posted back on the issue.

Additional framing from the dispatcher:
Design the first implementation slice for moving agent-facing internally emitted copy into an i18n/copy-bundle style folder. Use the director scoping comment as constraints. Post a concrete implementation plan with package/directory shape, stable message ID/API approach, override/config stance, migration order, and examples for one prompt plus one structured issue comment. Do not implement code in this pass.


Recommendation

Move the first slice into a ward-owned embedded copy bundle, not .ward/ yet. The clean seam is an internal/agentcopy package with a defaults/ asset directory and typed render functions. That package can be imported by both cmd/ward and internal/reviewpanel, which rules out putting the logic only under cmd/ward/*assets. The .ward/ override story should wait for the broader config-driven runtime work in #650, because current docs explicitly keep core agent/container runtime data ward-owned and baked while WARD_CONFIG_REF only steers edge KDL surfaces.

This should be framed as a copy-bundle seam, not full locale i18n yet. The immediate goal is customization and centralization of agent-facing generated prose. Design the bundle so locale layering can come later, but do not make locale selection, fallback chains, or translation coverage part of slice 1.

Decisions To Make Now

  • Owner/package: use internal/agentcopy, with embedded defaults under internal/agentcopy/defaults/.
  • Scope boundary: include only ward-generated, agent-facing workflow copy.
  • Lookup contract: stable message IDs plus typed render helpers. No raw map[string]string lookups at call sites.
  • Override stance: baked defaults now. Defer .ward/ operator overrides until the config-runtime seam is intentionally widened.
  • Protocol boundary: keep machine markers and parse-critical tokens code-owned constants, even when surrounding prose moves into templates.

Why This Shape Fits The Current Repo

  • internal/reviewpanel.RefutePrompt needs the same bundle seam as cmd/ward prompt builders, so the copy layer must live in an importable internal package rather than package main.
  • The repo already has an asset precedent: embedded default bundles plus drift/parse tests. This proposal matches that pattern, but for copy rather than KDL.
  • Current docs in docs/config-source.md draw a hard line: configurable edge surfaces, baked core runtime. Agent workflow copy belongs on the core-runtime side for now.

First-Slice Surfaces

Include these in slice 1:

  • Prompts: agentSeedPromptWorkflow, preflightPrompt, askPrompt, interactivePrompt, directorDecidePrompt, triagePrompt, internal/reviewpanel.RefutePrompt.
  • Structured tracker comments: reservationCommentBody, reservationReleaseCommentBody, directorMergeDoneComment.

Explicitly exclude for now:

  • Normal CLI help text and generic user-facing errors.
  • Generated guardfile docs and KDL text.
  • Low-level debug/log spam unless it is intentionally part of the agent protocol.
  • Agent-authored final WARD-OUTCOME prose, because ward mostly instructs the engineer to write that rather than synthesizing it itself.

Proposed Package/API

Use a typed API over embedded templates:

  • internal/agentcopy/bundle.go - embed/load/cache default templates.
  • internal/agentcopy/ids.go - stable message IDs.
  • internal/agentcopy/prompts.go - typed input structs and renderers for prompts.
  • internal/agentcopy/comments.go - typed input structs and renderers for tracker comments.
  • internal/agentcopy/defaults/*.md.tmpl - one template per message.
  • internal/agentcopy/agentcopy_test.go - coverage/golden tests.

Suggested ID style:

  • prompt.agent-seed.v1
  • prompt.preflight.v1
  • prompt.ask.v1
  • prompt.interactive.v1
  • prompt.director-decide.v1
  • prompt.triage.v1
  • prompt.review-refute.v1
  • comment.reservation-held.v1
  • comment.reservation-released.v1
  • comment.director-merge-done.v1

Suggested public API shape:

  • func AgentSeed(in AgentSeedInput) string
  • func Preflight(in PreflightInput) string
  • func Ask(in AskInput) string
  • func Interactive(in InteractiveInput) string
  • func DirectorDecide(in DirectorDecideInput) string
  • func Triage(in TriageInput) string
  • func ReviewRefute(in ReviewRefuteInput) string
  • func ReservationHeld(in ReservationHeldInput) string
  • func ReservationReleased(in ReservationReleasedInput) string
  • func DirectorMergeDone(in DirectorMergeDoneInput) string

Internally those helpers can call one renderer keyed by ID, but callers should never pass free-form IDs or untyped map[string]any data.

Important Constraint: keep protocol tokens out of operator-editable prose

Several surfaces are parse-sensitive today. The copy seam must not let later customization silently break protocol behavior.

Keep these code-owned:

  • WARD-OUTCOME: marker line semantics.
  • WARD-RESERVATION: visible marker lines.
  • Hidden markers like <!-- ward-needs-redispatch --> and reservation markers.
  • Required fenced JSON instructions for RefutePrompt.
  • Any parser-anchored headings/summary blocks if tests currently depend on them.

A good rule is: templates own prose, code owns protocol. Templates may interpolate code-owned constants, but the constants themselves should not move into freely editable text bundles.

Override / Config Recommendation

Do not put the first slice under public .ward/ config yet.

Reasoning:

  • The repo currently documents a narrow config seam for edge KDL surfaces only.
  • Agent workflow copy is core runtime behavior, not just decoration.
  • If .ward/ overrides land before the runtime config work is settled, ward risks inventing a second config channel with different precedence, discovery, and failure semantics.

Pragmatic path:

  • Slice 1: embedded defaults only.
  • Slice 2 or follow-up after #650: add an optional override bundle source, but reuse the same IDs, typed API, parse-critical guardrails, and tests.

If a future override seam is wanted, the likely contract is a bundle directory such as .ward/copy/ that overlays only known IDs and fails loud on unknown/malformed files. But that should be a follow-up, not part of this first extraction.

Migration Order

  1. Create internal/agentcopy with embedded defaults, ID registry, renderer, and tests.
  2. Migrate one representative complex prompt: agentSeedPromptWorkflow.
  3. Migrate one representative structured issue comment: reservationCommentBody.
  4. Migrate the smaller advisor prompts: askPrompt, interactivePrompt.
  5. Migrate preflightPrompt.
  6. Migrate director prompts: directorDecidePrompt, triagePrompt.
  7. Migrate internal/reviewpanel.RefutePrompt once the shared package is proven stable.
  8. Migrate the remaining structured comments: reservationReleaseCommentBody, directorMergeDoneComment.
  9. Replace byte-fragile inline-string tests with bundle-aware golden/coverage tests.

That order gives one prompt and one comment as the proving ground before the wider sweep.

Concrete Examples

Example prompt template candidate: prompt.agent-seed.v1

Work on {{.ForgeName}} issue {{.Ref}} ({{printf "%q" .Title}}).

URL: {{.URL}}

{{.CarryIssueBanner}}

{{.CloneAnchorLine}}

{{.Action}} Then carry it end to end per your container doctrine - {{.WorkflowCarryClause}}{{if .OperatorNote}}

Operator note (added at dispatch via --details; treat it as authoritative and let it override the issue text where they conflict):
{{.OperatorNote}}{{end}}{{if .GrantedRepoClause}}

{{.GrantedRepoClause}}{{end}}{{if .SubsystemBlock}}

{{.SubsystemBlock}}{{end}}{{if .ReviewGateClause}}

{{.ReviewGateClause}}{{end}}{{if .HeadlessReflection}}

{{.HeadlessReflection}}{{end}}{{.InlineIssueBody}}

Example structured comment template candidate: comment.reservation-held.v1

Holder: container `{{.Container}}` on host `{{.Host}}`.

Reserved by `ward agent --harness {{.Harness}}` (reserved {{.ReservedAt}}). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale ({{.TTL}} TTL). `--force` overrides.

**Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh**. That is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).{{if .PreflightJustification}}

The pre-flight judged this issue **GO** for an unattended run. Its justification:

<details><summary>pre-flight read (GO)</summary>

{{.PreflightJustification}}

</details>{{end}}{{if .SeedContext}}

{{.SeedContext}}{{end}}

The Go helper would still wrap that body with the existing hidden marker and collapsedIssueComment(...) so the visible/protocol envelope stays code-owned.

Test Strategy

Add three kinds of tests:

  • ID coverage test: every exported typed renderer resolves a known template ID, and every embedded template has a typed owner.
  • Golden shape tests: representative outputs for agentSeedPromptWorkflow, reservationCommentBody, and RefutePrompt, asserting the full rendered text or a normalized golden file.
  • Protocol guard tests: assert parse-critical markers still appear exactly as required, for example WARD-OUTCOME:, WARD-RESERVATION:, hidden redispatch markers, <details> wrappers, and the fenced JSON instruction block in RefutePrompt.

This is better than only string-fragment assertions, because the whole point of the refactor is to move large prose blocks without losing behavior.

Open Questions

  • Should the bundle file format be plain .md.tmpl or raw .txt.tmpl? Recommendation: .md.tmpl, because most surfaces are Markdown comments/prompts already.
  • Should a future locale layout be defaults/en/<id>.md.tmpl from day one? Recommendation: no. Keep a flat default bundle first. Locale subdirs can come later without changing IDs.
  • Should the bundle also absorb tiny one-line stderr/status lines now? Recommendation: no. Keep slice 1 on substantial multiline agent-facing copy.

Risks

  • Protocol drift: moving parse-sensitive text into editable templates can break director/reaper/comment parsing if markers are not kept code-owned.
  • Import/cycle mistakes: putting the bundle under cmd/ward would make internal/reviewpanel awkward or impossible to wire cleanly.
  • Premature config surface: adding .ward/ overrides now could conflict with the current WARD_CONFIG_REF model and create an inconsistent second runtime-config path.
  • Template logic creep: if too much branching moves into templates, ward will trade inline strings for an untyped mini-language. Keep nontrivial decisions in Go and pass resolved clauses into templates.
  • Test brittleness during migration: many current tests assert substrings from inline prose. The migration should deliberately convert those to bundle/golden/protocol tests rather than drag old brittleness into the new seam.

Advisory Recommendation To Post Back

Start with a ward-owned embedded copy bundle under internal/agentcopy, not .ward/ yet. Use stable message IDs with typed render helpers, migrate one complex prompt plus one structured issue comment first, and keep protocol markers code-owned while moving only prose into templates. After that seam is stable, the repo can decide whether a later .ward/copy/ overlay belongs in the broader config-runtime work, but the first slice should solve centralization and customization readiness without inventing a second runtime config system.


Researched and posted automatically by ward agent advisor --harness codex (ward#179). This is one-shot research, not a carried change - verify before acting on it.

— Codex, via ward agent

### 🔎 ward agent advisor `ward agent advisor --harness codex` ran a one-shot **standard** research pass on this question: > Read the issue title, body, and comment thread below as the research brief. Identify the decisions, options, open questions, and risks, then give a clear advisory recommendation that can be posted back on the issue. > > Additional framing from the dispatcher: > Design the first implementation slice for moving agent-facing internally emitted copy into an i18n/copy-bundle style folder. Use the director scoping comment as constraints. Post a concrete implementation plan with package/directory shape, stable message ID/API approach, override/config stance, migration order, and examples for one prompt plus one structured issue comment. Do not implement code in this pass. --- **Recommendation** Move the first slice into a ward-owned embedded copy bundle, not `.ward/` yet. The clean seam is an `internal/agentcopy` package with a `defaults/` asset directory and typed render functions. That package can be imported by both `cmd/ward` and `internal/reviewpanel`, which rules out putting the logic only under `cmd/ward/*assets`. The `.ward/` override story should wait for the broader config-driven runtime work in [#650](https://forgejo.coilysiren.me/coilyco-flight-deck/ward/issues/650), because current docs explicitly keep **core agent/container runtime data** ward-owned and baked while `WARD_CONFIG_REF` only steers edge KDL surfaces. This should be framed as a **copy-bundle seam**, not full locale i18n yet. The immediate goal is customization and centralization of agent-facing generated prose. Design the bundle so locale layering can come later, but do not make locale selection, fallback chains, or translation coverage part of slice 1. **Decisions To Make Now** - **Owner/package**: use `internal/agentcopy`, with embedded defaults under `internal/agentcopy/defaults/`. - **Scope boundary**: include only ward-generated, agent-facing workflow copy. - **Lookup contract**: stable message IDs plus typed render helpers. No raw `map[string]string` lookups at call sites. - **Override stance**: baked defaults now. Defer `.ward/` operator overrides until the config-runtime seam is intentionally widened. - **Protocol boundary**: keep machine markers and parse-critical tokens code-owned constants, even when surrounding prose moves into templates. **Why This Shape Fits The Current Repo** - `internal/reviewpanel.RefutePrompt` needs the same bundle seam as `cmd/ward` prompt builders, so the copy layer must live in an importable internal package rather than `package main`. - The repo already has an asset precedent: embedded default bundles plus drift/parse tests. This proposal matches that pattern, but for copy rather than KDL. - Current docs in `docs/config-source.md` draw a hard line: configurable edge surfaces, baked core runtime. Agent workflow copy belongs on the core-runtime side for now. **First-Slice Surfaces** Include these in slice 1: - Prompts: `agentSeedPromptWorkflow`, `preflightPrompt`, `askPrompt`, `interactivePrompt`, `directorDecidePrompt`, `triagePrompt`, `internal/reviewpanel.RefutePrompt`. - Structured tracker comments: `reservationCommentBody`, `reservationReleaseCommentBody`, `directorMergeDoneComment`. Explicitly exclude for now: - Normal CLI help text and generic user-facing errors. - Generated guardfile docs and KDL text. - Low-level debug/log spam unless it is intentionally part of the agent protocol. - Agent-authored final `WARD-OUTCOME` prose, because ward mostly instructs the engineer to write that rather than synthesizing it itself. **Proposed Package/API** Use a typed API over embedded templates: - `internal/agentcopy/bundle.go` - embed/load/cache default templates. - `internal/agentcopy/ids.go` - stable message IDs. - `internal/agentcopy/prompts.go` - typed input structs and renderers for prompts. - `internal/agentcopy/comments.go` - typed input structs and renderers for tracker comments. - `internal/agentcopy/defaults/*.md.tmpl` - one template per message. - `internal/agentcopy/agentcopy_test.go` - coverage/golden tests. Suggested ID style: - `prompt.agent-seed.v1` - `prompt.preflight.v1` - `prompt.ask.v1` - `prompt.interactive.v1` - `prompt.director-decide.v1` - `prompt.triage.v1` - `prompt.review-refute.v1` - `comment.reservation-held.v1` - `comment.reservation-released.v1` - `comment.director-merge-done.v1` Suggested public API shape: - `func AgentSeed(in AgentSeedInput) string` - `func Preflight(in PreflightInput) string` - `func Ask(in AskInput) string` - `func Interactive(in InteractiveInput) string` - `func DirectorDecide(in DirectorDecideInput) string` - `func Triage(in TriageInput) string` - `func ReviewRefute(in ReviewRefuteInput) string` - `func ReservationHeld(in ReservationHeldInput) string` - `func ReservationReleased(in ReservationReleasedInput) string` - `func DirectorMergeDone(in DirectorMergeDoneInput) string` Internally those helpers can call one renderer keyed by ID, but callers should never pass free-form IDs or untyped `map[string]any` data. **Important Constraint: keep protocol tokens out of operator-editable prose** Several surfaces are parse-sensitive today. The copy seam must not let later customization silently break protocol behavior. Keep these code-owned: - `WARD-OUTCOME:` marker line semantics. - `WARD-RESERVATION:` visible marker lines. - Hidden markers like `<!-- ward-needs-redispatch -->` and reservation markers. - Required fenced JSON instructions for `RefutePrompt`. - Any parser-anchored headings/summary blocks if tests currently depend on them. A good rule is: **templates own prose, code owns protocol**. Templates may interpolate code-owned constants, but the constants themselves should not move into freely editable text bundles. **Override / Config Recommendation** Do **not** put the first slice under public `.ward/` config yet. Reasoning: - The repo currently documents a narrow config seam for edge KDL surfaces only. - Agent workflow copy is core runtime behavior, not just decoration. - If `.ward/` overrides land before the runtime config work is settled, ward risks inventing a second config channel with different precedence, discovery, and failure semantics. Pragmatic path: - Slice 1: embedded defaults only. - Slice 2 or follow-up after `#650`: add an optional override bundle source, but reuse the same IDs, typed API, parse-critical guardrails, and tests. If a future override seam is wanted, the likely contract is a bundle directory such as `.ward/copy/` that overlays only known IDs and fails loud on unknown/malformed files. But that should be a follow-up, not part of this first extraction. **Migration Order** 1. Create `internal/agentcopy` with embedded defaults, ID registry, renderer, and tests. 2. Migrate one representative complex prompt: `agentSeedPromptWorkflow`. 3. Migrate one representative structured issue comment: `reservationCommentBody`. 4. Migrate the smaller advisor prompts: `askPrompt`, `interactivePrompt`. 5. Migrate `preflightPrompt`. 6. Migrate director prompts: `directorDecidePrompt`, `triagePrompt`. 7. Migrate `internal/reviewpanel.RefutePrompt` once the shared package is proven stable. 8. Migrate the remaining structured comments: `reservationReleaseCommentBody`, `directorMergeDoneComment`. 9. Replace byte-fragile inline-string tests with bundle-aware golden/coverage tests. That order gives one prompt and one comment as the proving ground before the wider sweep. **Concrete Examples** Example prompt template candidate: `prompt.agent-seed.v1` ```md Work on {{.ForgeName}} issue {{.Ref}} ({{printf "%q" .Title}}). URL: {{.URL}} {{.CarryIssueBanner}} {{.CloneAnchorLine}} {{.Action}} Then carry it end to end per your container doctrine - {{.WorkflowCarryClause}}{{if .OperatorNote}} Operator note (added at dispatch via --details; treat it as authoritative and let it override the issue text where they conflict): {{.OperatorNote}}{{end}}{{if .GrantedRepoClause}} {{.GrantedRepoClause}}{{end}}{{if .SubsystemBlock}} {{.SubsystemBlock}}{{end}}{{if .ReviewGateClause}} {{.ReviewGateClause}}{{end}}{{if .HeadlessReflection}} {{.HeadlessReflection}}{{end}}{{.InlineIssueBody}} ``` Example structured comment template candidate: `comment.reservation-held.v1` ```md Holder: container `{{.Container}}` on host `{{.Host}}`. Reserved by `ward agent --harness {{.Harness}}` (reserved {{.ReservedAt}}). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale ({{.TTL}} TTL). `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh**. That is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).{{if .PreflightJustification}} The pre-flight judged this issue **GO** for an unattended run. Its justification: <details><summary>pre-flight read (GO)</summary> {{.PreflightJustification}} </details>{{end}}{{if .SeedContext}} {{.SeedContext}}{{end}} ``` The Go helper would still wrap that body with the existing hidden marker and `collapsedIssueComment(...)` so the visible/protocol envelope stays code-owned. **Test Strategy** Add three kinds of tests: - **ID coverage test**: every exported typed renderer resolves a known template ID, and every embedded template has a typed owner. - **Golden shape tests**: representative outputs for `agentSeedPromptWorkflow`, `reservationCommentBody`, and `RefutePrompt`, asserting the full rendered text or a normalized golden file. - **Protocol guard tests**: assert parse-critical markers still appear exactly as required, for example `WARD-OUTCOME:`, `WARD-RESERVATION:`, hidden redispatch markers, `<details>` wrappers, and the fenced JSON instruction block in `RefutePrompt`. This is better than only string-fragment assertions, because the whole point of the refactor is to move large prose blocks without losing behavior. **Open Questions** - Should the bundle file format be plain `.md.tmpl` or raw `.txt.tmpl`? Recommendation: `.md.tmpl`, because most surfaces are Markdown comments/prompts already. - Should a future locale layout be `defaults/en/<id>.md.tmpl` from day one? Recommendation: no. Keep a flat default bundle first. Locale subdirs can come later without changing IDs. - Should the bundle also absorb tiny one-line stderr/status lines now? Recommendation: no. Keep slice 1 on substantial multiline agent-facing copy. **Risks** - **Protocol drift**: moving parse-sensitive text into editable templates can break director/reaper/comment parsing if markers are not kept code-owned. - **Import/cycle mistakes**: putting the bundle under `cmd/ward` would make `internal/reviewpanel` awkward or impossible to wire cleanly. - **Premature config surface**: adding `.ward/` overrides now could conflict with the current `WARD_CONFIG_REF` model and create an inconsistent second runtime-config path. - **Template logic creep**: if too much branching moves into templates, ward will trade inline strings for an untyped mini-language. Keep nontrivial decisions in Go and pass resolved clauses into templates. - **Test brittleness during migration**: many current tests assert substrings from inline prose. The migration should deliberately convert those to bundle/golden/protocol tests rather than drag old brittleness into the new seam. **Advisory Recommendation To Post Back** Start with a ward-owned embedded copy bundle under `internal/agentcopy`, not `.ward/` yet. Use stable message IDs with typed render helpers, migrate one complex prompt plus one structured issue comment first, and keep protocol markers code-owned while moving only prose into templates. After that seam is stable, the repo can decide whether a later `.ward/copy/` overlay belongs in the broader config-runtime work, but the first slice should solve centralization and customization readiness without inventing a second runtime config system. --- Researched and posted automatically by `ward agent advisor --harness codex` (ward#179). This is one-shot research, not a carried change - verify before acting on it. <!-- ward-agent-reply --> <!-- ward-agent-signature --> — Codex, via `ward agent`
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#632
No description provided.