release: agent-sync + /council native workflow (5.260710.5) - #2542
Conversation
…ping feat(skills): plugin resource shipping — skills carry their own resources
…cs (agent-sync G3)
…saved-workflow input
feat(agent-sync): genie update converges every detected coding agent
📝 WalkthroughWalkthroughChangesAgent synchronization
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request implements the agent-sync feature, allowing genie update and genie install to converge all detected coding agents (Claude Code, Codex, and Hermes) from a single source root. It introduces the core synchronization engine, integrates it into the update and install commands, refactors the Claude Code SessionStart hook to delegate to the CLI, and adds a wish linter and fresh-install smoke tests. The review feedback identifies several critical cross-platform compatibility issues on Windows (including appending .exe to binary paths, using shell: IS_WINDOWS for process execution, and using 'junction' for directory symlinks), robustness improvements in orphan cleanup, and a resource leak in the smoke test script where process.exit(1) bypasses temporary directory cleanup.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| * /council stamp. | ||
| */ | ||
| function findGenieBinary() { | ||
| const canonical = join(GENIE_DIR, 'bin', 'genie'); |
There was a problem hiding this comment.
On Windows, the compiled or installed executable has a .exe extension (i.e., genie.exe). Checking for genie without the extension will fail to locate the canonical binary in bin/. We should use IS_WINDOWS to append the correct extension.
| const canonical = join(GENIE_DIR, 'bin', 'genie'); | |
| const canonical = join(GENIE_DIR, 'bin', IS_WINDOWS ? 'genie.exe' : 'genie'); |
| execFileSync(geniePath, ['update'], { | ||
| env: { ...process.env, GENIE_UPDATE_SYNC_ONLY: '1' }, | ||
| stdio: 'ignore', | ||
| timeout: 45000, | ||
| }); |
There was a problem hiding this comment.
On Windows, global CLI shims (like genie.cmd or genie.ps1) are executed via the shell. Running execFileSync with 'genie' directly without shell: IS_WINDOWS will fail with ENOENT. Adding shell: IS_WINDOWS ensures cross-platform compatibility.
execFileSync(geniePath, ['update'], {
env: { ...process.env, GENIE_UPDATE_SYNC_ONLY: '1' },
stdio: 'ignore',
timeout: 45000,
shell: IS_WINDOWS,
});| function fail(message: string): never { | ||
| console.error(`fresh-install-smoke: FAIL — ${message}`); | ||
| process.exit(1); | ||
| } |
There was a problem hiding this comment.
Calling process.exit(1) inside fail() immediately terminates the process synchronously, which bypasses the finally block in runWishScaffoldSmoke and leaks the temporary directory on disk. Changing fail to throw an error allows the finally block to execute and clean up resources before the process exits.
function fail(message: string): never {
throw new Error(message);
}| function main(): void { | ||
| const { skillsDir } = parseArgs(process.argv.slice(2)); | ||
| if (!existsSync(skillsDir)) fail(`skills dir not found: ${skillsDir}`); | ||
| const refs = checkSkillDirReferences(skillsDir); | ||
| runWishScaffoldSmoke(skillsDir); | ||
| const summary = `${refs} \${CLAUDE_SKILL_DIR} reference(s) resolved, wish scaffold works with no genie on PATH`; | ||
| console.log(`fresh-install-smoke: OK (${summary})`); | ||
| } |
There was a problem hiding this comment.
To support throwing errors from fail() (which ensures finally blocks are executed to clean up temporary directories), we should wrap the main execution in a try-catch block to log the failure and exit with a non-zero code.
| function main(): void { | |
| const { skillsDir } = parseArgs(process.argv.slice(2)); | |
| if (!existsSync(skillsDir)) fail(`skills dir not found: ${skillsDir}`); | |
| const refs = checkSkillDirReferences(skillsDir); | |
| runWishScaffoldSmoke(skillsDir); | |
| const summary = `${refs} \${CLAUDE_SKILL_DIR} reference(s) resolved, wish scaffold works with no genie on PATH`; | |
| console.log(`fresh-install-smoke: OK (${summary})`); | |
| } | |
| function main(): void { | |
| try { | |
| const { skillsDir } = parseArgs(process.argv.slice(2)); | |
| if (!existsSync(skillsDir)) fail(`skills dir not found: ${skillsDir}`); | |
| const refs = checkSkillDirReferences(skillsDir); | |
| runWishScaffoldSmoke(skillsDir); | |
| const summary = `${refs} \\\u0024{CLAUDE_SKILL_DIR} reference(s) resolved, wish scaffold works with no genie on PATH`; | |
| console.log(`fresh-install-smoke: OK (${summary})`); | |
| } catch (err) { | |
| console.error(`fresh-install-smoke: FAIL — ${err instanceof Error ? err.message : String(err)}`); | |
| process.exit(1); | |
| } | |
| } |
| mkdirSync(dirname(linkPath), { recursive: true }); | ||
| const stat = lstatSafe(linkPath); | ||
| if (stat === null) { | ||
| symlinkSync(hermesRoot, linkPath); |
There was a problem hiding this comment.
On Windows, creating directory symlinks using symlinkSync without specifying the 'junction' type can fail with EPERM unless the process runs with elevated Administrator privileges. Specifying 'junction' on Windows avoids this requirement and works seamlessly.
| symlinkSync(hermesRoot, linkPath); | |
| symlinkSync(hermesRoot, linkPath, process.platform === 'win32' ? 'junction' : undefined); |
| if (stat.isSymbolicLink()) return reconcileExistingSymlink(linkPath, hermesRoot, report); | ||
| const backup = ctx.backupInto('hermes', backupName, linkPath); | ||
| rmSync(linkPath, { recursive: true, force: true }); | ||
| symlinkSync(hermesRoot, linkPath); |
There was a problem hiding this comment.
On Windows, creating directory symlinks using symlinkSync without specifying the 'junction' type can fail with EPERM unless the process runs with elevated Administrator privileges. Specifying 'junction' on Windows avoids this requirement and works seamlessly.
| symlinkSync(hermesRoot, linkPath); | |
| symlinkSync(hermesRoot, linkPath, process.platform === 'win32' ? 'junction' : undefined); |
| for (const entry of readdirSync(targetParent, { withFileTypes: true })) { | ||
| if (entry.name.endsWith(STAGING_SUFFIX) || entry.name.endsWith(PREV_SUFFIX)) continue; | ||
| const dir = join(targetParent, entry.name); | ||
| if (classifyEntry(dir, entry) !== 'dir' || sourceNames.has(entry.name)) continue; | ||
| const manifest = readManifest(dir); | ||
| if (manifest === null) continue; | ||
| if (computeDirDigest(dir) === manifest.digest) { | ||
| ctx.backupInto(agent, entry.name, dir); | ||
| rmSync(dir, { recursive: true, force: true }); | ||
| report.skills.push({ name: entry.name, action: 'removed' }); | ||
| } else { | ||
| report.skills.push({ name: entry.name, action: 'kept-modified-orphan' }); | ||
| report.advisories.push(`kept modified orphan ${entry.name} (${agent})`); | ||
| } | ||
| } |
There was a problem hiding this comment.
If readdirSync or any individual orphan removal throws an error (e.g., due to a locked file, permission issue, or transient I/O error), the entire orphan cleanup is aborted, and subsequent critical steps like workflow stamping are skipped. Wrapping the directory reading and the individual loop iterations in try-catch blocks makes the cleanup process much more resilient.
let entries: Dirent[] = [];
try {
entries = readdirSync(targetParent, { withFileTypes: true });
} catch (err) {
report.advisories.push(`failed to read target directory ${targetParent} for orphan cleanup: ${errMsg(err)}`);
return;
}
for (const entry of entries) {
try {
if (entry.name.endsWith(STAGING_SUFFIX) || entry.name.endsWith(PREV_SUFFIX)) continue;
const dir = join(targetParent, entry.name);
if (classifyEntry(dir, entry) !== 'dir' || sourceNames.has(entry.name)) continue;
const manifest = readManifest(dir);
if (manifest === null) continue;
if (computeDirDigest(dir) === manifest.digest) {
ctx.backupInto(agent, entry.name, dir);
rmSync(dir, { recursive: true, force: true });
report.skills.push({ name: entry.name, action: 'removed' });
} else {
report.skills.push({ name: entry.name, action: 'kept-modified-orphan' });
report.advisories.push(`kept modified orphan ${entry.name} (${agent})`);
}
} catch (err) {
report.advisories.push(`failed to remove orphan ${entry.name} (${agent}): ${errMsg(err)}`);
}
}| execFileSync(binaryPath, ['update'], { env, stdio: 'inherit', timeout: 120_000 }); | ||
| }); | ||
| try { | ||
| exec(join(GENIE_BIN, 'genie'), { ...process.env, GENIE_UPDATE_SYNC_ONLY: '1' }); |
There was a problem hiding this comment.
On Windows, the executable is named genie.exe. Executing genie without the extension can fail or behave unexpectedly depending on the environment. Specifying the platform-specific binary name is safer and more robust.
const binaryName = process.platform === 'win32' ? 'genie.exe' : 'genie';
exec(join(GENIE_BIN, binaryName), { ...process.env, GENIE_UPDATE_SYNC_ONLY: '1' });There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b1f07913ac
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| try { | ||
| const binPath = join(genieHome, 'bin', name); | ||
| const homePath = join(genieHome, name); | ||
| if (existsSync(binPath) && !existsSync(homePath)) { |
There was a problem hiding this comment.
Refresh existing auxiliary trees during reinstall
When a user reruns the curl installer on an existing install, install.sh extracts the new tarball under ~/.genie/bin/{plugins,skills,templates} and then calls genie install, but this guard leaves the existing canonical ~/.genie/plugins tree untouched. Since runSync/resolveGenieSource prefer ~/.genie/plugins/genie over the freshly extracted bin/plugins/genie, the post-install agent sync can restamp Claude/Codex/Hermes from stale skills and workflows while the binary has already been replaced. The installer path needs to refresh or atomically swap the canonical auxiliary trees when a new bin copy is present, not only populate them the first time.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/genie-commands/update.ts`:
- Around line 1618-1620: Extract the duplicated errMsg helper from update.ts and
src/lib/agent-sync.ts into a shared utility such as src/lib/err-msg.ts,
preserving its Error message and String fallback behavior. Update both modules
to import and use the shared errMsg function, then remove their local
definitions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: a7f83a8c-802e-4b53-8061-79da831174c7
⛔ Files ignored due to path filters (3)
CLAUDE.mdis excluded by!*.mdplugins/genie/scripts/council-stamp.cjsis excluded by!plugins/genie/scripts/**plugins/genie/scripts/smart-install.jsis excluded by!plugins/genie/scripts/**
📒 Files selected for processing (40)
.claude-plugin/marketplace.json.genie/INDEX.md.genie/wishes/agent-sync/DESIGN.md.genie/wishes/agent-sync/WISH.md.genie/wishes/agent-sync/validate/g1-engine.sh.genie/wishes/agent-sync/validate/g2-wiring.sh.genie/wishes/agent-sync/validate/g3-gate.sh.genie/wishes/council-workflow/WISH.md.genie/wishes/council-workflow/validate/g4-consumers.sh.genie/wishes/plugin-resource-shipping/WISH.md.github/workflows/ci.ymlpackage.jsonplugins/genie/.claude-plugin/plugin.jsonplugins/genie/README.mdplugins/genie/package.jsonplugins/genie/workflows/council.jsscripts/build.jsscripts/fresh-install-smoke.test.tsscripts/fresh-install-smoke.tsscripts/skills-lint.test.tsscripts/skills-lint.tsscripts/smart-install.jsskills/README.mdskills/brainstorm/SKILL.mdskills/review/SKILL.mdskills/wish/SKILL.mdskills/wish/templates/wish-template.mdsrc/genie-commands/__tests__/update.test.tssrc/genie-commands/doctor.test.tssrc/genie-commands/doctor.tssrc/genie-commands/install.test.tssrc/genie-commands/install.tssrc/genie-commands/uninstall.test.tssrc/genie-commands/uninstall.tssrc/genie-commands/update.tssrc/lib/agent-sync.test.tssrc/lib/agent-sync.tssrc/lib/council-workflow-stamp.test.tssrc/lib/genie-home.tstests/e2e/v5-lifecycle.sh
💤 Files with no reviewable changes (1)
- scripts/smart-install.js
| function errMsg(err: unknown): string { | ||
| return err instanceof Error ? err.message : String(err); | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Consider extracting errMsg to a shared utility.
errMsg duplicates the same pattern already present in src/lib/agent-sync.ts. Extracting it to a shared src/lib/err-msg.ts (or similar) would eliminate the duplication and ensure consistent error formatting across modules.
♻️ Optional: extract to shared utility
+// src/lib/err-msg.ts
+export function errMsg(err: unknown): string {
+ return err instanceof Error ? err.message : String(err);
+}Then in update.ts:
-function errMsg(err: unknown): string {
- return err instanceof Error ? err.message : String(err);
-}
+import { errMsg } from '../lib/err-msg.js';🧰 Tools
🪛 ast-grep (0.44.1)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { execFileSync, execSync, spawn } from 'node:child_process';
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/genie-commands/update.ts` around lines 1618 - 1620, Extract the
duplicated errMsg helper from update.ts and src/lib/agent-sync.ts into a shared
utility such as src/lib/err-msg.ts, preserving its Error message and String
fallback behavior. Update both modules to import and use the shared errMsg
function, then remove their local definitions.
…on, replay-safe sweep Three ship-time LOW follow-ups from wish plugin-resource-shipping (PR #2540): 1. fresh-install-smoke.ts: fail() called process.exit(1), which skips finally blocks, so a phase-b failure orphaned its mkdtemp work dir despite the try/finally in runWishScaffoldSmoke. fail() now throws a SmokeFailure that main() catches and translates to the same exit-1 + stderr contract, so the existing finally runs on every exit path. Colocated test induces a phase-b failure and asserts no genie-fresh-install-* temp dir survives. 2. skills-lint.ts unguarded-repo-lint rule: the same-line guard was line.includes('package.json'), so any incidental mention (trailing comment, echo arg, reference after the command) exempted a repo-only lint invocation. Tightened to require a package.json probe that short-circuits (&&) into the command. Added fixtures for the false-exemption cases and broader probe shapes. 3. plugin-resource-shipping WISH.md G1 validation sweep (inline, not a validate/ dir): the recursive grep tripped on the lint rule's own negative fixtures in skills-lint.test.ts on replay. Switched to git grep -In with :(exclude) pathspecs (.genie history + the fixture file); still catches real stale refs.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/fresh-install-smoke.test.ts`:
- Around line 63-119: Clarify the scope of the “-fixture-” exclusion in
scaffoldWorkDirs() with a brief comment: it excludes fixture directories created
internally by the smoke script, not the test’s phaseb-fixture- temporary
directories, which do not use the genie-fresh-install- prefix.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: ef181512-246c-4d11-8fba-2dacb0b85217
📒 Files selected for processing (9)
.claude-plugin/marketplace.json.genie/wishes/plugin-resource-shipping/WISH.mdpackage.jsonplugins/genie/.claude-plugin/plugin.jsonplugins/genie/package.jsonscripts/fresh-install-smoke.test.tsscripts/fresh-install-smoke.tsscripts/skills-lint.test.tsscripts/skills-lint.ts
| describe('phase-b failure cleanup', () => { | ||
| let skillsDir: string; | ||
|
|
||
| // Wish skill whose SKILL.md references its in-skill template (phase-a | ||
| // passes) but whose template omits `## Execution Groups`, so the phase-b | ||
| // structural check fails after the work dir already exists. | ||
| function writeWishFixture(templateBody: string): void { | ||
| const wishDir = join(skillsDir, 'wish'); | ||
| mkdirSync(join(wishDir, 'templates'), { recursive: true }); | ||
| writeFileSync( | ||
| join(wishDir, 'SKILL.md'), | ||
| ['# wish', '', '```bash', 'cp "${CLAUDE_SKILL_DIR}/templates/wish-template.md" out.md', '```', ''].join('\n'), | ||
| ); | ||
| writeFileSync(join(wishDir, 'templates', 'wish-template.md'), templateBody); | ||
| } | ||
|
|
||
| const FULL_SECTIONS = [ | ||
| '## Summary', | ||
| '## Scope', | ||
| '### IN', | ||
| '### OUT', | ||
| '## Success Criteria', | ||
| '## Execution Strategy', | ||
| ]; | ||
|
|
||
| beforeEach(() => { | ||
| skillsDir = mkdtempSync(join(tmpdir(), 'phaseb-fixture-')); | ||
| }); | ||
| afterEach(() => { | ||
| rmSync(skillsDir, { recursive: true, force: true }); | ||
| }); | ||
|
|
||
| test('a phase-b failure exits non-zero and leaves no scaffold temp dir behind', () => { | ||
| writeWishFixture(`${FULL_SECTIONS.join('\n')}\n`); // no '## Execution Groups' | ||
| const before = scaffoldWorkDirs(); | ||
|
|
||
| const result = runSmoke(['--skills-dir', skillsDir]); | ||
|
|
||
| expect(result.code).not.toBe(0); | ||
| expect(result.stderr).toContain('fresh-install-smoke: FAIL'); | ||
| expect(result.stderr).toContain('## Execution Groups'); | ||
|
|
||
| const leaked = [...scaffoldWorkDirs()].filter((n) => !before.has(n)); | ||
| expect(leaked).toEqual([]); | ||
| }); | ||
|
|
||
| test('a clean phase-b run exits 0 and leaves no scaffold temp dir behind', () => { | ||
| writeWishFixture(`${[...FULL_SECTIONS, '## Execution Groups'].join('\n')}\n`); | ||
| const before = scaffoldWorkDirs(); | ||
|
|
||
| const result = runSmoke(['--skills-dir', skillsDir]); | ||
|
|
||
| expect(result.code).toBe(0); | ||
| const leaked = [...scaffoldWorkDirs()].filter((n) => !before.has(n)); | ||
| expect(leaked).toEqual([]); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Clarify the -fixture- filter scope.
The scaffoldWorkDirs() filter at line 13 excludes -fixture- dirs, but the test's own fixture dirs use phaseb-fixture- (line 89) which already doesn't match the genie-fresh-install- prefix. The -fixture- exclusion targets the smoke script's internal fixture dirs, not the test's. A one-line comment on line 13 clarifying this would prevent future confusion about whether the filter is redundant.
Based on learnings: "Test command boundaries, flags, plugin contracts, exit codes, stderr, and error-message formats, not only happy-path stdout." — the test suite correctly covers exit codes, stderr markers, and cleanup contracts.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/fresh-install-smoke.test.ts` around lines 63 - 119, Clarify the scope
of the “-fixture-” exclusion in scaffoldWorkDirs() with a brief comment: it
excludes fixture directories created internally by the smoke script, not the
test’s phaseb-fixture- temporary directories, which do not use the
genie-fresh-install- prefix.
Source: Learnings
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
.genie/wishes/council-workflow/qa/overnight-observations-20260710.md (1)
97-102: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winFix the shell line continuations.
The backslashes are followed by spaces and
#comments, so they do not escape the newline. This recipe will break instead of running onelangwatch analytics query.npx -y langwatch analytics query \ - --metric performance.total_cost \ # or performance.cost_billed | performance.total_tokens - --aggregation sum \ # trace-count uses: --metric trace-count --aggregation cardinality + --metric performance.total_cost \ + --aggregation sum \ --group-by metadata.model \ --start-date 2026-07-10T00:00:00Z --end-date 2026-07-10T23:59:59Z \ --time-scale full --format json + +# Alternatives: performance.cost_billed, performance.total_tokens, or +# trace-count with cardinality aggregation.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.genie/wishes/council-workflow/qa/overnight-observations-20260710.md around lines 97 - 102, Fix the shell command continuations in the affected recipe so each trailing backslash is the final character on its line; move any inline # comments to separate lines or remove them, ensuring the command executes as one continuous langwatch analytics query..genie/wishes/council-workflow/WISH.md (1)
101-101: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winRemove the obsolete SessionStart stamping contract.
The paragraph first pins stamping to the SessionStart hook, then says
genie updateowns stamping and SessionStart only delegates. The downstream implementation insrc/genie-commands/update.ts:1524-1590supports the latter; retain one current contract and move historical behavior to a note.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.genie/wishes/council-workflow/WISH.md at line 101, Update the stamping contract paragraph to describe the current design: `genie update` owns re-stamping through `resolveStampInputs`, while the SessionStart hook only throttles and delegates, with the CLI-less fallback retained where applicable. Remove obsolete requirements that `smart-install.js` stamp before early-exit guards, and move prior SessionStart-owned behavior into a clearly labeled historical note.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.genie/brainstorms/genie-spend/DRAFT.md:
- Around line 62-64: The calibration section mixes span-level
performance.total_cost with billable cost_billed, making the totals
non-comparable. Update the “$/day trend” and “$/model split” entries to use one
accounting metric consistently, or explicitly label the figures as
non-comparable and explain their different accounting bases.
In @.genie/brainstorms/genie-token-efficiency-program/MORNING-BRIEF-20260710.md:
- Around line 7-8: Synchronize all release references in the morning brief,
including the entries around the PR `#2542` description and lines 47–50, with the
authoritative plugin metadata version v5.260710.7. Replace v5.260710.5 and
v5.260710.6 where they describe the current release, or explicitly label them as
historical if retention is required; ensure the merge and promotion instructions
consistently target the same release artifact.
In @.genie/wishes/agent-sync/COORDINATION.md:
- Around line 11-21: Remove the unconditional destructive commands from the
“Branch surgery required first” section in COORDINATION.md, and archive the
historical checkout note or clearly mark it as conditional. Before suggesting
reset or rebase, require a clean worktree and verify the expected branch
ancestry and commit hashes; otherwise instruct the user to stop and inspect the
repository rather than discarding tracked work.
In @.genie/wishes/council-workflow/WISH.md:
- Line 5: Update the status in the WISH.md summary to reflect that G5 remains
pending live-QA and the group is PARTIAL, rather than claiming G1–G5 all SHIP;
keep the existing pending-gate details and references intact.
In @.genie/wishes/rolling-pr-auth-hardening/WISH.md:
- Line 95: Synchronize the execution-group acceptance checklist near the
referenced section with the stated resolution: mark criteria 1–3 as complete,
while leaving criterion 4 blocked on the required RELEASE_PLEASE_TOKEN setup, or
explicitly clarify that only the top-level criteria were verified. Update the
wish consistently so its completion evidence is not contradictory.
In @.genie/wishes/routing-matrix/qa/routing-pin-qa-20260710.md:
- Around line 97-102: Fix the query recipe’s shell continuations by ensuring
every backslash is the final character on its line; move the explanatory
comments for performance.total_cost, performance.cost_billed,
performance.total_tokens, and trace-count outside the continued command.
- Around line 101-102: Update both QA query recipes around the shown command and
the additionally referenced lines to use an end date of 2026-07-10T06:51:00Z,
matching the reported analysis window; alternatively, explicitly document that
the commands intentionally regenerate a full-day report.
In @.genie/wishes/skills-fable5-revamp/reports/execution-review-20260710.md:
- Line 82: Update verification.md’s diff-shape count from “12 A / 27 M” to “13 A
/ 28 M”, accounting for verification.md as the added file and
scripts/skills-lint.ts as the additional modified file.
---
Outside diff comments:
In @.genie/wishes/council-workflow/qa/overnight-observations-20260710.md:
- Around line 97-102: Fix the shell command continuations in the affected recipe
so each trailing backslash is the final character on its line; move any inline #
comments to separate lines or remove them, ensuring the command executes as one
continuous langwatch analytics query.
In @.genie/wishes/council-workflow/WISH.md:
- Line 101: Update the stamping contract paragraph to describe the current
design: `genie update` owns re-stamping through `resolveStampInputs`, while the
SessionStart hook only throttles and delegates, with the CLI-less fallback
retained where applicable. Remove obsolete requirements that `smart-install.js`
stamp before early-exit guards, and move prior SessionStart-owned behavior into
a clearly labeled historical note.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: a561f529-bf66-4fd0-8ef4-8717adfd497a
📒 Files selected for processing (20)
.claude-plugin/marketplace.json.genie/INDEX.md.genie/brainstorms/always-on-genie/DRAFT.md.genie/brainstorms/cross-agent-delegate/DRAFT.md.genie/brainstorms/genie-spend/DRAFT.md.genie/brainstorms/genie-spend/genie-spend-calibration-20260710.md.genie/brainstorms/genie-token-efficiency-program/HANDOFF-20260710.md.genie/brainstorms/genie-token-efficiency-program/MORNING-BRIEF-20260710.md.genie/brainstorms/skill-absorbs/DRAFT.md.genie/wishes/agent-sync/COORDINATION.md.genie/wishes/council-workflow/WISH.md.genie/wishes/council-workflow/qa/overnight-observations-20260710.md.genie/wishes/rolling-pr-auth-hardening/WISH.md.genie/wishes/routing-matrix/WISH.md.genie/wishes/routing-matrix/qa/routing-pin-qa-20260710.md.genie/wishes/skills-fable5-revamp/WISH.md.genie/wishes/skills-fable5-revamp/reports/execution-review-20260710.mdpackage.jsonplugins/genie/.claude-plugin/plugin.jsonplugins/genie/package.json
| **$/day trend point (span-level `performance.total_cost`):** 07-08 full **$4,352** · 07-09 full **$1,230** (pins merged 21:51Z) · 07-10 00:00–06:51Z **$1,613** partial → **~$5,650/day run-rate** (upper-ish bound, not typical). The 21-day baseline averages ~$850/day, but recent dogfood days sit well above — the exact heavy-spend spike `genie spend` needs to surface. | ||
|
|
||
| **$/model split (07-10, billable `cost_billed`):** Fable $956 (**57%**) · Opus $562 (34%) · Haiku $159 (9%) — Fable share rose on every measure this window (see the pin-QA file). |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Reconcile the cost metrics used in this calibration.
The daily trend uses span-level performance.total_cost ($1,613), while the model split uses billable cost_billed ($1,677). Presenting them in the same calibration section without explaining the difference can produce misleading totals and percentages. Use one metric consistently or clearly label the figures as non-comparable.
Based on the supplied calibration evidence and release documentation, these figures use different accounting bases.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.genie/brainstorms/genie-spend/DRAFT.md around lines 62 - 64, The
calibration section mixes span-level performance.total_cost with billable
cost_billed, making the totals non-comparable. Update the “$/day trend” and
“$/model split” entries to use one accounting metric consistently, or explicitly
label the figures as non-comparable and explain their different accounting
bases.
| ### 1. Merge promotion PR #2542 → stable release *(human-via-UI, §19)* | ||
| [PR #2542](https://github.com/automagik-dev/genie/pull/2542) `release: agent-sync + /council native workflow` is OPEN, base `main` ← head `dev`. **Verified: it already carries the resource-shipping LOW follow-ups (`65759f53`) and dev tip `9b15140f` — its head IS the live dev branch (v5.260710.6).** Only the *title label* says "5.260710.5" (stale from when it was created before #2543 merged); the diff is current. No rolling-PR refresh needed for correctness — merge it as-is via the GitHub UI. This mints the signed CalVer stable release that carries agent-sync + /council. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Synchronize the release references before using this brief.
The document references v5.260710.5 and v5.260710.6, while the supplied plugin metadata is now v5.260710.7. This can cause the release operator to merge or promote the wrong artifact. Replace these with one authoritative version, or explicitly mark the older values as historical.
Based on the supplied PR objectives and plugin metadata, the release identifiers are inconsistent.
Also applies to: 47-50
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.genie/brainstorms/genie-token-efficiency-program/MORNING-BRIEF-20260710.md
around lines 7 - 8, Synchronize all release references in the morning brief,
including the entries around the PR `#2542` description and lines 47–50, with the
authoritative plugin metadata version v5.260710.7. Replace v5.260710.5 and
v5.260710.6 where they describe the current release, or explicitly label them as
historical if retention is required; ensure the merge and promotion instructions
consistently target the same release artifact.
| ## 1. Branch surgery required first | ||
| This branch (`wish/agent-sync`) carries three foreign commits stacked on your 63f63c95 — | ||
| `805afcd4` (G1), `0584639d` (G3), `422dc6dd` (G2) of wish **plugin-resource-shipping**. They were | ||
| committed here by accident (shared checkout; your session switched the branch mid-flight of our | ||
| workflow). They are now **merged into dev via PR #2540** (rebuilt as `ecbb67fc`/`203c97df`/`bbd6439e`), | ||
| so the copies here are pure duplicates: | ||
|
|
||
| ```bash | ||
| git reset --hard 63f63c95 # shed duplicates (your docs commit becomes tip; G1 work is in untracked src/lib/*) | ||
| git rebase origin/dev # pick up #2540 + council merge + version bumps (dev tip ≥ bedd2062) | ||
| ``` |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Remove or guard the destructive branch-surgery instructions.
git reset --hard followed by a fixed-hash rebase can discard current tracked work and rewrite the branch if this historical checkout state is no longer exact. Archive this dated note or require clean-worktree and ancestry checks before any destructive command.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.genie/wishes/agent-sync/COORDINATION.md around lines 11 - 21, Remove the
unconditional destructive commands from the “Branch surgery required first”
section in COORDINATION.md, and archive the historical checkout note or clearly
mark it as conditional. Before suggesting reset or rebase, require a clean
worktree and verify the expected branch ancestry and commit hashes; otherwise
instruct the user to stop and inspect the repository rather than discarding
tracked work.
| | Field | Value | | ||
| |-------|-------| | ||
| | **Status** | DRAFT — design review SHIP + plan review SHIP (2026-07-09, same independent reviewer, 1 fix pass each); `/work` user-gated | | ||
| | **Status** | EXECUTED (2026-07-10) — G1–G5 all SHIP (see INDEX poured entry); design + plan reviews SHIP (2026-07-09, same independent reviewer, 1 fix pass each). **Live-QA ritual (Felipe: `/council "revisar tudo"`) and the final execution review remain pending post-stable-release** — the g5-gate parks in `qa/` until then. First real dogfood tonight surfaced and fixed a string-args defect (`ec68cd8f`): see [qa/overnight-observations-20260710.md](qa/overnight-observations-20260710.md) | |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Do not mark G5 as shipped while its live-QA criterion is unchecked.
Line 5 says “G1–G5 all SHIP,” but lines 176 and 178 explicitly keep G5 live QA pending and mark the group PARTIAL. Use a status that reflects the pending release gate.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.genie/wishes/council-workflow/WISH.md at line 5, Update the status in the
WISH.md summary to reflect that G5 remains pending live-QA and the group is
PARTIAL, rather than claiming G1–G5 all SHIP; keep the existing pending-gate
details and references intact.
| ## Review Results | ||
|
|
||
| _Populated by `/review`._ | ||
| **Resolution (2026-07-10): already implemented on dev, no dispatch needed.** A council freshness probe found the hardening had landed independently: `c4fdb32b` adds the fail-fast guard on an absent/dead PAT and splits the read path (`gh pr list` on `github.token`) from the create path (PAT), and `422caaa2` makes the workflow a healthy no-op when dev==main. `git branch -r --contains` confirms both commits are on `origin/dev` and `origin/main`. Acceptance criteria 1–3 are satisfied by the shipped code; criterion 4 (hourly run creates the rolling PR again) stays blocked on Felipe minting/refreshing `RELEASE_PLEASE_TOKEN` with `contents:read` + `pull-requests:write`. No engineering was dispatched for this wish. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Synchronize the acceptance checklist with the resolution.
The resolution says criteria 1–3 are satisfied, but the execution-group checklist at lines 64-66 remains unchecked. Check those boxes or explicitly state that only the top-level criteria were verified; otherwise the wish presents conflicting completion evidence.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.genie/wishes/rolling-pr-auth-hardening/WISH.md at line 95, Synchronize the
execution-group acceptance checklist near the referenced section with the stated
resolution: mark criteria 1–3 as complete, while leaving criterion 4 blocked on
the required RELEASE_PLEASE_TOKEN setup, or explicitly clarify that only the
top-level criteria were verified. Update the wish consistently so its completion
evidence is not contradictory.
| npx -y langwatch analytics query \ | ||
| --metric performance.total_cost \ # or performance.cost_billed | performance.total_tokens | ||
| --aggregation sum \ # trace-count uses: --metric trace-count --aggregation cardinality | ||
| --group-by metadata.model \ | ||
| --start-date 2026-07-10T00:00:00Z --end-date 2026-07-10T23:59:59Z \ | ||
| --time-scale full --format json |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Fix the shell line continuations in the query recipe.
Comments after the backslashes prevent newline escaping, so this command is not executable as written. Move comments outside the continued command or place each backslash at the end of its line.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.genie/wishes/routing-matrix/qa/routing-pin-qa-20260710.md around lines 97 -
102, Fix the query recipe’s shell continuations by ensuring every backslash is
the final character on its line; move the explanatory comments for
performance.total_cost, performance.cost_billed, performance.total_tokens, and
trace-count outside the continued command.
| --start-date 2026-07-10T00:00:00Z --end-date 2026-07-10T23:59:59Z \ | ||
| --time-scale full --format json |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Make the QA queries reproduce the reported time window.
The report analyzes 2026-07-10T00:00:00Z through approximately 06:51Z, but both recipes query through 23:59:59Z. Running them later will produce different totals. Pin the end time to 06:51:00Z or document that these commands intentionally regenerate a full-day report.
Also applies to: 112-114
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.genie/wishes/routing-matrix/qa/routing-pin-qa-20260710.md around lines 101
- 102, Update both QA query recipes around the shown command and the
additionally referenced lines to use an end date of 2026-07-10T06:51:00Z,
matching the reported analysis window; alternatively, explicitly document that
the commands intentionally regenerate a full-day report.
|
|
||
| **LOW-1 — Omni half (G5/G6) is not independently verifiable from this checkout.** The omni plugin lives in `automagik-dev/omni`, which is not present in the genie repo (`plugins/` holds only `genie` and `hermes-genie`). My SHIP for G5/G6 rests entirely on `verification.md`'s pasted `G5-OK`/`G6-OK` and the recorded per-group execution reviews. *Recommendation:* have the reviewer with the omni checkout (or the live-QA pass) re-confirm the omni 1,329→631 numbers and the omni-ops routing-table→references resolution before treating the omni PR as reviewed. This is a review-environment limitation, not evidence of a defect. | ||
|
|
||
| **LOW-2 — `verification.md` diff-shape count is one commit stale.** It records genie "12 A / 27 M"; the final delivered branch (`a4f089a5`) is "13 A / 28 M". The extra `M` is `scripts/skills-lint.ts`, modified by the lint-fix commit `a4f089a5` that landed *after* verification.md was authored at `af81783b`. Cosmetic staleness in the record; the load-bearing invariant (zero D, zero R, all files in-scope) holds. No action required beyond awareness. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- target file around the cited line ---\n'
sed -n '1,140p' .genie/wishes/skills-fable5-revamp/reports/execution-review-20260710.md
printf '\n--- locate verification.md references ---\n'
rg -n "verification\.md|12 A|27 M|13 A|28 M|+1 A|+1 M|scripts/skills-lint\.ts" .genie/wishes/skills-fable5-revamp -S
printf '\n--- list report files in scope ---\n'
find .genie/wishes/skills-fable5-revamp -maxdepth 3 -type f | sortRepository: automagik-dev/genie
Length of output: 248
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- target file around the cited line ---'
sed -n '1,140p' .genie/wishes/skills-fable5-revamp/reports/execution-review-20260710.md
echo
echo '--- locate verification.md references ---'
rg -n "verification\.md|12 A|27 M|13 A|28 M|\+1 A|\+1 M|scripts/skills-lint\.ts" .genie/wishes/skills-fable5-revamp -S
echo
echo '--- files under reports ---'
find .genie/wishes/skills-fable5-revamp/reports -maxdepth 2 -type f | sortRepository: automagik-dev/genie
Length of output: 21249
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- verification.md diff-shape section ---'
sed -n '96,112p' .genie/wishes/skills-fable5-revamp/verification.md
echo
echo '--- name-status vs cited merge-base ---'
git diff --name-status 63015670 a4f089a5 -- .genie/wishes/skills-fable5-revamp | sort
echo
echo '--- added files under the wish tree at a4f089a5 ---'
git diff --name-only --diff-filter=A 63015670 a4f089a5 -- .genie/wishes/skills-fable5-revamp | sortRepository: automagik-dev/genie
Length of output: 3262
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- all added files from merge-base 63015670 to a4f089a5 ---'
git diff --name-status --diff-filter=A 63015670 a4f089a5 | sort
echo
echo '--- all modified files from merge-base 63015670 to a4f089a5 ---'
git diff --name-status --diff-filter=M 63015670 a4f089a5 | sortRepository: automagik-dev/genie
Length of output: 1611
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- added-file listing inside verification.md, if present ---'
rg -n "^\s*A\s|^\s*genie:\s+12 A|^\s*genie:\s+13 A|reports/g8-v4-footprint\.md|scripts/skills-lint\.ts" .genie/wishes/skills-fable5-revamp/verification.md -n -S
echo
echo '--- nearby context in verification.md ---'
sed -n '100,120p' .genie/wishes/skills-fable5-revamp/verification.mdRepository: automagik-dev/genie
Length of output: 2830
Fix the diff-shape count in verification.md .genie/wishes/skills-fable5-revamp/verification.md:106-110 should say 13 A / 28 M, not 12 A / 27 M. The missing added file is .genie/wishes/skills-fable5-revamp/verification.md itself; the extra modified file is scripts/skills-lint.ts.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.genie/wishes/skills-fable5-revamp/reports/execution-review-20260710.md at
line 82, Update verification.md’s diff-shape count from “12 A / 27 M” to “13 A /
28 M”, accounting for verification.md as the added file and
scripts/skills-lint.ts as the additional modified file.
Promotes dev to main: agent-sync (genie update converges Claude Code/Codex/Hermes — #2541), /council string-args fix, plugin-resource-shipping (#2540), hook-injection-hardening, routing matrix. All dev CI green at b1f0791.
Summary by CodeRabbit
genie updatenow performs agent synchronization for Claude Code, Codex, and Hermes with backed-up, atomic managed updates and managed-orphan cleanup.genie install,genie doctor, andgenie uninstallnow include synchronized agent asset handling and reporting.agent-syncwish spec and/councildistribution model wheregenie updateis the canonical path./councilnow accepts more input shapes reliably (including audit-prefixed requests).