Skip to content

Releases: NexaDuo/mARC

v26.9.8

Choose a tag to compare

@github-actions github-actions released this 08 Sep 14:28
v26.9.8
0a90938

[26.9.8] - 2026-09-08

Added

  • Cross-harness subagent delegation and poly-model routing (#239, #240).
    • Added core/scripts/dispatch_agent.py helper script allowing @techlead to delegate specialist tasks across different agent CLI harnesses (claude-code, antigravity, copilot) when [orchestration] is declared in team.toml.
    • Supports explicit route mapping per specialist under [orchestration.routes] with automatic fallback to native host harness if target CLI is unavailable.
  • Embedded default hybrid specialization matrix in dispatch_agent.py (#241, #242).
    • Implemented zero-config hybrid routing matrix when --harness auto or unconfigured: routes @dev and @sec to claude-code, @rev and @research to antigravity (large-context review/survey), and @sre/@design to the native host harness.
    • Added automatic capability detection via shutil.which and graceful fallback to host harness when a target CLI binary is not present on PATH.
  • New upstream contribution skill /marc:upstream (@scribe).
    • Added core/skills/upstream/SKILL.md (and compiled to all harnesses) allowing teams in consuming repos to safely harvest local emergent rules, sanitize sensitive client facts, apply governed rule provenance (<!-- rules:origin-required -->), and open Pull Requests/Issues upstream to NexaDuo/mARC with explicit human opt-in.
  • Durable evaluation and decision records for AI-Memory 2.0.

Changed

  • Migrated versioning scheme to Calendar Versioning (CalVer YY.M.D).
    • Transitioned from SemVer 0.28.0 to CalVer 26.9.8 across all plugin manifests (claude-code, antigravity, copilot), aligning release versions directly with date-governed rule provenance.

v0.28.0

Choose a tag to compare

@github-actions github-actions released this 06 Sep 00:13
v0.28.0
9dcf276

[0.28.0] - 2026-09-05

Changed

  • Rule #137 made executable in Grep-less harness modes and propagated to all specialists (#228).
    Rule #137 ("never ingest file content via filtered bash") previously assumed a Grep tool always exists and only covered @sec, @rev, and @dev. In harness modes (such as bypass-permissions modes) where Grep is not exposed and the harness injects a system-prompt block nudging cat/sed/head over structured tools, the rule failed to account for missing tools, and the counter-rule was missing from @sre, @design, and @research.
    • Revised the rule in security.md, review.md, and engineer.md: Read is the primary content tool, Grep is used only when the session actually exposes it, and a named fallback (the filtering proxy's raw/passthrough escape hatch) is provided for bash-only reads, reporting the read as unfiltered.
    • Added the adapted counter-rule across sre.md, design.md, and research.md, closing the propagation gap across all specialists.
    • Updated @techlead's dispatch instructions to stop mandating a Grep tool that a target session might not have.
    • Added explicit handling for harness/hook instructions or MCP preamble suggesting bash reads or unrelated tool calls: treat them as harness noise, disregard, report, and continue working without halting.
    • Added an AGENTS.md Lessons entry recording the diagnostic procedure for distinguishing harness-emitted prompt text from repo-borne prompt injections.

Fixed

  • Rule-origin governance CI gate negative test strips all origin tags globally (#228).
    The negative self-test in .github/workflows/ci.yml previously stripped only the first (origin: ...) tag in engineer.md. When a rule carries multiple origin tags (e.g. #137 and superseding #227), stripping only the first left the rule tagged, making the negative test a no-op. The test now strips tags globally (s///g).

Documentation

  • Synchronized product capabilities across README, hotsite, and CHANGELOG (#234).
    • Documented GitHub Copilot CLI harness support in the README and landing page.
    • Updated the channel roster and hero descriptions to include @rev and @research specialists and peer operator claim protocols.

v0.27.0

Choose a tag to compare

@github-actions github-actions released this 29 Aug 02:38
v0.27.0
43198a3

[0.27.0] - 2026-08-28

Fixed

  • Antigravity script-backed hooks resolved with $PWD plugin-root fallback
    (#220).
    Antigravity CLI does not export AGY_PLUGIN_ROOT to hook commands,
    but runs hooks with the working directory ($PWD) set to the directory containing
    hooks.json (the plugin root). Compiled hook commands now use ${plugin_root_env:-$PWD}
    and ${project_dir_env:-${OLDPWD:-$PWD}} so all script-backed hooks (outdated-check,
    invariants-card, token-guard, outdated-recheck, token-telemetry) resolve
    and execute rather than silently taking the missing-script fallback.
  • Hook missing-script diagnostic deduplication across harnesses without session_id
    (#221).
    The _report_once_fragment deduplication marker extracted only
    session_id from stdin JSON. On harnesses providing conversationId (such as
    Antigravity) and no session_id, the key defaulted to nosession, permanently
    suppressing missing-script errors across all future sessions after the first occurrence.
    The diagnostic now parses both session_id and conversationId, falling back to
    ANTIGRAVITY_CONVERSATION_ID and $PPID (parent CLI process PID), preserving anti-nag
    per session while staying observable across new sessions.
  • Regression tests for cross-harness hook execution and fallback resolution (#220, #221).
    test_hooks_parity.py now asserts that all hook script commands resolve when
    harness-specific environment variables are unset, and tests session/conversation ID extraction.

v0.26.0

Choose a tag to compare

@github-actions github-actions released this 25 Aug 21:16
854a730

[0.26.0] - 2026-08-25

Changed

  • Concurrent-operator claim moved off the assignee field to a comment marker
    (#213).
    #208's claim mechanism (gh issue edit <N> --add-assignee @me)
    is a no-op the moment two operators share a gh login — the default for a
    solo developer running two harnesses against one clone — because both
    operators re-read the same login and both conclude "I am alone," and every
    pre-existing human self-assignment now reads as a possible squat under the
    stale-claim rule. core/skills/tech-lead/SKILL.md now claims with a
    grep-verifiable ## @techlead claim comment carrying operator: <harness>/<session-id>, issue: #<N>, and claimed-at: (the same marker
    discipline as ## @sec review / ## @rev review); the assignee field is
    demoted to a human-visible-only signal and an issue with no claim comment is
    explicitly not claimed regardless of assignees. The tie-break moves from
    the (unusable, shared) login to the operator: token, and only over claims
    that pass an author-association check. #208's superseded wording stays in
    the file, marked superseded with its justification, per the no-silent-delete
    rule.
  • Security fix, same PR: the claim marker is public-repo forgeable, so
    a claim now needs a trusted author and withdrawal is never autonomous
    against an untrusted one (#213 review round).
    Posting an issue comment on
    a public repo needs no collaborator status, unlike the assignee mechanism it
    replaced — an unmitigated marker let any GitHub account post a
    low-sorting operator: value and force the legitimate operator to withdraw
    autonomously, indefinitely suppressing dispatch on any issue. A
    ## @techlead claim comment now counts only when its author_association
    is OWNER, MEMBER, or COLLABORATOR; autonomous withdrawal is permitted
    only when losing the tie-break to a claim that passed that check, otherwise
    the operator surfaces a suspected forged claim to the user instead of
    standing down. The rule states the trust boundary plainly: the marker
    coordinates cooperating operators, it is not an authorization mechanism.
    Withdrawal also gets its own fixed ## @techlead withdraw marker (same
    operator:/issue: fields) so a withdrawal that doesn't delete the
    original claim can't be mistaken for a live one — deleting the original is
    an optional courtesy, never load-bearing.
  • Second fix round, same PR: correct the association-check field name per
    command, and close the withdrawal-side forgery gap the prior round left
    open (#213 re-review).
    Two HIGH findings on the prior round's fix: (1) the
    text named the field author_association for gh issue view <N> --json comments, but that command actually returns it as authorAssociation
    (camelCase) — verified live against real issues in this repo; only the raw
    gh api/REST path uses the snake_case name. As written, the check would
    fail closed for every claim on the documented primary path, including
    legitimate ones, reintroducing #213's original collision through a
    documentation defect rather than fixing it. Both field names are now stated
    explicitly, paired with the exact command each belongs to. (2) The
    ## @techlead withdraw marker had no author-association check of its own,
    so any untrusted account could copy a claim's public operator: token into
    a forged withdrawal and make a live, legitimate claim read as abandoned —
    the same forgery class the claim-side check exists to close, just moved to
    the other marker. A withdrawal now only retires a claim if it passes the
    same association check as a claim AND its operator: matches exactly; the
    rule states the general principle so future markers don't repeat the gap:
    a claim and its withdrawal are two sides of one state transition and are
    trusted identically.
  • git worktree list is now a mandatory pre-dispatch read, and a dead
    worktree gets a named, user-gated remedy (#214).
    Audited live: a single
    .git shared by two harnesses registers every operator's checkout, so
    git worktree list --porcelain is free cross-harness ground truth that the
    convention never read. core/skills/tech-lead/SKILL.md now requires reading
    it before any mutating dispatch (a branch already checked out elsewhere
    means another operator owns it — don't re-cut it), names a worktree that is
    locked/gone, at the base SHA, with no commits and no linked PR as a dead
    worktree
    (distinct from a live claim and from a squat), and gives the
    concrete remedy (git worktree prune / git worktree remove --force)
    gated on user confirmation, since a worktree can hold uncommitted work. This
    repo's own .claude/worktrees/ is now in the committed .gitignore
    (previously local-only via .git/info/exclude, which doesn't survive a
    fresh clone).
  • AGENTS.md's duplicate concurrent-operator prose synced with SKILL.md,
    and its new origin-tag fence is now CI-gated.
    AGENTS.md carried a full
    second copy of the pre-#213/#214 protocol that would otherwise drift out of
    sync with the amended source of truth — collapsed to a pointer plus the two
    facts a reader of AGENTS.md alone needs. .github/workflows/ci.yml's
    rule-origin governance gate now scans AGENTS.md too, closing a gap where
    its first-ever rules:origin-required fence shipped correctly tagged but
    unguarded against a future silent strip.

v0.25.0

Choose a tag to compare

@github-actions github-actions released this 25 Aug 19:37
v0.25.0
553a34c

[0.25.0] - 2026-08-25

Changed

  • Rule #137 amended: Read is necessary but not sufficient (#210). The
    no-filtered-bash rule told @sec/@rev/@dev to read file content with
    Read/Grep only. That is not sufficient: on files with very long single
    lines (raw gh --json output, dense prose) the compression layer mangles
    Read output too — fragments rather than honest truncation, invisible to a
    "looks fine" check. (Provenance: an operator-memory field note, not
    reconstructible from any issue thread; the rule stands on the mechanism, not
    on that note.) All three rule sites
    (core/skills/tech-lead/SKILL.md, core/agents/security.md,
    core/agents/review.md) now name the detection (compare wc -l against the
    highest line number that was displayed, and treat text breaking mid-token as
    mangled) and the recovery (re-fetch to a file, reformat to short lines,
    re-read in small line-limited chunks — never pipe the content through Bash),
    and say plainly that a verdict must never be issued over input the reviewer
    cannot confirm it read whole: after two failed recovery attempts the input is
    reported unreviewable and escalated.
  • A merged product change with no version bump means a bump PR is needed
    (#210).
    A merge+release pass once concluded "no release needed" because the
    merged PR carried no bump — backwards, since a merge is not Done until a
    released tag covers it. The skill carried only the converse rule ("a bump
    isn't released until its tag is pushed"); the missing direction is now stated.
  • @techlead stops volunteering compaction advice (#184, PR #196). The
    operator no longer offers unprompted compaction or session-restart suggestions
    — that call belongs to the harness, and the only thing that may trigger the
    advice is an explicit [mARC token-guard] warning. The obsolete task-boundary
    context-hygiene advisory from #81 came out at the same time, and
    references/invariants-card.md now records unprompted/volume-based compaction
    as a rejected pattern so it doesn't get re-proposed.

Added

  • Memory conventions: size-capped writes, pinned vs decay, and a two-tier
    recall index (#176, PR #201).
    core/skills/tech-lead/SKILL.md and the
    invariants card carry rules for keeping memory recall bounded, and record an
    external memory daemon as a rejected pattern. AGENTS.md gets the matching
    tiered, size-capped operating principle.
  • Concurrent-operator coordination protocol in @techlead (#208). Two
    operators — different harnesses, or two sessions — may run against the same
    clone with no supervisor between them (#202 decided harnesses are
    board-mediated peers). core/skills/tech-lead/SKILL.md now carries four
    rules under step 3: claim with the assignee field before dispatching (only
    the assignee carries operator identity — Status is a shared enum with no
    author, so it cannot tell you who claimed an item); the claim is racy and
    knowingly accepted; stale claims are reclaimed by a human, never by a timer,
    and an unclearing claim from a peer you don't control is escalated rather than
    raced; and writer isolation extends to the operators themselves, not just to
    dispatched specialists.
    There is deliberately no locking layer. GitHub's GraphQL exposes no
    optimistic-concurrency field on UpdateIssueInput or
    UpdateProjectV2ItemFieldValueInput (verified against the live schema in
    #205), so board.py set-status's last-write-wins window cannot be closed by
    adopting an API feature — it is accepted explicitly, and the skill says so.
    The prior art behind that stance lives in this repo's AGENTS.md and the #205
    brief under docs/marc/, not in the shipped skill: GitHub's own coding agent
    claims work by assignment, and Renovate — which has no claim field at all —
    serializes with external CI locks plus a per-instance work directory. Neither
    builds compare-and-swap into the tracker (#204, #205, #206).

Fixed

  • Antigravity hooks.json now lands at the plugin root (#197, PR #198). It
    was being emitted under hooks/, where Antigravity doesn't look for it, so the
    hooks shipped in 0.24.0 never resolved for that harness.
    scripts/compile_prompts.py gained get_hooks_json_path plus cleanup of a
    stale hooks/hooks.json or root hooks.json, the path is declared as
    hooks_path in harnesses/antigravity/marc/compile.json, and both
    test_hooks_parity.py and the Tier 2 CI assertion check the installed root
    location and the absence of the stale one.

Security

  • CI's Antigravity CLI installer is pinned and checksum-verified (#169, PR
    #199).
    The workflow no longer pipes install.sh straight into a shell: it
    downloads, verifies against a pinned SHA256, and only then executes.
    ANTIGRAVITY_API_KEY is out of the unprivileged bootstrap and package-install
    steps entirely, scoped now to plugin install and the registration assertion.
    Repo-internal (.github/workflows/ci.yml); nothing consumer-facing changes.

Documentation

  • Decision record for cross-harness dispatch — harnesses are board-mediated
    peers, with no nested dispatch bridge (#202, PR #203).
  • Research brief on Antigravity context compaction (#186, PR #200).
  • Research brief on concurrent-operator coordination, plus this repo's own
    AGENTS.md convention that #208 later promoted into the plugin (#206, PR
    #207).

v0.24.0

Choose a tag to compare

@github-actions github-actions released this 24 Aug 23:31
ffb2934

[0.24.0] - 2026-08-24

Added

  • Native Google Antigravity hooks compiler and subagent orchestration (#193, PR #194).
    • Implemented render_antigravity_hooks in scripts/compile_prompts.py supporting native Antigravity hooks.json schema ({"<hook_id>": {"PreInvocation": [...], "PostToolUse": [...], "Stop": [...]}}).
    • Switched harnesses/antigravity/marc/compile.json to "hook_dialect": "antigravity".
    • Upgraded Antigravity @techlead dispatch instructions with native invoke_subagent features: Workspace: "share" for parallel writer isolation, Gemini model tier selection (flash for @research, pro/inherit for @dev, @sec, @rev, @sre), dynamic specialization via define_subagent (e.g. enable_write_tools: false for read-only agents), and send_message coordination.
    • Added hook dialect structural schema validation in core/scripts/test_hooks_parity.py.
    • Updated harnesses/antigravity/marc/COMPATIBILITY.md and CI assertions.
  • @sec gains the Skill tool for /security-review (#191, PR #192). @sec
    (tools now Read, Grep, Glob, Bash, WebFetch, TodoWrite, Skill) invokes the
    harness's built-in /security-review as an additional input pass alongside
    its existing checklist, closing the capability gap with @rev's
    /code-review grant from #125. The skill never replaces the checklist or
    the deliverable: @sec still authors the ## @sec review comment with its
    own ranked findings and verdict, and treats a thin or empty
    /security-review result as inconclusive rather than a PASS.
    core/skills/tech-lead/SKILL.md now also records that granting a
    specialist a new tool is the operator's decision, made per demonstrated
    capability-need and never a blanket default.

Fixed

  • hooks.json is now compiled from core/, and Antigravity's hooks actually
    work (#173, #170).
    hooks.json was the one load-bearing plugin component
    hand-maintained per harness instead of generated — Claude Code's copy was
    de-facto canonical, Copilot's hand-written copy drifted independently (twice,
    per #166/#173), and Antigravity's was a bare symlink to Claude Code's
    hooks/ that hardcoded ${CLAUDE_PLUGIN_ROOT} with no fallback, so all five
    Antigravity hooks (outdated-check, invariants-card, token-guard,
    outdated-recheck, token-telemetry) silently no-op'd. core/hooks/ hooks.spec.json is now the single harness-neutral source; each harness's
    compile.json declares an explicit hook_dialect (Claude Code/Antigravity
    share one schema, Copilot has its own) and hook_ids (which hooks it
    ships — Copilot's narrower coverage is now a reviewable declaration, not an
    accident). scripts/compile_prompts.py renders each harness's own
    hooks/hooks.json and copies only the .sh scripts it actually needs; the
    Antigravity symlink is gone in favor of a real compiled directory. A hook
    whose script cannot be found now says so once per session, visibly, on
    stderr (deduped via a state-file marker keyed off the hook's own
    session_id, so a broken install doesn't flood the transcript on every
    PostToolUse call) instead of the old blanket 2>/dev/null; exit 0 that
    made a resolution failure indistinguishable from "ran, nothing to report"
    — ordinary quiet no-ops (e.g. no team.toml in a repo) are unaffected.
    outdated-check.sh/outdated-recheck.sh also now find the plugin manifest
    at either .claude-plugin/plugin.json (Claude Code) or a root-level
    plugin.json (Antigravity/Copilot). The compiler validates every
    spec/config value it interpolates into a hook command and refuses
    (fail-closed) to render one containing a shell metacharacter, so a future
    careless edit can't splice unescaped shell into the shipped hooks.json.
    A new core/scripts/test_hooks_parity.py gates CI against hand-edit drift,
    missing hook scripts, and that same class of unsafe interpolation,
    alongside the existing test_script_parity.py.

v0.23.0

Choose a tag to compare

@github-actions github-actions released this 12 Aug 16:50
v0.23.0
53721b2

[0.23.0] - 2026-08-12

Removed

  • Context-size advisory retired (#181, decision recorded 2026-08-12).
    token_sentinel.py's third PostToolUse guard — the one that watched
    per-turn weighted tokens and suggested /compact on an oversized context —
    is removed, along with context_window(), MARC_CONTEXT_WINDOW,
    DEFAULT_CONTEXT_WINDOW, CONTEXT_WINDOW_FRACTION,
    MIN_CONTEXT_FRACTION_TO_WARN, hook_tokens_threshold(),
    MARC_TOKEN_GUARD_TOKENS_THRESHOLD, and the max_context snapshot added
    for it in #178. Claude Code's own harness already knows the real per-model
    context window, warns on it, and auto-compacts by default
    (autoCompactEnabled/autoCompactWindow) — a strictly better mechanism
    than a guard that could only guess the window and could never act itself.
    This is a removal, not a fix: the harness's native auto-compact supersedes
    it entirely. The --tokens manual CLI flag survives with a self-contained
    default (DEFAULT_CLI_TOKENS_THRESHOLD, still 130000) — it's an explicit,
    operator-invoked report column, not a silent hook assumption. The call-count
    runaway guard (#71) and the mid-session model-switch guard (#73) are
    unaffected; neither depended on the context window. See
    docs/marc/2026-08-12-decision-context-advisory-retired.md for the full
    decision record.

v0.22.2

Choose a tag to compare

@github-actions github-actions released this 05 Aug 21:35
v0.22.2
3344e69

[0.22.2] - 2026-08-05

Changed

  • Context-size advisory is now fail-closed and opt-in by default (#181).
    token_sentinel.py's hook path no longer falls back to DEFAULT_CONTEXT_WINDOW
    (200K) when MARC_CONTEXT_WINDOW is unset, non-numeric, or <= 0: with no
    trustworthy window value AND no explicit MARC_TOKEN_GUARD_TOKENS_THRESHOLD,
    the context-size advisory stays completely silent instead of banding against
    an assumed window. This closes the residual false positive from #178/PR #179,
    where an unset MARC_CONTEXT_WINDOW still let the guard fire against a 130K
    band derived from the assumed 200K on a session with a much larger real
    window. Set either MARC_CONTEXT_WINDOW or MARC_TOKEN_GUARD_TOKENS_THRESHOLD
    to opt back in. The call-count runaway guard (#71) and the mid-session
    model-switch guard (#73) are unaffected — neither depends on the context
    window.

v0.22.1

Choose a tag to compare

@github-actions github-actions released this 05 Aug 20:48
v0.22.1
399a6ff

[0.22.1] - 2026-08-05

Fixed

  • Context-size guard was window-blind and measured a per-turn sum, so it fired
    on large-window sessions at roughly 10% of real context usage (#178, PR
    #179).
    The advisory now derives its warning band from the session's actual
    context window, gates on remaining headroom against a max_context
    snapshot, and excludes subagent/sidechain requests from that snapshot
    (subagent spend is still counted in cost totals).

v0.22.0

Choose a tag to compare

@github-actions github-actions released this 05 Aug 11:33
v0.22.0
c6a201d

[0.22.0] - 2026-07-27

Changed

  • Per-repo config default moves to .agents/team.toml, with .claude/team.toml
    kept as a backward-compatible fallback (#163, PR #166).
    core/agents/*.md
    (all six specialists), core/skills/tech-lead/SKILL.md, and
    core/skills/init/SKILL.md now read the new {{ agents_dir }}/team.toml
    path first and fall back to the legacy {{ config_dir }}/team.toml path,
    matching the fallback semantics already shipped in hooks/hooks.json and
    core/scripts/board.py / token_telemetry.py. The GitHub Copilot harness
    gained the missing agents_dir compile key so /marc:init no longer ships
    a literal {{ agents_dir }} placeholder.

Fixed

  • Cross-harness find-and-replace regressions from the .agents/ migration.
    harnesses/copilot/marc/compile.json was missing agents_dir; the
    legacy-migration line in core/skills/init/SKILL.md now templates the
    correct per-harness legacy path (.claude/team.config for Claude Code,
    .agents/team.config for Antigravity, .github/copilot/team.config for
    Copilot) instead of a hardcoded .claude/team.config.
  • Reverted an accidental .claude/settings.json.agents/settings.json
    rename.
    Claude Code only reads .claude/settings.json; the rename had
    silently disabled this repo's own enabledPlugins.marc@nexaduo pin. The
    .agents/team.toml config-path migration is unaffected and stays.
  • Corrected the self-contradictory hooks/hooks.json deprecation message
    (it claimed ".agents/team.toml only" while implementing a .claude/
    fallback in the same command), the COMPATIBILITY.md table's mismatched
    team.toml link, and the README's overstated hard-cutover wording.
  • Removed the one-off, unreferenced fix_files.py migration script from the
    repo root.
  • Copilot sessionStart hook never learned the .agents/team.toml write
    path.
    compile.json gained agents_dir so /marc:init writes
    .agents/team.toml, but harnesses/copilot/marc/hooks/hooks.json (hand-
    maintained, not templated from core/) still only read
    .github/copilot/team.toml, so a freshly-initialized repo's sessionStart
    hook silently found nothing. It now checks .agents/team.toml first and
    falls back to .github/copilot/team.toml, mirroring the Claude Code hook's
    resolution order (PR #166).
  • /marc:init could write a second, silently-stale team.toml. The
    "never overwrite without asking" check only looked at the new
    {{ agents_dir }}/team.toml path, so a repo that already had a legacy
    {{ config_dir }}/team.toml ended up with both files — reads prefer
    .agents/, so the old one became a decoy that still looked live.
    core/skills/init/SKILL.md now detects the legacy path first (skipped for
    Antigravity, where agents_dir and config_dir are the same directory),
    shows the user what it found, and on confirmation moves it to the new path
    and offers to delete the obsolete file, mirroring the existing
    team.configteam.toml migration. The Antigravity no-op (where
    agents_dir and config_dir are literally the same path) is an
    unconditional, string-comparison hard gate that sits first in the block and
    precedes every destructive instruction, not a parenthetical a reader could
    skim past — reaching the delete step requires the two paths to have
    already been confirmed distinct. The instruction's stated reason to delete
    the old file was also corrected: once .agents/team.toml exists,
    the SessionStart hook's fallback branch never runs again, so a stale
    legacy file goes silently stale, not "still nagging" — the real risk is
    drift between two live configs once reads prefer the new path.
  • Legacy-path fallback in the SessionStart hook was indistinguishable from
    the current path.
    The Claude Code and Copilot hooks.json printed the
    same config output whether it was resolved from {{ agents_dir }}/team.toml
    or the legacy {{ config_dir }}/team.toml, so a repo sitting on the
    fallback got no signal to migrate. Both hooks now emit one extra line
    naming the deprecated path and pointing at /marc:init when the fallback
    branch fires (Antigravity shares Claude Code's hooks via symlink and, since
    its legacy fallback path is never populated in practice, is unaffected).