Skip to content
Open
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
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.11.0](https://github.com/LarsCowe/bmalph/compare/v2.10.0...v2.11.0) (2026-03-24)
## [Unreleased]

### Features

* **platform:** add support for Google Antigravity (agy) agent

## [2.11.0](https://github.com/LarsCowe/bmalph/compare/v2.10.0...v2.11.0) (2026-03-24)

### Features

Expand Down
Empty file modified bin/bmalph.js
100644 → 100755
Empty file.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bmalph",
"version": "2.11.0",
"version": "2.12.0",
"description": "Unified AI Development Framework - BMAD phases with Ralph execution loop",
"type": "module",
"bin": {
Expand Down
98 changes: 98 additions & 0 deletions ralph/drivers/antigravity.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/bin/bash
# Antigravity (agy) driver for Ralph

driver_name() {
echo "antigravity"
}

driver_display_name() {
echo "Antigravity (agy)"
}

driver_cli_binary() {
echo "agy"
}

driver_min_version() {
echo "0.1.0"
}

driver_check_available() {
command -v "$(driver_cli_binary)" &>/dev/null
}

driver_valid_tools() {
VALID_TOOL_PATTERNS=()
}

driver_supports_tool_allowlist() {
return 1
}

driver_permission_denial_help() {
echo " - $DRIVER_DISPLAY_NAME uses its native permission and approval model."
echo " - Keep CLAUDE_PERMISSION_MODE=bypassPermissions in $RALPHRC_FILE for unattended loops."
echo " - Alternatively, configure toolPermission to 'always-proceed' in settings.json."
}

driver_build_command() {
local prompt_file=$1
local loop_context=$2
local session_id=$3

CLAUDE_CMD_ARGS=("$(driver_cli_binary)")

if [[ ! -f "$prompt_file" ]]; then
echo "ERROR: Prompt file not found: $prompt_file" >&2
return 1
fi

local resolved_permission_mode="${CLAUDE_PERMISSION_MODE:-bypassPermissions}"
if [[ "$resolved_permission_mode" == "bypassPermissions" ]]; then
CLAUDE_CMD_ARGS+=("--dangerously-skip-permissions")
fi

if [[ "$CLAUDE_USE_CONTINUE" == "true" && -n "$session_id" ]]; then
CLAUDE_CMD_ARGS+=("--conversation" "$session_id")
fi

local prompt_content
prompt_content=$(cat "$prompt_file")
if [[ -n "$loop_context" ]]; then
prompt_content="$loop_context

$prompt_content"
fi

# Using --print to run non-interactively and print the response.
CLAUDE_CMD_ARGS+=("--print" "$prompt_content")
}

driver_supports_sessions() {
return 0
}

driver_supports_live_output() {
return 0
}

driver_prepare_live_command() {
LIVE_CMD_ARGS=("${CLAUDE_CMD_ARGS[@]}")
}

driver_stream_filter() {
# If Antigravity doesn't output JSON, we just return empty string to pass raw stdout.
echo '.'
}

driver_extract_session_id_from_output() {
# We might need to handle conversation ID extraction later, but for now
# this will rely on fallback session id or just pass
echo ""
return 1
}

driver_fallback_session_id() {
echo ""
return 1
}
2 changes: 1 addition & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ program
.option("-d, --description <desc>", "Project description")
.option(
"--platform <id>",
"Target platform (claude-code, codex, opencode, cursor, windsurf, copilot, aider)"
"Target platform (claude-code, codex, opencode, cursor, windsurf, copilot, aider, antigravity)"
)
.option("--dry-run", "Preview changes without writing files")
.action(
Expand Down
31 changes: 31 additions & 0 deletions src/platform/antigravity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { Platform } from "./types.js";
import { buildPlatformDoctorChecks } from "./doctor-checks.js";

export const antigravityPlatform: Platform = {
id: "antigravity",
displayName: "Antigravity (agy)",
tier: "full",
instructionsFile: "AGENTS.md", // Standard file used by Antigravity rules
commandDelivery: { kind: "skills", dir: ".agents/skills", frontmatterName: "command" }, // Since it supports bmad skills via frontmatter
instructionsSectionMarker: "## BMAD-METHOD Integration",
generateInstructionsSnippet: () => `
## BMAD-METHOD Integration

Use bmalph to navigate phases. Use the available slash commands to discover all commands.

### Available Agents

| Command | Agent | Role |
|---------|-------|------|
| \`/analyst\` | Analyst | Research, briefs, discovery |
| \`/architect\` | Architect | Technical design, architecture |
| \`/pm\` | Product Manager | PRDs, epics, stories |
| \`/sm\` | Scrum Master | Sprint planning, status, coordination |
| \`/dev\` | Developer | Implementation, coding |
| \`/ux-designer\` | UX Designer | User experience, wireframes |
| \`/qa\` | QA Engineer | Test automation, quality assurance |
`,
getDoctorChecks() {
return buildPlatformDoctorChecks(this);
},
};
3 changes: 2 additions & 1 deletion src/platform/detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ const STRONG_DETECTION_MARKERS: Array<{ platform: PlatformId; markers: string[]
{ platform: "windsurf", markers: [".windsurf"] },
{ platform: "copilot", markers: [".github/copilot-instructions.md"] },
{ platform: "aider", markers: [".aider.conf.yml"] },
{ platform: "antigravity", markers: [".agents"] },
];

const ROOT_INSTRUCTION_MARKERS: Array<{ marker: string; candidates: PlatformId[] }> = [
{ marker: "AGENTS.md", candidates: ["codex", "opencode", "cursor"] },
{ marker: "AGENTS.md", candidates: ["codex", "opencode", "cursor", "antigravity"] },
{ marker: "CLAUDE.md", candidates: ["claude-code", "cursor"] },
];

Expand Down
2 changes: 2 additions & 0 deletions src/platform/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { cursorPlatform } from "./cursor.js";
import { windsurfPlatform } from "./windsurf.js";
import { copilotPlatform } from "./copilot.js";
import { aiderPlatform } from "./aider.js";
import { antigravityPlatform } from "./antigravity.js";

const PLATFORMS: ReadonlyMap<PlatformId, Platform> = new Map([
["claude-code", claudeCodePlatform],
Expand All @@ -15,6 +16,7 @@ const PLATFORMS: ReadonlyMap<PlatformId, Platform> = new Map([
["windsurf", windsurfPlatform],
["copilot", copilotPlatform],
["aider", aiderPlatform],
["antigravity", antigravityPlatform],
]);

export function getPlatform(id: PlatformId): Platform {
Expand Down
1 change: 1 addition & 0 deletions src/platform/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const PLATFORM_IDS = [
"windsurf",
"copilot",
"aider",
"antigravity",
] as const;
export type PlatformId = (typeof PLATFORM_IDS)[number];

Expand Down
4 changes: 2 additions & 2 deletions tests/platform/registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ describe("registry", () => {
});

describe("getAllPlatforms", () => {
it("returns array of 7 platforms", () => {
it("returns array of 8 platforms", () => {
const platforms = getAllPlatforms();
expect(platforms).toHaveLength(7);
expect(platforms).toHaveLength(8);
});
});

Expand Down