When I first connected Claude to my Antigravity workspace and saw the response stream back, I noticed something unexpected: Opus 4 and Sonnet 4 don't just differ in speed — they have a different quality of reasoning. It reminded me of the difference between a fine-tipped brush and a broad one. Neither is universally better; each belongs to a specific kind of task.
I've been building apps independently since 2014. Over 50 million downloads across wallpaper and wellness apps taught me that choosing the right tool — not the most powerful one — is what sustains a product over years. The same principle applies here.
This article covers how to integrate Claude Opus 4, Sonnet 4, and Haiku 4.5 into Antigravity, along with the reasoning behind model selection and three production-grade implementation patterns.
The Current State of Antigravity × Claude Integration
As of May 2026, Antigravity (Google's AI coding IDE) supports external model integrations alongside its native Gemini family. Claude models from Anthropic can be connected via the Model Context Protocol (MCP) or direct API calls from agent scripts.
Developers are reaching for Claude for specific reasons: complex architectural reasoning, nuanced code review, and tasks where the quality of a single output justifies a higher cost. Gemini 2.5 Pro handles large codebase context well; Claude Opus 4 handles deep reasoning chains exceptionally.
In my own workflow — automating maintenance across wallpaper and content apps — I run Antigravity agents that route to different Claude models depending on what the task actually requires.
Three Models, Three Use Cases
Claude Opus 4 — For Tasks That Demand Deep Reasoning
Opus 4 is Anthropic's highest-capability model. It excels at multi-step reasoning, nuanced code review, and architectural decisions where getting it right the first time matters.
Best for:
- Architecture design discussions
- Security risk analysis in authentication or payment flows
- Identifying subtle, hard-to-reproduce bugs
- Synthesizing long documents into structured decisions
Cost:
- Input: $15 / 1M tokens
- Output: $75 / 1M tokens
The key question I ask before invoking Opus 4: "Would Sonnet 4 genuinely miss something here?" If the answer is no, I use Sonnet 4.
Claude Sonnet 4 — The Daily Driver
Sonnet 4 hits the sweet spot between cost, speed, and quality for most day-to-day coding tasks. It's my default model in Antigravity agent workflows.
Best for:
- Code generation and refactoring
- Writing and updating unit tests
- Implementing API endpoints from specifications
- Drafting technical documentation
Cost:
- Input: $3 / 1M tokens
- Output: $15 / 1M tokens
- Roughly 1/5 the cost of Opus 4, with quality that meets or exceeds requirements for 80% of tasks
Claude Haiku 4.5 — For Speed and High-Volume Tasks
Haiku 4.5 is the fastest, cheapest model in the Claude family. When you need near-instant responses or are processing large volumes of small tasks, Haiku is the right choice.
Best for:
- Inline code completion suggestions
- Log classification and summarization
- Large-scale text preprocessing pipelines
- Real-time chat interfaces
Cost:
- Input: $0.80 / 1M tokens
- Output: $4 / 1M tokens
- Roughly 1/4 the cost of Sonnet 4
Implementation Pattern 1: MCP Server Integration
The cleanest way to bring Claude into Antigravity is through an MCP server that handles model routing, cost logging, and fallback logic.
// .antigravity/mcp_settings.json
{
"mcpServers": {
"claude-integration": {
"command": "node",
"args": ["/path/to/claude-mcp-server/dist/index.js"],
"env": {
"ANTHROPIC_API_KEY": "${ANTHROPIC_API_KEY}",
"DEFAULT_MODEL": "claude-sonnet-4-6",
"FALLBACK_MODEL": "claude-haiku-4-5-20251001"
}
}
}
}Here's the core MCP server implementation. It includes automatic model selection based on task complexity, cost logging, and Opus-to-Sonnet fallback on errors.
// claude-mcp-server/src/index.ts
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
// Select model based on declared task complexity
function selectModel(taskComplexity: "low" | "medium" | "high"): string {
const modelMap = {
low: "claude-haiku-4-5-20251001",
medium: "claude-sonnet-4-6",
high: "claude-opus-4-6",
};
return modelMap[taskComplexity];
}
// Estimate cost before committing to a request
function estimateCost(
model: string,
inputTokens: number,
outputTokens: number
): number {
const pricing: Record<string, { input: number; output: number }> = {
"claude-opus-4-6": { input: 15, output: 75 },
"claude-sonnet-4-6": { input: 3, output: 15 },
"claude-haiku-4-5-20251001": { input: 0.8, output: 4 },
};
const p = pricing[model] ?? pricing["claude-sonnet-4-6"];
return (inputTokens * p.input + outputTokens * p.output) / 1_000_000;
}
// Core Claude call with fallback
async function callClaude(params: {
messages: Anthropic.MessageParam[];
system?: string;
taskComplexity?: "low" | "medium" | "high";
maxTokens?: number;
}): Promise<{ content: string; usage: Anthropic.Usage }> {
const model = selectModel(params.taskComplexity ?? "medium");
try {
const response = await client.messages.create({
model,
max_tokens: params.maxTokens ?? 4096,
system:
params.system ??
"You are an expert software engineer. Provide accurate, practical code.",
messages: params.messages,
});
const textContent = response.content.find((c) => c.type === "text");
if (!textContent || textContent.type !== "text") {
throw new Error("No text content in response");
}
const cost = estimateCost(
model,
response.usage.input_tokens,
response.usage.output_tokens
);
console.error(
`[Claude] model=${model} cost=$${cost.toFixed(4)} ` +
`tokens=${response.usage.input_tokens}+${response.usage.output_tokens}`
);
return { content: textContent.text, usage: response.usage };
} catch (error) {
// If Opus 4 fails, fall back to Sonnet 4
if (model === "claude-opus-4-6") {
console.error("[Claude] Opus 4 failed, falling back to Sonnet 4");
return callClaude({ ...params, taskComplexity: "medium" });
}
throw error;
}
}Implementation Pattern 2: Structured Output with Tool Calls
When an Antigravity agent needs to call external APIs or return typed data, Claude's tool call feature enables reliable structured output.
// code-review-with-tools.ts
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const codeReviewTool: Anthropic.Tool = {
name: "submit_code_review",
description: "Return structured code review results",
input_schema: {
type: "object" as const,
properties: {
severity: {
type: "string",
enum: ["critical", "warning", "info"],
},
category: {
type: "string",
enum: ["security", "performance", "maintainability", "logic", "style"],
},
issues: {
type: "array",
items: {
type: "object",
properties: {
line: { type: "number" },
description: { type: "string" },
suggestion: { type: "string" },
},
required: ["line", "description", "suggestion"],
},
},
overall_score: {
type: "number",
minimum: 0,
maximum: 100,
},
},
required: ["severity", "category", "issues", "overall_score"],
},
};
async function reviewCode(code: string, language: string) {
const response = await client.messages.create({
// Use Opus 4 for code review — accuracy justifies the cost
model: "claude-opus-4-6",
max_tokens: 2048,
tools: [codeReviewTool],
tool_choice: { type: "tool", name: "submit_code_review" },
messages: [
{
role: "user",
content: `Review the following ${language} code:\n\n\`\`\`${language}\n${code}\n\`\`\``,
},
],
});
const toolUse = response.content.find((c) => c.type === "tool_use");
if (!toolUse || toolUse.type !== "tool_use") {
throw new Error("Expected tool use response");
}
return toolUse.input as {
severity: string;
category: string;
issues: Array<{ line: number; description: string; suggestion: string }>;
overall_score: number;
};
}
// Example: this catches the SQL injection on line 2 with severity: "critical"
async function main() {
const vulnerableCode = `
async function fetchUser(userId) {
const result = await db.query('SELECT * FROM users WHERE id = ' + userId);
return result;
}
`;
const review = await reviewCode(vulnerableCode, "javascript");
console.log(`Quality score: ${review.overall_score}/100`);
review.issues.forEach((issue) => {
console.log(`Line ${issue.line}: ${issue.description}`);
console.log(` Fix: ${issue.suggestion}`);
});
}Tool calls ensure Claude's output is machine-readable from the first response, eliminating the need to parse free-form text.
Implementation Pattern 3: Streaming for Real-Time UI
For any interface where a user watches Claude respond in real time, the streaming API is the right approach.
// streaming-claude.ts
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
async function* streamClaudeResponse(
userMessage: string,
conversationHistory: Anthropic.MessageParam[] = []
): AsyncGenerator<string> {
const messages: Anthropic.MessageParam[] = [
...conversationHistory,
{ role: "user", content: userMessage },
];
const stream = await client.messages.stream({
model: "claude-sonnet-4-6", // Sonnet 4 for balanced speed + quality
max_tokens: 1024,
messages,
system:
"You are a development assistant running inside Antigravity IDE. " +
"Give concise, practical answers.",
});
let inputTokens = 0;
let outputTokens = 0;
for await (const chunk of stream) {
if (
chunk.type === "content_block_delta" &&
chunk.delta.type === "text_delta"
) {
yield chunk.delta.text;
} else if (chunk.type === "message_start") {
inputTokens = chunk.message.usage.input_tokens;
} else if (chunk.type === "message_delta") {
outputTokens = chunk.usage.output_tokens;
}
}
const cost = (inputTokens * 3 + outputTokens * 15) / 1_000_000;
console.error(
`[Streaming] tokens=${inputTokens}+${outputTokens} cost=$${cost.toFixed(4)}`
);
}
// Usage in an Antigravity agent script
async function runSession() {
const history: Anthropic.MessageParam[] = [];
const question = "How do I improve the performance of this TypeScript code?";
process.stdout.write("Claude: ");
let fullResponse = "";
for await (const chunk of streamClaudeResponse(question, history)) {
process.stdout.write(chunk);
fullResponse += chunk;
}
console.log();
history.push({ role: "user", content: question });
history.push({ role: "assistant", content: fullResponse });
}Cost Optimization: An Indie Developer Perspective
When AdMob revenue was my primary income, I tracked every dollar of server cost. I approach Claude API costs with the same discipline.
Intelligent Model Routing
// cost-aware-router.ts
interface TaskConfig {
requiresDeepReasoning: boolean;
isRepetitive: boolean;
latencyRequirement: "realtime" | "normal" | "batch";
}
function chooseModel(config: TaskConfig): string {
if (config.latencyRequirement === "realtime") {
return "claude-haiku-4-5-20251001";
}
if (config.requiresDeepReasoning && !config.isRepetitive) {
return "claude-opus-4-6";
}
if (config.isRepetitive && config.latencyRequirement === "batch") {
return "claude-haiku-4-5-20251001";
}
return "claude-sonnet-4-6"; // default
}
// Monthly budget projection
function estimateMonthlyBudget(dailyTasks: {
deepAnalysis: number; // Opus 4
codeGeneration: number; // Sonnet 4
quickQueries: number; // Haiku 4.5
}): number {
const avgTokens = { opus: 3000, sonnet: 1500, haiku: 500 };
const dailyCost =
(dailyTasks.deepAnalysis * avgTokens.opus * (15 + 75)) / 1_000_000 +
(dailyTasks.codeGeneration * avgTokens.sonnet * (3 + 15)) / 1_000_000 +
(dailyTasks.quickQueries * avgTokens.haiku * (0.8 + 4)) / 1_000_000;
return dailyCost * 30;
}
const budget = estimateMonthlyBudget({
deepAnalysis: 5,
codeGeneration: 50,
quickQueries: 200,
});
console.log(`Estimated monthly cost: $${budget.toFixed(2)}`);
// → ~$12–18/month for a solo developer workflowRate Limit Handling
// retry-with-backoff.ts
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
async function callWithRetry(
params: Anthropic.MessageCreateParamsNonStreaming,
maxRetries = 3
): Promise<Anthropic.Message> {
let lastError: Error | null = null;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.messages.create(params);
} catch (error) {
if (error instanceof Anthropic.RateLimitError) {
const waitMs = Math.pow(2, attempt) * 1000 + Math.random() * 500;
console.warn(`Rate limited. Waiting ${waitMs}ms (attempt ${attempt + 1}/${maxRetries})`);
await new Promise((r) => setTimeout(r, waitMs));
lastError = error;
continue;
}
if (error instanceof Anthropic.APIError && error.status === 529) {
const waitMs = 5000 + Math.random() * 3000;
console.warn(`API overloaded. Waiting ${waitMs}ms`);
await new Promise((r) => setTimeout(r, waitMs));
lastError = error;
continue;
}
throw error;
}
}
throw lastError ?? new Error("Max retries exceeded");
}Practical Notes for Antigravity Users
Context window management: Antigravity agents accumulate conversation history quickly. As history grows, so does the cost per request. Build in periodic summarization or selective pruning to keep token counts under control.
System prompt framing: Explicitly telling Claude it's operating inside Antigravity IDE improves the relevance of code suggestions. A simple "You are an agent running inside Antigravity IDE" in the system prompt makes a measurable difference.
Japanese content: Both Sonnet 4 and Opus 4 handle Japanese with high quality — useful if you're building multilingual apps or writing documentation in Japanese. Haiku 4.5 works in Japanese but struggles with complex grammatical structures.
My Current Model Allocation (May 2026)
For transparency, here's how I actually use these models today:
- Image classification for wallpaper apps: Haiku 4.5 — high volume, cost is the constraint
- New feature architecture discussions: Opus 4 — a wrong design costs far more than the API fee
- Code generation and refactoring: Sonnet 4 — the right balance for most tasks
- App store copy in multiple languages: Sonnet 4 — quality meets the bar at acceptable cost
This allocation keeps my monthly API cost at $15–25 while meaningfully improving my development throughput.
Model selection isn't about always using the most powerful option — it's about matching capability to need. Start with Sonnet 4 as your default, promote to Opus 4 when reasoning depth genuinely matters, and delegate high-volume work to Haiku 4.5. One week of conscious cost logging will reveal the right mix for your specific workflow.
I hope this helps you get started. Thanks for reading.