Handing Off IDE Work to the Chat Agent: Passing Context Through a File After the Two-App Split
Since Antigravity 2.0 split into an IDE and a chat-style agent app, context you build up in one does not carry into the other. Here is a file-based approach that makes a single file in your repo the source of truth for handoff, with a schema, a validation script, and a way to pin it with a Guide skill.
Before kicking off my sites' overnight auto-updates, I opened the chat-style agent app to throw one last verification at a change I had built up in the IDE. But that app had none of the back-and-forth I had just been having on the IDE side. Which files did I touch, with what intent, and which checks had I not run yet? I ended up explaining everything from scratch. What was meant to be a quick confirmation dissolved into re-explanation.
Now that Antigravity 2.0 has split into a VS Code-based IDE and a chat-style agent interface, this "context I built in one app is absent in the other" situation happens daily. The two apps share the model and the agent harness, but their conversation histories are separate. As an indie developer running several tasks in parallel, I constantly want to hand a flow I shaped by hand in the IDE over to a disposable agent on the chat side just for verification. Re-explaining every time defeats the purpose of splitting the apps.
What I settled on over the past two weeks was to stop expecting conversation history to carry the handoff, and instead place a single "handoff brief" file inside the repo that both apps read. It is unglamorous, but whether I cross between apps or look back the next morning, one file tells me where things stand.
Why You Should Not Rely on Conversation History for Handoff
I do not blame the two-app design itself. The IDE is "where you move your hands," while the chat agent is "where you delegate and orchestrate tasks," so independent histories are actually natural. The problem is our own habit of throwing the next move as if it assumes "what we just discussed."
Using conversation history as the medium for handoff carries three weaknesses. First, history lives inside the app, outside the repo, so it never rides along with review or verification. Second, history only grows chronologically, so the key points get buried in noise. Third, for tomorrow's you or for the chat-side agent, "how far are we, and what comes next" cannot be read instantly from a long history.
Handoff does not need the full conversation. It needs three things: the current position, the next move, and the checks not yet run. Structure those into one file, and the medium moves outside the app, referenceable identically from both.
The Handoff Brief Schema
I keep a file at a fixed path, .antigravity/handoff.md, with machine-readable frontmatter and a human-facing body. The frontmatter is read by the validation script; the body is read by the agent and by me. Two layers.
---task: "Change article preview cut position to be based on H2 count"updated_by: "ide" # ide | chat — which side updated lastupdated_at: "2026-07-02T10:40:00+09:00"status: "in_progress" # in_progress | ready_for_verify | donebranch: "feature/preview-cut"touched: - "src/app/[locale]/articles/[category]/[slug]/page.tsx" - "src/lib/content.ts"open_checks: - "A short article (2 H2s) must not expose the full body" - "The table of contents must not shrink to one item after the paywall"handoff_to: "chat" # who picks the work up next---## Current positionChanged the preview cut from a fixed character slice to being based onH2 positions. Implementation now cuts before the second-and-later H2.## Next moveOn the chat side, open one short article with only 2 H2s and visuallyconfirm the preview does not show the entire body.## Assumptions not yet passed- The build passes, but I have not verified rendering on a real device.- getArticleContent in content.ts is unchanged.
The point is that open_checks and status sit in the frontmatter (machine-readable) too. If they lived only in the body, an agent might helpfully summarize and quietly turn "not verified" into "verified." As a machine-readable array, the script below can judge whether the brief is marked done while checks remain unconsumed.
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦A file-based source of truth that carries work context across the IDE and chat apps even though their conversation histories are separate
✦A handoff-brief schema with machine-readable frontmatter, plus a Node script that checks its freshness and consistency
✦How to pin 'update the brief before handing off' deterministically with a Guide skill so the two apps never drift apart
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
A Script That Validates the Brief's Freshness and Consistency
Just placing a file guarantees you will eventually get a stale brief — you kept editing in the IDE, but updated_at stayed old. So I wrote a script that mechanically checks whether the brief has fallen out of sync with the actual work. It is written in Node, but what it does is simple.
// scripts/check-handoff.mjsimport { readFileSync } from "node:fs";import { execSync } from "node:child_process";const raw = readFileSync(".antigravity/handoff.md", "utf8");const fm = raw.match(/^---\n([\s\S]*?)\n---/);if (!fm) { console.error("❌ handoff.md has no frontmatter"); process.exit(1);}// Minimal YAML read (self-rolled to avoid adding a dependency)const meta = {};let key = null;for (const line of fm[1].split("\n")) { const kv = line.match(/^(\w+):\s*(.*)$/); const item = line.match(/^\s*-\s*(.*)$/); if (kv) { key = kv[1]; meta[key] = kv[2] ? kv[2].replace(/^"|"$/g, "") : []; } else if (item && Array.isArray(meta[key])) meta[key].push(item[1].replace(/^"|"$/g, ""));}const problems = [];// (1) Freshness: is the brief's updated_at older than any touched file's last change?const touched = Array.isArray(meta.touched) ? meta.touched : [];const briefTime = new Date(meta.updated_at).getTime();for (const f of touched) { try { const mtime = execSync(`git log -1 --format=%cI -- "${f}"`).toString().trim(); if (mtime && new Date(mtime).getTime() > briefTime) { problems.push(`Stale: ${f} changed after the brief was updated`); } } catch { /* uncommitted is covered separately by status */ }}// (2) Consistency: done, yet open_checks remain?const checks = Array.isArray(meta.open_checks) ? meta.open_checks : [];if (meta.status === "done" && checks.length > 0) { problems.push(`status is done but ${checks.length} checks remain`);}// (3) Explicit recipientif (meta.status === "ready_for_verify" && !meta.handoff_to) { problems.push("awaiting verification but handoff_to is empty");}if (problems.length) { console.error("🛑 The handoff brief has problems:"); for (const p of problems) console.error(" - " + p); process.exit(1);}console.log("✅ The handoff brief is consistent with the current work");
The script compares the last commit time of each file in touched against the brief's updated_at to see whether the brief has been left behind. It also rejects the self-contradiction of remaining checks while marked done. I run it both in a pre-commit hook and at the moment the chat side receives the work. It once caught exactly the drift I feared — I had touched content.ts afterward but forgotten to update the brief.
Pinning "Update the Brief When Done" Toward Determinism with a Guide Skill
The built-in Guide skill added in the 6/26 update is good at making an agent reproduce a recurring procedure. I pinned the procedure "when you reach a stopping point, update handoff.md and pass check-handoff before handing off" into it. Rather than trusting the agent's goodwill, it is a scaffold that makes it walk the same order every time.
# .antigravity/guides/handoff.mdname: handoff-briefdescription: The handoff procedure to run before passing work to another app or agentsteps: - Reflect changed files into the frontmatter's touched list - Re-select status from in_progress / ready_for_verify / done - List checks not yet run under open_checks (no guessing them away) - Update updated_by and updated_at to the current actor and time - Run `node scripts/check-handoff.mjs`, confirm ✅, then hand off
Because a Guide skill works advisorily, I do not make it the sole gate; I always sandwich the final check-handoff.mjs as a deterministic backstop. The skill prompts the procedure, the script guarantees the result — a two-stage split. Since adopting this division, the mismatch where the brief advances on one app while the other stays stale has all but disappeared.
Avoiding "Taking It at Face Value" on the Receiving Side
When I have the chat-style agent read the brief, I add a line that keeps it from believing the contents outright. The brief is only the sender's claim, not a guarantee of fact. Concretely, I place constraints like these in the receiving prompt.
What the sender wrote
What the receiver must confirm
Files listed in touched
Open the actual diff and reconcile it with the brief's stated intent
Each open_checks item
Reproduce one by one, returning each as done or still open
status: ready_for_verify
Run the build and type-check yourself before accepting
Shaping it so "the receiver re-checks the given assumptions from the ground up" means the verification net catches things even when the brief is a bit sloppy. Conversely, writing quick key points and confirming on the receiving side fit the speed of solo development better than laboring to write a perfect brief.
Pitfalls I Noticed in Operation
Running this for about two weeks surfaced a few things.
First, do not get greedy about the brief's granularity. Stuff several tasks into one file and it becomes unclear which open_checks belongs to which work. I commit to one brief per unit of work, mark it status: done when finished, and treat it as archived.
Second, if the two apps' time references drift, the updated_at comparison breaks. Always write the brief's time as ISO 8601 with a timezone (+09:00), and I aligned the script to git log's commit time (%cI) as well. Write a bare time string and this freshness check becomes meaningless.
Finally, treat the brief as a "map of the current position," not a replacement for conversation history. Try to record the entire past, and you have merely built a long history in another place. Narrowing to two points — where we are now and where we go next — made cross-app handoff dramatically lighter.
I take the tooling splitting into two apps, IDE and chat, as a positive: a place has appeared for a human to explicitly put context. Start by dropping a single .antigravity/handoff.md into your repo and passing check-handoff.mjs once. Cross-app handoff will start from confirmation instead of re-explanation.
Share
Thank You for Reading
Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.