Skip to content

Chameleon

v3.1.2 Breaking

This release includes breaking changes for platform teams planning a safe upgrade.

✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →

✓ No known CVEs patched in this version

Topics

ai-coding-assistant archetype ast-analysis claude-code claude-plugin code-conventions
+12 more
code-review code-style developer-tools javascript linter mcp mcp-server prompt-engineering python ruby rails typescript

Affected surfaces

auth breaking_upgrade rce_ssrf

Summary

AI summary

Updates P1, str, and nonexistent across a mixed release.

Changes in this release

Bugfix Medium

Daemon proxy now respects CHAMELEON_TRUST_REVALIDATE=1 and runs revalidate check in-process.

Daemon proxy now respects CHAMELEON_TRUST_REVALIDATE=1 and runs revalidate check in-process.

Source: llm_adapter@2026-07-13

Confidence: high

Bugfix Medium

PR‑review auto‑pass now detects removed but still imported exports as contract breaks.

PR‑review auto‑pass now detects removed but still imported exports as contract breaks.

Source: llm_adapter@2026-07-13

Confidence: high

Bugfix Medium

bootstrap_repo(force=True) refuses to downgrade/destroy profiles written by newer chameleon engine.

bootstrap_repo(force=True) refuses to downgrade/destroy profiles written by newer chameleon engine.

Source: llm_adapter@2026-07-13

Confidence: high

Bugfix Medium

`.chameleon/conventions.md` added to merge‑driver routing and tested in gitattributes checks.

`.chameleon/conventions.md` added to merge‑driver routing and tested in gitattributes checks.

Source: llm_adapter@2026-07-13

Confidence: high

Bugfix Medium

Method, class, and constant naming conventions now surface in all convention delivery channels.

Method, class, and constant naming conventions now surface in all convention delivery channels.

Source: llm_adapter@2026-07-13

Confidence: high

Bugfix Medium

refresh_repo forces re‑derive of corrupted or stale artifacts (profile.summary.md, profile.json schema version, reverse_index.json, exports_index.json).

refresh_repo forces re‑derive of corrupted or stale artifacts (profile.summary.md, profile.json schema version, reverse_index.json, exports_index.json).

Source: llm_adapter@2026-07-13

Confidence: high

Bugfix Medium

detect_repo and get_pattern_context consistently report profile_corrupted when profile.json is missing but core artifacts exist.

detect_repo and get_pattern_context consistently report profile_corrupted when profile.json is missing but core artifacts exist.

Source: llm_adapter@2026-07-13

Confidence: high

Bugfix Medium

detect_repo and get_pattern_context reject non‑absolute file_path values with a validation error.

detect_repo and get_pattern_context reject non‑absolute file_path values with a validation error.

Source: llm_adapter@2026-07-13

Confidence: high

Bugfix Medium

preflight-and-advise guards against non‑string session_id to avoid crash.

preflight-and-advise guards against non‑string session_id to avoid crash.

Source: llm_adapter@2026-07-13

Confidence: high

Bugfix Medium

The idiom‑review off‑switch no longer silences the independent “no passing test run” reminder.

The idiom‑review off‑switch no longer silences the independent “no passing test run” reminder.

Source: llm_adapter@2026-07-13

Confidence: high

Bugfix Low

multi_lens_review now includes route reason in both "ran" and "skipped" events for auditability.

multi_lens_review now includes route reason in both "ran" and "skipped" events for auditability.

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Bugfix Low

detect_repo correctly walks up to top-level config to report monorepo workspace's production-ref lock after init.

detect_repo correctly walks up to top-level config to report monorepo workspace's production-ref lock after init.

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Bugfix Low

Idiom teaching with source= no longer renders corrupted gist due to improved metadata-line regex.

Idiom teaching with source= no longer renders corrupted gist due to improved metadata-line regex.

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Bugfix Low

lint_file's node-kind-mismatch violation now caps unbounded repr() output like sibling violations.

lint_file's node-kind-mismatch violation now caps unbounded repr() output like sibling violations.

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Bugfix Low

python -m chameleon_mcp.daemon without start subcommand now writes a pidfile for proper daemon status reporting.

python -m chameleon_mcp.daemon without start subcommand now writes a pidfile for proper daemon status reporting.

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Bugfix Low

Intent capture regex broadened to match slash-delimited paths and single-digit numerals as constants.

Intent capture regex broadened to match slash-delimited paths and single-digit numerals as constants.

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Bugfix Low

Python async/await signals are now surfaced in search_codebase and get_pattern_context outputs.

Python async/await signals are now surfaced in search_codebase and get_pattern_context outputs.

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Bugfix Low

search_codebase correctly labels stale calls and symbol indexes as "stale" rather than mislabeling them as corrupt.

search_codebase correctly labels stale calls and symbol indexes as "stale" rather than mislabeling them as corrupt.

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Bugfix Low

_profile_needs_rederive now validates constant_index.json schema_version alongside other index files.

_profile_needs_rederive now validates constant_index.json schema_version alongside other index files.

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Bugfix Low

Orphaned merge-driver temporary file sweep now runs on both full bootstrap and partial refresh paths.

Orphaned merge-driver temporary file sweep now runs on both full bootstrap and partial refresh paths.

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Bugfix Low

/chameleon-doctor's recent-hook-errors check no longer misattributes benign banners as errors, preserving real timestamps.

/chameleon-doctor's recent-hook-errors check no longer misattributes benign banners as errors, preserving real timestamps.

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Bugfix Low

using-chameleon/SKILL.md corrected documentation: idiom_judge default is on (matches code).

using-chameleon/SKILL.md corrected documentation: idiom_judge default is on (matches code).

Source: granite4.1:30b@2026-07-14-audit

Confidence: low

Full changelog

Whole-plugin from-scratch real-invocation QA campaign: 36 parallel testers
exercised every hook, skill, and MCP tool against the real profiled repos
across TypeScript/Ruby/Python and every supported framework, weighted toward
the freshest v3.1.0/v3.1.1 memory-channel code. 26 findings confirmed (each
independently adversarially re-verified) and fixed. The fix wave itself went
through two further verification passes before shipping: a per-fix adversarial
re-check (which caught and repaired a fix-introduced test regression, see
"Fixed" below) and a second independent review of the cumulative diff (which
caught a fix-introduced false-positive bug in the PR-review auto-pass fix
itself, plus two smaller parity gaps — all repaired, see "Fixed").

Fixed

  • Daemon proxy silently defeated CHAMELEON_TRUST_REVALIDATE=1 (P1). The
    long-lived chameleon-mcp daemon's environment is frozen at spawn time, so
    preflight-and-advise proxying get_pattern_context to it never observed a
    per-call revalidate override — a profile that genuinely diverged from its
    trust grant kept reading as trusted instead of stale whenever a daemon
    spawned without the flag was already running, the default steady-state
    condition. CHAMELEON_TRUST_REVALIDATE=1 now bypasses the daemon proxy and
    runs the check in-process. hook_helper.py.
  • PR-review auto-pass missed a removed-but-still-imported export (P1).
    get_autopass_verdict's blast-radius fact only counted a file's CURRENT
    importers, so deleting an export five other files still imported could
    score auto_pass_eligible=true/risk=low with no mention of the break —
    the exact defect class the safety net exists to catch. It now folds
    query_symbol_importers's "broken" entries into the verdict as a real
    contract break, scoped to names that were actually exported at the diff's
    own old_ref (an independent review of this same fix caught that the first
    version compared only against the CURRENT export set with no notion of
    old_ref, so a file touched for an unrelated reason with a pre-existing
    dangling import — present at both old_ref and HEAD — would have been
    misattributed to the diff under review; both directions are now covered by
    a real two-scenario regression test). tools.py.
  • bootstrap_repo(force=True) had no too-new-schema guard. It would
    silently downgrade/destroy a profile written by a newer chameleon engine —
    the exact case refresh_repo already refuses even under force. Bootstrap
    now applies the same refusal. tools.py.
  • .chameleon/conventions.md was missing from the merge-driver routing.
    Absent from .gitattributes-template, a real two-branch merge with
    divergent taught idioms left raw git conflict markers embedded in the
    mirror instead of the driver ever running. Routed alongside
    COMMITTED/principles.md/profile.summary.md (decline-cleanly,
    refresh-repairs), and added to test_gitattributes_template.py's tested
    sets.
  • Method/class/constant naming conventions never reached the model.
    method_casing/class_casing/constant_casing were derived and stored in
    conventions.json but rendered into none of the three convention-delivery
    channels (SessionStart, the conventions.md mirror, the Tier-1 PreToolUse
    echo) — a model could be flagged for violating a naming rule it was never
    shown. All three now surface it, mirroring how file-naming already does.
    conventions.py.
  • refresh_repo under-repaired corrupted/stale artifacts. A corrupted
    (non-empty garbage) profile.summary.md passed the repair guard's
    emptiness-only check and stayed corrupt indefinitely; an old-but-readable
    profile.json schema_version noop'd instead of re-deriving; a stale
    reverse_index.json/exports_index.json schema_version was never
    validated. All three now force a re-derive like their sibling artifacts do.
    tools.py.
  • detect_repo/get_pattern_context misreported a torn-down profile.
    When profile.json was missing but core artifacts remained, both reported
    a clean no_profile instead of profile_corrupted — inconsistent with
    get_status on the identical directory, contradicting the code's own
    stated invariant. Both now call the same corruption check regardless of
    whether profile.json itself exists. tools.py.
  • detect_repo/get_pattern_context silently resolved a relative
    file_path against the MCP server's own CWD
    , contrary to their
    documented absolute-path contract (the sibling get_archetype already
    guards against this exact failure mode). Both now reject a non-absolute
    path with a validation-error envelope instead of disclosing whatever repo
    happens to sit at the resolved location. tools.py.
  • preflight-and-advise crashed on a non-string session_id. The one
    call site (of ~11 in the file) without an isinstance(str) guard let a
    malformed payload reach str.encode() and raise an unhandled
    AttributeError past the hook's own try/except. Guarded to match every
    other call site. hook_helper.py.
  • The idiom-review off-switch silenced an unrelated reminder.
    enforcement.idiom_review: false also killed the independent "no passing
    test run this turn" reminder, because both were computed inside the same
    gate function. The reminder now fires independently of the idiom-review
    switch. hook_helper.py.
  • multi_lens_review's "ran" check event dropped its route reason, unlike
    the "skipped" branch — no way to audit after the fact whether a turn's
    judge spawn was intent-forced. The reason now rides in both. hook_helper.py.
  • detect_repo misreported a monorepo workspace's production-ref lock
    immediately after init, reading only the workspace's own (nonexistent)
    config instead of walking up to the toplevel's lock the way refresh_repo
    already does. tools.py.
  • An idiom taught with source= rendered a corrupted gist — the
    citation text leaked into the directive because _summarize_idiom_block's
    metadata-line regex didn't recognize Source:, unlike the sibling parser
    in idiom_coverage.py. tools.py.
  • lint_file's node-kind-mismatch violation embedded an unbounded
    repr()
    of every top-level node kind, with no cap unlike sibling
    violation classes in the same module. lint_engine.py.
  • A bare python -m chameleon_mcp.daemon (no start subcommand) never
    wrote a pidfile
    , so daemon_status()/stop_daemon() reported a live,
    request-serving daemon as not-running. daemon.py.
  • Intent capture missed realistic checkable constants — the identifier
    regex never matched slash-delimited paths, and the numeral regex required
    2+ digits. Broadened both. intent_capture.py.
  • Python's async/await signal was computed but never surfaced in
    search_codebase/get_pattern_context — an async FastAPI endpoint
    rendered indistinguishably from a sync one. symbol_signatures.py.
  • search_codebase mislabeled a stale calls index as (corrupt)
    instead of the shared calls-index-stale reason sibling tools already use.
    A review pass on this fix found the identical (corrupt) mislabel three
    lines above for a stale symbol index, missed in the same edit — fixed too,
    now distinguishing symbol-index-stale from genuine corruption. tools.py.
  • _profile_needs_rederive validated constant_index.json (Ruby's
    cross-file existence index) for JSON-parseability only, not schema_version
    ,
    unlike the exports/reverse index check right above it — currently latent
    (the format has only ever shipped schema_version 1) but would have silently
    survived every refresh once a newer schema ships. Now validated the same way
    its siblings are; found and fixed during the same review pass as the two
    items above. tools.py.
  • The orphaned merge-driver tmp-file sweep only ran on full bootstrap,
    not the partial-refresh path /chameleon-refresh takes for small diffs.
    tools.py.
  • /chameleon-doctor's recent-hook-errors check could misattribute a
    benign banner as the error
    , dropping the real timestamped line that
    pulled it into the surfaced tail. tools.py.
  • using-chameleon/SKILL.md misdocumented idiom_judge's default as
    "opt-in, default off"; the code default is on, matching every other doc
    that states it.

Full unit suite green (5545 passed, 3 skipped), ruff clean.

Weekly OSS security release digest.

The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.

No spam, unsubscribe anytime.

Share this release

Track Chameleon

Get notified when new releases ship.

Sign up free

About Chameleon

All releases →

Related context

Earlier breaking changes

  • v3.0.0 MCP surface folded from 48 tools to 19; remaining 32 operator tools become actions on three dispatchers.

Beta — feedback welcome: [email protected]