Skip to content

feat(ai-tools): migrate Gemini CLI → Antigravity CLI + OpenCode#5

Merged
yulonglin merged 1 commit into
mainfrom
ai-cli-migration
Jun 17, 2026
Merged

feat(ai-tools): migrate Gemini CLI → Antigravity CLI + OpenCode#5
yulonglin merged 1 commit into
mainfrom
ai-cli-migration

Conversation

@yulonglin

@yulonglin yulonglin commented Jun 17, 2026

Copy link
Copy Markdown
Owner

Summary

Gemini CLI consumer access ends 2026-06-18. This migrates the dotfiles off Gemini CLI to its official successor Antigravity CLI (agy) plus OpenCode (OSS, multi-provider, homebrew/core) as a model-agnostic option.

Split out of #4 (part 1 of 2) — this is the higher-risk half (it changes auto-commit automation), isolated so it can be reverted independently.

Changes

  • helpers.sh: install_gemini_cliinstall_opencode (core formula) + install_antigravity_cli (cask antigravity-cli; Linux = manual per curl|bash policy)
  • install.sh / config.sh / update-ai-tools / ai-check: swap Gemini → OpenCode + Antigravity; drop Coven + Crazytieguy/tap (third-party tap violates the no-new-taps policy)
  • auto_commit_worker.sh + ai_automation.sh: auto-commit backend order codex,geminicodex,opencode
  • sync_claude_to_gemini.shsync_claude_to_antigravity.sh (skills → ~/.gemini/antigravity-cli/skills; permission sync into settings.json, unmapped rules to a sidecar)
  • remove GEMINI.md + gemini/GEMINI.md (AGENTS.md is the successor instruction file)
  • supply-chain-security.md: two-gate (security-floor → adoption) tool-selection rule
  • README: Gemini CLI section → Antigravity CLI + OpenCode

Verification

  • Package names verified against formulae.brew.sh: antigravity-cli cask exists, ships the agy binary, and zaps ~/.gemini/antigravity-cli; opencode is in homebrew/core.
  • ⚠️ Runtime still pending a real Mac: agy permission-schema load, glob match semantics (see the sync script header TODO).

Merge note

Shares 3 files with the app-setup PR (install.sh, config.sh, supply-chain-security.md). Merging both is conflict-free except one trivial "keep both" conflict in supply-chain-security.md (adjacent section inserts).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added OpenCode and Antigravity CLI as new AI code automation tools with integrated skill synchronization.
  • Documentation

    • Updated AI assistant configuration and setup guides.
    • Added supply chain security policies for tool adoption.
  • Chores

    • Refreshed installation and update workflows for AI tools.
    • Updated backend processing order defaults.

Gemini CLI consumer access ends 2026-06-18; Google's official successor is
Antigravity CLI (`agy`). OpenCode (OSS, multi-provider, homebrew/core) is
installed alongside as a model-agnostic option.

- helpers.sh: install_gemini_cli → install_opencode (core formula) +
  install_antigravity_cli (cask antigravity-cli; Linux = manual per curl|bash policy)
- install.sh / config.sh / update-ai-tools / ai-check: swap Gemini → OpenCode + Antigravity;
  drop Coven + Crazytieguy/tap (third-party tap violates no-new-taps policy)
- auto_commit_worker + ai_automation: backend order codex,gemini → codex,opencode
- scripts: sync_claude_to_gemini.sh → sync_claude_to_antigravity.sh
  (skills → ~/.gemini/antigravity-cli/skills; AGENTS.md; permission sync to settings.json)
- supply-chain-security.md: two-gate modernity/adoption selection rule
- remove GEMINI.md + gemini/GEMINI.md (AGENTS.md is the successor instruction file)
- README: Gemini CLI section → Antigravity CLI + OpenCode

Verified against formulae.brew.sh: antigravity-cli cask (ships `agy`),
opencode in homebrew/core. Runtime behavior (agy permission load, glob
semantics) still pending Mac verification — see sync script header TODO.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Gemini CLI is retired and replaced with Antigravity CLI (its successor) and OpenCode across the dotfiles. A new scripts/sync_claude_to_antigravity.sh script replaces sync_claude_to_gemini.sh, carrying skill symlinks and permissions into Antigravity's config. Installer helpers, update tooling, runtime config defaults, aliases, and documentation are all updated to reflect the new tool set.

Changes

Gemini CLI → Antigravity CLI + OpenCode

Layer / File(s) Summary
Installer functions and update tooling
scripts/shared/helpers.sh, install.sh, custom_bins/update-ai-tools, scripts/cleanup/setup_ai_update.sh, scripts/cloud/setup.sh
Removes install_gemini_cli; adds install_opencode (Homebrew on macOS, Bun on Linux) and install_antigravity_cli (Homebrew cask on macOS, manual-only on Linux). Updates install.sh macOS/Linux branches and the update script to swap Gemini for OpenCode + Antigravity.
New Claude-to-Antigravity sync script
scripts/sync_claude_to_antigravity.sh, scripts/sync_claude_to_gemini.sh
Adds a 285-line script that cleans stale symlinks, creates Antigravity skill entries from Claude skills, and runs embedded Python to map Claude permissions into Antigravity's settings.json inside a marker-delimited block with an unmapped-rules sidecar. Removes the old Gemini sync script.
Runtime config defaults and alias wiring
config/ai_automation.sh, claude/hooks/auto_commit_worker.sh, config/aliases.sh, config.sh
Changes AUTO_COMMIT_BACKEND_ORDER default from codex,gemini to codex,opencode. Adds an opencode case in run_backend. Updates ai-check alias and component registry descriptions.
Documentation updates and Gemini content removal
GEMINI.md, gemini/GEMINI.md, README.md, claude/rules/supply-chain-security.md
Removes GEMINI.md redirect and 242 lines of Gemini agent guidance. Replaces the README Gemini CLI section with Antigravity + OpenCode docs. Adds a two-gate tool-selection security policy to supply-chain rules.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SyncScript as sync_claude_to_antigravity.sh
  participant SkillsFS as Antigravity Skills Dir
  participant Python as Embedded Python
  participant AntigravityJSON as settings.json

  User->>SyncScript: run script
  SyncScript->>SkillsFS: remove stale/broken symlinks
  SyncScript->>SkillsFS: create skill entries from Claude skills
  SyncScript->>Python: pass Claude settings.json path
  Python->>Python: map Claude permissions → command()/read_file() entries
  Python->>AntigravityJSON: merge mapped block (preserving user rules)
  Python->>SyncScript: write/clear unmapped sidecar
  SyncScript->>User: print completion + TODO notes
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 Gemini's gone, the orbit has shifted,
New tools have landed, the old ones uplifted.
Antigravity soars on a Homebrew cask,
OpenCode answers each auto-commit task.
Symlinks and settings in JSON aligned—
A rabbit reviewed it and liked what it signed! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: migrating from Gemini CLI to Antigravity CLI + OpenCode, which is the primary focus across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ai-cli-migration

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

🤖 Hi @yulonglin, I've received your request, and I'm working on it now! You can track my progress in the logs for more details.

@github-actions

Copy link
Copy Markdown

🤖 I'm sorry @yulonglin, but I was unable to process your request. Please see the logs for more details.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 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 `@claude/hooks/auto_commit_worker.sh`:
- Around line 249-252: In the opencode case block, update the run_with_timeout
command to include the --dir flag that specifies the working directory for the
opencode run command. Modify the line containing run_with_timeout 240 opencode
run "$prompt" to add --dir "$REPO_ROOT" before the output redirection, so the
opencode command executes in the correct repository directory and avoids relying
on the PWD environment variable which may not be set correctly in script
execution contexts.

In `@config.sh`:
- Line 36: The ai-tools install component description on line 36 includes
"Antigravity CLI" in its tool list, but the ai-update deploy component
description on line 67 omits "Antigravity CLI", creating an inconsistency.
Update the ai-update component description on line 67 to include "Antigravity
CLI" in the tool list so that both the ai-tools and ai-update descriptions
reference the same set of tools.

In `@custom_bins/update-ai-tools`:
- Around line 172-174: The brew upgrade command for the antigravity-cli cask is
missing the --greedy flag, which causes Homebrew to skip updates since this cask
declares auto_updates: true. Add the --greedy flag to the brew upgrade command
line between --cask and the cask name antigravity-cli to ensure the upgrade
actually proceeds rather than being silently skipped.

In `@README.md`:
- Line 291: The README.md note at line 291 incorrectly states that permission
sync is not yet ported, but the actual script
`scripts/sync_claude_to_antigravity.sh` now includes permissions mapping and
merge functionality. Update the note to accurately reflect that the script
currently performs both skills and permissions sync, replacing the outdated
statement about permission sync not being ported with current details about how
permissions are handled (including what was adapted or any remaining caveats).
- Line 278: The wording in the Gemini CLI retirement statement uses past tense
("was retired on") for a date in the future, which is inaccurate. Change the
tense from past to future by replacing "was retired on" with future-tense
phrasing such as "will be retired on" or "access ends on" while keeping the date
2026-06-18 unchanged. This ensures the statement correctly reflects that the
retirement has not yet occurred.

In `@scripts/sync_claude_to_antigravity.sh`:
- Around line 1-2: The shell script is missing strict error handling mode which
can cause failed commands to be silently ignored during filesystem mutations and
JSON writes. Add `set -euo pipefail` as a new line immediately after the
`#!/bin/bash` shebang at the start of the script. This enables the script to
exit on errors, treat undefined variables as errors, and properly handle pipe
failures, ensuring that any command failures are caught and prevent silent
failures.
- Line 42: Add a shellcheck directive comment immediately before the `source
"$HELPER"` statement to address the SC1090 warning about dynamic source paths.
Include a comment line that tells shellcheck how to handle the dynamic sourcing
(typically `# shellcheck source=/dev/null` or similar) directly above the source
command to suppress the warning and keep CI/static checks clean.
- Around line 52-70: The skill synchronization logic does not handle cases where
a skill changes type between sync runs, which can cause symlinks to point to old
targets or fail to replace existing directories. Before executing the ln or
mkdir commands in each case statement (user_skill, standalone_skill,
plugin_skill, agent_skill), add logic to remove any existing target at
$TARGET_DIR/$name if it exists and is incompatible with the current skill type
(e.g., remove a symlink when a directory is needed, or remove a directory when a
symlink is needed). This normalization of the destination shape per skill type
should happen before any ln or mkdir operations to ensure clean transitions.
- Around line 112-114: The BEGIN and END marker strings (lines 112-114) violate
Antigravity's permission schema by being inserted as literal array elements into
permissions.allow/deny/ask arrays at line 248, when the schema expects only
"action(target)" formatted strings. Replace the marker-based tracking approach
with sidecar metadata (already initialized at line 108) to track which entries
are managed by the script. Modify the merge_bucket() logic (lines 217-240) and
the final permissions write (line 248) to use set-difference filtering instead
of searching for BEGIN and END sentinel strings, removing old managed entries by
comparing against stored metadata rather than marker positions. Test the output
on a real Antigravity configuration before merging to validate the new approach
works correctly.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: d6b75dc4-8010-43da-a2fa-6f68d1e00dfc

📥 Commits

Reviewing files that changed from the base of the PR and between 07b120d and ed5abd6.

📒 Files selected for processing (15)
  • GEMINI.md
  • README.md
  • claude/hooks/auto_commit_worker.sh
  • claude/rules/supply-chain-security.md
  • config.sh
  • config/ai_automation.sh
  • config/aliases.sh
  • custom_bins/update-ai-tools
  • gemini/GEMINI.md
  • install.sh
  • scripts/cleanup/setup_ai_update.sh
  • scripts/cloud/setup.sh
  • scripts/shared/helpers.sh
  • scripts/sync_claude_to_antigravity.sh
  • scripts/sync_claude_to_gemini.sh
💤 Files with no reviewable changes (3)
  • GEMINI.md
  • scripts/sync_claude_to_gemini.sh
  • gemini/GEMINI.md

Comment on lines +249 to 252
opencode)
command -v opencode >/dev/null 2>&1 || return 1
run_with_timeout 240 opencode run "$prompt" >> "$log_file" 2>&1
;;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check opencode CLI for working directory flags
if command -v opencode &>/dev/null; then
  echo "=== opencode help output ==="
  opencode --help 2>&1 | head -50
  echo ""
  echo "=== opencode run help ==="
  opencode run --help 2>&1 | head -30
else
  echo "opencode not installed"
fi

Repository: yulonglin/dotfiles

Length of output: 85


🌐 Web query:

opencode CLI working directory --cd flag documentation

💡 Result:

The OpenCode CLI does not use a --cd flag to specify the working directory. Instead, it provides the following flags to set the working directory [1][2]: --cwd: Sets the current working directory (often with the short alias -c) [1][2]. --dir: Specifies the working directory to start the TUI in [3][4]. In some versions or documentation, the flag --cwd is explicitly listed with the short alias -c (e.g., opencode -c /path/to/project) [1][2][5]. Additionally, you can often simply pass the path as an argument directly when starting the command, such as opencode /path/to/project [6]. Please check your specific version's help documentation by running opencode --help to confirm which flag is available in your installation [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
# Check the context around lines 249-252 and the function signature
cat -n claude/hooks/auto_commit_worker.sh | sed -n '240,260p'

Repository: yulonglin/dotfiles

Length of output: 1085


🏁 Script executed:

#!/bin/bash
# Look at the run_backend function signature and how REPO_ROOT is used
cat -n claude/hooks/auto_commit_worker.sh | sed -n '35,70p'

Repository: yulonglin/dotfiles

Length of output: 1522


🏁 Script executed:

#!/bin/bash
# Check how codex backend uses --cd and the full context
cat -n claude/hooks/auto_commit_worker.sh | sed -n '240,260p'

Repository: yulonglin/dotfiles

Length of output: 1085


🌐 Web query:

opencode run command syntax working directory --cwd flag example

💡 Result:

In the OpenCode CLI, the --cwd flag is primarily used for configuring the working directory when starting a server process (e.g., listening on a host/port) [1][2][3]. To specify the working directory for a standard opencode run command, you should use the --dir flag [1][2][3]. Example usage: opencode run "list the files" --dir /path/to/your/project Key details: - --dir: Specifies the directory to run in or the path on a remote server when attaching [1][2]. - --cwd: Used in the context of server startup configurations, such as setting the working directory for the server process, defining the hostname, or enabling mDNS [1][2][3]. Note that when running opencode run programmatically (e.g., from a Python subprocess), there is a known issue where the tool may prefer the environment's PWD variable over the process's actual working directory [4]. If you experience unexpected path behavior in scripts, explicitly providing the --dir flag is the recommended workaround [4].

Citations:


Pass working directory to the opencode run command using the --dir flag.

The opencode backend at line 251 invokes opencode run "$prompt" without specifying a working directory, while the codex backend explicitly uses --cd "$REPO_ROOT". The OpenCode CLI uses the --dir flag (not --cd) to set the working directory for the run command. Without this flag, opencode may execute in an incorrect directory, causing auto-commit operations to fail or run against the wrong repository.

Additionally, OpenCode has a known issue where it may prefer the environment's PWD variable over the process's actual working directory when run from scripts, making explicit --dir specification the recommended workaround.

Update line 251 to:

run_with_timeout 240 opencode run "$prompt" --dir "$REPO_ROOT" >> "$log_file" 2>&1
🤖 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 `@claude/hooks/auto_commit_worker.sh` around lines 249 - 252, In the opencode
case block, update the run_with_timeout command to include the --dir flag that
specifies the working directory for the opencode run command. Modify the line
containing run_with_timeout 240 opencode run "$prompt" to add --dir "$REPO_ROOT"
before the output redirection, so the opencode command executes in the correct
repository directory and avoids relying on the PWD environment variable which
may not be set correctly in script execution contexts.

Comment thread config.sh
"zsh|ZSH + oh-my-zsh + powerlevel10k theme|all|true"
"tmux|Terminal multiplexer|all|true"
"ai-tools|Claude Code, Gemini CLI, Codex CLI|all|true"
"ai-tools|Claude Code, Codex CLI, OpenCode, Antigravity CLI|all|true"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Inconsistent tool list between install and update component descriptions.

Line 36 (ai-tools install description) includes "Antigravity CLI", but line 67 (ai-update deploy description) omits it, listing only "Claude, Codex, OpenCode". According to the update script header (context snippet), the actual update functionality does include Antigravity CLI. The description should match.

📝 Suggested fix to align descriptions
-    "ai-update|Daily auto-update: Claude, Codex, OpenCode|all|true"
+    "ai-update|Daily auto-update: Claude, Codex, OpenCode, Antigravity|all|true"

Also applies to: 67-67

🤖 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 `@config.sh` at line 36, The ai-tools install component description on line 36
includes "Antigravity CLI" in its tool list, but the ai-update deploy component
description on line 67 omits "Antigravity CLI", creating an inconsistency.
Update the ai-update component description on line 67 to include "Antigravity
CLI" in the tool list so that both the ai-tools and ai-update descriptions
reference the same set of tools.

Comment on lines +172 to +174
# NOTE: if the cask declares `auto_updates true`, brew skips it unless --greedy.
# Verify on a real Mac whether --greedy is needed for `agy` to actually move.
NONINTERACTIVE=1 HOMEBREW_NO_AUTO_UPDATE=1 brew upgrade --cask antigravity-cli 2>&1 \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check antigravity-cli cask auto_updates setting

if ! command -v brew &>/dev/null; then
  echo "brew not available - check requires macOS"
  exit 0
fi

echo "Fetching antigravity-cli cask metadata..."
brew info --cask antigravity-cli

echo ""
echo "Look for 'auto_updates' in the output above."
echo "If set to 'true', line 174 should use:"
echo "  brew upgrade --cask --greedy antigravity-cli"

Repository: yulonglin/dotfiles

Length of output: 104


🏁 Script executed:

cat -n custom_bins/update-ai-tools | sed -n '160,180p'

Repository: yulonglin/dotfiles

Length of output: 1027


🌐 Web query:

antigravity-cli brew cask auto_updates

💡 Result:

The Homebrew cask for antigravity-cli explicitly includes the auto_updates true directive in its configuration [1]. This enables automatic updates for the application when managing it via Homebrew, allowing it to integrate with standard Homebrew Cask update workflows [1][2]. The official Homebrew Cask definition for antigravity-cli is maintained in the Homebrew/homebrew-cask repository [1]. Because it is defined as a cask, users can install it using the command brew install --cask antigravity-cli [3][4][5]. The inclusion of auto_updates true is standard practice for casks that provide their own internal update mechanisms, which in this case leverages a JSON-based manifest to track and apply updates [1].

Citations:


Add --greedy flag to brew upgrade command for antigravity-cli.

The antigravity-cli cask declares auto_updates: true, which means Homebrew will skip updates unless --greedy is specified. Without this flag, line 174's upgrade command will silently fail to update the tool.

Update to:

NONINTERACTIVE=1 HOMEBREW_NO_AUTO_UPDATE=1 brew upgrade --cask --greedy antigravity-cli 2>&1 \
🤖 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 `@custom_bins/update-ai-tools` around lines 172 - 174, The brew upgrade command
for the antigravity-cli cask is missing the --greedy flag, which causes Homebrew
to skip updates since this cask declares auto_updates: true. Add the --greedy
flag to the brew upgrade command line between --cask and the cask name
antigravity-cli to ensure the upgrade actually proceeds rather than being
silently skipped.

Comment thread README.md
### Antigravity CLI (Google) + OpenCode

[Gemini CLI](https://github.com/google-gemini/gemini-cli) can sync with Claude Code configurations:
Gemini CLI was retired by Google on **2026-06-18**; [Antigravity CLI](https://antigravity.google/docs/cli-features) (`agy`) is its official successor. [OpenCode](https://opencode.ai) is installed alongside as a model-agnostic OSS option. Both are installed by the `ai-tools` component.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the retirement tense/date wording.

As of June 17, 2026, "was retired on 2026-06-18" is premature. Use future-tense phrasing (e.g., "access ends on June 18, 2026") until that date.

🤖 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 `@README.md` at line 278, The wording in the Gemini CLI retirement statement
uses past tense ("was retired on") for a date in the future, which is
inaccurate. Change the tense from past to future by replacing "was retired on"
with future-tense phrasing such as "will be retired on" or "access ends on"
while keeping the date 2026-06-18 unchanged. This ensures the statement
correctly reflects that the retirement has not yet occurred.

Comment thread README.md
- Project instructions come from `AGENTS.md` (Antigravity reads it natively)

**Note:** Gemini CLI uses a different skills format. The sync script adapts Claude's configuration but some features may not translate directly.
**Note:** Antigravity CLI is closed-source and brand-new; its skills/permissions schema differs from Claude's. The skills sync is adapted but untested end-to-end — permission sync is not yet ported (see the script header).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Documentation contradicts current script behavior on permission sync.

This line says permission sync is not ported, but scripts/sync_claude_to_antigravity.sh now performs permissions mapping + merge. Please align the README note with the actual current behavior and caveats.

🤖 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 `@README.md` at line 291, The README.md note at line 291 incorrectly states
that permission sync is not yet ported, but the actual script
`scripts/sync_claude_to_antigravity.sh` now includes permissions mapping and
merge functionality. Update the note to accurately reflect that the script
currently performs both skills and permissions sync, replacing the outdated
statement about permission sync not being ported with current details about how
permissions are handled (including what was adapted or any remaining caveats).

Comment on lines +1 to +2
#!/bin/bash

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add strict shell mode at script start.

The script performs filesystem mutation and JSON writes; without strict mode, failed commands can be silently ignored and still print success.

As per coding guidelines, "Shell scripts must use #!/bin/bash shebang with set -euo pipefail at the start".

Suggested patch
 #!/bin/bash
+set -euo pipefail
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#!/bin/bash
#!/bin/bash
set -euo pipefail
🤖 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/sync_claude_to_antigravity.sh` around lines 1 - 2, The shell script
is missing strict error handling mode which can cause failed commands to be
silently ignored during filesystem mutations and JSON writes. Add `set -euo
pipefail` as a new line immediately after the `#!/bin/bash` shebang at the start
of the script. This enables the script to exit on errors, treat undefined
variables as errors, and properly handle pipe failures, ensuring that any
command failures are caught and prevent silent failures.

Source: Coding guidelines

echo "Error: enumerate_claude_skills.sh not found at $HELPER" >&2
exit 1
fi
source "$HELPER"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Address shellcheck SC1090 for dynamic source.

Add an explicit shellcheck source directive before source "$HELPER" so CI/static checks stay clean.

As per coding guidelines, "Run shellcheck path/to/script.sh before shipping shell scripts".

Suggested patch
+# shellcheck source=scripts/helpers/enumerate_claude_skills.sh
 source "$HELPER"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
source "$HELPER"
# shellcheck source=scripts/helpers/enumerate_claude_skills.sh
source "$HELPER"
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 42-42: ShellCheck can't follow non-constant source. Use a directive to specify location.

(SC1090)

🤖 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/sync_claude_to_antigravity.sh` at line 42, Add a shellcheck directive
comment immediately before the `source "$HELPER"` statement to address the
SC1090 warning about dynamic source paths. Include a comment line that tells
shellcheck how to handle the dynamic sourcing (typically `# shellcheck
source=/dev/null` or similar) directly above the source command to suppress the
warning and keep CI/static checks clean.

Sources: Coding guidelines, Linters/SAST tools

Comment on lines +52 to +70
enumerate_claude_skills "$SOURCE_DIR" | while IFS=$'\t' read -r type name path; do
case "$type" in
user_skill)
ln -sfn "$path" "$TARGET_DIR/$name"
echo " User Skill: $name"
;;
standalone_skill)
mkdir -p "$TARGET_DIR/$name"
ln -sfn "$path" "$TARGET_DIR/$name/SKILL.md"
echo " Standalone Skill: $name"
;;
plugin_skill)
ln -sfn "$path" "$TARGET_DIR/$name"
echo " Plugin Skill: $name"
;;
agent_skill)
mkdir -p "$TARGET_DIR/$name"
ln -sfn "$path" "$TARGET_DIR/$name/SKILL.md"
echo " Agent Skill: $name"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle skill type transitions before writing targets.

If a skill name changes type across runs (e.g., previous plugin_skill symlink, now standalone_skill wrapper dir), current logic can write SKILL.md through an old symlink target or fail to replace existing directories cleanly. Normalize destination shape per type before ln/mkdir.

Suggested patch
+sync_skill_entry() {
+  local type="$1"
+  local name="$2"
+  local path="$3"
+  local dest="$TARGET_DIR/$name"
+
+  case "$type" in
+    user_skill|plugin_skill)
+      if [ -d "$dest" ] && [ ! -L "$dest" ]; then
+        rm -rf -- "$dest"
+      fi
+      ln -sfn "$path" "$dest"
+      ;;
+    standalone_skill|agent_skill)
+      if [ -L "$dest" ]; then
+        rm -f -- "$dest"
+      fi
+      mkdir -p "$dest"
+      ln -sfn "$path" "$dest/SKILL.md"
+      ;;
+  esac
+}
+
 enumerate_claude_skills "$SOURCE_DIR" | while IFS=$'\t' read -r type name path; do
-    case "$type" in
-        user_skill)
-            ln -sfn "$path" "$TARGET_DIR/$name"
-            echo "  User Skill: $name"
-            ;;
-        standalone_skill)
-            mkdir -p "$TARGET_DIR/$name"
-            ln -sfn "$path" "$TARGET_DIR/$name/SKILL.md"
-            echo "  Standalone Skill: $name"
-            ;;
-        plugin_skill)
-            ln -sfn "$path" "$TARGET_DIR/$name"
-            echo "  Plugin Skill: $name"
-            ;;
-        agent_skill)
-            mkdir -p "$TARGET_DIR/$name"
-            ln -sfn "$path" "$TARGET_DIR/$name/SKILL.md"
-            echo "  Agent Skill: $name"
-            ;;
-    esac
+    sync_skill_entry "$type" "$name" "$path"
+    echo "  ${type}: $name"
 done
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
enumerate_claude_skills "$SOURCE_DIR" | while IFS=$'\t' read -r type name path; do
case "$type" in
user_skill)
ln -sfn "$path" "$TARGET_DIR/$name"
echo " User Skill: $name"
;;
standalone_skill)
mkdir -p "$TARGET_DIR/$name"
ln -sfn "$path" "$TARGET_DIR/$name/SKILL.md"
echo " Standalone Skill: $name"
;;
plugin_skill)
ln -sfn "$path" "$TARGET_DIR/$name"
echo " Plugin Skill: $name"
;;
agent_skill)
mkdir -p "$TARGET_DIR/$name"
ln -sfn "$path" "$TARGET_DIR/$name/SKILL.md"
echo " Agent Skill: $name"
sync_skill_entry() {
local type="$1"
local name="$2"
local path="$3"
local dest="$TARGET_DIR/$name"
case "$type" in
user_skill|plugin_skill)
if [ -d "$dest" ] && [ ! -L "$dest" ]; then
rm -rf -- "$dest"
fi
ln -sfn "$path" "$dest"
;;
standalone_skill|agent_skill)
if [ -L "$dest" ]; then
rm -f -- "$dest"
fi
mkdir -p "$dest"
ln -sfn "$path" "$dest/SKILL.md"
;;
esac
}
enumerate_claude_skills "$SOURCE_DIR" | while IFS=$'\t' read -r type name path; do
sync_skill_entry "$type" "$name" "$path"
echo " ${type}: $name"
done
🤖 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/sync_claude_to_antigravity.sh` around lines 52 - 70, The skill
synchronization logic does not handle cases where a skill changes type between
sync runs, which can cause symlinks to point to old targets or fail to replace
existing directories. Before executing the ln or mkdir commands in each case
statement (user_skill, standalone_skill, plugin_skill, agent_skill), add logic
to remove any existing target at $TARGET_DIR/$name if it exists and is
incompatible with the current skill type (e.g., remove a symlink when a
directory is needed, or remove a directory when a symlink is needed). This
normalization of the destination shape per skill type should happen before any
ln or mkdir operations to ensure clean transitions.

Comment on lines +112 to +114
BEGIN = "// BEGIN CLAUDE SYNC (auto-generated)"
END = "// END CLAUDE SYNC"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check the repository structure and locate the file
git ls-files | grep -E "(sync|antigravity)" | head -20

Repository: yulonglin/dotfiles

Length of output: 873


🏁 Script executed:

# Now let's read the script to understand the issue
wc -l scripts/sync_claude_to_antigravity.sh

Repository: yulonglin/dotfiles

Length of output: 104


🏁 Script executed:

# Read the file around lines 112-114
sed -n '105,120p' scripts/sync_claude_to_antigravity.sh

Repository: yulonglin/dotfiles

Length of output: 570


🏁 Script executed:

# Read the file around lines 217-240
sed -n '210,245p' scripts/sync_claude_to_antigravity.sh

Repository: yulonglin/dotfiles

Length of output: 1127


🏁 Script executed:

# Get the full context - read the entire script in sections to understand the flow
head -150 scripts/sync_claude_to_antigravity.sh | tail -50

Repository: yulonglin/dotfiles

Length of output: 1800


🏁 Script executed:

# Search for Antigravity-related files and documentation
find . -type f -name "*antigravity*" -o -name "*permission*" | head -20

Repository: yulonglin/dotfiles

Length of output: 176


🏁 Script executed:

# Look for any error handling or validation in the sync script
grep -n "permission\|validate\|error\|except" scripts/sync_claude_to_antigravity.sh

Repository: yulonglin/dotfiles

Length of output: 1720


🏁 Script executed:

# Check if there's any Antigravity configuration or settings file
find . -type f \( -name "*.json" -o -name "*.rules" \) | grep -E "(antigravity|permission)" | head -10

Repository: yulonglin/dotfiles

Length of output: 44


🏁 Script executed:

# Look at the codex rules mentioned in the context
cat codex/rules/claude_sync.rules 2>/dev/null || echo "File not found"

Repository: yulonglin/dotfiles

Length of output: 5969


🏁 Script executed:

# Check for any documentation about permission format
find . -type f \( -name "*.md" \) -exec grep -l "permission\|Antigravity" {} \; | head -10

Repository: yulonglin/dotfiles

Length of output: 1947


🏁 Script executed:

# Look for usage of sidecar_path in the script
grep -n "sidecar" scripts/sync_claude_to_antigravity.sh

Repository: yulonglin/dotfiles

Length of output: 766


🏁 Script executed:

# Check the full merge_bucket function and surrounding context more carefully
sed -n '195,260p' scripts/sync_claude_to_antigravity.sh

Repository: yulonglin/dotfiles

Length of output: 2395


🏁 Script executed:

# Look at the documentation comment at the top about the schema
sed -n '1,40p' scripts/sync_claude_to_antigravity.sh

Repository: yulonglin/dotfiles

Length of output: 2213


🏁 Script executed:

# Check if there are any tests or validation of the generated permissions
find . -type f -name "*.sh" -o -name "*test*" | xargs grep -l "antigravity\|sync_claude" 2>/dev/null | head -10

Repository: yulonglin/dotfiles

Length of output: 155


🏁 Script executed:

# Check if there's any actual error handling or validation feedback in the script
tail -20 scripts/sync_claude_to_antigravity.sh

Repository: yulonglin/dotfiles

Length of output: 1309


🏁 Script executed:

# Look for any GitHub issues or documentation about this problem
find . -type f \( -name "*.md" -o -name "ISSUE*" -o -name "TODO*" \) -exec grep -l "BEGIN\|END\|antigravity.*validation\|permission.*format" {} \; 2>/dev/null | head -5

Repository: yulonglin/dotfiles

Length of output: 282


Review marker strings violate Antigravity permission schema; use sidecar metadata instead.

The BEGIN and END markers (lines 112–114) are inserted as literal array elements into permissions.allow/deny/ask (line 248), but Antigravity's documented schema expects only "action(target)" strings in these arrays. If Antigravity validates strictly, these markers may cause validation errors or be silently rejected.

Track which entries your script manages using sidecar metadata (already initialized at line 108), then recompute arrays by filtering out old entries via set-difference rather than relying on in-array sentinel strings. The script's own TODO comment (line 277) acknowledges this hasn't been validated on real Antigravity, so test the current output on a real Mac before merging.

Applies to the merge_bucket() logic at lines 217–240 and the final write at line 248.

🤖 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/sync_claude_to_antigravity.sh` around lines 112 - 114, The BEGIN and
END marker strings (lines 112-114) violate Antigravity's permission schema by
being inserted as literal array elements into permissions.allow/deny/ask arrays
at line 248, when the schema expects only "action(target)" formatted strings.
Replace the marker-based tracking approach with sidecar metadata (already
initialized at line 108) to track which entries are managed by the script.
Modify the merge_bucket() logic (lines 217-240) and the final permissions write
(line 248) to use set-difference filtering instead of searching for BEGIN and
END sentinel strings, removing old managed entries by comparing against stored
metadata rather than marker positions. Test the output on a real Antigravity
configuration before merging to validate the new approach works correctly.

@yulonglin yulonglin merged commit 92fd3a2 into main Jun 17, 2026
66 of 67 checks passed
yulonglin pushed a commit that referenced this pull request Jun 17, 2026
Post-merge cleanup for PRs #5/#6:
- README/CLAUDE.md: replace remaining 'Gemini CLI' mentions with the actual
  installed/updated set (Codex, OpenCode, Antigravity CLI)
- docs/cross-tool-extensibility.md: repoint the now-deleted sync_claude_to_gemini.sh
  to sync_claude_to_antigravity.sh; note Gemini CLI retirement (2026-06-18)
- app-picker: descriptions containing commas (e.g. Notion) broke gum --selected
  pre-selection; normalise commas in labels so the CSV is unambiguous

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant