fix: respect conversation language across all harnesses - #353
Conversation
|
@raj-jain-aws This is the v2 rebuild of #290 (now closed), reshaped onto the current |
|
Same on the v2 branch with Korean intents. Across 4 independent dry-run fixtures (different intent shapes — greenfield SaaS, a feature add on an existing service, a consumer-app MVP, a local-only full-stack service) the persona-authored artifacts under each intent's Glad to see this PR — happy to test it against the four Korean fixtures once it merges. |
5b12844 to
c53929a
Compare
Add a conversation-language rule to the Mandated section of core/memory/org.md so the framework default — inherited by all four harnesses (claude, codex, kiro, kiro-ide) through the shared memory layer — instructs agents to write every human-readable artifact in the language the human last used. The rule states a principle rather than an enumerated allow-list: anything a person reads or reviews (requirements, stories, plans, specs, reviews, questions, discovered practices, discovered/affirmed rules, evidence, rationale) follows the conversation language, and only machine-parsed/verified content stays English (stable IDs, enum values, code, paths, mermaid keywords, template section headings matched by the required-sections sensor, and machine-read state files). Rule-layer artifacts following an ALWAYS/NEVER directive shape are written in the human's language too; the marker keyword may stay. Verified on the kiro harness end-to-end: ideation through operation artifacts render in Japanese while IDs, code, tool names, template headings, and state/audit files stay English. Bumps version 2.1.1 -> 2.1.2 with matching README badge and CHANGELOG.
|
Update (2026-06-27): Rebased and reworked for the v2-unified architecture (introduced 2026-06-15 in
|
c53929a to
445fd88
Compare
Add a conversation-language rule to the Mandated section of core/memory/org.md so the framework default — inherited by all four harnesses (claude, codex, kiro, kiro-ide) through the shared memory layer — instructs agents to write every human-readable artifact in the language the human last used. The rule states a principle rather than an enumerated allow-list: anything a person reads or reviews (requirements, stories, plans, specs, reviews, questions, discovered practices, discovered/affirmed rules, evidence, rationale) follows the conversation language, and only machine-parsed/verified content stays English (stable IDs, enum values, code, paths, mermaid keywords, template section headings matched by the required-sections sensor, and machine-read state files). Rule-layer artifacts following an ALWAYS/NEVER directive shape are written in the human's language too; the marker keyword may stay. Verified on the kiro harness end-to-end: ideation through operation artifacts render in Japanese while IDs, code, tool names, template headings, and state/audit files stay English. Bumps version 2.1.1 -> 2.1.2 with matching README badge and CHANGELOG.
Add a conversation-language rule to the Mandated section of core/memory/org.md so the framework default — inherited by all four harnesses (claude, codex, kiro, kiro-ide) through the shared memory layer — instructs agents to write every human-readable artifact in the language the human last used. The rule states a principle rather than an enumerated allow-list: anything a person reads or reviews (requirements, stories, plans, specs, reviews, questions, discovered practices, discovered/affirmed rules, evidence, rationale) follows the conversation language, and only machine-parsed/verified content stays English (stable IDs, enum values, code, paths, mermaid keywords, template section headings matched by the required-sections sensor, and machine-read state files). Rule-layer artifacts following an ALWAYS/NEVER directive shape are written in the human's language too; the marker keyword may stay. Verified on the kiro harness end-to-end: ideation through operation artifacts render in Japanese while IDs, code, tool names, template headings, and state/audit files stay English. Bumps version 2.1.1 -> 2.1.2 with matching README badge and CHANGELOG.
445fd88 to
d94506d
Compare
Add a conversation-language rule to the Mandated section of core/memory/org.md so the framework default — inherited by all four harnesses (claude, codex, kiro, kiro-ide) through the shared memory layer — instructs agents to write every human-readable artifact in the language the human last used. The rule states a principle rather than an enumerated allow-list: anything a person reads or reviews (requirements, stories, plans, specs, reviews, questions, discovered practices, discovered/affirmed rules, evidence, rationale) follows the conversation language, and only machine-parsed/verified content stays English (stable IDs, enum values, code, paths, mermaid keywords, template section headings matched by the required-sections sensor, and machine-read state files). Rule-layer artifacts following an ALWAYS/NEVER directive shape are written in the human's language too; the marker keyword may stay. Verified on the kiro harness end-to-end: ideation through operation artifacts render in Japanese while IDs, code, tool names, template headings, and state/audit files stay English. Bumps version 2.1.4 -> 2.1.5 with matching README badge and CHANGELOG.
d94506d to
04d48be
Compare
|
Update (2026-07-01): Rebased onto the latest |
6f75d4c to
b0fe356
Compare
|
Rebased onto current v2 ( |
apackeer
left a comment
There was a problem hiding this comment.
Thank you for continuing to rework this across the v2 changes. The underlying issue is valid, and core/memory/org.md is the right harness-neutral source. I am requesting changes before the second-pass review:
-
Please replace “the human’s most recent message” with a stable conversation-language rule. A normal workflow turn may contain only
Approve,Looks correct, an option number, pasted code, or an English error. Retain the established conversation language unless the human explicitly asks to change it, and define the source delegated agents and reviewers use to resolve that language. -
Please scope the English exception to machine-parsed syntax rather than whole “tool-read” files. Several Markdown artifacts mix localized prose with fixed tokens. Preserve exact protocol tokens and parsed islands such as
[Answer]:, source tags and required headings, YAML keys (units,name,kind,depends_on),## Review,READY/NOT-READY, IDs, enums, paths, code, Mermaid syntax, and template headings; localize the surrounding human-readable prose. -
Please rebase onto current
v2, regenerate alldist/projections, and add regression coverage for language continuity, delegated execution, and preservation of machine tokens. The current revision has no attached CI checks, so please also rerun the relevant packaging, memory-seed, steering-delivery, and version-sync tests. -
This is user-visible, so please add the required patch-version bump, README badge, and CHANGELOG entry. The release note should explain that fresh installs receive the new framework rule, while existing non-default spaces must merge it into each
aidlc/spaces/<space>/memory/org.mdand start a fresh session. Runtime self-healing intentionally does not overwrite an existing memory tree.
The direction is sound; these changes are needed to make the behavior stable across the current v2 execution and upgrade paths.
49f074d to
ecf8049
Compare
|
Thanks — all four addressed. Two mistakes of my own turned up under point 1, so those first. 1. Resolution order and stabilityWhat changed.
My earlier version named Worse, Routing the switch through the learnings write path was wrong too. Delivery is verified on all five harnesses: dispatch hook on Claude/Codex/opencode, agent-resource preload on Kiro CLI (all 15 configs carry the memory glob), always-included steering on Kiro IDE. 2. The English exceptionWhat changed.
Enumerating wasn't enough on its own. Grepping the engine turned up the exact comparisons above. One correction. I claimed The run produced one more clause worth adding: glossing a literal when you show it to a human is fine, what you write to the file is the literal. The conductor showed 3. Rebase and testsRebased onto New file
Why one line matters: I broke each contract on purpose to confirm the tests red. Runs (serial; the suite is flaky under
The new file is registered in the 4. Version2.5.37 → 2.5.38, badge, Upgrade path: fresh installs receive the rules with the seeded Verified on a real runkiro,
Found outside this PR's scope
Happy to open issues for either. LimitationIt is a prose rule, so the tests pin the text, its shape and its delivery — not that a model writes in the resolved language. Making that deterministic needs a real field on |
leandrodamascena
left a comment
There was a problem hiding this comment.
Thank you for the thorough rework. The previous review points are addressed: language resolution is stable, delegated agents receive the rule layer, machine-parsed tokens remain exact, and the upgrade path is documented.
I also verified the focused suite locally: 105 tests / 1,013 assertions passed, along with typecheck, package parity, and Biome.
No blocking findings from the second pass. The remaining limitation, appropriately documented, is that language compliance is model-directed rather than deterministically enforced.
|
One remaining blocking issue: the resolution order conflicts with the promised immediate language switch.
That means a normal sequence can fail:
The learning writer appends rules rather than replacing them, and the runtime rule model is strictly additive, so persistence does not reliably resolve this either; it can leave both language rules present. Please make the current brief authoritative for delegated work, with persisted memory as a fallback, or introduce a deterministic single-current-language record/replacement rule. A regression case should cover an existing persisted language followed by an explicit switch and a delegated stage. |
|
Thank you for the detailed feedback — the ordering conflict was real, and chasing it turned up a second defect in the same rule that I fixed alongside it. The fixThe first two sources are inverted:
Your append-only point needed its own clause. Confirmed: Your scenario also exposed a gap indirectly: the precedence list addresses delegated agents and reviewers, so nothing bound the orchestrator, and your step 3 was an assumption the rule did not guarantee. A persisted rule now never outranks the brief or a later explicit switch request, which binds both sides. Verified livekiro,
The second defectThe stability rule's main clause was an imperative addressed to the agent — "record the switch as a single-line rule under Now the ritual is the ONLY sanctioned write path, a direct memory edit is forbidden outright, and that rationalisation is closed. A declined persistence is stated to be a correct outcome, because the brief carries the language anyway. The run also showed persistence failing to land twice on its own ( Tests
To be precise about what they prove: they pin wording and delivery, not that a model then writes in the resolved language. The run is the evidence for behaviour; the tests are the evidence the contract cannot silently regress. That limitation is real and I have not closed it — closing it needs a field on VersionStill 2.5.38 — upstream |
Two corrections to my previous comment, and the tests that came out of themRe-reading my own claims against the source turned up two that were wrong. Both are now fixed in 1.
|
|
Verified the new work through
Two test limitations are also worth tightening during that pass:
Local verification on the current PR head:
So the precedence fix is substantively in the right direction, but I am keeping this blocked on the overbroad memory-write rule and the required rebase/version conflict resolution. |
809e631 to
a128159
Compare
|
Thank you for the review on 1. Write-path rule scope. Scoped to both routes you offered. The clause now reads 2. Rebase and version. Rebased onto 3. The switch regression injecting the brief line. Your point stands — that the conductor observes an explicit switch and regenerates the line is still unproven, and the new 4. c2 inspecting Kiro IDE's CLI-only surface. Correct. The new Verification
|
Human-readable artifacts followed the skill files' English instead of the workflow's conversation language (awslabs#288). Adds four `## Mandated` rules to the harness-neutral rule layer in `core/memory/org.md`, so one authored source reaches all five harnesses through `bun scripts/package.ts`. - resolution: the `Conversation language:` line the orchestrator must state in every delegated brief is AUTHORITATIVE, because it is regenerated from the live conversation on every dispatch and can never be staler than a rule on disk. A persisted rule in `project.md`/`team.md` is the fallback, then the verbatim `**Project**` description, then any handed artifact. The brief line is mandatory because every file-reading source can be empty: on greenfield, a stage whose `consumes` are all `conditional_on: brownfield` reaches its lead with no upstream artifact at all. - stability: a turn with no language signal (`Approve`, an option number, pasted code, a quoted error, a bare path) never switches the language. Only an explicit human request does, and it takes effect immediately. - what to localize / preserved tokens: the English exception is scoped to machine-parsed tokens rather than whole tool-read files, with the literals the engine compares exactly named (`[Answer]:`, `A. Accept assumptions`, `None.`, `AGREE:`/`OBJECT:`, `**Collaborator:** <agent-slug>`, `READY`). Persisting a language switch goes only through the §13 learnings ritual and never through a direct agent edit; the prohibition is scoped to that so it does not countermand the deterministic writers a stage invokes by contract (`aidlc-state.ts practices-promote` owns the stamped `## Mandated` / `## Forbidden` rules and the five replaced `team.md` sections, not the `## Corrections` language record). Coverage: `tests/unit/t266-conversation-language-rule.test.ts`, 16 tests / 504 assertions. - the four rules present as a closed set under `## Mandated` with nothing countermanding them, one physical line each so the claim-sources sensor can quote them, byte parity across all ten shipped `org.md` projections - delegate delivery: the dispatch-rules rewrite carries all four rules, and every harness ships a delegate-facing surface - conductor delivery: every harness's `memoryInclude` seam reaches the shipped `org.md` in that harness's own syntax — Claude's `@`-import, the Codex `AIDLC_RULES_DIR`, Kiro IDE's always-included steering `#[[file:...]]` reference (its real binding surface, not the CLI-only agent JSON), the Kiro CLI conductor's resource glob, and opencode's `instructions` glob — with an exhaustive switch so a new harness cannot ship an unproven include - the brief outranks persisted memory, asserted position-independently; the two-rule tie-break exercised; and the explicit-switch obligation shown to bind the orchestrator on every subsequent dispatch rather than only the delegate - a clause-bounded scan proving no rule claims an unscoped write monopoly over the active-space memory tree Known limitation: the rules are prose, so the tests pin their text, shape, and delivery — not that a model then writes in the resolved language. Making that deterministic would mean the engine rather than the model producing the line, which is a change to the dispatch path rather than to the rule layer and out of scope here. Upgrade: fresh installs receive the rules with their seeded `default` space. An existing workspace keeps its own memory tree, because runtime self-healing intentionally does not overwrite one, so merge the four rules into each `aidlc/spaces/<space>/memory/org.md` by hand and start a fresh session for them to load.
a128159 to
4d5524d
Compare
|
Correction to the version above: #689 took 2.5.43 while I was pushing, so this is rebased onto |
|
Thanks for the latest update. The two prior blockers are addressed: the write-path rule is now scoped so it no longer countermanded This is close. I see one remaining policy ambiguity to resolve, with two manifestations:
Small test follow-up while touching t266: add I am not asking to expand this into deterministic language enforcement, tool-generated audit localization, or a broader architecture change. Once the session boundary and persisted fallback are made internally consistent and those focused assertions are added, I have no other blocker from this pass. |
…e precedence Resolves the one remaining policy ambiguity in the conversation-language rule layer, in both places it surfaced. Session boundary. The stability rule promised continuity "for the whole workflow", which the engine cannot deliver: an explicitly switched language the human declines to persist is carried only by the `Conversation language:` line, and the resume context injected at session start carries scope, phase, stage, status, agent and next action but NO language. The guarantee is now scoped to the session — still covering every stage, dispatch, reviewer pass and gate inside it — and the fresh-session path is defined and total: the persisted rule, else the artifacts the workflow already produced, else the verbatim initial description, and it ASKS the human rather than defaulting to English when all are silent. Re-resolving is explicitly not a switch, so it never enters the §13 write path. Cross-file precedence. The persisted fallback grouped `project.md` and `team.md` while its LAST-one-wins tie-break covered duplicates within one file only, so a newer team-level rule could face a staler project-level one with no defined winner — and position cannot settle it, because the runtime chain concatenates `org → team → project → phase`, delivering team BEFORE project regardless of write order. Persistence is now project-only (`NEVER in team.md`), `project.md` always outranks a `team.md` default by stated rule rather than by position, and the tie-break is bounded to `project.md`. t266 gains three tests (16 → 19, 504 → 564 assertions): the session-scoped guarantee with its total fallback, the project-only precedence with the concatenation order named, and `e3` — the split-team/project delivery regression, which dispatches with no brief language line (the only case the persisted fallback decides), asserts both files reach the delegate, pins that team really does precede project in the bundle, and pins that the precedence clause arrives with them. `REQUIRED_TOKENS` gains `Initial description:` and `Workflow-selected scope:`. Each new assertion was confirmed red by breaking the contract it pins, including reverting e3 to the single-file shape. Version held at 2.5.44 (unreleased upstream, which is at 2.5.43); the CHANGELOG entry for it is updated rather than a sibling added for the same feature.
|
Thank you for reading this so carefully, and sorry for the extra rounds. Both points came down to the same thing you spotted — I had written promises the engine doesn't keep. Fixed in The guarantee is session-scoped now, and I made the fresh-session path explicit rather than leaving it to inference: re-resolve before the first dispatch, from the persisted rule, else the artifacts already written, else the initial description — and if all of them are silent, ask instead of assuming English. I also spelled out that re-resolving isn't a switch, so it can't drift into the §13 write path. Persistence is project-only, and
|
apackeer
left a comment
There was a problem hiding this comment.
Verified through b0f0cb77. The remaining review points are resolved: the guarantee is now explicitly session-scoped with a total fresh-session fallback; language-switch persistence is project-only with stated project-over-team precedence; the split team.md/project.md case is covered; and the two exact source-register prefixes are pinned.
Local verification:
- focused package/memory/steering/version/language suite: 136 pass / 0 fail
bun run check: exit 0 (all five package projections, three TypeScript configs, and Biome)
No blocking findings. The documented model-directed limitation remains appropriately scoped.
|
@apackeer @leandrodamascena I see the CI workflow is currently waiting for a maintainer's approval to run. |
Summary
Human-readable AI-DLC artifacts follow the workflow's conversation language instead of defaulting to English. The behavior is added as four rules in the
## Mandatedsection ofcore/memory/org.md— the harness-neutral rule layer — so one authored source propagates to all five harnesses (claude, codex, kiro, kiro-ide, opencode) throughbun scripts/package.ts.Fixes #288
Changes
Four rules, each a single physical line so the claim-sources sensor can quote one verbatim:
Conversation language — resolutionConversation language:line the orchestrator must state in every brief (authoritative), then an explicit rule inproject.md— project-only, and always outranking ateam.mddefault by stated rule rather than by bundle position — then the verbatim**Project**description inaidlc-state.md, then any artifact the agent was handed. The brief ranks first because it is regenerated from the live conversation on every dispatch, so it can never be staler than a rule on disk — and it is mandatory because every file-reading source can be empty (a greenfield run of a stage whoseconsumesare allconditional_on: brownfieldreaches its lead with no upstream artifact at all).Conversation language — stabilityApprove,Looks correct, an option letter or number, pasted code, a quoted error or stack trace, a bare path — never switches it. Only an explicit human request does, and it takes effect immediately; recording it under## Correctionsinproject.mdis durability, not activation, so nothing waits on the human-gated learnings ritual — which is the only sanctioned write path for persisting a language switch, leaving the deterministic writers a stage invokes by contract (such asaidlc-state.ts practices-promote) untouched.Conversation language — what to localizeALWAYS …/NEVER ….Conversation language — preserved tokens[Answer]:, the mandatoryX. Other (please specify), theA. Accept assumptions/B. Convert to follow-up questionsconfirmation answers the engine compares literally, theNone./Nonesentinels,AGREE:/OBJECT:, the**Collaborator:** <agent-slug>first line, the[desc]/[scope]/[assumption]/[Q<n>]/[memory:M<n>]source-register tags, template H2 headings the sensors match verbatim,READY/NOT-READY, fenced YAML keys and enums,aidlc-state.mdand audit-shard field labels, stable IDs, code, paths, mermaid keywords, and cross-references.Diff: 21 files, +1230 / -29 —
core/memory/org.md, 10 regenerateddist/projections (5 harnesses × memory-seed + workspace-shell), 6aidlc-version.tscopies, README badge, CHANGELOG, the newtests/unit/t266-conversation-language-rule.test.ts, and its coverage-ratchet registration.Review feedback
All four review rounds are addressed.
stabilityrule enumerates the no-signal turn shapes explicitly. Theresolutionrule defines the four-source order, with the mandatory brief line first so a subagent that never sees the conversation always has a source that exists.preserved tokensrule replaces the file-level exception with a principle plus the named token list above. Prose surrounding a preserved token is localized, and a Markdown artifact is no longer treated as English just because a tool parses part of it.v2, regeneratedist/, add regression coverage, rerun packaging / memory-seed / steering-delivery / version-synca795583a(0 commits behindupstream/v2). All 10dist/projections regenerated;bun scripts/package.ts --checkis clean for all five harnesses. Coverage added as t266 (19 tests / 564 assertions) — see Test Plan.## [2.5.44] - 2026-08-06heading added with a bold Upgrade: note stating that fresh installs receive the rules with their seededdefaultspace while an existing workspace must merge the four rules into eachaidlc/spaces/<space>/memory/org.mdby hand and start a fresh session, because runtime self-healing intentionally does not overwrite an existing memory tree.The second round raised three follow-ups — a persisted Japanese rule surviving a switch back to English, an explicit switch taking effect before the learnings ritual, and a delegated stage inheriting the language — addressed in this revision.
The third round raised two blockers — the write-path rule countermanding
practices-discovery's required Step 7 (aidlc-state.ts practices-promote), and another rebase/re-bump — both addressed here, together with the two test limitations it flagged:c3for Kiro IDE's real delivery surface, ande2for the orchestrator-side switch obligation.The fourth round raised one policy ambiguity in two places — the guarantee claiming the whole workflow while an unpersisted switch survives only the session, and the persisted fallback grouping
project.mdwithteam.mdwhile its tie-break covered duplicates within one file only — both addressed here with the narrower option it recommended, together with the split-team/project regression (e3) and the twoREQUIRED_TOKENSprefixes it asked for.User experience
Before: agents default to English for every artifact regardless of the conversation language. Non-English speakers must repeatedly ask for translation, and a delegated subagent that never saw the conversation has nothing to resolve the language from.
After: human-readable artifacts are written in the resolved conversation language; only machine-parsed tokens stay English.
Approvemid-workflow does not flip the language to English. An explicit switch takes effect on the next dispatch whether or not the human accepts the persistence prompt, and a resumed session re-resolves the language instead of quietly reverting to English.Verified end to end on the kiro harness: ideation through operation artifacts render in Japanese while IDs, code, tool names, template headings, and state/audit files stay English.
Test Plan
tests/unit/t266-conversation-language-rule.test.ts— 19 tests / 564 assertions, registered in the coverage ratchet:## Mandatedin the authored source; every shipped harness carriesorg.mdbyte-for-byteentries.includes(rule)requires an exact match after the line-wise reduce)core/hooks/aidlc-dispatch-rules.ts, an exact match on the Kiro memory glob, and the glob resolved to theorg.mdthat actually ships the rules); and every harness's conductor-facingmemoryIncludeseam reaches that sameorg.mdin its own syntax — Claude's@-import, the CodexAIDLC_RULES_DIR, Kiro IDE's always-included steering#[[file:…]]reference (its real binding surface, not the CLI-only agent JSON), the Kiro CLI conductor's resource glob, and opencode'sinstructions— with an exhaustive switch so a new harness cannot ship an unproven include## Mandatedrule can countermand the four (negative space — appending "ALWAYS write every artifact in English; the rules above are advisory only" previously left the whole suite green while inverting the feature)project.mdoutranks ateam.mddefault by stated rule, and the tie-break is bounded toproject.md. The supersededholds for the whole workflowand`project.md` or `team.md` — the FALLBACKshapes are gone from all ten projectionsteam.md, the switch inproject.md, dispatched with no brief language line (the only case the persisted fallback decides). Both files reach the delegate, the bundle is pinned to deliver team before project — so the stated precedence is load-bearing rather than decorative, and a positional reading would pick the stale rule — and the precedence clause is pinned to arrive in the same prompt## Mandatedrule claims an unscoped write monopoly over the active-space memory tree, so the prohibition cannot be re-broadened by an appended sentenceFocused suite (
t145-packaging-parity,t-memory-seed,t150-codex-packaging,t237-linter-sensor-version-pin,t240-opencode-packaging,t248-steering-content-delivery,t266,t68-version-changelog-sync,gen-coverage-registry): 136 pass / 0 fail / 2314 assertions.bun run check: exit 0 —package --checkclean on all five harnesses,tsc --noEmitacross all three tsconfigs,biome check --error-on-warningsover 571 files.bun tests/run-tests.ts --ci --no-llm: 299 test files, 6195 assertions, 2 failed files / 3 failed assertions —t248-codekb-scope-diffandt163-reaper-steal-race. Both confirmed pre-existing: agit worktreeon cleanupstream/v2fails 3 files / 5 assertions, so this set is a subset of the base.Known limitation
The rules are prose, so the tests pin their text, shape, and delivery — not that the model actually writes in the resolved language. Making that deterministic would mean the engine rather than the model producing the
Conversation language:line, which is a change to the dispatch path rather than to the rule layer and out of scope here.Checklist
Acknowledgment
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.