Google is sunsetting consumer Gemini CLI access on 2026-06-18 and
consolidating into Antigravity CLI. codeagent-wrapper already ships a
working AntigravityBackend (confirmed by shelling to `agy`), and
~/.claude/.ccg/prompts/antigravity/*.md role prompts already exist —
only the command markdown files still hardcoded --backend gemini.
Updates multi-frontend.md, multi-execute.md, multi-plan.md, and
multi-workflow.md to route frontend calls through --backend antigravity
instead of --backend gemini, point role-prompt paths at
prompts/antigravity/ instead of prompts/gemini/, and drop the
gemini-only --gemini-model flag (antigravity has no CLI equivalent;
codeagent-wrapper picks its default model).
multi-backend.md is unaffected (codex-only, no frontend routing).
* feat(skills): add dev-team skill — multi-persona collaborative session
Adds skills/dev-team/SKILL.md, a community skill inspired by the
BMAD Method's "party mode": PM, Architect, Developer, and QA respond
to the same topic in parallel, then a synthesis step names tensions
explicitly instead of averaging them.
Reads PROJECT-CONTEXT.md from the repo root when present, and offers
to generate it when missing, folding in the closed project-context
skill's (#2310) generation workflow per affaan-m's review — that
skill's premise (every agent reads the file) wasn't implemented
anywhere, so the capability now lives directly in the one skill that
actually reads it.
Rebuilt on current upstream/main as a skill-only diff: the shared
format-code.ts Windows fix and github-coordination branch-coverage
tests that were previously bundled here (and duplicated across the
story-lifecycle and project-context sibling PRs) now live in #2459.
* fix(manifests): register dev-team skill in workflow-quality install module
* fix(docs): repair README lint errors and Windows hook-install path regression
Fixes CI inherited from the README 2.1 restructure (19b05476):
- MD058: blank lines around tables (delegation map, Codex role configs)
- MD001: Option A/B headings under Ecosystem Tools h2 jump to h4
- MD024: duplicate 'What's included' headings (Codex, Copilot sections)
- restore %USERPROFILE%\\.claude escaping required by
tests/scripts/manual-hook-install-docs.test.js
* feat(skills): address review — trust boundary, harness-neutral I/O, contract test
Address maintainer review on #2309:
- untrusted-context boundary now travels with every persona prompt:
inline label on the context section, personas marked analysis-only
with no state-changing tool use
- personas receive a bounded declarative summary (≤150 words, fixed
fields, secrets and imperative content stripped) — never the raw
PROJECT-CONTEXT.md
- context loading uses harness-native file tools; POSIX-only
'test -f && cat' removed
- all references resolve on main: story-lifecycle follow-up replaced
with /plan and epic-* commands, ecc:plan-prd corrected to the
/plan-prd command; boundary vs team-builder and council made explicit
- added tests/docs/dev-team-skill.test.js contract test (roles,
parallel dispatch, synthesis guardrails, trust boundary, registration)
* docs: refresh Turkish skill count
* ci: retrigger checks (flaky stop-hooks-stdout timeout on macos node20 npm cell)
---------
Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
* fix(hooks): context-monitor noise — loop-detection false positives and per-call cost-warning spam
Two independent noise sources in the PostToolUse context monitor injected
agent-facing warnings on nearly every tool call:
1. LOOP WARNING false positives. hashToolCall() hashed only the first 160
chars of a Bash command, so distinct long commands sharing a prefix
(heredocs, long one-liners) collided and consecutive DIFFERENT calls
looked like a stuck loop. Additionally LOOP_THRESHOLD=3 against a
5-entry ring buffer fired on legitimate repetition (retries, polling).
Fix: hash the full command (digest truncated, not the input — same
treatment the Edit/Write branch already got), and require all 5 of the
last 5 calls to be identical before warning.
2. COST NOTICE spam. run() deduped warnings on exact message text, but the
cost figure embedded in the text moves on nearly every call, so once a
session crossed $5 a 'new' COST NOTICE was injected per tool call for
the rest of the session. Context warnings had the same defect via the
remaining-% figure. Fix: dedupe on a stable per-tier key
(cost:notice/warning/critical, context:warning/critical, scope) so each
tier fires exactly once and re-fires only on genuine escalation. The
existing ECC_CONTEXT_MONITOR_COST_WARNINGS opt-out is unchanged.
Tests: loop threshold updated (5-of-5 fires, 4-of-5 does not), long
shared-prefix Bash hash regression, and a run()-level tier-dedupe test
(notice fires once, silent on cost tick, re-emits on escalation).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: keep context warning state immutable
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
* feat(session-start): rank injected instincts by project/stack relevance
Instinct selection at SessionStart ranked purely by confidence, so a
high-confidence instinct about an unrelated stack could take an injection
slot from a lower-confidence instinct that is actually relevant to the
current project.
Rank by confidence + location/stack relevance instead: project-scoped
instincts, and instincts whose domain/trigger matches the detected stack
(languages/frameworks via detectProjectType, plus terraform/dbt markers),
get a small additive boost. The confidence>=threshold floor and the
injection cap are unchanged, and ranking degrades to confidence-only when
nothing matches or when ECC_INSTINCT_RELEVANCE_RANKING is set to off.
The ranking helpers live in scripts/lib/instinct-relevance.js with unit
coverage in tests/lib/, plus an end-to-end ordering test in tests/hooks/.
Completes part (b) of #2371; part (a) (configurable count + threshold)
shipped in #2413.
Fixes#2371
* refactor(session-start): drop redundant confidence tiebreaker in instinct sort
Greptile flagged that the secondary `right.confidence` comparison in
summarizeActiveInstincts' sort was dead code when relevance ranking is
disabled and, when enabled, was reached only on a floating-point tie of the
combined score — where it skipped the intended scope-label tiebreaker.
Remove it: the primary combined-score comparison already reduces to
confidence-only ordering when relevance is off, so behavior there is
unchanged; a genuine combined-score tie now falls through to the documented
scope-first, then id, order.
* test: isolate instinct relevance environment
---------
Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
* fix(quarkus-verification): use current ghcr.io/zaproxy/zaproxy:stable image
The owasp/zap2docker-* images are deprecated (ZAP left the OWASP org). The
current canonical image published by the ZAP project is
ghcr.io/zaproxy/zaproxy:stable; the packaged scan scripts (zap-api-scan.py)
are unchanged.
Applies to the source skill and the ja-JP, tr translated copies.
Refs: https://www.zaproxy.org/docs/docker/about/
* chore(quarkus-verification): bump GitHub Actions v3 -> v4
actions/checkout, actions/setup-java, actions/cache and codecov/codecov-action
were pinned at v3 (which runs on the deprecated Node 16 runtime). Bump to v4.
Applies to the source skill and the ja-JP, tr translated copies.
* docs(quarkus): finish current CI example refresh
---------
Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
* feat: add living-docs-governance skill (maintain-phase project doc system)
Rebased onto latest main to resolve the merge conflict (the branch had gone
DIRTY as main advanced). Trimmed to just the skill file (no top-level
README/AGENTS edits), mirroring the merged #2381. Previously approved by
@powershello before this rebase.
* fix: register living-docs-governance install path
* docs: sync skill catalog count
* fix: publish living-docs-governance skill
* fix: adopt existing docs before adding governance files
Feedback sent from the canvas only reached an agent through a live
/api/await long poll. When a turn ended with no await parked,
queueFeedback wrote the message to sessions.json and nothing ever
consumed it, so sending appeared to do nothing at all. The presence pill
made it worse: workingKeys had no expiry and the feedback handler never
broadcast presence, so it froze on "agent working" while nobody was
listening.
Delivery:
- Add the stop:plan-canvas-pending hook. It drains undelivered feedback
and blocks the Stop, handing the messages to the agent, so a canvas
message lands even when no await is running. Scoped to sessions under
cwd so parallel agents cannot swallow each other's feedback; set
ECC_PLAN_CANVAS_STOP_SCOPE=all to widen. Honors stop_hook_active and
fails open on every error path.
- run-with-flags.js did not await a hook's run(), so any async hook
silently degraded to pass-through. Fixed; plan-canvas-pending is the
only async hook today.
Presence and indicators:
- Presence is now ended/typing/thinking/listening/queued/waiting.
thinking and typing self-expire (90s/30s) and a 5s sweep pushes the
decay to an idle browser, so the pill can no longer stick.
- Broadcast presence when feedback is queued, and clear the activity
state when an agent reply lands.
- Add POST /api/session/:key/typing so agents can drive the indicator.
- Chat shows an animated dots bubble for thinking and typing, plus an
explicit note when a message is queued with nobody listening.
Respects prefers-reduced-motion.
- Send status reports what actually happened instead of always claiming
the agent will pick it up.
CLI and skill:
- Add `ecc-plan-canvas pending` and `typing <file> --state ...`.
- SKILL.md documents background await as the primary pattern and makes
replying in the canvas mandatory.
Tests: 6 new server cases covering queued presence, the typing endpoint,
state expiry and the sweep, plus a new hook suite covering delivery,
drain-once, stop_hook_active, cwd scoping and fail-open.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
ecc memory writes and --body-file reads fail on Windows. sameFileIdentity()
compares the dev field of a path-based stat against a handle-based fstat, and
libuv 1.49.0 through 1.50.x resolve path-based stat() and lstat() on Windows
through GetFileInformationByName, which leaves the volume serial unset while
fstat() reports it. The comparison never matches, so the TOCTOU guard rejects
every operation.
Keep the inode strict and compare dev only when both sides report one. POSIX
always reports a non-zero dev, so the original strict behaviour is preserved
there.
Request the guard's stats as BigInt. On the affected libuv versions dev is 0,
which leaves the inode as the only identity signal, and Windows file IDs run
past Number.MAX_SAFE_INTEGER where two distinct files can collapse to the same
number-valued inode.
Fixes#2626
main has been red since the Itô skill series landed. Two independent
problems, both in test files rather than shipped behavior:
- tests/ci/ito-inference-skill.test.js asserted a stale copy of the
capability:ito-compute description. #2706 added device revocation to
the lifecycle and updated manifests/install-components.json, but this
expectation was not updated with it. The manifest is the shipped
artifact, so the test expectation is what was wrong.
- three ito test files matched YAML frontmatter indentation with two
literal spaces inside a regex literal, which trips no-regex-spaces.
Replaced with an explicit ` {2}` quantifier, which matches identically.
The basket-compare occurrence was not visible in CI: npm run lint is
`eslint . && markdownlint ...`, so ESLint reported only the first file
and stopped. Fixing only what CI printed would have left main red on the
next run. The markdownlint half of that chain had therefore never
executed; it passes.
Verified on this branch: full suite 3707/3707, repo-wide ESLint clean,
and markdownlint clean under the exact CI glob.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix: ship new Ito skills through install manifests
* ci: audit shipped dependencies separately from tooling
* test(release): pass previous version to heading helper
Two ECC skills chaining off an ito-compute booking, per the Full-Stack Harness
Engineering Plan (2026-08-06):
- ito-inference: serve a model on booked GPUs via ecc ito serve (Layer 0.2).
- ito-training: run a staged, eval-gated training pipeline via ecc ito train
(Layer 0.3).
Both match the existing ito-compute skill: origin ECC, delegate to the canonical
CLI/backend, implement no parallel serving/training stack, chain off a completed
booking, and never book, reserve, or spend. They report the missing capability
while the desk serve-on-booking / training-run backends are scaffolds.
Co-authored-by: Affaan Mustafa <affaan@itomarkets.com>
Completes the model re-tiering from #2442: the gan-planner, gan-generator,
and gan-evaluator agents were already re-pinned to sonnet, but the
gan-style-harness script and docs still defaulted GAN_PLANNER_MODEL,
GAN_GENERATOR_MODEL, and GAN_EVALUATOR_MODEL to opus. Align the script
defaults, skill docs (en/ja/zh), and example commands with the landed
agent tiers. Opus remains available via the existing env overrides.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
release.test.js only greps release.sh for one of the five
update_latest_release_heading call sites, and plugin-manifest.test.js
only checks the headings committed today. Neither executes the rewrite,
so a helper that silently no-ops on a missing heading would ship green.
Extract the embedded node program from release.sh and run it against
fixtures to pin the fail-closed contract: bump stable and prerelease
headings, leave the rest of the file untouched, and exit non-zero
without writing when no heading matches. Also pin all five call sites so
the docs/zh-CN/README.md regression cannot recur.
Runs standalone via node tests/scripts/release-heading.test.js.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The Stop hook formats every JS/TS file edited during a response, grouped by the project root each file happens to sit in. That includes trees under .claude/plugins, which are third-party checkouts we only read.
Formatting them writes to code the user does not own. It also does real damage when a repo's committed code has drifted from its own formatter config: the rewrite is not a no-op but a wholesale reformat, so an unrelated bugfix ends up carrying hundreds of untouched lines. I hit this contributing to this repo — a 162-line fix arrived as a 478-line diff, most of it reformatted code the change never went near.
Skips both the user-level install root and a project-local one, mirroring the lookup in scripts/harness-audit.js. Paths are resolved before the prefix comparison, and a sibling such as .claude/plugins-backup does not match. The user own .claude config outside plugins is still formatted.
Adds 7 tests for the predicate, plus an end-to-end check that a clone file listed in the accumulator is left byte-identical. Suite 16 to 23.
Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
isCommitNoVerifyShortFlag anchored on the first character, so it only recognised the flag when it led the cluster. Git clusters short options, which means git commit -an is -a plus the bypass flag and skips the hooks. -sn and -vn slip through the same way, while -na and -nm are caught — the difference is position, not intent.
Scanning now walks the cluster and stops at a value-taking option, since that option swallows the rest as its inline value. The n in -mn stays message text, and the existing -tn case keeps working.
Adds 4 tests: the three clustered forms that were escaping, plus -mn to pin the inline-value boundary. Verified the three fail against current main. Suite 25 to 29.
Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
* fix: exclude ECC skills from antigravity install target
* test(install): cover antigravity skills exclusion
Two tests encoded the collision the parent commit fixes.
install-manifests used skills/example as its example of a supported
antigravity path; it now asserts skills are filtered and uses
commands/example for the positive case, so the test still proves
supported paths survive filtering.
install-apply asserted .agent/skills/tdd-workflow/SKILL.md exists. That
directory is antigravity's agent directory and already receives ECC
agents/, so the assertion was pinning ECC skills and ECC agents to the
same destination. Inverted, with the reason recorded inline.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Calum Reeves <reevesc88@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* fix(continuous-learning): cluster instincts by keyword overlap in /evolve
`cmd_evolve` grouped instincts by exact string equality of the whole
normalized trigger sentence. Triggers are free-form sentences, so every
instinct landed in its own bucket and `skill_candidates` was always empty.
`agent_candidates` is derived from `skill_candidates`, so agents never
generated either — `/evolve --generate` could only ever emit commands.
Measured on a 42-instinct project: 42 instincts produced 42 unique cluster
keys, largest cluster size 1.
Group on keyword overlap instead. Jaccard is the wrong metric here — trigger
keyword sets average ~7 words, so even clearly related pairs top out around
0.33 — so this uses the overlap coefficient (shared / smaller set) at 0.5,
plus a floor of 2 shared keywords so one incidental word cannot pull
unrelated instincts together. The same 42 instincts now yield 4 clusters.
Also unify the command/agent slug used by the preview and the writer. The
preview called `.replace('a ', '')`, which strips "a " anywhere in the
string, mangling "extracting data from Reddit" into
`/extracting-datfrom-R` while `--generate` wrote `extracting-data-from.md`.
Both paths now share `_evolved_command_name()` / `_evolved_agent_name()`.
Adds tests/scripts/instinct-cli-evolve.test.js, which fails on the previous
implementation (0 clusters instead of 1; preview name `extracting-datfrom-R`)
and covers the negative cases so unrelated triggers still stay apart.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(continuous-learning): correct clustering metric name in docstring
The docstring said "Jaccard" while the implementation uses the overlap
coefficient, which is the point of the change.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(continuous-learning): generate every evolve candidate and cut slugs on word boundaries
_generate_evolved() wrote only skill_candidates[:5], workflow_instincts[:5]
and agent_candidates[:3]. On a project with 36 command candidates that meant
5 files and no warning, so the output read as complete while 86% of the
candidates were dropped.
Generation is now unbounded by default and takes a --limit N flag for callers
that want a cap. A cap that truncates says so:
Note: writing 3 of 36 command candidates (--limit 3); 33 skipped.
The analysis preview keeps showing five per kind but now names the remainder
("... and 31 more command candidates not shown") instead of presenting a
sample as the whole set.
Slugs were also cut with a hard slice, which split words mid-token and
produced /investigating-comple, /learning-about-compl and
/researching-mechanis. _truncate_slug() retreats to the last separator that
fits, and keeps the full head when the cut already lands on one, so
"analyzing large text files" stays /analyzing-large-text rather than losing
a word. A first word longer than the limit still falls back to a hard cut
because no boundary is available.
Shorter slugs collide more easily, and a collision used to mean one file
silently overwriting another. _assign_unique_slugs() suffixes duplicates
(-2, -3) and is called by both the preview and the writer over the same
ordered list, so advertised names and written names cannot drift apart.
Skill directory naming moved to _evolved_skill_name(); it previously used its
own inline slug expression, so it was the one truncation the shared helper
did not cover.
Adds tests/scripts/instinct-cli-evolve-generate.test.js: 7 cases covering
word-boundary cuts, the separator-aligned cut, unbounded generation, --limit
reporting, collision dedup, preview remainder and preview/writer agreement.
Six of the seven fail against the previous implementation.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
npm audit --audit-level=high fails CI on two new high-severity
advisories:
- fast-uri GHSA-7p8r-x3mc-p8w7 (host confusion via backslash
authority introducer) — pinned at 3.1.4 via overrides/resolutions;
bump pins to the patched 3.1.5 (still within ajv's ^3.0.1 range)
- brace-expansion GHSA-rgw5-rvv9-x895 (DoS via unbounded intermediate
arrays) — in-range lockfile bump 5.0.8 -> 5.0.9 under minimatch
npm audit now reports 0 vulnerabilities. yarn.lock regenerated with
Yarn 4.9.2 to keep resolutions in sync.
Address CodeRabbit review on #2311: dedupe the local test(name, fn)
harness and route all reporter output through a shared helper
(tests/lib/helpers/mini-test-runner.js) instead of direct console.log.
The auto-update command's inline ECC_ROOT resolver delegates to
resolveEccRoot() with the default probe (scripts/lib/utils.js). A
hooks-runtime-only install copies scripts/lib/ into ~/.claude, so the
partial install satisfies the probe and shadows the full plugin root
under ~/.claude/plugins/marketplaces/. The command then fails with
MODULE_NOT_FOUND because ~/.claude/scripts/auto-update.js does not
exist.
Pass {probe: scripts/auto-update.js} so the resolver only accepts a
root that actually contains the script the command runs. Applied to
the command doc and its ja-JP/zh-CN translations, with regression
tests for both the resolver behavior and the embedded snippets.
* fix(mcp): accept reserved _meta field in tools/call params
The memory MCP server rejected any tools/call whose params contained a key
other than name/arguments, returning -32602 "Unknown or missing memory tool."
MCP clients (e.g. Claude Code) attach the spec-reserved `_meta` field
(such as progressToken) to request params, so every tool call from a
compliant client failed and the entire memory MCP surface was unreachable —
even though initialize/tools-list and the `ecc memory` CLI kept working.
Per the MCP base protocol, `_meta` is reserved for request metadata and
must be accepted. Add it to the params key allowlist.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(mcp): validate _meta shape and cover tools/call param allowlist
Address CodeRabbit review on #2670:
- Validate params._meta when present: accept metadata objects, reject null,
arrays, and scalar values (reuses isRecord). Keeps _meta optional and
preserves existing name/arguments/unexpected-key rejection.
- Add regression tests: accept _meta with progressToken, reject malformed
_meta values, and continue rejecting unrelated top-level params.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix: add claude-opus-5 to KNOWN_MODEL_WINDOW_TOKENS
claude-opus-5 has a 1M context window (verified: 250k tokens at 25%
usage = ~1M), but was missing from the model table. This caused
resolveContextWindowTokens() to fall back to the 200k default when
tokens < 200k, incorrectly triggering compact warnings in the first
20% of a 1M session.
Same failure class as #2290 (Opus 4.x) and #2461 (fable-5/mythos-5).
The env override (ECC_CONTEXT_WINDOW_TOKENS) remains the escape hatch
for unlisted models.
Refs: #2290, #2461, #2468
* test: add regression test for claude-opus-5 context window
Verifies resolveContextWindowTokens returns LARGE_CONTEXT_WINDOW_TOKENS
for claude-opus-5 at 50k tokens, matching the behavior of fable-5 and
mythos-5 in the known-model table.
* fix(hooks,lib): fix hook detection and parsing edge cases
- auto-tmux-dev: dev\b -> dev(?![\w-]) so one-shot dev-build/dev-docs scripts
are not detached into tmux; align command shapes (yarn run dev, bun dev) with
pre-bash-dev-server-block.js DEV_PATTERN.
- pre-bash-commit-quality: skip obvious non-secret placeholders (env refs,
${...}, <...>, whitelisted tokens) in the api-key rule without suppressing
real high-entropy secrets; make -m message extraction quote- and
escaped-quote-aware so `-m "fix: \"x\""` / apostrophes are not truncated.
- pre-compact: annotate the CURRENT worktree's session (match **Worktree:** /
legacy **Project:**) instead of the newest *-session.tmp across all projects,
layered onto the LLM-summary flow from #2388; a present-but-blank Worktree
header is treated as non-legacy (no foreign project fallback).
- shell-substitution: stop double-appending a trailing backslash in an
unterminated backtick span.
- utils readStdinJson: on overflow, settle and resolve {} immediately (clear
timer + listeners) instead of waiting for end/timeout and parsing a partial
prefix; surface the overflow on stderr.
Regression tests added/extended (new tests/hooks/pre-compact.test.js).
Addresses review feedback on #2405. The earlier block-no-verify change was
dropped: its message-value skip on merge/cherry-pick/am/rebase would let
`git rebase -m --no-verify` bypass the hook (rebase's -m is the boolean
--merge), a false-negative worse than the contrived false-positive it fixed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(ci): align hook fixtures and drain oversized stdin
---------
Co-authored-by: djpjronline-netizen <276112803+djpjronline-netizen@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>