Google Gemini (Antigravity & JetSki)
Native ADLC integration for Google Gemini (Antigravity/JetSki): an in-session rails-guard hook plus the unbypassable CI diff gate that is the real enforcement layer.
ADLC × Google Gemini (antigravity / jetski)
Native ADLC integration for the Google Gemini agent harnesses (Antigravity agy and JetSki jetski). Two layers:
- In-session rails-guard (advisory). A
PreToolUseplugin hook denies edits to frozen rails. It is best-effort: the host fails open on a non-zero hook exit, so a hook crash/timeout/Windows-path failure can let a rail write through. - CI diff gate (the guarantee).
scripts/rails-guard-ci.mjsis the unbypassable, cross-platform control. Make it a required check.
Install
One-liner via npx (recommended). The helper CLI fetches the package and registers it in one step:
(cd "$(mktemp -d)" && npx --package=@adlc/gemini adlc-gemini install)Global npm install. Install @adlc/gemini globally, then let the bundled helper register it:
npm install -g @adlc/gemini
adlc-gemini installLocal project install. If you prefer to install @adlc/gemini inside a project's node_modules, run the binary you just installed:
npm install @adlc/gemini
./node_modules/.bin/adlc-gemini installLocal checkout (from source). For local development or installing directly from a local adlc source checkout, run the checkout's own helper so it stages the plugin for you:
node /abs/path/to/adlc/plugins/adlc-gemini/bin/cli.mjs installNever hand the plugin directory to the host yourself. The host resolves its install
target as plugin@marketplace before deciding whether that target is a
filesystem path, so an @ anywhere in the argument is read as the separator.
Every location npm gives a scoped package contains one, so
[agent] plugin install $(npm root -g)/@adlc/gemini fails with
unknown marketplace: adlc/gemini and installs nothing. A source checkout is
not reliably safe either: an @ in any parent directory — a clone under
/home/user@example.com/..., say — reproduces the same failure. The helper stages
the plugin under an @-free path and installs from there; the host copies the
contents into ~/.gemini/config/plugins/adlc-gemini/, so the staging
directory is discarded afterwards.
Both halves of the one-liner are load-bearing, and each was reproduced against a real npm install before being adopted. This is a machine-level install that never needs your repository, so running it from a scratch directory costs nothing.
@latest—npx @adlc/geminiresolves a bare name against the current project first, so a repo shipping a workspace or dependency named@adlc/geminigets its binary executed. A version spec forces registry resolution; it pins nothing, it only refuses local shadowing.cd "$(mktemp -d)"— npm reads the current project's.npmrcand prepends itsnode_modules/.binto the child's PATH, so a hostile repo can redirect the@adlcscope to its own registry or plant a bin namedagyorjetskifor the helper to invoke. An empty directory removes both.
Universal installer (planned, not yet supported). Support for Google Gemini inside the vendor-neutral plugins installer is currently in development and not yet present. Once implemented, you will be able to install it via:
npx plugins add voodootikigod/adlcNote on native marketplace: the native .agents marketplace registration command ([agent] plugin install adlc-gemini@adlc) is currently subject to a CLI limitation where the CLI rejects unregistered third-party marketplaces with unknown marketplace: adlc. Global npm or local installation is the recommended path.
Then run /adlc-init inside your agent session (or execute the steps manually to bootstrap .adlc/ in your repository). Enforcement: export ADLC_P4_ENFORCEMENT=1 with an active ticket.
Install timeout. Each subprocess is bounded by ADLC_AGY_TIMEOUT_MS (milliseconds, default 120000). A failure reading timed out after 120000ms is that bound, not the host crashing. The value must be positive and finite.
Formal ADLC coverage
| Phase | Gemini surface |
|---|---|
| P0 Triage | /adlc-init, adlc-ticket skill → .adlc/tickets.json |
| P1 Interrogate | adlc spec-lint/premortem/parallax via the adlc CLI |
| P2 Decompose | adlc coldstart/model-router/merge-forecast |
| P3 Rail | PreToolUse rails-guard hook (advisory) + CI gate (guarantee) |
| P4 Build | doctrine skill; adlc flail-detector/consensus-fix |
| P5 Prosecute | adlc-prosecutor skill + prosecutor agent; adlc hollow-test/behavior-diff |
| P6 Integrate | human gate via adlc gate-manifest |
| P7 Distill | adlc lesson-foundry/rejection-mining |
Rail enforcement: two layers
The hooks are a best-effort, in-session layer, not the control:
-
In-session (advisory). The
PreToolUsehook returns{ "allow_tool": false, "deny_reason": "..." }on a frozen-rail edit. The host should block it, but the hook is subject to several fail-open conditions (see "Platform notes" below). The hook is configured to fail open so a hook bug/timeout/incompatibility can never brick your session. Bash/shell writes are not gated in-session (a Turing-complete shell can't be reliably parsed). -
Commit-time (unbypassable). The real control is the CI rail-freeze gate (
scripts/rails-guard-ci.mjs). It reads the frozen rail set from the trusted base ref and rejects any PR that edits a path frozen there, regardless of how the edit was made. Make it a required check.Scope limit: because the rail set is read from the base ref, the gate protects rails already frozen on the base branch. A PR that introduces a new rail and edits that path in the same PR is not caught. First-time rails are enforced only once they land on the base branch. Freeze rails in a separate, merged commit before the build PR if you need same-PR protection.
Rail contract
Enforcement is identical to the sibling integrations (the engine is @adlc/core,
not re-implemented here):
- Active ticket via
ADLC_TICKETor.adlc/current-ticket.json; a conflict between the two fails closed (denied). - Enforcement is phase-scoped to
ADLC_P4_ENFORCEMENT=1; otherwise no-op. - Rails in force = the single active ticket's
railsplus the trust-root rails.adlc/tickets.jsonand.adlc/current-ticket.json(not a union across tickets). - No-op when the repo is not ADLC-initialized, enforcement is off, or no active ticket resolves.
- Symlink aliases whose real target is a frozen rail are resolved and denied.
Platform notes / limitations
- POSIX only in-session (
$HOMEcommand path); Windows in-session is unsupported, but the CI gate protects Windows users regardless. - Shell (
run_command) writes are not gated in-session (CI gate catches them).
Appendix: verified hook contract (1.0.13+)
This appendix documents the native hook contract verified by direct probing. These facts are the foundation for the in-session rails-guard implementation and belong in any document describing the integration's enforcement surface.
| # | Fact |
|---|---|
| V1 | Google Gemini has a native plugin system: [agent] plugin install <path> installs into ~/.gemini/config/plugins/<name>/. Manifest is Claude-Code-shaped: root plugin.json (name, version) + skills/, agents/, commands/ (auto-converted to skills), root hooks.json. |
| V2 | [agent] plugin validate checks component presence only, not deep hook schema. Validation is not sufficient; runtime load must be tested. |
| V3 | hooks.json schema, verified working: { "<hook-name>": { "PreToolUse": [ { "matcher": ".*", "hooks": [ { "type":"command", "command":"<cmd>", "timeout":15 } ] } ] } }. Top level is keyed by hook name, then event, then an array of {matcher, hooks:[handler]}. |
| V4 | matcher is a regex on the tool name. .* matches all. |
| V5 | Deny contract: a hook denies by writing stdout {"allow_tool": false, "deny_reason": "..."} and exiting 0. {"allow_tool": true} allows. Non-zero exit = hook FAILURE = FAIL-OPEN (tool proceeds). |
| V6 | Hooks fire in --print (headless) mode: a write to a rail was actually blocked. So rails-guard protects both interactive sessions and the headless fleet path. |
| V7 | stdin payload (verbatim): {"toolCall":{"name":"write_to_file","args":{"TargetFile":"/abs","CodeContent":"…","Overwrite":true}},"workspacePaths":[],"conversationId":…,"transcriptPath":…,"stepIdx":3}. |
| V8 | Hook cwd is the plugin dir (~/.gemini/config/plugins/<name>/), not the repo. In --print mode workspacePaths was observed empty ([]). There is no workspace-root env var (env exposes ANTIGRAVITY_CONVERSATION_ID, not a workspace path). |
| V9 | The host expands $HOME (and shell env vars) in the command string; there is no ${CLAUDE_PLUGIN_ROOT}/${AGY_PLUGIN_ROOT}. Because plugins always install to $HOME/.gemini/config/plugins/<name>/, node $HOME/.gemini/config/plugins/adlc-gemini/hooks/adlc-rails-guard.cjs is portable across users with no install-time rewrite. |
Go deeper
Source: plugins/adlc-gemini/.
The rail-freeze gate this integration automates: Tests Are the Spec.
pi
Native ADLC extension for the pi coding agent: in-session rail, scope, and suppression enforcement with git-diff revert, plus five phase skills.
GitHub Copilot
Native ADLC integration for the GitHub Copilot CLI: seven lifecycle hooks, six phase skills, allowlisted MCP gate tools, and six read-only prosecution agents, backed by the unbypassable CI rail gate.