Calendar Day
Monday, July 13, 2026
Planned Effort
8 story points (Medium) — sprint item #1 (merges Test 4 + 5 + compounds)
Problem
Adding a new Claude Code tool type is a ~7-step manual checklist spanning Python backend and JS SPA. CONTRIBUTING.md § "Adding a new tool type" (L144–154) and utils/tool_dispatch.py (L22–36) document seven coordinated hand-edits:
utils/tool_dispatch.py — _FILE_ACTIVITY_HANDLERS + _TOOL_RESULT_DISPATCH entry (predicate + builder + priority)
models/tool_results.py — ToolNameLiteral, TypedDict, is_*_tool_result guard, ToolResultUnion
utils/md_exporter.py — _render_tool_use / _render_tool_result branches
static/js/render/registry.js — 24 hand-listed imports + TOOL_USE_RENDERERS + TOOL_RESULT_RENDERERS maps
static/js/render/tool_use/*.js + tool_result/*.js modules
static/tool_types.json — regenerate via scripts/gen_tool_types_manifest.py
PR #127 changed dispatch selection (priority-based _winning_dispatch_entry); PR #124 added adversarial fixtures. Neither reduced the extension surface. tests/test_tool_dispatch_sync.py enforces tool-use name parity only — no result_type→renderer parity test (owned by Tuesday item #3).
Goal
One merged PR that replaces the 7-site manual checklist with a single registration record + scripts/scaffold_tool_type.py generator, measurably reducing hand-edited files. Generator output must pass existing sync, ordering, and adversarial guards.
Scope
Part A — Registration record design
- Single source-of-truth per tool type: name, side-effect handler, result TypedDict fields, predicate keys, overlap priority, render summary.
- Extend the
KNOWN_TOOL_TYPES (derived from _FILE_ACTIVITY_HANDLERS keys) pattern to the result side.
Part B — scripts/scaffold_tool_type.py (new)
Emit from the registration record:
_TOOL_RESULT_DISPATCH entry + builder stub (utils/tool_dispatch.py)
ToolNameLiteral / TypedDict / is_* guard additions (models/tool_results.py)
_render_tool_use / _render_tool_result branches (utils/md_exporter.py)
- JS
tool_use/*.js + tool_result/*.js module stubs
registry.js imports + map entries (eliminates 24 hand-listed imports)
- Parser fixture
- Regenerated
static/tool_types.json
Codegen emits stubs a human completes (field mapping, render HTML) — not fabricated semantics.
Part C — Overlap-priority preservation
When the record declares an overlap, generator writes priority= and appends a row to ORDERING_INVARIANTS in tests/test_tool_dispatch_ordering.py (e.g. plan beats file_write).
Part D — Docs
CONTRIBUTING.md § "Adding a new tool type" — point at generator; document before/after file count.
docs/architecture.md dispatch-table section updated.
Part E — Tests
Out of scope
result_type→renderer parity contract test — Tuesday item #3 owns it; this generator's output must pass it.
Acceptance Criteria
Verification
cd C:\Users\Jasen\CppAliance\claude-code-chat-browser
.\.venv\Scripts\Activate.ps1
python scripts/scaffold_tool_type.py --name example_tool --dry-run
pytest tests/test_tool_dispatch_sync.py tests/test_tool_dispatch_ordering.py tests/test_tool_dispatch_adversarial.py -q
pytest -q
mypy -p api -p utils -p models -p scripts
ruff check .
npm test
Calendar Day
Monday, July 13, 2026
Planned Effort
8 story points (Medium) — sprint item #1 (merges Test 4 + 5 + compounds)
Problem
Adding a new Claude Code tool type is a ~7-step manual checklist spanning Python backend and JS SPA.
CONTRIBUTING.md§ "Adding a new tool type" (L144–154) andutils/tool_dispatch.py(L22–36) document seven coordinated hand-edits:utils/tool_dispatch.py—_FILE_ACTIVITY_HANDLERS+_TOOL_RESULT_DISPATCHentry (predicate + builder +priority)models/tool_results.py—ToolNameLiteral, TypedDict,is_*_tool_resultguard,ToolResultUnionutils/md_exporter.py—_render_tool_use/_render_tool_resultbranchesstatic/js/render/registry.js— 24 hand-listed imports +TOOL_USE_RENDERERS+TOOL_RESULT_RENDERERSmapsstatic/js/render/tool_use/*.js+tool_result/*.jsmodulesstatic/tool_types.json— regenerate viascripts/gen_tool_types_manifest.pyPR #127 changed dispatch selection (priority-based
_winning_dispatch_entry); PR #124 added adversarial fixtures. Neither reduced the extension surface.tests/test_tool_dispatch_sync.pyenforces tool-use name parity only — noresult_type→renderer parity test (owned by Tuesday item #3).Goal
One merged PR that replaces the 7-site manual checklist with a single registration record +
scripts/scaffold_tool_type.pygenerator, measurably reducing hand-edited files. Generator output must pass existing sync, ordering, and adversarial guards.Scope
Part A — Registration record design
KNOWN_TOOL_TYPES(derived from_FILE_ACTIVITY_HANDLERSkeys) pattern to the result side.Part B —
scripts/scaffold_tool_type.py(new)Emit from the registration record:
_TOOL_RESULT_DISPATCHentry + builder stub (utils/tool_dispatch.py)ToolNameLiteral/ TypedDict /is_*guard additions (models/tool_results.py)_render_tool_use/_render_tool_resultbranches (utils/md_exporter.py)tool_use/*.js+tool_result/*.jsmodule stubsregistry.jsimports + map entries (eliminates 24 hand-listed imports)static/tool_types.jsonCodegen emits stubs a human completes (field mapping, render HTML) — not fabricated semantics.
Part C — Overlap-priority preservation
When the record declares an overlap, generator writes
priority=and appends a row toORDERING_INVARIANTSintests/test_tool_dispatch_ordering.py(e.g.planbeatsfile_write).Part D — Docs
CONTRIBUTING.md§ "Adding a new tool type" — point at generator; document before/after file count.docs/architecture.mddispatch-table section updated.Part E — Tests
test_tool_dispatch_sync.py+test_tool_dispatch_ordering.py.Out of scope
result_type→renderer parity contract test — Tuesday item #3 owns it; this generator's output must pass it.Acceptance Criteria
CONTRIBUTING.md.CONTRIBUTING.mdanddocs/architecture.mdupdated.Verification