chameleon 3.0.0
Added (2026-07-11)
.chameleon/conventions.md— the CLAUDE.md-channel mirror. Bootstrap,
refresh, and teach/unteach now maintain a rendered conventions file for the
repo to wire into Claude's memory channel. Measured motive: the identical
rules were followed 100% via this channel vs 40% as a hook advisory (see
tests/effectiveness/results-published/migration-ab-2026-07-11.md).
/chameleon-initoffers three consent-gated wirings, none of which edit an
existing file by default: a one-line.claude/rules/chameleon-conventions.md
(auto-loads for the whole team),CLAUDE.local.md(personal), or a
CLAUDE.mdimport on explicit preference. Kill switch
CHAMELEON_CONVENTIONS_MD=0. A refresh repairs a missing mirror
(_profile_needs_rederive), and any engine upgrade already forces the full
re-derive that writes it — existing profiles gain the file on their first
refresh after upgrading.- Multi-convention effectiveness campaign published (30 tasks x TS/Ruby/
Python x 4 arms x 2 models, deterministic scorer, the repo's own
cluster-bootstrap bar): chameleon 1.00 conformance on every task, every
language, both models; bar MET vs no-plugin on both models; MET vs
stale-CLAUDE.md on haiku; ceiling-tie vs perfectly-maintained CLAUDE.md.
Instruments committed (tests/study_*.py); all results in
tests/effectiveness/results-published/(including the null dogfood
retrospective and the unfavorable single-convention run, per policy). - Judge-panel calibration gate computed: kappa 1.000 on the 13-pair golden
set (Fable-reference labels, provenance in
tests/effectiveness/golden/LABELS_PROVENANCE.md— not human labels).
Changed (2026-07-11)
- SessionStart injection reorders: the
<chameleon-conventions>block now
leads the context (before the skill text) and carries explicit
anti-majority framing ("existing files may be mid-migration; never infer a
convention from sibling-file majority against a rule here"). - The
// chameleon-ignoreescape hatch is scoped to human-approved
exceptions in both the import-preference deny reason and the
using-chameleon skill: the model must not self-approve an override because
existing files still use the blocked pattern. - pr-review gains a mechanical dependency demotion sweep before verdict
rendering (a new-dependency's name alone can never be a BLOCK/FIX).
Fixed (2026-07-11)
- Journey act 12b phase-41 checker read the raw stream-json transcript, so
line-based assertions saw escaped\n— a structural false positive that
failed the dependency-ACK check on every run. Both historical "failures"
re-adjudicate as passes; live re-run green.
Breaking (v3)
-
MCP surface folded from 48 tools to 19. The 16 comprehension/conformance
tools stay top-level (detect_repo,get_pattern_context,get_archetype,
get_canonical_excerpt,get_rules,lint_file,search_codebase,
describe_codebase,get_callers,get_callees,get_blast_radius,
query_symbol_importers,get_crossfile_context,get_contract_breaks,
get_duplication_candidates,explain_edit); the remaining 32 operator
tools become actions on three dispatchers, called as
<dispatcher>(action="<old tool name>", params={...original arguments, names and values unchanged...}):Old top-level tool New dispatcher / action bootstrap_repochameleon_lifecycle(action="bootstrap_repo")refresh_repochameleon_lifecycle(action="refresh_repo")trust_profilechameleon_lifecycle(action="trust_profile")list_profileschameleon_lifecycle(action="list_profiles")merge_profileschameleon_lifecycle(action="merge_profiles")teach_profilechameleon_lifecycle(action="teach_profile")teach_profile_structuredchameleon_lifecycle(action="teach_profile_structured")teach_competing_importchameleon_lifecycle(action="teach_competing_import")unteach_competing_importchameleon_lifecycle(action="unteach_competing_import")propose_archetype_renameschameleon_lifecycle(action="propose_archetype_renames")apply_archetype_renameschameleon_lifecycle(action="apply_archetype_renames")disable_sessionchameleon_lifecycle(action="disable_session")pause_sessionchameleon_lifecycle(action="pause_session")get_autopass_verdictchameleon_review(action="get_autopass_verdict")refute_findingchameleon_review(action="refute_finding")record_review_verdictchameleon_review(action="record_review_verdict")record_finding_fatechameleon_review(action="record_finding_fate")get_review_historychameleon_review(action="get_review_history")scan_dependency_changeschameleon_review(action="scan_dependency_changes")dep_auditchameleon_review(action="dep_audit")get_statuschameleon_telemetry(action="get_status")get_drift_statuschameleon_telemetry(action="get_drift_status")get_drift_antipatternschameleon_telemetry(action="get_drift_antipatterns")get_shadow_reportchameleon_telemetry(action="get_shadow_report")get_override_auditchameleon_telemetry(action="get_override_audit")get_longitudinal_signalschameleon_telemetry(action="get_longitudinal_signals")get_finding_fate_statschameleon_telemetry(action="get_finding_fate_stats")get_idiom_coveragechameleon_telemetry(action="get_idiom_coverage")check_idiom_candidateschameleon_telemetry(action="check_idiom_candidates")get_prose_rule_candidateschameleon_telemetry(action="get_prose_rule_candidates")daemon_statuschameleon_telemetry(action="daemon_status")doctorchameleon_telemetry(action="doctor")Rationale: a context-lean tool surface — a session now loads 19 tool schemas
instead of 48; the underlying Python functions keep their names and
signatures, so direct imports (tests, QA batteries) are unaffected.
Changed
- Repository restructured around an installable
plugin/dir. The
marketplace source now points at./plugin(plugin.json, .mcp.json, hooks/,
skills/, agents/, bin/, mcp/, and the runtime scripts ts_dump.mjs,
prism_dump.rb, libcst_dump.py, chameleon-merge-driver.sh, setup.sh), so a
marketplace install copies only the runtime surface instead of the whole
repo (previously ~4.9MB of tests/ and docs/ shipped with every install).
tests/, docs/, and dev tooling (bump-version.sh, prune-plugin-cache.sh, ...)
stay outside the installed plugin; the release tarball likewise now packs
plugin/+ README/LICENSE/CHANGELOG only. No runtime behavior change —
everything in-plugin resolves viaCLAUDE_PLUGIN_ROOTas before. - Interpreter resolution is cached and the per-edit ladder is bounded. The
resolved interpreter argv persists to a version-keyed cache (validated on
read), and per-edit hooks cap the uv probe at 5s — bounded even where
timeout(1)is absent (Git Bash, coreutils-less macOS), previously uncapped.
Kill switchCHAMELEON_INTERP_CACHE=0. - pr-review skill split for progressive disclosure: a lean SKILL.md plus
lazyreferences/*.md, and the fixed reviewer/scout roles are now packaged
agents/(chameleon:pattern-reviewer,code-scout,web-researcher).
Fixed
- The daemon now starts under deep plugin-data paths. AF_UNIX caps
sun_pathat ~104 bytes, so a deepCHAMELEON_PLUGIN_DATAmade every bind
fail and the latency daemon silently never engaged (hooks fell back
in-process forever). The socket moved to a short user-private
<tmpdir>/chameleon-<uid>/d-<hash>.sock; pidfile and logs stay in the data
dir. - Python test files no longer bucket into production role archetypes.
python_role_for_pathroutedtests/api/routes/test_x.pytoroute, so the
per-edit hook injected a production route canonical when editing a test; it now
gates on the canonical test-path detector first. - Python linter config is read from sub-project dirs (a monorepo
backend/ pyproject.toml), matching the TypeScript workspace-config fallback. - Skill-surface fixes: the refresh skill's re-lock call now passes the
requiredpath; receiving-code-review gained anargument-hint; the
pr-review fan-out claim about reviewer tool grants is now an enforced in-agent
directive rather than an unenforceable grant statement.