Designing Knowledge Freshness for Antigravity AI Agents — A Runtime Architecture for Model Cutoffs, Corpus Staleness, and Real-World Time Drift
Antigravity agents have to juggle three independent time axes — model cutoff, RAG corpus update, real-world clock — or they will confidently cite six-month-old documentation. Here is the runtime architecture I use, with working TypeScript code and the TTL thresholds I run in production.
I have been running personal iOS and Android apps since 2014, and as the catalog grew toward 50 million cumulative downloads I learned, painfully, that the most dangerous failure mode is "answers that were correct six months ago and quietly went wrong." AdMob policy, App Store review guidelines, Google Play target API levels — these documents update without fanfare and they do not break your build, they just make your reasoning subtly out of date.
When I started building agents in Antigravity, I hit the same trap several times. The agent would tell me, with full confidence, that "as of late 2024 you should call AdRequest.Builder().build() to set test devices," and the recommendation would be obsolete by the time I shipped. The model's knowledge was frozen while the real documentation kept moving.
This article is the operational design I now use to keep that drift visible and manageable. It walks through how to reason about knowledge freshness inside an Antigravity agent, with working code rather than abstract diagrams.
Decompose freshness into three independent time axes
The first move is conceptual. An agent's knowledge has at least three time axes, and conflating them produces vague countermeasures.
The first is the model's own cutoff date. Whatever LLM you call has a fixed last-training-data date — early 2025 for current Gemini 2.5 generations, mid-2025 for Claude 4 generations. Anything newer than that simply is not in the model's weights.
The second is the RAG corpus update date. Internal documents, official manuals, your own codebase — each chunk has its own "last touched" timestamp. Ideally you store this per document, better still per paragraph.
The third is the real-world current time. AdMob policy may have changed today. Google may announce something new next week. This is the timestamp against which you judge how much your other two axes can still be trusted.
Storing these as three distinct fields from day one is what makes failure post-mortems tractable later. Antigravity agent designs should keep them separate.
Introduce a Freshness Oracle as a first-class component
The pattern I use in personal-developer projects is to place a small service called the Freshness Oracle next to the agent. Before the agent commits to an answer, it asks the Oracle to grade the freshness of whatever knowledge source it is about to lean on, and then decides how to respond.
Three verdicts are enough: fresh (within tolerance, use directly), stale (past tolerance, use with explicit caveats), and expired (out of tolerance entirely, do not use). The Oracle computes this from corpus-side metadata and the topic the query is touching.
The important part is that TTLs vary by topic. AdMob policy gets 30 days, iOS review guidelines 60, Play target API 90 — all reverse-engineered from how often each source actually updates in practice. My AdMob TTL is the shortest because, looking back over the last two years, AdMob-related material in my own corpus changed roughly once a month.
✦
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 working TypeScript implementation of a Freshness Oracle that separates model cutoff, corpus update date, and real-world clock into three independent signals
✦Time-aware prompting patterns and freshness metadata schemas you can copy into your own Antigravity agent, with the TTL thresholds I actually run on AdMob, App Review, and Play target API topics
✦An operational checklist and observability dashboard spec to catch silent corpus staleness — the kind that does not crash anything but quietly returns outdated answers
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.
Make prompts time-aware so the model knows what "now" is
Once the Oracle has graded the source, you inject time context into the prompt. Skip this and the model will assume its own cutoff date is "today."
The system message gets three things at the top: the actual execution time (ISO format with timezone), the source's last update date, and the Oracle's verdict.
// time-aware-prompt.tsimport type { FreshnessVerdict } from "./freshness-oracle";export function buildSystemPrompt( now: Date, source: { id: string; topic: string; updatedAt: Date }, verdict: FreshnessVerdict): string { const nowStr = now.toISOString(); const sourceDate = source.updatedAt.toISOString().slice(0, 10); const guardClause = verdict.status === "expired" ? `BLOCK: this source is ${verdict.ageDays}d old, well past its ${verdict.ttlDays}d TTL. Do not use it. Ask the user to verify against the current official source.` : verdict.status === "stale" ? `WARN: this source is ${verdict.ageDays}d old, past its ${verdict.ttlDays}d TTL. If you cite it, prefix the claim with "as of [date]" and tell the user to confirm against the latest source.` : `OK: this source is ${verdict.ageDays}d old, within its ${verdict.ttlDays}d TTL.`; return [ `### Time Context`, `- Current time: ${nowStr}`, `- Source: ${source.id} (${source.topic})`, `- Source last updated: ${sourceDate}`, ``, guardClause, ``, `### Answering policy`, `- Always reason against the time context above`, `- Do not assert facts newer than your training cutoff with confidence`, `- When uncertain, surface that uncertainty explicitly`, ].join("\n");}
What I noticed in my own personal-developer projects is that adding the guardClause flips the tone of the answers. Before injection, the agent loved to say "as of May 2026, X is the recommended approach." After injection, the answer shifts to "since the source was last updated in December 2025, any change after that needs separate verification." Both Gemini 2.5 Pro and Claude 4.5 Sonnet behaved similarly under this nudge.
Design the RAG corpus lifecycle deliberately
The Oracle only works because the corpus carries correct metadata. Skimp on corpus lifecycle management and the Oracle hands back garbage verdicts.
In my running corpus every document carries: source_url, fetched_at, source_published_at, topic, ttl_override, and evidence_hash (a digest of the body).
I think of the lifecycle in four phases:
Ingest: pull the source, attach metadata, persist
Validate: periodically check that the source URL still resolves and the body hash matches the recorded one
Refresh: when TTL hits, re-fetch. If the body changed, update evidence_hash; if not, only bump fetched_at
Retire: mark expired when the URL 404s, the publisher deprecates it, or the age passes 2× TTL without a refresh
The non-obvious detail here is that you do not update evidence_hash if the body did not change. Keeping that field stable on no-op refreshes preserves a clean audit trail of "when did this document actually change." My corpus shows four evidence_hash flips on the AdMob policy document over the past eighteen months, every one of which affected real implementation choices in my apps.
Patterns that break in production
Once you run this in production you will see the same failure modes again and again. Three of them are near-certain.
The first is silent staleness. The URL stays the same, the body changes only slightly, and that slight change matters. AdMob SDK version requirements are the canonical example — you cannot detect this without diffing whole documents, which is exactly what evidence_hash is for.
The second is topic drift. The query touches a topic that does not exist in your TTL map, or exists but with the wrong TTL. "Antigravity new feature" needs a tight TTL; if it accidentally inherits the 365-day general-tech default, the agent will confidently quote month-old beta behavior as if it were current. Periodically audit Oracle logs for topic-classification accuracy.
The third is silent unreachability. The source URL 404s but the fetcher swallows it and bumps fetched_at anyway. The Oracle then happily reports the stale data as fresh. My fetcher retires a doc if any of these triggers fire: non-200 status, an unreasonably small Content-Length, or a Last-Modified header that has not advanced.
Dashboard signals worth watching
If you are putting an Antigravity agent into production, plot these metrics on a Crashlytics-style daily dashboard. These are what I actually watch on my own indie projects.
Median source age: median ageDays across corpus references in the last 24 hours
Stale ratio: share of references the Oracle graded stale (target: ≤ 5%)
Expired access rate: share graded expired (target: 0%; even 1% is an alert)
Top-10 TTL violators: topics most often past TTL in the past 7 days
Hash-change count: number of evidence_hash flips in the past 7 days
I keep a weekly chart of AdMob hash-change counts. Weeks where that bar spikes almost always correlate with real AdMob policy moves, and they are the weeks I read agent outputs in that topic with extra skepticism.
Operational checklist
A short checklist for putting an Antigravity agent into production with knowledge freshness in mind. I run through this for my own indie apps.
Every corpus document has topic and fetched_at populated
Topic-specific TTLs are defined in TOPIC_TTL; product-specific topics have their own values
When the Oracle returns expired, the agent's response path actually blocks the answer
System prompts always inject current time, source date, and the guardClause
The corpus refresh job runs at half the TTL interval per topic
evidence_hash history is preserved across refreshes
The dashboard above is wired up, with an alert on non-zero expired ratio
Hitting 1–4 alone cuts the "confidently wrong because outdated" failure mode dramatically. 5–7 turn corpus staleness from a reactive problem into a proactive one.
Knowledge freshness is not a glamorous feature, but it is the quiet substrate that holds long-running agents together. From a decade of running mobile apps as an indie developer, I can say that the unflashy design decisions you make at the start are exactly the ones that determine how heavy your operational load feels a year later.
Hope this saves you some of the cycles it cost me to figure out.
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.