agent-intern 0.13.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_intern-0.13.0.dist-info/METADATA +572 -0
- agent_intern-0.13.0.dist-info/RECORD +10 -0
- agent_intern-0.13.0.dist-info/WHEEL +5 -0
- agent_intern-0.13.0.dist-info/entry_points.txt +2 -0
- agent_intern-0.13.0.dist-info/licenses/LICENSE +21 -0
- agent_intern-0.13.0.dist-info/top_level.txt +4 -0
- codex_bridge.py +550 -0
- server.py +2022 -0
- swarm.py +518 -0
- swarm_watch.py +560 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-intern
|
|
3
|
+
Version: 0.13.0
|
|
4
|
+
Summary: MCP server bridging the Antigravity (agy) and OpenAI Codex CLIs so Claude Code can drive them as sub-agents
|
|
5
|
+
Author: Sinan Tüfekçi
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/SinanTufekci/agent-intern
|
|
8
|
+
Project-URL: Repository, https://github.com/SinanTufekci/agent-intern
|
|
9
|
+
Project-URL: Issues, https://github.com/SinanTufekci/agent-intern/issues
|
|
10
|
+
Project-URL: Sponsor, https://github.com/sponsors/SinanTufekci
|
|
11
|
+
Keywords: mcp,claude,claude-code,antigravity,gemini,agy,llm,ai
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
21
|
+
Classifier: Topic :: Utilities
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: fastmcp>=2.0.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
28
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
<div align="center">
|
|
32
|
+
|
|
33
|
+
# Claude Code × Antigravity CLI + OpenAI Codex — MCP Bridge
|
|
34
|
+
|
|
35
|
+
<img src="assets/bridge-animation.svg" width="100%" alt="Claude Code bridging Antigravity CLI and OpenAI Codex" />
|
|
36
|
+
|
|
37
|
+
**Drive Google's [Antigravity](https://antigravity.google/) (Gemini 3.5 Flash) *and* [OpenAI Codex](https://developers.openai.com/codex/) as sub-agents inside [Claude Code](https://claude.com/claude-code) — text answers, image generation, and real coding work, on quota you already pay for.**
|
|
38
|
+
|
|
39
|
+
[](https://github.com/SinanTufekci/agent-intern/actions/workflows/ci.yml)
|
|
40
|
+
[](https://pypi.org/project/agent-intern/)
|
|
41
|
+
[](LICENSE)
|
|
42
|
+
[](https://www.python.org/)
|
|
43
|
+
[](https://modelcontextprotocol.io/)
|
|
44
|
+
[](https://glama.ai/mcp/servers/SinanTufekci/agent-intern)
|
|
45
|
+
[](https://antigravity.google/)
|
|
46
|
+
[](#requirements)
|
|
47
|
+
[](https://github.com/sponsors/SinanTufekci)
|
|
48
|
+
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
`agy`, Google's Antigravity CLI, ships a headless print mode (`agy -p`) that's **broken**: it
|
|
54
|
+
authenticates, talks to the model, gets the answer back… and then writes it to the *controlling
|
|
55
|
+
terminal* instead of its stdout — so anything capturing stdout gets nothing (and, run under a TUI,
|
|
56
|
+
agy's text leaks straight into the host's prompt). This bridge runs `agy -p` anyway, **detaches it
|
|
57
|
+
from your terminal** so it can't leak, reads the answer straight out of agy's *own* transcript
|
|
58
|
+
files, and hands it to Claude Code as clean MCP tools. Delegate cheap tool-calling work to Gemini
|
|
59
|
+
without leaving your terminal.
|
|
60
|
+
|
|
61
|
+
> [!WARNING]
|
|
62
|
+
> **This runs unsandboxed code with your privileges.** `agy -p` auto-executes its tools
|
|
63
|
+
> (read/write files, run shell commands, reach the network) with **no usable approval gate**.
|
|
64
|
+
> `--sandbox` (fixed for `-p` in agy 1.0.6+) blocks only *shell commands* — file writes and
|
|
65
|
+
> network egress stay wide open — so it's no real boundary. The `workspace` argument is a
|
|
66
|
+
> *starting context*, **not** a security boundary. Only use it with **trusted prompts on trusted
|
|
67
|
+
> content**; for real isolation, run the bridge inside a container or VM. **[Full details →](#security)**
|
|
68
|
+
|
|
69
|
+
> [!NOTE]
|
|
70
|
+
> **Now with OpenAI Codex too.** The same bridge exposes `codex_ask` / `codex_continue` /
|
|
71
|
+
> `codex_ask_watch` / `codex_swarm` / `codex_status`, driving OpenAI's `codex exec` on your existing
|
|
72
|
+
> Codex login. Codex is the *well-behaved* sibling: it writes its answer straight to a file the bridge
|
|
73
|
+
> requests (no transcript-scraping), supports model selection, and has a **real** sandbox. See
|
|
74
|
+
> [Codex bridge](#codex-bridge).
|
|
75
|
+
|
|
76
|
+
## Why you'd want this
|
|
77
|
+
|
|
78
|
+
| | |
|
|
79
|
+
|---|---|
|
|
80
|
+
| 🧠 **Second opinion** | Ask a different model family mid-task without switching tools. |
|
|
81
|
+
| 🎨 **Image generation** | Have Gemini draw an image and get the saved file back — no extra API key or image tool. |
|
|
82
|
+
| 💸 **Cheap delegation** | Burn Antigravity AI Pro quota on grunt work instead of Claude tokens. |
|
|
83
|
+
| 📁 **Cross-repo reads** | Point it at another project directory and let Gemini read/answer there. |
|
|
84
|
+
| 🔌 **Zero new auth** | Piggybacks the login you already did in the Antigravity IDE — no keys to manage. |
|
|
85
|
+
|
|
86
|
+
## How it works
|
|
87
|
+
|
|
88
|
+
```mermaid
|
|
89
|
+
flowchart LR
|
|
90
|
+
A([Claude Code]) -- "MCP tool call" --> B["agy bridge<br/>(server.py)"]
|
|
91
|
+
B -- "agy -p prompt" --> C[Antigravity CLI]
|
|
92
|
+
C -- "Gemini 3.5 Flash (High)" --> M((model))
|
|
93
|
+
M -- "answer" --> C
|
|
94
|
+
C -. "writes (stdout stays empty)" .-> T[("transcript.jsonl")]
|
|
95
|
+
B -- "reads final PLANNER_RESPONSE" --> T
|
|
96
|
+
B -- "plain text" --> A
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`agy -p` persists its real answer — the one it never sends to stdout — to:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
~/.gemini/antigravity-cli/brain/<conv-id>/.system_generated/logs/transcript.jsonl
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The bridge runs agy, locates the conversation via `cache/last_conversations.json` (falling back to
|
|
106
|
+
the newest `brain/` directory touched since launch), streams the transcript, and returns the final
|
|
107
|
+
`source=MODEL, status=DONE, type=PLANNER_RESPONSE` entry — the answer, minus the intermediate
|
|
108
|
+
tool-calling steps. `antigravity_continue` pins the workspace's **exact** conversation id via
|
|
109
|
+
`--conversation`, so it never resumes the wrong thread.
|
|
110
|
+
|
|
111
|
+
## Set up in 60 seconds
|
|
112
|
+
|
|
113
|
+
**Prerequisite (either method):** install agy and sign in to Antigravity **once** (via the IDE or
|
|
114
|
+
`agy -i`) so it has a credential to reuse.
|
|
115
|
+
|
|
116
|
+
### Recommended — no clone, you control updates
|
|
117
|
+
|
|
118
|
+
With [`uv`](https://docs.astral.sh/uv/) installed, register the bridge straight from
|
|
119
|
+
[PyPI](https://pypi.org/project/agent-intern/) under `mcpServers` in `~/.claude.json` — no
|
|
120
|
+
path to hardcode, no `git pull` to remember:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
"agent-intern": {
|
|
124
|
+
"command": "uvx",
|
|
125
|
+
"args": ["agent-intern"]
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
uvx pins to the version it first caches and does **not** auto-upgrade, so you never run an update you
|
|
130
|
+
didn't choose — important, since the bridge runs [unsandboxed code](#security): a surprise (or
|
|
131
|
+
compromised) release can't execute until you opt in. When the startup check warns that a newer
|
|
132
|
+
release is out, upgrade deliberately and restart Claude Code:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
uvx agent-intern@latest # fetch + run the newest release (refreshes uv's cache)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
> [!TIP]
|
|
139
|
+
> Prefer hands-off auto-updates? Put `"args": ["agent-intern@latest"]` in the config instead —
|
|
140
|
+
> every launch runs the newest release. Convenient, but it pulls new code without asking each time.
|
|
141
|
+
|
|
142
|
+
### From source
|
|
143
|
+
|
|
144
|
+
Clone it instead if you want to hack on the bridge or pin a local copy:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
git clone https://github.com/SinanTufekci/agent-intern.git
|
|
148
|
+
cd agent-intern
|
|
149
|
+
pip install fastmcp
|
|
150
|
+
python test_smoke.py # 3 real round-trips (ask, continue, image) — should print three PASS lines
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
> [!NOTE]
|
|
154
|
+
> The smoke test costs a tiny bit of AI Pro quota and takes ~30–60 s.
|
|
155
|
+
|
|
156
|
+
Then point Claude Code at the absolute path to `server.py` under `mcpServers` in `~/.claude.json`:
|
|
157
|
+
|
|
158
|
+
<table>
|
|
159
|
+
<tr><th>Windows</th><th>macOS / Linux</th></tr>
|
|
160
|
+
<tr><td>
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
"agent-intern": {
|
|
164
|
+
"command": "python",
|
|
165
|
+
"args": ["C:\\path\\to\\server.py"]
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
</td><td>
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
"agent-intern": {
|
|
173
|
+
"command": "python3",
|
|
174
|
+
"args": ["/path/to/server.py"]
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
</td></tr>
|
|
179
|
+
</table>
|
|
180
|
+
|
|
181
|
+
Restart Claude Code. **Eleven tools** appear — six for Antigravity (**`antigravity_ask`**, **`antigravity_continue`**, **`antigravity_image`**, **`antigravity_swarm`**, **`antigravity_image_swarm`**, **`antigravity_status`**) and five for Codex (**`codex_ask`**, **`codex_continue`**, **`codex_ask_watch`**, **`codex_swarm`**, **`codex_status`**) — each prefixed `mcp__agent-intern__`. The single-prompt Antigravity tools take a **`watch=true`** flag for the live browser view; Codex has a dedicated **`codex_ask_watch`**.
|
|
182
|
+
|
|
183
|
+
> *"Use antigravity_ask to summarize the README of this repo in three bullets."* → Claude routes the prompt
|
|
184
|
+
> through the bridge, agy reads the file under the workspace root, and the answer comes back as a
|
|
185
|
+
> plain string.
|
|
186
|
+
|
|
187
|
+
## Tools
|
|
188
|
+
|
|
189
|
+
| Tool | Purpose |
|
|
190
|
+
|---|---|
|
|
191
|
+
| `antigravity_ask(prompt, workspace?, timeout_s?=180, watch?=false)` | Start a **new** Antigravity conversation. Pass `watch=true` to open the live browser view (see [Watch mode](#watch-mode)). |
|
|
192
|
+
| `antigravity_continue(prompt, workspace?, timeout_s?=180, watch?=false)` | Continue the conversation **rooted at `workspace`** (pinned by id). `watch=true` opens the live view. |
|
|
193
|
+
| `antigravity_image(prompt, output_path?, workspace?, timeout_s?=240, watch?=false)` | Generate an image with Antigravity; saves the file (extension corrected to the real bytes) and returns its path + format/size. `watch=true` streams progress and **shows the image** inline. |
|
|
194
|
+
| `antigravity_swarm(prompts, workspaces?, max_concurrency?=4, timeout_s?=180, watch?=false)` | Run **several prompts in parallel** as independent agy workers; returns every answer in one block (see [Swarm](#swarm)). |
|
|
195
|
+
| `antigravity_image_swarm(prompts, output_paths?, workspaces?, max_concurrency?=4, timeout_s?=240, watch?=false)` | Generate **several images in parallel** (one worker per prompt). |
|
|
196
|
+
| `antigravity_status()` | Setup diagnostics: **the bridge's own version + whether a newer release is available**, plus agy version/compat, state dirs, and newest-transcript readability. Spends no quota. |
|
|
197
|
+
|
|
198
|
+
`workspace` defaults to the MCP server's current working directory. Point it at a real project dir
|
|
199
|
+
for context-aware answers — agy gives the model access to files under that root.
|
|
200
|
+
|
|
201
|
+
`antigravity_image` forces agy to save to an explicit absolute path — without one, agy
|
|
202
|
+
falls back to its own scratch dir (`~/.gemini/antigravity-cli/scratch/`). It then
|
|
203
|
+
corrects the file extension to match the real bytes: agy's image model picks the
|
|
204
|
+
format itself (JPEG for photo-like images, PNG for flat graphics), so a requested
|
|
205
|
+
`out.png` may come back as `out.jpg`. The returned path always reflects the true
|
|
206
|
+
format.
|
|
207
|
+
|
|
208
|
+
<a id="codex-bridge"></a>
|
|
209
|
+
|
|
210
|
+
## 🤖 Codex bridge
|
|
211
|
+
|
|
212
|
+
Alongside Antigravity, the bridge drives **[OpenAI Codex](https://developers.openai.com/codex/)** via
|
|
213
|
+
`codex exec`. Where `agy -p` is broken (it never writes to stdout, so the bridge scrapes transcript
|
|
214
|
+
files), `codex exec` is well-behaved: it writes its final message to a file the bridge asks for via
|
|
215
|
+
`-o/--output-last-message`, so the answer comes back clean — no scraping. Continue works by capturing
|
|
216
|
+
the session id from codex's own rollout files (`~/.codex/sessions/.../rollout-*.jsonl`) and resuming
|
|
217
|
+
with `codex exec resume <id>`.
|
|
218
|
+
|
|
219
|
+
| Tool | Purpose |
|
|
220
|
+
|---|---|
|
|
221
|
+
| `codex_ask(prompt, workspace?, sandbox?="read-only", model?, timeout_s?=180)` | Start a **new** Codex session. `sandbox` is a **real** boundary (see below); `model` selects the model (`-m`). |
|
|
222
|
+
| `codex_continue(prompt, workspace?, timeout_s?=180)` | Continue the Codex session **rooted at `workspace`** — resumes the exact session id, falling back to the newest on-disk session for that cwd after a server restart. |
|
|
223
|
+
| `codex_ask_watch(prompt, workspace?, sandbox?, model?, timeout_s?=180)` | Like `codex_ask`, but open the live browser view, streaming codex's steps from its `--json` event stream (same viewer as the Antigravity watch — see [Watch mode](#watch-mode)). |
|
|
224
|
+
| `codex_swarm(prompts, workspaces?, sandbox?, model?, max_concurrency?=4, timeout_s?=180)` | Run **several Codex prompts in parallel** as independent one-shot workers; every result in one block. |
|
|
225
|
+
| `codex_status()` | Setup diagnostics: codex version, login status (`codex login status`), sessions dir. Spends no quota. |
|
|
226
|
+
|
|
227
|
+
**How it differs from the Antigravity tools**
|
|
228
|
+
|
|
229
|
+
- **Real sandbox.** `sandbox` accepts `read-only` (default — reads and answers, writes nothing),
|
|
230
|
+
`workspace-write` (may edit files under the workspace), or `danger-full-access` (no sandbox —
|
|
231
|
+
avoid). Unlike agy's no-op `--sandbox`, codex's `-s` actually enforces this. `codex exec` has no
|
|
232
|
+
interactive approval gate, so this flag **is** your safety boundary — opt into write access deliberately.
|
|
233
|
+
- **Model selection works.** `model` maps to codex's `-m`; agy hangs on a model switch in print mode,
|
|
234
|
+
codex does not.
|
|
235
|
+
- **No image tool.** Codex is a coding agent, not an image model — there's no `codex_image`. Its
|
|
236
|
+
strength is reasoning and real code/repo work.
|
|
237
|
+
- **Auth.** Uses your existing Codex login (ChatGPT account or API key). Run `codex login` once; check
|
|
238
|
+
with `codex_status`. No new keys for the bridge to manage.
|
|
239
|
+
|
|
240
|
+
> [!WARNING]
|
|
241
|
+
> `codex exec` runs the model as an **autonomous agent with no interactive approval gate**. The
|
|
242
|
+
> `sandbox` flag (default `read-only`) is the real boundary, but `workspace-write` /
|
|
243
|
+
> `danger-full-access` let it modify files — and a swarm runs N agents at once. Only use it with
|
|
244
|
+
> **trusted prompts on trusted content**.
|
|
245
|
+
|
|
246
|
+
<a id="watch-mode"></a>
|
|
247
|
+
|
|
248
|
+
## 👁️ Watch mode — Agent Intern (experimental)
|
|
249
|
+
|
|
250
|
+
Pass **`watch=true`** to `antigravity_ask`, `antigravity_continue`, or `antigravity_image`
|
|
251
|
+
to **watch agy work live in a little terminal-style browser window** called
|
|
252
|
+
**Agent Intern**. agy still runs headless; alongside it the bridge serves a tiny page on
|
|
253
|
+
`127.0.0.1` and opens it in a small, chromeless app window that streams agy's steps —
|
|
254
|
+
its planner narration (▸), the **real commands** it runs (`$`), and completions (✓) —
|
|
255
|
+
read live from the transcript, with the final answer rendered as Markdown (and, for
|
|
256
|
+
`antigravity_image` with `watch=true`, the generated image shown inline).
|
|
257
|
+
|
|
258
|
+
<div align="center">
|
|
259
|
+
<table>
|
|
260
|
+
<tr>
|
|
261
|
+
<td width="50%" align="center"><b><code>antigravity_ask</code> / <code>antigravity_continue</code></b></td>
|
|
262
|
+
<td width="50%" align="center"><b><code>antigravity_image</code> — image inline</b></td>
|
|
263
|
+
</tr>
|
|
264
|
+
<tr>
|
|
265
|
+
<td><img src="assets/watch-ask.gif" width="100%" alt="Agent Intern watch window streaming agy's steps for a text ask — narration, the real commands it runs, completions — then rendering the final Markdown answer"></td>
|
|
266
|
+
<td><img src="assets/watch-image.gif" width="100%" alt="Agent Intern watch window streaming an image generation and rendering the finished image inline"></td>
|
|
267
|
+
</tr>
|
|
268
|
+
</table>
|
|
269
|
+
<sub>Real captures — agy runs headless while the <b>Agent Intern</b> window live-streams its steps (▸ narration · <code>$</code> commands · ✓ completions), then shows the final answer or image.</sub>
|
|
270
|
+
</div>
|
|
271
|
+
|
|
272
|
+
- **Cross-platform & best-effort.** Prefers a Chromium browser (`--app` mode) for the
|
|
273
|
+
windowed look; falls back to a normal browser window. If nothing can open, the run
|
|
274
|
+
still completes and returns normally.
|
|
275
|
+
- **Window size.** Set **`AGY_WATCH_WINDOW_SIZE`** (e.g. `AGY_WATCH_WINDOW_SIZE=480,700`)
|
|
276
|
+
to resize the window; default is `560,760`. Press **Enter / Esc** in the window to
|
|
277
|
+
close it.
|
|
278
|
+
- **One window, reused.** Repeated watch calls **reuse the already-open window**
|
|
279
|
+
instead of stacking a new one each time — the open page resets itself for the new
|
|
280
|
+
run (the swarm dashboard rebuilds for the new fan-out). If you closed the window, the
|
|
281
|
+
next run opens a fresh one. Set **`AGY_WATCH_ALWAYS_NEW=1`** to force a new window
|
|
282
|
+
every time.
|
|
283
|
+
- **Progress, keyboard & copy.** Each panel shows a time progress bar (elapsed /
|
|
284
|
+
timeout). The swarm dashboard adds an overall done/total bar and per-row time bars;
|
|
285
|
+
use **↑/↓** to select a worker and **↵** to open its detail window. Answers render
|
|
286
|
+
as Markdown with a **copy** button, and a "jump to latest" badge appears if you
|
|
287
|
+
scroll up.
|
|
288
|
+
- **Coarse, not token-level.** agy flushes its transcript in chunks, so you get a
|
|
289
|
+
handful of live steps, not character streaming. The returned value is identical to
|
|
290
|
+
the non-watch call. Nothing is sent anywhere but your own machine.
|
|
291
|
+
|
|
292
|
+
<a id="swarm"></a>
|
|
293
|
+
|
|
294
|
+
## 🐝 Swarm — run agy workers in parallel
|
|
295
|
+
|
|
296
|
+
`antigravity_swarm` and `antigravity_image_swarm` fan a list of prompts out to
|
|
297
|
+
**independent agy workers that run truly concurrently** (capped at
|
|
298
|
+
`max_concurrency`, default 4), then return every worker's result in one block.
|
|
299
|
+
Good for independent, cheap sub-tasks — summarise N files, ask the same question
|
|
300
|
+
about N repos, generate N images — without paying for them one at a time.
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
antigravity_swarm(prompts=[
|
|
304
|
+
"Summarise src/auth.py in 2 bullets.",
|
|
305
|
+
"Summarise src/db.py in 2 bullets.",
|
|
306
|
+
"List the public functions in src/api.py.",
|
|
307
|
+
])
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
<div align="center">
|
|
311
|
+
<img src="assets/watch-swarm.gif" width="62%" alt="Agent Swarm dashboard: three agy workers running in parallel, each row showing its repo, prompt, latest step and a per-worker time bar, while the overall done/total counter climbs 0/3 → 2/3 → 3/3">
|
|
312
|
+
<br>
|
|
313
|
+
<sub><code>antigravity_swarm(..., watch=true)</code> — one row per worker; the done/total bar climbs as workers finish. Click a row (or <b>↑/↓</b> then <b>↵</b>) to pop that agent into its own window.</sub>
|
|
314
|
+
</div>
|
|
315
|
+
|
|
316
|
+
**How it stays correct under concurrency.** The single-agent tools serialize
|
|
317
|
+
through a lock because agy rewrites `last_conversations.json` on every call, so
|
|
318
|
+
concurrent runs sharing one state dir would race. The swarm sidesteps this
|
|
319
|
+
entirely: each worker runs with its **own isolated `HOME`/`USERPROFILE`**, so
|
|
320
|
+
agy's `brain/`, `cache/`, and `last_conversations.json` never collide — no lock
|
|
321
|
+
needed. Auth still works because agy reads it from the **OS credential store**,
|
|
322
|
+
not from `~/.gemini` (verified on agy 1.0.9). Each worker's `cwd` is still its
|
|
323
|
+
real `workspace`, so file access there is unchanged — HOME redirection isolates
|
|
324
|
+
*state only*. Measured ~**2.8× speedup at 3 workers** (the AI Pro backend does
|
|
325
|
+
not serialize per-account); higher `max_concurrency` trades quota/rate-limit
|
|
326
|
+
pressure for wall-clock.
|
|
327
|
+
|
|
328
|
+
- **`workspaces`** — omit for the server cwd; pass a **1-item list** to point every
|
|
329
|
+
worker at the same dir; pass **one entry per prompt** for per-worker dirs.
|
|
330
|
+
- **Error isolation** — a worker that fails is reported in place; the others still
|
|
331
|
+
return.
|
|
332
|
+
- **`watch=true`** — opens a thin live **Agent Swarm** dashboard (one row per
|
|
333
|
+
worker showing the repo, prompt, and latest step). **Click a row** to pop that
|
|
334
|
+
agent out into its own window streaming its full step log, beside the dashboard.
|
|
335
|
+
|
|
336
|
+
> [!WARNING]
|
|
337
|
+
> A swarm launches **N unsandboxed agy agents at once** — N× the prompt-injection
|
|
338
|
+
> "lethal trifecta" surface of a single call (see [Security](#security)). Only use
|
|
339
|
+
> it with **trusted prompts on trusted content**.
|
|
340
|
+
|
|
341
|
+
## Model & auth
|
|
342
|
+
|
|
343
|
+
- **Model:** effectively **Gemini 3.5 Flash (High)** — whatever the `"model"` field in agy's
|
|
344
|
+
`settings.json` is set to. agy 1.0.5 added a `--model` flag (and a `models` subcommand) that *is*
|
|
345
|
+
wired into print mode, but **switching to a different model in `-p` hangs the call** (verified on
|
|
346
|
+
1.0.5: passing the already-active label returns in seconds, any other label hangs >60 s). So the
|
|
347
|
+
bridge stays single-model; change it via agy's `settings.json` if you need a different one. Flash
|
|
348
|
+
High is speed-optimized for tool-calling, so this fits best as a *fast sub-agent for cheap work*,
|
|
349
|
+
not a heavy reasoning partner.
|
|
350
|
+
- **Auth:** piggybacks whatever credential store `agy` uses on your OS (Windows Credential Manager,
|
|
351
|
+
macOS Keychain, libsecret on Linux — the bridge never touches it directly). Log in once; every
|
|
352
|
+
call after that silent-auths on the **same AI Pro quota** you already pay for.
|
|
353
|
+
|
|
354
|
+
<a id="security"></a>
|
|
355
|
+
|
|
356
|
+
## ⚠️ Security
|
|
357
|
+
|
|
358
|
+
`agy -p` runs the model as an **autonomous agent that auto-executes its own tools** — reading and
|
|
359
|
+
writing files, running shell commands, and reaching the network — with **no approval gate and no
|
|
360
|
+
opt-out**. This isn't a choice the bridge makes; it's how agy's print mode works. Re-verified
|
|
361
|
+
empirically on **agy 1.0.9 / Windows** (all three checks below still hold):
|
|
362
|
+
|
|
363
|
+
- Print mode runs out-of-workspace file writes and live network fetches **even without**
|
|
364
|
+
`--dangerously-skip-permissions` — that flag is a **no-op** for `-p`. There is **no** agy flag
|
|
365
|
+
that disables tool execution in print mode.
|
|
366
|
+
- agy 1.0.5 integrated a permission system (its logs show `toolPermission=request-review`), but it
|
|
367
|
+
**still does not gate print-mode execution** — a fresh `-p` run created a file outside the
|
|
368
|
+
workspace with no prompt.
|
|
369
|
+
- `--sandbox` is **not** a usable boundary. agy 1.0.6 fixed its propagation into `-p` (the 1.0.6/1.0.7
|
|
370
|
+
changelog calls this "sandbox isolation correctly enforced") and it now **does** block terminal/
|
|
371
|
+
shell command execution — but re-verified on 1.0.9 that it leaves the `write_to_file` tool and
|
|
372
|
+
network **wide open**: under `--sandbox` the model still wrote a file *outside* its workspace. agy
|
|
373
|
+
1.0.9 hardened the sandbox's *command* path (stricter exact-match command checks; `.git` added to
|
|
374
|
+
its dangerous-paths list), but none of that closes the out-of-workspace `write_to_file` hole. On
|
|
375
|
+
top of that, a `--sandbox` run whose blocked terminal command halts it writes **no JSONL
|
|
376
|
+
transcript** (only the SQLite `.db`, re-confirmed on 1.0.9), so the bridge couldn't read a
|
|
377
|
+
response — so the bridge deliberately never passes `--sandbox`.
|
|
378
|
+
|
|
379
|
+
**What that means for you:**
|
|
380
|
+
|
|
381
|
+
- The `workspace` argument is only a *starting context*, **not a security boundary** — the agent
|
|
382
|
+
can and does act outside it.
|
|
383
|
+
- Every call effectively runs **arbitrary code with your user privileges**.
|
|
384
|
+
- Only invoke this with **trusted prompts on trusted content**. Untrusted input here is the classic
|
|
385
|
+
prompt-injection *lethal trifecta*: private-data access + code execution + network egress.
|
|
386
|
+
- For real isolation, run the **whole bridge inside a container or VM**.
|
|
387
|
+
|
|
388
|
+
The bridge itself does only cross-platform filesystem reads under `~/.gemini/antigravity-cli/` — no
|
|
389
|
+
private APIs, no token theft. The risk above is entirely in what the agy sub-agent is allowed to do.
|
|
390
|
+
|
|
391
|
+
## FAQ
|
|
392
|
+
|
|
393
|
+
<details>
|
|
394
|
+
<summary><b>Is this against Google's Terms of Service?</b></summary>
|
|
395
|
+
|
|
396
|
+
It runs the **official `agy` CLI under your own AI Pro session** — no private APIs, no token theft,
|
|
397
|
+
no quota abuse. It just bridges what the CLI already does. That said, your AI Pro / Antigravity ToS
|
|
398
|
+
apply, and you're responsible for staying within them.
|
|
399
|
+
</details>
|
|
400
|
+
|
|
401
|
+
<details>
|
|
402
|
+
<summary><b>Will it break when agy updates?</b></summary>
|
|
403
|
+
|
|
404
|
+
Possibly — it reads agy's **internal, undocumented** state files, so a release can change paths or
|
|
405
|
+
schemas and break it silently. Re-verified working on **1.0.10** (transcript schema and `-p` JSONL
|
|
406
|
+
output unchanged; live ask round-trip + `antigravity_status` diagnostics pass). The known future risk
|
|
407
|
+
is agy's **SQLite (`.db`) conversation format** (added in 1.0.4, slated to become the default): agy
|
|
408
|
+
1.0.10 still **dual-writes** every conversation to `~/.gemini/antigravity-cli/conversations/<id>.db`
|
|
409
|
+
alongside the JSONL transcript, so once it stops writing JSONL the reader needs a SQLite path. Pin a
|
|
410
|
+
known-good `agy` version if you depend on this.
|
|
411
|
+
</details>
|
|
412
|
+
|
|
413
|
+
<details>
|
|
414
|
+
<summary><b>Why only Gemini 3.5 Flash?</b></summary>
|
|
415
|
+
|
|
416
|
+
agy 1.0.5 added a `--model` flag, but switching to a different model in `-p` **hangs** (print mode
|
|
417
|
+
waits on a step it never gets headless), so in practice you get whatever model agy's `settings.json`
|
|
418
|
+
selects — Gemini 3.5 Flash (High) by default. The bridge doesn't expose a model knob because it
|
|
419
|
+
would hang on any real switch.
|
|
420
|
+
</details>
|
|
421
|
+
|
|
422
|
+
<details>
|
|
423
|
+
<summary><b>Can it generate images?</b></summary>
|
|
424
|
+
|
|
425
|
+
**Yes — that's the `antigravity_image` tool.** agy's print mode generates real images on
|
|
426
|
+
your AI Pro quota; `antigravity_image` drives it, saves the file to a path you choose (or
|
|
427
|
+
a timestamped default in your workspace), fixes the extension to match the real
|
|
428
|
+
bytes (agy picks JPEG or PNG itself), and returns the path. Verified on **agy 1.0.9 / Windows**.
|
|
429
|
+
It's request/response only and runs a normal, unsandboxed agy session (see
|
|
430
|
+
[Security](#security)).
|
|
431
|
+
</details>
|
|
432
|
+
|
|
433
|
+
<details>
|
|
434
|
+
<summary><b>Does it cost extra money?</b></summary>
|
|
435
|
+
|
|
436
|
+
No. It uses the same **AI Pro quota** you already pay for. The smoke test spends a negligible
|
|
437
|
+
amount.
|
|
438
|
+
</details>
|
|
439
|
+
|
|
440
|
+
<details>
|
|
441
|
+
<summary><b>Does it stream responses?</b></summary>
|
|
442
|
+
|
|
443
|
+
The final answer is request/response — `agy -p` returns it all at once, so the tools return when agy
|
|
444
|
+
finishes (each call typically takes 10–30 s). If you want to *watch* agy work as it goes, pass
|
|
445
|
+
**`watch=true`** to `antigravity_ask` / `antigravity_continue` / `antigravity_image`: it opens the
|
|
446
|
+
**Agent Intern** browser window and live-streams agy's steps read from the transcript — see
|
|
447
|
+
[Watch mode](#watch-mode). It's coarse (a handful of steps, not token-by-token), and the returned
|
|
448
|
+
value is identical to the non-watch call.
|
|
449
|
+
</details>
|
|
450
|
+
|
|
451
|
+
<details>
|
|
452
|
+
<summary><b>Can I run several calls at once?</b></summary>
|
|
453
|
+
|
|
454
|
+
The **single-agent** tools (`antigravity_ask` / `antigravity_continue` / `antigravity_image`) are
|
|
455
|
+
**serialized** inside the server: agy rewrites `last_conversations.json` on every call, so concurrent
|
|
456
|
+
runs sharing one state dir would race and could return the wrong conversation. A `threading.Lock`
|
|
457
|
+
makes extra requests queue rather than race.
|
|
458
|
+
|
|
459
|
+
For real parallelism use **[`antigravity_swarm`](#swarm)** — it runs each worker in its own isolated
|
|
460
|
+
state dir, so they don't race and the lock isn't needed (~2.8× at 3 workers). That's the supported
|
|
461
|
+
way to run many agy calls at once.
|
|
462
|
+
</details>
|
|
463
|
+
|
|
464
|
+
## Status & caveats
|
|
465
|
+
|
|
466
|
+
- ✅ **Verified on agy 1.0.10** — base dir, `last_conversations.json`, the
|
|
467
|
+
`brain/.../transcript.jsonl` path, the transcript schema, and the `-p`/`-c`/`--print-timeout`
|
|
468
|
+
flags are all unchanged; a live ask round-trip + `antigravity_status` diagnostics pass. The 1.0.5
|
|
469
|
+
`-p` metadata fix also means agy no longer litters the workspace dir.
|
|
470
|
+
- 🖥️ **Console-detach (new)** — agy `-p` writes its progress/answer to the *controlling terminal*,
|
|
471
|
+
not stdout; under a TUI that text leaks into the host's prompt (seen on 1.0.9 before the fix). The
|
|
472
|
+
bridge now spawns agy detached from the terminal (`CREATE_NO_WINDOW` / a new POSIX session), so it
|
|
473
|
+
can't leak; the answer is still read from the transcript.
|
|
474
|
+
- ⏳ **SQLite migration is the real risk** — agy 1.0.10 still dual-writes a `.db` per conversation;
|
|
475
|
+
see the [FAQ](#faq). `_read_response` raises a clear, SQLite-aware error if the JSONL transcript
|
|
476
|
+
ever disappears.
|
|
477
|
+
- 🐛 **Stdout bug persists** — `-p` still doesn't print the answer to stdout on 1.0.9 (the 1.0.9
|
|
478
|
+
"print-mode resumption" changelog fix did **not** change this for fresh `-p`). If a future release
|
|
479
|
+
fixes stdout, this workaround becomes redundant but harmless.
|
|
480
|
+
- 👁️ **Watch mode is experimental** — pass `watch=true` to `antigravity_ask` / `antigravity_continue` /
|
|
481
|
+
`antigravity_image` to open the **Agent Intern** browser window and watch agy work live (coarse
|
|
482
|
+
steps; image shown inline). Best-effort and cross-platform; see [Watch mode](#watch-mode).
|
|
483
|
+
- 🔒 **No real sandbox** — agy's `--sandbox` (since 1.0.6) blocks only shell commands in `-p` but still
|
|
484
|
+
leaves file writes and network egress open (and breaks transcript reading), so it's no boundary;
|
|
485
|
+
see [Security](#security).
|
|
486
|
+
|
|
487
|
+
## Requirements
|
|
488
|
+
|
|
489
|
+
- Python 3.10+
|
|
490
|
+
- **For the Antigravity tools:** [`agy`](https://antigravity.google/) 1.0.0+ on `PATH` (state-file layout re-verified on **1.0.10**) and an active Antigravity / AI Pro session
|
|
491
|
+
- **For the Codex tools:** [`codex`](https://developers.openai.com/codex/) on `PATH` and logged in (`codex login`) — verified on **codex-cli 0.141.0**
|
|
492
|
+
|
|
493
|
+
Each backend is independent — install only the CLI(s) you plan to use; the other tools simply report "not found" via their `*_status` tool.
|
|
494
|
+
|
|
495
|
+
> [!TIP]
|
|
496
|
+
> If `agy` isn't reliably on `PATH` (e.g. a new terminal or reboot drops it on Windows), set the
|
|
497
|
+
> **`AGY_BIN`** env var to its full path and the bridge will use that instead of `"agy"` — e.g.
|
|
498
|
+
> `AGY_BIN=%LOCALAPPDATA%\agy\bin\agy.exe`. Likewise, set **`CODEX_BIN`** if `codex` isn't reliably on
|
|
499
|
+
> `PATH` (the native Windows installer puts it under `%LOCALAPPDATA%\Programs\OpenAI\Codex\bin\`).
|
|
500
|
+
|
|
501
|
+
The bridge uses only cross-platform Python (`Path.home()`, `subprocess`) and reads paths under
|
|
502
|
+
`~/.gemini/antigravity-cli/`, which `agy` writes the same way on every OS. **Developed and verified
|
|
503
|
+
on Windows; macOS and Linux should work unmodified provided `agy -i` runs there.** If you test it on
|
|
504
|
+
those platforms, please open an issue / PR to confirm.
|
|
505
|
+
|
|
506
|
+
## Development
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
pip install -e ".[dev]" # fastmcp + pytest + ruff
|
|
510
|
+
pytest test_server.py test_swarm.py # offline unit tests — no agy, no quota
|
|
511
|
+
ruff check . && ruff format --check .
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
`test_server.py` and `test_swarm.py` cover the pure parsing/version/swarm logic with temp fixtures
|
|
515
|
+
(no agy needed); `test_smoke.py` is the live end-to-end check (ask, continue, image, and a parallel
|
|
516
|
+
swarm) that spends a little quota. Set **`AGY_BRIDGE_DEBUG=1`**
|
|
517
|
+
to log per-call diagnostics (resolved conversation id, agy exit code, elapsed) to stderr — and on
|
|
518
|
+
startup the server warns if your installed agy is newer than the version it was verified against.
|
|
519
|
+
|
|
520
|
+
**Staying up to date.** Updates are opt-in by design: plain `uvx agent-intern` pins to the
|
|
521
|
+
version it first cached, and a `git clone` never auto-updates — so the bridge only ever runs code
|
|
522
|
+
you chose to install (it runs unsandboxed, so this is deliberate, not laziness). Nothing updates a
|
|
523
|
+
*running* server either; new versions take effect on the next Claude Code restart. You find out about
|
|
524
|
+
a release two ways, both best-effort GitHub tag checks against the running code (`__version__` in
|
|
525
|
+
`server.py`):
|
|
526
|
+
|
|
527
|
+
- **In chat — [`antigravity_status`](#tools)** leads with a `bridge version` row, e.g.
|
|
528
|
+
`v0.10.3 (latest)` or `v0.10.3 -> v0.10.4 available; upgrade: uvx agent-intern@latest`. This
|
|
529
|
+
is the notice you actually see in the MCP client's UI (an available update stays `[ok]` — it's
|
|
530
|
+
informational, not a fault).
|
|
531
|
+
- **At startup — stderr**, where the server logs the same one-line warning. This lands in the host's
|
|
532
|
+
MCP logs only (e.g. via `/mcp` in Claude Code), not the chat.
|
|
533
|
+
|
|
534
|
+
Upgrade with `uvx agent-intern@latest` (or `git pull`) and restart, or opt into hands-off
|
|
535
|
+
auto-updates by putting `agent-intern@latest` in the config. Both checks are silent when
|
|
536
|
+
offline or rate-limited and never block startup. Control them with:
|
|
537
|
+
|
|
538
|
+
| Env var | Effect |
|
|
539
|
+
|---|---|
|
|
540
|
+
| `AGY_BRIDGE_NO_UPDATE_CHECK=1` | Skip the GitHub check entirely (fully offline startup). |
|
|
541
|
+
| `AGY_BRIDGE_REPO=owner/name` | Point the check at a fork instead of the upstream repo. |
|
|
542
|
+
|
|
543
|
+
**Releasing.** Bump the version in **both** `pyproject.toml` and `server.py` (`__version__`), update
|
|
544
|
+
[`CHANGELOG.md`](CHANGELOG.md), then tag:
|
|
545
|
+
|
|
546
|
+
```bash
|
|
547
|
+
git tag vX.Y.Z && git push origin vX.Y.Z
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
The tag triggers two workflows: `release.yml` cuts a GitHub Release with auto-generated notes, and
|
|
551
|
+
`publish.yml` builds and uploads to PyPI via [Trusted Publishing](https://docs.pypi.org/trusted-publishers/)
|
|
552
|
+
(no stored token — `publish.yml` verifies the tag matches `pyproject.toml` first). One-time setup:
|
|
553
|
+
register the trusted publisher at `pypi.org/manage/project/agent-intern/settings/publishing/`
|
|
554
|
+
(repo `SinanTufekci/agent-intern`, workflow `publish.yml`, environment `pypi`).
|
|
555
|
+
|
|
556
|
+
## Contributing
|
|
557
|
+
|
|
558
|
+
Personal project, **best-effort maintenance** — issues and PRs welcome, but no uptime/compat
|
|
559
|
+
promises. If `agy -p` ever starts printing to stdout correctly, this whole repo becomes a fun
|
|
560
|
+
historical artefact.
|
|
561
|
+
|
|
562
|
+
## 🌐 Community & Acknowledgments
|
|
563
|
+
|
|
564
|
+
- **Qiita (Japan):** A huge thanks to `@fallout` and the Japanese developer community for featuring this project and providing invaluable feedback!
|
|
565
|
+
- [Detailed Hybrid Setup Guide (Claude Code × Antigravity CLI)](https://qiita.com/fallout/items/5097f0575b58f4c69b81)
|
|
566
|
+
- [Quick Installation Guide](https://qiita.com/fallout/items/d699df3d6931c07eb38d)
|
|
567
|
+
|
|
568
|
+
> 💡 **Path Resolution Fix:** Thanks to their community's real-world testing, we identified and resolved a Windows PATH edge case where the MCP server inherits a *stale* `PATH` at startup and can't find `agy`. The `AGY_BIN` environment-variable fallback was implemented directly inspired by their report!
|
|
569
|
+
|
|
570
|
+
## License
|
|
571
|
+
|
|
572
|
+
[MIT](LICENSE). Do whatever you want with it.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
codex_bridge.py,sha256=0HowNFLEXbwavBJrRbCsc-wQMj2JnM8bcIJqC7YEmSA,21150
|
|
2
|
+
server.py,sha256=n2P295RF_SKh3zBnuBco2pMuVPj9nbOcrLE9jG4ARrU,83685
|
|
3
|
+
swarm.py,sha256=oqs5qUi9i7sR6ggsacAb5mzjiEHC-zUU_lVqzkfJAGs,19363
|
|
4
|
+
swarm_watch.py,sha256=Oqh38c04iIjgBthEmnXZLej-92Z9mP82zEhKuEaUifs,28035
|
|
5
|
+
agent_intern-0.13.0.dist-info/licenses/LICENSE,sha256=jKIvui3kMkxnLZtwxyJOOXV9kNLdIfNqdSohJC1wtyw,1070
|
|
6
|
+
agent_intern-0.13.0.dist-info/METADATA,sha256=hvj8awzeHXp7shA4NIN-azHRfzdCk2bYF208dO2wwVM,32727
|
|
7
|
+
agent_intern-0.13.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
8
|
+
agent_intern-0.13.0.dist-info/entry_points.txt,sha256=oZaZ-GkIcgeUdyl4UsLK2AsO3zA_aVBn7nKsll244ek,45
|
|
9
|
+
agent_intern-0.13.0.dist-info/top_level.txt,sha256=cJyFLFt2AcI52PtWKWpkzUyYLu97UF5LM5HaWh2tSCg,38
|
|
10
|
+
agent_intern-0.13.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sinan Tufekci
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|