Commit Graph
4 Commits
Author SHA1 Message Date
Hotragn Pettugani d3a3f573e3 fix(aider): CONVENTIONS.md is a roster index, not 3.8 million characters of agents (#871)
Aider loads a conventions file into context and keeps it there for the whole
session — that is what the file is for, and the docs say to load it with
--read so prompt caching can hold it. This integration concatenated every
agent body into it. At 279 agents that is 3,816,372 characters, roughly a
million tokens. No model takes that. Anyone who ran

    ./scripts/install.sh --tool aider

got a CONVENTIONS.md that either blows the context window on the first turn
or bills for a million tokens trying.

CONVENTIONS.md is now the roster index it was described as: one entry per
agent with the name, the description, the division, and the path to the
agent file. 96,823 characters, down from 3.8 million. The header explains
how to pull a single agent's full instructions into the session:

    /read-only /path/to/agency-agents/engineering/engineering-frontend-developer.md

Naming an agent in a prompt still works the way it did — the description is
what the model needed for that, and it is still there.

test-convert-outputs.sh now holds the index to being an index: it fails if
CONVENTIONS.md grows past 250,000 characters, if it does not list exactly
one path per roster agent, or if any path it prints does not resolve. The
existing round-trip check on the accumulated file still covers the names and
descriptions.
2026-09-20 18:35:10 -05:00
ad9264e309 fix(convert): track code fences when splitting OpenClaw sections, and pin it with an invariant (#855)
convert_openclaw() split on `## ` without tracking fenced code blocks, tearing six fenced examples across SOUL.md/AGENTS.md in five agents and leaving dangling fences in each. Implementation from #854 (@guozi-lab): fence helpers in lib.sh used by convert.sh and lint-agents.sh, CommonMark indent aware. Regression test from #853 (@dajiaohuang): every source fenced block must land whole in exactly one output file — verified to fail on the unfixed converter.

Reported by @AmineOzil. Closes #849. Supersedes #853 and #854.

Co-Authored-By: fruit <200041037+guozi-lab@users.noreply.github.com>
Co-Authored-By: Wu Shuwen <108231307+dajiaohuang@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 11:57:20 -05:00
Michael SitarzewskiandClaude Fable 5.1 449e0c71b1 test(convert): manifest v2 — one line per agent, platform-neutral hashes, advisory drift on PRs (#844)
See the PR for the why/what/proof. Contributors no longer touch scripts/convert-outputs.sha256; drift is advisory on pull requests and strict on main.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 18:59:03 -05:00
Michael SitarzewskiandClaude Fable 5.1 04eadbd3e5 test(convert): regression eval for generated outputs + app contracts; fix two get_field bugs it found (#829)
Adds scripts/test-convert-outputs.sh, the output half of the regression eval
(the install half landed in #828), and wires it plus the previously
un-wired test-agent-selection.sh (#779) into CI.

Why an eval at all: every converter bug so far passed lint and the existing
tests while the installed product was broken. #778 shipped a double-wrapped
description that was valid YAML, so a wrapper check passed; #817 dropped a
whole tool from --parallel and every remaining tool looked fine. Those are
invariant violations, not syntax errors.

Layer A (no history needed), for every agent x every converted tool:
  round-trip   parsed(generated).description == source description
  strict-parse every generated frontmatter / TOML / YAML parses with a real
               parser (kimi/vibe carry only an identifier: id == slug and the
               prose file exists; aider/windsurf: "## Name" + description line)
  count        every tool emits exactly one output per roster agent
  source       every SOURCE frontmatter strict-parses and carries no leaked
               quote — the desktop app reads sources with js-yaml (#473)
Layer B: scripts/convert-outputs.sha256, one aggregate hash per tool plus
divisions.json / tools.json / runbooks.json. A flipped line means outputs or a
contract changed; --update regenerates deliberately so review sees the blast
radius. Date-stable (no generated file embeds a date).

The expected side is derived by an INDEPENDENT strict parse of each source,
never by lib.sh's get_field: the generator uses get_field, so an expected
value derived the same way would move with a get_field bug and hide it —
which is exactly how #778 stayed invisible. That independence found two
shipping defects on the first green run:

- get_field returned only the first line of a multi-line plain scalar.
  Three healthcare agents write their description as an indented
  continuation; every generated output for them shipped it truncated
  mid-sentence while the app showed the whole thing. get_field now folds
  continuation lines the way YAML does (newline -> single space).
- get_field stripped only "field: " (one space). The same three files use
  column-aligned frontmatter (name:        X), so their generated names
  carried leading whitespace in every tool's output. Plain-scalar padding
  is now trimmed.

After both fixes get_field agrees with PyYAML on name and description for
all 273 sources. Acceptance: re-introducing #778's double-wrap, a dropped
tool, a divisions.json change, and an unquoted source each fail the eval
(the double-wrap via Layer A round-trip, not only the manifest).

Refs #778 #817 #473 #810 #826 #828 #779

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 07:58:13 -05:00