Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ bin/gstack-global-discover*
.hermes/
.gbrain/
.gbrain-source
.gemini/
.context/
extension/.auth.json
# xterm assets are vendored from npm at build time; not source-of-truth.
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Invoke them by name (e.g., `/office-hours`).
| `/retro` | Weekly retro with per-person breakdowns and shipping streaks. |
| `/health` | Code quality dashboard (type checker, linter, tests, dead code). |
| `/benchmark` | Performance regression detection (page load, Core Web Vitals). |
| `/benchmark-models` | Cross-model benchmark for skills (Claude, GPT, Gemini side-by-side). |
| `/benchmark-models` | Cross-model benchmark for skills (Claude, GPT, Gemini, and Agy side-by-side). |
| `/cso` | OWASP Top 10 + STRIDE security audit. |
| `/setup-gbrain` | Set up gbrain for cross-machine session memory sync. |
| `/sync-gbrain` | Keep gbrain current with this repo's code; refresh agent search guidance in CLAUDE.md. |
Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## [1.61.0.0] - 2026-07-12

## **Permanent Antigravity (Agy) integration and benchmark support are live.**
## **gstack now runs on Agy, registers/updates plugins automatically, and supports Agy model benchmarks.**

Agy integration is now permanent and first-class. Running setup with `--host agy` generates and imports Agy-compatible skills, excludes incompatible skills, and registers the gstack plugin in Agy's plugin configuration. This release also fixes several test-suite and helper issues that were causing CI failures, and adds Agy model benchmarking.

### Itemized changes

#### Added

- `hosts/agy.ts`: Declarative host configuration for Agy.
- `test/helpers/providers/agy.ts`: Agy benchmark runner adapter that executes `agy --print` with safely skipped permissions.
- `docs/AGY.md`: User documentation for Agy installation and integration.

#### Fixed

- `setup`: Support `--host agy` flag, build `plugin.json` and skill directories under `.gemini/config/plugins/gstack`, and trigger `agy plugin install`.
- `bin/gstack-codex-session-import`: Added `-r` flag to `xargs` pipeline to prevent listing files in current directory when empty.
- `test/gbrain-detect-install.test.ts`: Appended bun's executable directory to test environment `PATH` to resolve shebang resolution failures.
- `test/gbrain-refresh-install-render.test.ts`: Resolved regex pattern mismatch in status check.

## [1.60.1.0] - 2026-07-09

## **The /autoplan dual-voice eval is back on the board, catching real regressions.**
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ gstack/
│ ├── claude.ts # Primary host config
│ ├── codex.ts, factory.ts, kiro.ts # Existing hosts
│ ├── opencode.ts, slate.ts, cursor.ts, openclaw.ts # IDE hosts
│ ├── hermes.ts, gbrain.ts # Agent runtime hosts
│ ├── hermes.ts, gbrain.ts, agy.ts # Agent runtime hosts
│ └── index.ts # Registry: exports all, derives Host type
├── scripts/ # Build + DX tooling
│ ├── gen-skill-docs.ts # Template → SKILL.md generator (config-driven)
Expand Down
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,11 @@ worth the review overhead.

## Multi-host development

gstack generates SKILL.md files for 8 hosts from one set of `.tmpl` templates.
gstack generates SKILL.md files for 11 hosts from one set of `.tmpl` templates.
Each host is a typed config in `hosts/*.ts`. The generator reads these configs
to produce host-appropriate output (different frontmatter, paths, tool names).

**Supported hosts:** Claude (primary), Codex, Factory, Kiro, OpenCode, Slate, Cursor, OpenClaw.
**Supported hosts:** Claude (primary), Codex, Factory, Kiro, OpenCode, Slate, Cursor, OpenClaw, Hermes, GBrain, and Agy.

### Generating for all hosts

Expand All @@ -321,7 +321,8 @@ to produce host-appropriate output (different frontmatter, paths, tool names).
bun run gen:skill-docs # Claude (default)
bun run gen:skill-docs --host codex # Codex
bun run gen:skill-docs --host opencode # OpenCode
bun run gen:skill-docs --host all # All 8 hosts
bun run gen:skill-docs --host agy # Google Antigravity
bun run gen:skill-docs --host all # All 11 hosts

# Or use build, which does all hosts + compiles binaries
bun run build
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ These are conversational skills. Your OpenClaw agent runs them directly via chat

### Other AI Agents

gstack works on 10 AI coding agents, not just Claude. Setup auto-detects which
gstack works on 11 AI coding agents, not just Claude. Setup auto-detects which
agents you have installed:

```bash
Expand All @@ -121,10 +121,13 @@ Or target a specific agent with `./setup --host <name>`:
| Kiro | `--host kiro` | `~/.kiro/skills/gstack-*/` |
| Hermes | `--host hermes` | `~/.hermes/skills/gstack-*/` |
| GBrain (mod) | `--host gbrain` | `~/.gbrain/skills/gstack-*/` |
| Google Antigravity (Agy) | `--host agy` | `~/.gemini/config/plugins/gstack/skills/` |

**Want to add support for another agent?** See [docs/ADDING_A_HOST.md](docs/ADDING_A_HOST.md).
It's one TypeScript config file, zero code changes.

For Agy plugin registration and model benchmarking, see the [Agy integration guide](docs/AGY.md).

## See it work

```
Expand Down Expand Up @@ -241,7 +244,7 @@ Beyond the slash-command skills, gstack ships standalone CLIs for workflows that

| Command | What it does |
|---------|-------------|
| `gstack-model-benchmark` | **Cross-model benchmark** — run the same prompt through Claude, GPT (via Codex CLI), and Gemini; compare latency, tokens, cost, and (optionally) LLM-judge quality score. Auth detected per provider, unavailable providers skip cleanly. Output as table, JSON, or markdown. `--dry-run` validates flags + auth without spending API calls. |
| `gstack-model-benchmark` | **Cross-model benchmark** — run the same prompt through Claude, GPT (via Codex CLI), Gemini, and Agy; compare latency, tokens, cost, and (optionally) LLM-judge quality score. Auth detected per provider, unavailable providers skip cleanly. Output as table, JSON, or markdown. `--dry-run` validates flags + auth without spending API calls. See the [Agy integration guide](docs/AGY.md) for Agy setup. |
| `gstack-taste-update` | **Design taste learning** — writes approvals and rejections from `/design-shotgun` into a persistent per-project taste profile. Decays 5%/week. Feeds back into future variant generation so the system learns what you actually pick. |
| `gstack-ios-qa-daemon` | **iOS QA daemon** — Mac-side broker between an agent and a connected iPhone over USB CoreDevice. Loopback by default; `--tailnet` opens a Tailscale-facing listener with identity-gated capability tiers. Single-instance via flock on `~/.gstack/ios-qa-daemon.pid`. See [docs/howto-ios-testing-with-gstack.md](docs/howto-ios-testing-with-gstack.md). |
| `gstack-ios-qa-mint` | **iOS allowlist manager** — owner-grant CLI for the tailnet allowlist. `grant`/`revoke`/`list` against `~/.gstack/ios-qa-allowlist.json` (mode 0600). Remote agents never auto-allowlist; this is the explicit-intent path. |
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.60.1.0
1.61.0.0
8 changes: 4 additions & 4 deletions benchmark-models/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version: 1.0.0
description: Cross-model benchmark for gstack skills. (gstack)
triggers:
- cross model benchmark
- compare claude gpt gemini
- compare claude gpt gemini agy
- benchmark skill across models
- which model should I use
allowed-tools:
Expand All @@ -20,7 +20,7 @@ allowed-tools:
## When to invoke this skill

Runs the same prompt through Claude,
GPT (via Codex CLI), and Gemini side-by-side — compares latency, tokens, cost,
GPT (via Codex CLI), Gemini, and Agy side-by-side — compares latency, tokens, cost,
and optionally quality via LLM judge. Answers "which model is actually best
for this skill?" with data instead of vibes. Separate from /benchmark, which
measures web page performance. Use when: "benchmark models", "compare models",
Expand Down Expand Up @@ -578,12 +578,12 @@ If C: ask for the path. Verify it exists. Use as positional argument.
## Step 2: Choose providers

```bash
"$BIN" --prompt "unused, dry-run" --models claude,gpt,gemini --dry-run
"$BIN" --prompt "unused, dry-run" --models claude,gpt,gemini,agy --dry-run
```

Show the dry-run output. The "Adapter availability" section tells the user which providers will actually run (OK) vs skip (NOT READY — remediation hint included).

If ALL three show NOT READY: stop with a clear message — benchmark can't run without at least one authed provider. Suggest `claude login`, `codex login`, or `gemini login` / `export GOOGLE_API_KEY`.
If ALL four show NOT READY: stop with a clear message — benchmark can't run without at least one authenticated provider. Suggest `claude login`, `codex login`, `gemini login` / `export GOOGLE_API_KEY`, or logging in through `agy`.

If at least one is OK: AskUserQuestion:
- **Simplify:** "Which models should we include? The dry-run above showed which are authed. Unauthed ones will be skipped cleanly — they won't abort the batch."
Expand Down
8 changes: 4 additions & 4 deletions benchmark-models/SKILL.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ preamble-tier: 1
version: 1.0.0
description: |
Cross-model benchmark for gstack skills. Runs the same prompt through Claude,
GPT (via Codex CLI), and Gemini side-by-side — compares latency, tokens, cost,
GPT (via Codex CLI), Gemini, and Agy side-by-side — compares latency, tokens, cost,
and optionally quality via LLM judge. Answers "which model is actually best
for this skill?" with data instead of vibes. Separate from /benchmark, which
measures web page performance. Use when: "benchmark models", "compare models",
Expand All @@ -15,7 +15,7 @@ voice-triggers:
- "which model is best"
triggers:
- cross model benchmark
- compare claude gpt gemini
- compare claude gpt gemini agy
- benchmark skill across models
- which model should I use
allowed-tools:
Expand Down Expand Up @@ -69,12 +69,12 @@ If C: ask for the path. Verify it exists. Use as positional argument.
## Step 2: Choose providers

```bash
"$BIN" --prompt "unused, dry-run" --models claude,gpt,gemini --dry-run
"$BIN" --prompt "unused, dry-run" --models claude,gpt,gemini,agy --dry-run
```

Show the dry-run output. The "Adapter availability" section tells the user which providers will actually run (OK) vs skip (NOT READY — remediation hint included).

If ALL three show NOT READY: stop with a clear message — benchmark can't run without at least one authed provider. Suggest `claude login`, `codex login`, or `gemini login` / `export GOOGLE_API_KEY`.
If ALL four show NOT READY: stop with a clear message — benchmark can't run without at least one authenticated provider. Suggest `claude login`, `codex login`, `gemini login` / `export GOOGLE_API_KEY`, or logging in through `agy`.

If at least one is OK: AskUserQuestion:
- **Simplify:** "Which models should we include? The dry-run above showed which are authed. Unauthed ones will be skipped cleanly — they won't abort the batch."
Expand Down
2 changes: 1 addition & 1 deletion bin/gstack-codex-session-import
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ case "$MODE" in
exit 0
fi
LATEST=$(find "$CODEX_SESSIONS_ROOT" -type f -name "rollout-*.jsonl" -print 2>/dev/null \
| xargs ls -t 2>/dev/null | head -1 || true)
| xargs -r ls -t 2>/dev/null | head -1 || true)
if [ -z "$LATEST" ]; then
echo "NO_SESSIONS: no rollout-*.jsonl files under $CODEX_SESSIONS_ROOT"
exit 0
Expand Down
12 changes: 7 additions & 5 deletions bin/gstack-model-benchmark
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ import { runBenchmark, formatTable, formatJson, formatMarkdown, type BenchmarkIn
import { ClaudeAdapter } from '../test/helpers/providers/claude';
import { GptAdapter } from '../test/helpers/providers/gpt';
import { GeminiAdapter } from '../test/helpers/providers/gemini';
import { AgyAdapter } from '../test/helpers/providers/agy';

const ADAPTER_FACTORIES = {
claude: () => new ClaudeAdapter(),
gpt: () => new GptAdapter(),
gemini: () => new GeminiAdapter(),
agy: () => new AgyAdapter(),
};

type OutputFormat = 'table' | 'json' | 'markdown';
Expand Down Expand Up @@ -76,13 +78,13 @@ function positionalArgs(args: string[]): string[] {
return positional;
}

function parseProviders(s: string | undefined): Array<'claude' | 'gpt' | 'gemini'> {
function parseProviders(s: string | undefined): Array<'claude' | 'gpt' | 'gemini' | 'agy'> {
if (!s) return ['claude'];
const seen = new Set<'claude' | 'gpt' | 'gemini'>();
const seen = new Set<'claude' | 'gpt' | 'gemini' | 'agy'>();
for (const p of s.split(',').map(x => x.trim()).filter(Boolean)) {
if (p === 'claude' || p === 'gpt' || p === 'gemini') seen.add(p);
if (p === 'claude' || p === 'gpt' || p === 'gemini' || p === 'agy') seen.add(p);
else {
console.error(`WARN: unknown provider '${p}' — skipping. Valid: claude, gpt, gemini.`);
console.error(`WARN: unknown provider '${p}' — skipping. Valid: claude, gpt, gemini, agy.`);
}
}
return seen.size ? Array.from(seen) : ['claude'];
Expand Down Expand Up @@ -149,7 +151,7 @@ async function main(): Promise<void> {

async function dryRunReport(opts: {
prompt: string;
providers: Array<'claude' | 'gpt' | 'gemini'>;
providers: Array<'claude' | 'gpt' | 'gemini' | 'agy'>;
workdir: string;
timeoutMs: number;
output: OutputFormat;
Expand Down
5 changes: 4 additions & 1 deletion docs/ADDING_A_HOST.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Adding a New Host to gstack

gstack uses a declarative host config system. Each supported AI coding agent
(Claude, Codex, Factory, Kiro, OpenCode, Slate, Cursor, OpenClaw) is defined
(Claude, Codex, Factory, Kiro, OpenCode, Slate, Cursor, OpenClaw, Hermes, GBrain, Agy) is defined
as a typed TypeScript config object. Adding a new host means creating one file
and re-exporting it. Zero code changes to the generator, setup, or tooling.

Expand All @@ -17,6 +17,9 @@ hosts/
├── slate.ts # Slate (Random Labs)
├── cursor.ts # Cursor
├── openclaw.ts # OpenClaw (hybrid: config + adapter)
├── hermes.ts # Hermes
├── gbrain.ts # GBrain
├── agy.ts # Google Antigravity
└── index.ts # Registry: imports all, derives Host type
```

Expand Down
71 changes: 71 additions & 0 deletions docs/AGY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Google Antigravity (Agy) Integration

gstack supports Google Antigravity (Agy) as a first-class agent host. This integration allows you to generate and run Agy-compatible skills, load them dynamically via the `agy` plugin system, and benchmark agy models alongside Claude, OpenAI, and Gemini.

## Features

- **Automatic Setup**: Installs gstack skills directly into the Antigravity config directory via `./setup --host agy`.
- **Agy Plugin Compatibility**: Packages skills as a standard Agy plugin with a `plugin.json` manifest, automatically registered with `agy plugin install`.
- **Exclusion of Incompatible Skills**: Automatically filters out Claude-specific wrappers (like `gstack-codex`) from Agy generation.
- **Benchmark Integration**: Register Agy as a benchmark provider using `agy --print` to trace latency, quality, and tokens.

---

## Setup & Installation

To generate and install gstack skills into your local Antigravity environment:

```bash
./setup --host agy
```

### What Setup Does

1. **Precompile & Prepare**: Ensures the browse tool and other runtime dependencies are compiled.
2. **Generate Skills**: Runs `bun run gen:skill-docs --host agy` to generate Agy-compatible frontmatter.
3. **Initialize Plugin**: Creates the plugin directory structure under `.gemini/config/plugins/gstack`.
4. **Symlink/Copy Assets**: Places necessary executables (`bin`, `browse`, `review`, `qa`) into the plugin root.
5. **Register Plugin**: Invokes `agy plugin install` to import the gstack plugin into `~/.gemini/config/import_manifest.json`.

---

## Plugin Structure

When installed, the gstack plugin resides at:
`~/.gemini/config/plugins/gstack/`

The directory layout matches the standard Agy plugin structure:

```
~/.gemini/config/plugins/gstack/
├── plugin.json # Manifest declaring name, version, and license
├── skills/ # Generated Agy-compatible skills
│ ├── gstack/ # Root gstack skill (/gstack)
│ ├── gstack-qa/ # QA testing skill (/qa)
│ └── ...
├── bin/ # Shared executables and CLI tools
└── browse/ # Browse tool distribution files
```

---

## Benchmarking with Agy

Agy is registered as a model benchmark provider. You can execute prompts against Agy using the gstack benchmark runner.

### Pre-requisites
- The `agy` CLI must be installed and available in your `PATH`.
- Credentials must be configured in `~/.gemini/oauth_creds.json`.

### Run Benchmark
To run a dry run and check availability:
```bash
gstack-model-benchmark --models agy --dry-run
```

To execute a benchmark run:
```bash
gstack-model-benchmark --models agy --prompt "Explain quantum computing in one sentence."
```

The runner automatically passes `--dangerously-skip-permissions` to the CLI to run headless without hanging on interactive permission prompts.
59 changes: 59 additions & 0 deletions hosts/agy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { HostConfig } from '../scripts/host-config';

const agy: HostConfig = {
name: 'agy',
displayName: 'Antigravity',
cliCommand: 'agy',
cliAliases: [],

globalRoot: '.gemini/config/plugins/gstack/skills',
localSkillRoot: '.gemini/config/plugins/gstack/skills',
hostSubdir: '.gemini/config/plugins/gstack',
usesEnvVars: true,

frontmatter: {
mode: 'allowlist',
keepFields: [
'name',
'preamble-tier',
'version',
'description',
'allowed-tools',
'triggers',
'hooks',
'gbrain',
],
descriptionLimit: null,
},

generation: {
generateMetadata: false,
skipSkills: ['codex'],
},

pathRewrites: [
{ from: '~/.claude/skills/gstack', to: '$GSTACK_ROOT' },
{ from: '.claude/skills/gstack', to: '.gemini/config/plugins/gstack/skills' },
{ from: '.claude/skills', to: '.gemini/config/plugins/gstack' },
],

toolRewrites: {},

suppressedResolvers: ['GBRAIN_CONTEXT_LOAD', 'GBRAIN_SAVE_RESULTS'],

runtimeRoot: {
globalSymlinks: ['bin', 'browse/dist', 'browse/bin', 'gstack-upgrade', 'ETHOS.md'],
globalFiles: {
'review': ['checklist.md', 'TODOS-format.md'],
},
},

install: {
prefixable: false,
linkingStrategy: 'symlink-generated',
},

learningsMode: 'basic',
};

export default agy;
5 changes: 3 additions & 2 deletions hosts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ import cursor from './cursor';
import openclaw from './openclaw';
import hermes from './hermes';
import gbrain from './gbrain';
import agy from './agy';

/** All registered host configs. Add new hosts here. */
export const ALL_HOST_CONFIGS: HostConfig[] = [claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain];
export const ALL_HOST_CONFIGS: HostConfig[] = [claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain, agy];

/** Map from host name to config. */
export const HOST_CONFIG_MAP: Record<string, HostConfig> = Object.fromEntries(
Expand Down Expand Up @@ -65,4 +66,4 @@ export function getExternalHosts(): HostConfig[] {
}

// Re-export individual configs for direct import
export { claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain };
export { claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain, agy };
Loading
Loading