camelCase normalized `joined` and then prefixed, so the seam the `Tool` prefix creates was never covered: `Tool` ends in `l`, a combining-mark head composes with it, and a name headed by U+0301 was emitted as `Tool` + U+0301 while CPython compiles `Too` + U+013A. childClassName has the same shape -- both sides separately NFKC-stable, their join not: a base ending in a Hangul L jamo or LV syllable composes with a V or T jamo head. Beyond the declared-name/compiled-symbol mismatch, two byte-distinct names can fold onto one, and usedClassNames dedupes by raw bytes, so the collision counter never sees it. Normalize after the prefix decision and at the join, before the cap. The remaining joins need nothing: `Args`/`Output` and the digit suffix cannot compose backwards. Also record the Unicode-table skew. The predicate reads the engine's tables (Node 22.23.1: 17.0) and the interpreter reads its own (CPython 3.9.6: 13.0.0), so an interpreter older than the engine takes a bare name its tokenizer refuses -- U+1C89, U+10570, U+1E290 and U+1E4D0 are accepted here and rejected there. The other direction only degrades a legal name to subscript. Closing it needs the CPython floor, which the backend PR owns; state the asymmetry in the docstring and make the decision an explicit obligation in the note.
core/ — product API spine
English | 中文
The session log, system-prompt assembly, tool registry, agent vocabulary, and concrete loop that form the harness's default control spine. These are product packages — the stable surface plugins and consumers build against.
| Package | Role | ctx key |
|---|---|---|
scope/ |
Scoped-context registration primitive | library — no ctx key |
session/ |
Event-sourced session log and in-memory store | ctx.sessions |
system-prompt/ |
Prompt and tool-schema assembly registry | ctx.systemPrompt |
tools/ |
Scoped tool registry and execution pipeline | ctx.tools |
agent/ |
Agent interface, registry, and event vocabulary | ctx.agents |
agent-loop/ |
Default concrete agent driver | ctx.agentLoop |
scope supplies the shared scoping primitive. agent owns the public seam, while agent-loop is its default implementation; extension plugins depend on the seam so the driver remains swappable.
Runnable compositions belong to examples/agent-spine-demo; this group owns only the swappable spine pieces.