Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d81d14e
Add room poller scripts with auto-ack and 10s interval
Feb 23, 2026
8d6a7ec
feat(poller): add geminimb direct tmux poller script
Feb 23, 2026
5ff9447
Harden room poller scripts and constrain auto-ack triggers
Feb 23, 2026
fb92234
feat(poller): add smart auto-ack logic to room-poller.mjs
Feb 23, 2026
70258cd
Prep for public release: add .gitignore, remove secrets
Feb 23, 2026
7884294
fix(poller): update geminimb script to use ag-codex start-ack rules a…
Feb 23, 2026
d28210f
Update README with 3-agent realtime comms testing setup
Feb 23, 2026
96456ec
fix(poller): update geminimb to assume unaddressed tasks are implicit…
Feb 23, 2026
447e268
Update README: agents run on separate machines in different countries
Feb 23, 2026
bb303e1
Fix README: correct IDE apps and machine locations
Feb 23, 2026
57a9872
Add listen mode settings to room poller
Feb 23, 2026
8b19a47
fix(poller): update geminimb to tmux send-keys LLM nudge upon auto-ack
Feb 23, 2026
8adf054
Add full integration docs to README
Feb 23, 2026
11eeb19
fix(poller): update geminimb script with prime-on-start toggle and ho…
Feb 23, 2026
34d7408
Fix critical bugs: hardcoded key, undefined BASE_URL, schema, watch.mjs
Feb 23, 2026
d261385
fix(poller): replace broken tmux send-keys with direct ide-agent-queu…
Feb 23, 2026
3403f25
fix(poller): add required event_id to JSON queue payload for proper I…
Feb 23, 2026
b725ef2
Replace em/en dashes with plain hyphens in README
Feb 23, 2026
47fc00c
Remove hardcoded API key from geminimb script (3rd fix)
Feb 23, 2026
6131680
fix(poller): route geminimb JSON payloads to bridge_inbox instead of …
Feb 23, 2026
dcee7e1
fix(poller): switch geminimb to LLM-first by removing canned auto-ack…
Feb 23, 2026
97da6b6
Add AGPL v3 license
Feb 23, 2026
be641cf
chore(license): enforce AGPL-3.0-only repo-wide with SPDX headers
Feb 23, 2026
bb07e84
Add license section to README
Feb 23, 2026
e1dc471
feat(geminimb): implement autonomous headless gemini API generation i…
Feb 23, 2026
90ec246
fix(geminimb): pass null stdin to gemini api call to stop prompt gene…
Feb 23, 2026
b26085c
fix(geminimb): ensure direct mentions without task verbs still trigge…
Feb 23, 2026
b4841d8
Add Codex smart poller settings and docs for current runtime
Feb 23, 2026
d35cbfb
chore(license): enforce AGPL-3.0-only repo-wide with SPDX headers
Feb 23, 2026
4e87e0f
fix(poller): add PID lock to prevent duplicate poller instances
Feb 23, 2026
fb1998c
fix(geminimb): extract api key securely from env file to survive git …
Feb 23, 2026
6c7e023
fix(geminimb): handle multiline llm responses securely by replacing n…
Feb 23, 2026
564182d
fix: critical bugs in geminimb and antigravity pollers
Feb 23, 2026
e0d2ab1
fix(pollers): disable ag codex approvals, apply auth header and stric…
Feb 23, 2026
aaa6c34
fix(auth): revert wrong Authorization:Bearer headers back to X-API-Key
Feb 23, 2026
8c79bd2
feat: add Gemini timeout wrapper for antfarm bots
Feb 26, 2026
0293562
Add command-mode room poller for Codex GUI
Mar 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules/
*.jsonl
exec-approvals.json
ide-agent-kit.json
.env
*.log
/tmp/
661 changes: 661 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

283 changes: 264 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,93 @@
# IDE Agent Kit v0.1
# IDE Agent Kit - v0.1

Let IDE AIs (Claude Code, Codex, Cursor, VS Code agents, local LLM assistants) participate in team workflows.
Let IDE AIs (Claude Code, Codex, Cursor, VS Code agents, local LLM assistants) participate in team workflows - including realtime multi-agent communication via shared chat rooms.

## How it works

**Primary path: Webhooks (seconds)**
GitHub event → webhook server → normalized JSONL queue → IDE agent reads queue → acts → receipt.
This is the fast path. Events arrive in seconds. Use this when your IDE supports webhook ingestion or can poll a local queue file.

**Fallback path: tmux (minutes)**
Poller checks for events → sends command to tmux session → IDE agent wakes up → acts → receipt.
Use this when webhooks aren't available (e.g., no public endpoint) or as a backup.
**Realtime path: Room poller (seconds)**
Poller watches chat room → detects new messages → nudges IDE agent via tmux → agent reads and responds.
Three agents tested concurrently with <10s response times.

**Fallback path: tmux runner**
Run allowlisted commands in a named tmux session, capture output + exit code.

## v0.1 primitives

1. **Webhook relay** (primary) — ingest GitHub webhooks, normalize to a stable JSON schema, append to a local queue.
2. **tmux runner** (fallback) — run allowlisted commands in a named tmux session, capture output + exit code.
3. **Receipts** — append-only JSONL receipts with trace IDs + idempotency keys.
4. **IDE init** — generate starter configs for Claude Code, Codex, Cursor, or VS Code.
1. **Webhook relay** - ingest GitHub webhooks, normalize to a stable JSON schema, append to a local queue.
2. **Room poller** - watch Ant Farm chat rooms, auto-ack task requests, nudge IDE agents via tmux.
3. **tmux runner** - run allowlisted commands in a named tmux session, capture output + exit code.
4. **Receipts** - append-only JSONL receipts with trace IDs + idempotency keys.
5. **Session keepalive** - prevent macOS display/idle sleep for long-running remote sessions.
6. **IDE init** - generate starter configs for Claude Code, Codex, Cursor, or VS Code.

No dependencies. Node.js ≥ 18 only.

## Testing setup - 3 agents, realtime comms

This kit has been tested with three IDE agents from different AI providers, each running in its own IDE on separate machines - potentially in different countries. They communicate through shared [Ant Farm](https://antfarm.world) chat rooms over the internet, with no direct connections between them:

| Agent | Handle | Model | IDE / App | Machine | Poller |
|-------|--------|-------|-----------|---------|--------|
| claudemm | @claudemm | Claude Opus 4.6 | Claude Code CLI | Mac mini | `scripts/room-poll.sh` (10s) |
| antigravity | @antigravity | GPT 5.3 Codex | Codex macOS app | MacBook | `tools/antigravity_room_autopost.sh` (8s) |
| geminimb | @geminiMB | Gemini 3.1 | Antigravity macOS app | MacBook | `tools/geminimb_room_autopost.sh` (8s) |

All three agents share the same rooms (`feature-admin-planning`, `thinkoff-development`, `lattice-qcd`) and respond to messages within 3-10 seconds. Each agent only needs an API key and internet access - no VPN, shared filesystem, or direct networking between machines.

### How it works

Each agent runs in its own tmux session on its own machine. A background poller script watches the room API for new messages. When a new message arrives:

1. The poller detects it (every 8-10s)
2. If from the owner and looks like a task request → posts an immediate auto-ack
3. Sends a tmux keystroke nudge (`check rooms` + Enter) to the IDE agent's session
4. The IDE agent reads the full message and responds with its own intelligence

### Running an agent

```bash
# Claude Code (@claudemm) - uses the generic poller
export IAK_API_KEY=xfb_your_antfarm_key
export IAK_SELF_HANDLES="@claudemm,claudemm"
export IAK_TARGET_HANDLE="@claudemm"
export IAK_TMUX_SESSION="claude"
export IAK_POLL_INTERVAL=10
nohup ./scripts/room-poll.sh > /tmp/poll.log 2>&1 &

# Codex (@antigravity) - smart poller with real codex exec replies
export ANTIGRAVITY_API_KEY=xfb_your_antfarm_key
export ROOMS=feature-admin-planning
export SMART_MODE=1
export CODEX_APPROVAL_POLICY=on-request
export CODEX_SANDBOX_MODE=workspace-write
./tools/antigravity_room_autopost.sh tmux start
./tools/antigravity_room_autopost.sh tmux status
./tools/antigravity_room_autopost.sh tmux stop

# Gemini (@geminiMB) - dedicated poller with tmux lifecycle
export IAK_API_KEY=xfb_your_antfarm_key # or GEMINIMB_API_KEY
./tools/geminimb_room_autopost.sh tmux start
./tools/geminimb_room_autopost.sh tmux status
./tools/geminimb_room_autopost.sh tmux stop
```

### Keeping sessions alive

On macOS, prevent display/idle sleep so remote (VNC/SSH) sessions don't freeze:

```bash
# Via CLI
node bin/cli.mjs keepalive start
node bin/cli.mjs keepalive status
node bin/cli.mjs keepalive stop

# Or directly
caffeinate -d -i -s &
```

## Quick start

```bash
Expand All @@ -47,6 +114,172 @@ node bin/cli.mjs receipt tail --n 5
node bin/cli.mjs emit --to https://example.com/webhook --json receipt.json
```

## Room Poller

The repo includes three poller implementations for watching Ant Farm chat rooms:

**Generic poller** (`scripts/room-poll.sh` + `scripts/room-poll-check.py`):
- Works with any agent (Claude Code, Codex, etc.)
- Env-var-driven, no hardcoded secrets
- Auto-acks task requests from the owner
- Nudges IDE agent via tmux keystrokes

**Poll command (`ide-agent-kit poll`) nudge modes**:
- `poller.nudge_mode = "tmux"` (default): send `tmux send-keys`
- `poller.nudge_mode = "command"`: execute `poller.nudge_command` with `IAK_NUDGE_TEXT` in env (useful for GUI agents)
- `poller.nudge_mode = "none"`: queue-only polling, no nudge side effects

### Codex GUI setup (macOS)

For Codex Desktop GUI (non-tmux) use command-mode nudging:

```json
{
"poller": {
"rooms": "thinkoff-development,feature-admin-planning,lattice-qcd",
"handle": "@CodexMB",
"interval_sec": 8,
"api_key": "antfarm_xxx",
"seen_file": "/tmp/codex-room-seen.txt",
"nudge_mode": "command",
"nudge_command": "/ABSOLUTE/PATH/ide-agent-kit/tools/codex_gui_nudge.sh"
},
"tmux": {
"ide_session": "codex",
"nudge_text": "check room and respond [codex]"
}
}
```

Run:

```bash
node bin/cli.mjs poll --config /ABSOLUTE/PATH/ide-agent-kit-codex.json
```

macOS permissions required for GUI keystroke injection:
- Privacy & Security → Accessibility: allow Terminal/iTerm (whichever runs the poller)
- Privacy & Security → Automation: allow Terminal/iTerm to control `System Events`

**Gemini poller** (`tools/geminimb_room_autopost.sh`):
- Self-contained bash script with tmux lifecycle management
- Built-in hearing check responses with latency reporting
- Configurable mention-only or all-message modes

**Codex smart poller** (`tools/antigravity_room_autopost.sh`):
- Self-contained bash script with tmux lifecycle management
- All-message intake mode with stale/backlog protection
- Smart path uses `codex exec` to generate real replies
- Canned poller replies only for hearing/webhook checks

### Env vars (generic poller)

| Variable | Default | Description |
|----------|---------|-------------|
| `IAK_API_KEY` | (required) | Ant Farm API key |
| `IAK_ROOMS` | `thinkoff-development,feature-admin-planning,lattice-qcd` | Rooms to watch |
| `IAK_SELF_HANDLES` | `@claudemm,claudemm` | This agent's handles (skip own messages) |
| `IAK_TARGET_HANDLE` | `@claudemm` | Handle used in ack messages |
| `IAK_OWNER_HANDLE` | `petrus` | Only auto-ack from this user |
| `IAK_TMUX_SESSION` | `claude` | tmux session to nudge |
| `IAK_POLL_INTERVAL` | `10` | Seconds between polls |
| `IAK_ACK_ENABLED` | `1` | Auto-ack task requests (`1`/`0`) |
| `IAK_NUDGE_TEXT` | `check rooms` | Text sent to tmux on new messages |
| `IAK_LISTEN_MODE` | `all` | Filter: `all`, `humans`, `tagged`, or `owner` |
| `IAK_BOT_HANDLES` | (empty) | Comma-separated bot handles for `humans` mode |
| `IAK_FETCH_LIMIT` | `20` | Messages per room per poll |

### Env vars (Codex smart poller)

| Variable | Default | Description |
|----------|---------|-------------|
| `ANTIGRAVITY_API_KEY` | (required) | Ant Farm API key |
| `ROOMS` | `feature-admin-planning` | Comma-separated rooms to watch |
| `POLL_INTERVAL` | `8` | Seconds between polls |
| `FETCH_LIMIT` | `30` | Messages per room request |
| `MENTION_ONLY` | `0` | Intake mode: `0` all messages, `1` mention only |
| `SMART_MODE` | `1` | `1` enables `codex exec` real-response generation |
| `CODEX_WORKDIR` | repo root | Working directory for `codex exec` |
| `CODEX_APPROVAL_POLICY` | `on-request` | Codex approval policy for smart replies |
| `CODEX_SANDBOX_MODE` | `workspace-write` | Codex sandbox mode for smart replies |
| `MAX_REPLY_AGE_SEC` | `900` | Skip stale messages older than this age |
| `SKIP_PRESTART_BACKLOG` | `1` | Skip messages older than process start |

## Integrations

### GitHub Webhooks (`src/webhook-server.mjs`)

Receives GitHub webhook events, verifies HMAC signatures, normalizes them to a stable JSON schema, and appends to a local JSONL queue. Optionally nudges a tmux session when events arrive.

Supported events: `pull_request.opened`, `pull_request.synchronize`, `pull_request.closed`, `push`, `issue_comment.created`, `issues.opened`.

```bash
# Start the webhook server
node bin/cli.mjs serve --port 8787

# Configure GitHub to send webhooks to:
# http://your-host:8787/webhook
# Set a webhook secret in config for HMAC verification

# Ant Farm webhooks are also accepted at:
# http://your-host:8787/antfarm
```

Config keys: `listen.port`, `github.webhook_secret`, `github.event_kinds`, `queue.path`.

### OpenClaw Bot Fleet (`src/openclaw-*.mjs`)

Five modules for managing an [OpenClaw](https://openclaw.dev) multi-agent bot fleet via its CLI. Since the OpenClaw gateway uses WebSocket (not HTTP) for RPC, all modules shell out to the `openclaw` CLI, optionally over SSH for cross-user setups.

**Gateway** (`src/openclaw-gateway.mjs`):
- Start, stop, restart the OpenClaw gateway
- Check gateway status (deep health check)
- Config: `openclaw.home`, `openclaw.bin`, `openclaw.ssh`

**Sessions** (`src/openclaw-sessions.mjs`):
- Send messages to agents, list active sessions
- Agent-to-agent communication via `openclaw agent` CLI
- Supports sending to specific agents by name

**Exec Approvals** (`src/openclaw-exec.mjs`):
- Governance layer for agent command execution
- Manages an approval queue (pending → allow/deny)
- Reads OpenClaw's native exec-approvals allowlist (per-agent, glob-based)
- Files: `~/.openclaw/exec-approvals.json` (native), `./exec-approvals.json` (queue)

**Hooks** (`src/openclaw-hooks.mjs`):
- Register and manage event hooks for agents
- Events: `message:received`, `message:sent`, `command:new`, `command:reset`, `command:stop`, `agent:bootstrap`, `gateway:startup`
- Hook locations: `workspace/hooks/` (per-agent) and `~/.openclaw/hooks/` (shared)

**Cron** (`src/openclaw-cron.mjs`):
- Scheduled task management via `openclaw cron` CLI
- List, add, remove scheduled tasks for agents

```bash
# OpenClaw config (in team-relay config file)
{
"openclaw": {
"home": "/path/to/openclaw",
"bin": "/opt/homebrew/bin/openclaw",
"ssh": "family@localhost"
}
}
```

### Ant Farm Chat Rooms (`scripts/room-poll*.`)

See [Room Poller](#room-poller) above. Provides realtime multi-agent communication via shared chat rooms at [antfarm.world](https://antfarm.world).

### Other modules

- **Receipts** (`src/receipt.mjs`) - Append-only JSONL receipt log with trace IDs and idempotency keys
- **Emit** (`src/emit.mjs`) - Send receipts/payloads to external webhook URLs
- **Memory** (`src/memory.mjs`) - Persistent key-value memory for agents across sessions
- **Session Keepalive** (`src/session-keepalive.mjs`) - macOS `caffeinate` management for remote sessions
- **tmux Runner** (`src/tmux-runner.mjs`) - Run allowlisted commands in tmux sessions with output capture
- **Watch** (`src/watch.mjs`) - File watcher for JSONL queue changes

## Naming convention (frozen)

- JSON fields (events, receipts, config): **snake_case**
Expand All @@ -60,19 +293,20 @@ ide-agent-kit tmux run --cmd <command> [--session <name>] [--cwd <path>] [--time
ide-agent-kit emit --to <url> --json <file>
ide-agent-kit receipt tail [--n <count>]
ide-agent-kit init [--ide <claude-code|codex|cursor|vscode|gemini>] [--profile <balanced|low-friction>]
ide-agent-kit keepalive <start|stop|status> [--pid-file <path>] [--heartbeat-sec <sec>]
```

## Config

See `config/team-relay.example.json` for the full config shape. Key sections:

- `listen` host/port for webhook server
- `queue.path` where normalized events are appended (JSONL)
- `receipts.path` where action receipts are appended (JSONL)
- `tmux.allow` command allowlist (prefix match)
- `tmux.default_session` tmux session name
- `github.webhook_secret` HMAC secret for signature verification
- `github.event_kinds` which GitHub events to accept
- `listen` - host/port for webhook server
- `queue.path` - where normalized events are appended (JSONL)
- `receipts.path` - where action receipts are appended (JSONL)
- `tmux.allow` - command allowlist (prefix match)
- `tmux.default_session` - tmux session name
- `github.webhook_secret` - HMAC secret for signature verification
- `github.event_kinds` - which GitHub events to accept

### Low-friction profile

Expand All @@ -86,8 +320,8 @@ This profile broadens `tmux.allow` to include common read/build/test commands (`

## Schemas

- `schemas/event.normalized.json` normalized inbound event
- `schemas/receipt.json` action receipt
- `schemas/event.normalized.json` - normalized inbound event
- `schemas/receipt.json` - action receipt

## Tests

Expand All @@ -98,3 +332,14 @@ node --test test/*.test.mjs
## Example flow

See `examples/flow-pr-opened.md` for a complete PR → test → receipt walkthrough.

## License

GNU Affero General Public License v3.0 (AGPL-3.0). See [LICENSE](LICENSE) for details.
All source files include `SPDX-License-Identifier: AGPL-3.0-only`.
Source code for this deployment is available at commit [be641cf](https://github.com/ThinkOffApp/team-relay/tree/be641cf).

## Ant Farm Helpers

- `examples/antfarm/gemini_from_claude.sh` — non-interactive Gemini wrapper for room/autopost bots.
Uses `gemini -p` with a hard timeout to prevent stuck polling loops.
3 changes: 3 additions & 0 deletions bin/cli.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#!/usr/bin/env node

// SPDX-License-Identifier: AGPL-3.0-only

import { parseArgs } from 'node:util';
import { loadConfig } from '../src/config.mjs';
import { tmuxRun } from '../src/tmux-runner.mjs';
Expand Down
Loading