instructions: the agent speaks the KB language in chat - AGENTS.md § Conversation language, and instructions sync compiles the language tag into every published SKILL.md (#116); 10.0.0-beta.9
CI / verify (push) Successful in 8m6s
CI / pwsh (push) Successful in 2m50s
Release / release (push) Successful in 33s
Release / wiki-mirror (push) Skipped

Files changed:
- AGENTS.md
- CHANGES.md
- VERSION
- docs/explanation/language-boundaries.md
- docs/reference/commands/types-instructions-and-docs.md
- instructions/CONTRACT.md
- instructions/dev/stack-build/SKILL.md
- instructions/dev/stack-close/SKILL.md
- instructions/dev/stack-dev/SKILL.md
- kb/CONVENTIONS.md
- kb/CONVENTIONS.md.template
- tools/CONTRACT.md
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/instructions_cmd.py
- tools/chemenu/tests/test_doctor.py
- tools/chemenu/tests/test_instructions_cmd.py

Co-Authored-By: Claude Code <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
This commit is contained in:
torbenandClaude Code committed 2026-10-12 06:57:51 +02:00
1 parent c06bde2e95
commit 0f0a5799fd
16 files changed
+385 -54

No files matched your search

+16
View File
@@ -461,6 +461,22 @@ def test_unpublished_skills_fail(instance):
assert _status(checks, "skills") == "FAIL"
def test_a_changed_conversation_language_fails_skills_and_names_the_block(instance):
(config.KB_DIR / conventions.CONVENTIONS_FILENAME).write_text(
"---\nlanguage: de\nprofile: none\nsections:\n links: Relationships\n"
" footnotes: Footnotes\n---\n\n# conventions\n",
encoding="utf-8",
)
conventions.reset_cache()
checks = doctor.run_doctor()
assert _status(checks, "skills") == "FAIL"
assert "2 published copy/copies drifted" in _detail(checks, "skills")
assert "language block is for `en`, conventions say `de`" in _detail(checks, "skills")
instructions_cmd.sync(force=False)
assert _status(doctor.run_doctor(), "skills") == "OK"
def test_no_author_fails(instance, monkeypatch):
monkeypatch.delenv("WIKI_AUTHOR", raising=False)
monkeypatch.setattr(config, "default_author", lambda: None)
+179 -1
View File
@@ -10,7 +10,7 @@ from pathlib import Path
import pytest
import typer
from chemenu import config
from chemenu import config, conventions
from chemenu.tests.conftest import use_shipped_type_specs
from chemenu.commands import instructions_cmd
@@ -230,6 +230,184 @@ def test_drift_detects_missing_edited_and_extra(layer):
assert "extra" in instructions_cmd.drift(source, target)
# --- conversation language block --------------------------------------------
def _declare_language(root: Path, tag: str | None) -> None:
path = root / "kb" / "CONVENTIONS.md"
if tag is None:
path.unlink(missing_ok=True)
else:
path.write_text(f"---\nlanguage: {tag}\nprofile: none\n---\n\n# conventions\n", encoding="utf-8")
conventions.reset_cache()
def _rich_skill(layer) -> Path:
"""A skill whose frontmatter has a flag and a value holding `---`, plus a sibling file."""
source = layer / "instructions" / "wiki-demo"
(source / "SKILL.md").write_text(
"---\nname: wiki-demo\ndescription: Demo --- skill.\ndisable-model-invocation: true\n---\n\n# Demo\n\nSee gates.md.\n",
encoding="utf-8",
)
(source / "reference.md").write_text("# reference\n", encoding="utf-8")
return source
def _block_lines(text: str) -> list[str]:
return [line for line in text.splitlines() if line.startswith("> **Conversation language:")]
def test_sync_writes_the_language_block_directly_under_the_frontmatter_in_both_targets(layer):
source = _rich_skill(layer)
_declare_language(layer, "de")
instructions_cmd.sync(force=False)
source_text = (source / "SKILL.md").read_text(encoding="utf-8")
frontmatter_end = source_text.index("---\n\n# Demo") + len("---\n")
for harness in (".agents", ".claude"):
copy = _skill_copy(layer, harness)
text = (copy / "SKILL.md").read_text(encoding="utf-8")
assert len(_block_lines(text)) == 1
assert text[:frontmatter_end] == source_text[:frontmatter_end]
after = text[frontmatter_end:].split("\n")
assert after[0] == "" and after[1].startswith("> **Conversation language: `de`**")
assert "`AGENTS.md` § Conversation language" in after[1]
assert text.replace(after[1] + "\n\n", "", 1) == source_text
assert (copy / "reference.md").read_bytes() == (source / "reference.md").read_bytes()
assert instructions_cmd.drift(source, _skill_copy(layer, ".agents")) is None
assert instructions_cmd.drift(source, _skill_copy(layer, ".claude")) is None
def test_the_block_is_the_tag_and_never_a_language_name(layer):
_declare_language(layer, "pt-BR")
instructions_cmd.sync(force=False)
text = (_skill_copy(layer, ".claude") / "SKILL.md").read_text(encoding="utf-8")
assert "`pt-BR`" in _block_lines(text)[0]
assert "Portuguese" not in text
def test_a_second_sync_is_byte_identical_and_adds_no_second_block(layer):
_declare_language(layer, "de")
instructions_cmd.sync(force=False)
first = (_skill_copy(layer, ".agents") / "SKILL.md").read_bytes()
instructions_cmd.sync(force=False)
second = (_skill_copy(layer, ".agents") / "SKILL.md").read_bytes()
assert first == second
assert len(_block_lines(second.decode("utf-8"))) == 1
def test_without_a_declared_language_every_copy_is_the_source(layer, capsys):
source = _rich_skill(layer)
_declare_language(layer, None)
instructions_cmd.sync(force=False)
assert "no language declared" in " ".join(capsys.readouterr().out.split())
for harness in (".agents", ".claude"):
copy = _skill_copy(layer, harness)
assert (copy / "SKILL.md").read_bytes() == (source / "SKILL.md").read_bytes()
assert instructions_cmd.drift(source, copy) is None
def test_sync_names_the_language_it_stamped(layer, capsys):
_declare_language(layer, "de")
instructions_cmd.sync(force=False)
assert "conversation language `de`" in " ".join(capsys.readouterr().out.split())
def test_a_skill_without_closed_frontmatter_is_copied_unchanged(layer):
source = layer / "instructions" / "wiki-demo"
(source / "SKILL.md").write_text("---\nname: wiki-demo\n# never closed\n", encoding="utf-8")
_declare_language(layer, "de")
instructions_cmd.sync(force=False)
assert (_skill_copy(layer, ".claude") / "SKILL.md").read_bytes() == (source / "SKILL.md").read_bytes()
def test_a_crlf_skill_keeps_its_line_endings(layer):
source = layer / "instructions" / "wiki-demo"
(source / "SKILL.md").write_bytes(b"---\r\nname: wiki-demo\r\ndescription: Demo.\r\n---\r\n\r\n# Demo\r\n")
_declare_language(layer, "de")
instructions_cmd.sync(force=False)
data = (_skill_copy(layer, ".claude") / "SKILL.md").read_bytes()
assert data.count(b"\n") == data.count(b"\r\n")
assert instructions_cmd.drift(source, _skill_copy(layer, ".claude")) is None
def test_changing_the_language_after_sync_is_drift_that_names_the_block(layer):
source = layer / "instructions" / "wiki-demo"
_declare_language(layer, "en")
instructions_cmd.sync(force=False)
_declare_language(layer, "de")
for harness in (".agents", ".claude"):
assert instructions_cmd.drift(source, _skill_copy(layer, harness)) == (
"language block is for `en`, conventions say `de`"
)
instructions_cmd.sync(force=False)
assert instructions_cmd.drift(source, _skill_copy(layer, ".agents")) is None
def test_declaring_a_language_after_a_plain_sync_is_drift_that_names_the_block(layer):
source = layer / "instructions" / "wiki-demo"
instructions_cmd.sync(force=False)
_declare_language(layer, "de")
assert instructions_cmd.drift(source, _skill_copy(layer, ".agents")) == (
"language block missing, conventions say `de`"
)
def test_dropping_the_language_after_sync_is_drift_that_names_the_block(layer):
source = layer / "instructions" / "wiki-demo"
_declare_language(layer, "de")
instructions_cmd.sync(force=False)
_declare_language(layer, None)
assert instructions_cmd.drift(source, _skill_copy(layer, ".agents")) == (
"language block is for `de`, conventions declare no language"
)
def test_a_hand_edit_next_to_the_block_is_still_reported_as_a_difference(layer):
source = layer / "instructions" / "wiki-demo"
_declare_language(layer, "de")
instructions_cmd.sync(force=False)
target = _skill_copy(layer, ".agents") / "SKILL.md"
target.write_text(target.read_text(encoding="utf-8") + "extra\n", encoding="utf-8")
assert instructions_cmd.drift(source, _skill_copy(layer, ".agents")) == "differs in SKILL.md"
def test_a_hand_edit_of_another_file_is_still_reported(layer):
source = _rich_skill(layer)
_declare_language(layer, "de")
instructions_cmd.sync(force=False)
(_skill_copy(layer, ".claude") / "reference.md").write_text("# edited\n", encoding="utf-8")
assert instructions_cmd.drift(source, _skill_copy(layer, ".claude")) == "differs in reference.md"
def test_verify_reports_a_language_change_per_copy_and_sync_repairs_it(layer, capsys):
_declare_language(layer, "en")
instructions_cmd.sync(force=False)
instructions_cmd.verify()
capsys.readouterr()
_declare_language(layer, "de")
with pytest.raises(typer.Exit):
instructions_cmd.verify()
out = capsys.readouterr().out
for harness in (".agents", ".claude"):
assert f"{harness}/skills/wiki-demo: language block is for `en`, conventions say `de`" in out
instructions_cmd.sync(force=False)
instructions_cmd.verify()
assert "match their source" in " ".join(capsys.readouterr().out.split())
def test_every_real_skill_takes_the_block():
"""A source whose frontmatter the insertion cannot find would be published
without the language and nothing would say so."""
for source in instructions_cmd.skill_dirs():
text = (source / "SKILL.md").read_text(encoding="utf-8")
rendered = instructions_cmd.render_skill_md(text, "de")
assert rendered != text, source.name
assert len(_block_lines(rendered)) == 1, source.name
# --- verify -----------------------------------------------------------------