/research-lifecycle
Refresh local research context and the Drive grounding corpus. Triggers: stale context, R-number.
$ golems-cli skills install research-lifecycleUpdated 6 days ago
Anti-pattern: R75 says "FTS5 is 96.9% desynced" — but it's been fixed for days. Without lifecycle management, R76 starts from wrong assumptions.
Research context files live at docs.local/claude-web/projects/<project>/. After a sprint implements research findings, these files go STALE. The local corpus is the source; Google Drive is the grounding corpus Gemini reads. This skill refreshes both so the next research round starts from truth, not assumptions.
HARVEST GATE — research without a harvest path is PARKED, not done
Every research dispatch — fleet-fired OR Etan-fired in his own Gemini/NotebookLM UI (standing fire=Etan rule) — MUST carry these fields at dispatch time:
| Field | Required content |
|---|---|
| harvest_owner | Named agent/LEAD who owns pulling results back into the fleet |
| harvest_trigger | What event starts harvest (report complete, Drive export lands, cron poll, Etan says "it's done", etc.) |
| export_route | Where results land for the fleet: Drive path, docs.local/research/, collab ack, brain_store digest — adapters must name this explicitly |
Research without all three = PARKED. Do not mark done, do not brain_store conclusions, do not close the collab row until harvest completes or Etan explicitly parks it.
Applies to /gemini-research, /claude-desktop-research, and orc W5 research dispatches. The E07 integrity gate catches bad claims; this gate catches throughput — results sitting unharvested since morning.
THE LIFECYCLE
SPRINT COMPLETES (findings implemented)
│
├─ 1. NEWEST: Add sprint results as new context file
│ (what changed, benchmark numbers, PRs merged)
│
├─ 2. CONDENSED: Compress older context files
│ (files 01-50 → one condensed file)
│
├─ 3. UPDATED: Refresh description.md with current state
│ (facts first, narrative second)
│
├─ 4. ARCHIVED: Move implemented research results
│ (R-numbers whose findings are now in code)
│
└─ 5. MIRRORED: Update Drive AND NotebookLM
(Drive required; NotebookLM only when a project notebook exists)
STEP 1: NEWEST — Add Sprint Results
After a sprint that implements research findings, create a new context file:
# File: research-context/NN-sprint-results-{date}.mdFull SKILL.md source — includes LLM directives, anti-patterns, and technical instructions stripped from the Overview tab.
Anti-pattern: R75 says "FTS5 is 96.9% desynced" — but it's been fixed for days. Without lifecycle management, R76 starts from wrong assumptions.
Research context files live at docs.local/claude-web/projects/<project>/. After a sprint implements research findings, these files go STALE. The local corpus is the source; Google Drive is the grounding corpus Gemini reads. This skill refreshes both so the next research round starts from truth, not assumptions.
HARVEST GATE — research without a harvest path is PARKED, not done
Every research dispatch — fleet-fired OR Etan-fired in his own Gemini/NotebookLM UI (standing fire=Etan rule) — MUST carry these fields at dispatch time:
| Field | Required content |
|---|---|
| harvest_owner | Named agent/LEAD who owns pulling results back into the fleet |
| harvest_trigger | What event starts harvest (report complete, Drive export lands, cron poll, Etan says "it's done", etc.) |
| export_route | Where results land for the fleet: Drive path, docs.local/research/, collab ack, brain_store digest — adapters must name this explicitly |
Research without all three = PARKED. Do not mark done, do not brain_store conclusions, do not close the collab row until harvest completes or Etan explicitly parks it.
Applies to /gemini-research, /claude-desktop-research, and orc W5 research dispatches. The E07 integrity gate catches bad claims; this gate catches throughput — results sitting unharvested since morning.
THE LIFECYCLE
SPRINT COMPLETES (findings implemented)
│
├─ 1. NEWEST: Add sprint results as new context file
│ (what changed, benchmark numbers, PRs merged)
│
├─ 2. CONDENSED: Compress older context files
│ (files 01-50 → one condensed file)
│
├─ 3. UPDATED: Refresh description.md with current state
│ (facts first, narrative second)
│
├─ 4. ARCHIVED: Move implemented research results
│ (R-numbers whose findings are now in code)
│
└─ 5. MIRRORED: Update Drive AND NotebookLM
(Drive required; NotebookLM only when a project notebook exists)
STEP 1: NEWEST — Add Sprint Results
After a sprint that implements research findings, create a new context file:
# File: research-context/NN-sprint-results-{date}.md
## Sprint: {description}
- Date: {date}
- PRs merged: #{N}, #{N}, #{N}
## What Changed
- {specific change 1}: {before state} → {after state}
- {specific change 2}: {before} → {after}
## Benchmark Numbers
- {metric}: {old value} → {new value}
- {metric}: {old} → {new}
## What's Still Open
- {remaining issue 1}
- {remaining issue 2}Key: Include BEFORE and AFTER states. The researcher needs to know what was the problem AND what's the current state.
Naming: Use sequential numbers (91-, 92-, 93-...) to preserve ordering. Prefix with the topic.
STEP 2: CONDENSED — Compress Stale Context
When context files accumulate (>10 files or >50KB total), condense older ones:
BEFORE:
91-swift-python-root-cause.md (from 2 weeks ago, findings implemented)
92-brainbar-ux-current-state.md (from 1 week ago, partially stale)
93-inspiration-references.md (timeless, keep as-is)
94-search-improvement-collab.md (from yesterday, still current)
AFTER:
condensed-pre-R75.md (91 + 92 merged, updated to current state)
93-inspiration-references.md (unchanged — timeless content)
94-search-improvement-collab.md (unchanged — still current)
95-R75-sprint-results.md (NEW — what the sprint changed)
Condensation rules:
- Merge files about the SAME topic into one
- Update claims to current state (remove "FTS5 is broken" if it's fixed)
- Keep timeless content as-is (references, architecture decisions with rationale)
- Remove redundant context (if 3 files say "BrainBar is Swift", keep it in one place)
STEP 3: UPDATED — Refresh description.md
The project description file tells the researcher what the project IS. It must reflect current state.
Location: docs.local/claude-web/projects/<project>/description.md
Refresh checklist:
- Architecture claims match current code (check recent PRs)
- Stats are current (chunk count, entity count, test count)
- Open issues are actually still open (not fixed in latest sprint)
- "Known limitations" haven't been resolved
- No claims about features that are stubs (check with /never-fabricate)
Format: Facts first, narrative second. Lead with numbers, follow with explanation.
## Current State (as of {date})
- Chunks: 299,972 (FTS5: 100% synced ← was 3.1% before R75 sprint)
- Entities: 166 (0.055% coverage ← needs improvement)
- Tests: 675 passing
- MCP: BrainBar (Swift daemon), 5 working tools + 3 stubs
## Architecture
{current architecture, verified against code}STEP 4: ARCHIVED — Move Implemented Research
Research results (R-number files) whose findings are fully implemented should move to archived:
# Move completed research
mv docs.local/claude-web/projects/brainlayer/R38-knowledge-graph.md \
docs.local/claude-web/projects/archived/brainlayer/Archive criteria:
- ALL findings from the research are implemented (check PRs)
- Benchmark improvements are captured in a sprint results file
- The research is >1 sprint old (keep recent research active for reference)
DON'T archive:
- Research with partially-implemented findings (keep, mark which are done)
- Timeless architectural decisions (keep in main project)
- The LATEST research result (always keep the most recent R-number)
STEP 5: MIRRORED — Drive AND NotebookLM
The local corpus is the source to push. Drive is where Gemini grounds, so the Drive refresh is blocking; NotebookLM mirroring is conditional on a project notebook existing.
-
Prove Drive auth and account identity with real calls.
"MCP connected"is NOT evidence of Drive auth. CallauthGetStatus; continue only when the real call succeeds and returns authed. Tool discovery or a connected-tool count does not pass this gate. Then verify the active account before any upload, replacement, or deletion:# Project has a NotebookLM notebook: verify both identities. bash skills/golem-powers/_shared/research/verify-account.sh --expect research-account@example.com # No project notebook: verify Drive without requiring NotebookLM auth state. bash skills/golem-powers/_shared/research/verify-account.sh \ --expect research-account@example.com --drive-onlySave the successful JSON output in the lifecycle receipt. A call failure or account mismatch is blocking; switch profiles and rerun verification instead of reconciling the wrong Drive corpus.
-
Resolve the canonical destination. Use
/drive-usagefor the correct numbered folder and naming convention. Use/braindriveto resolve current folder IDs and the Gemini-facing corpus; do not trust stale hard-coded IDs. -
Reconcile the managed Drive corpus to local truth. Upload or replace every current local context file under the canonical project corpus, keeping local and Drive relative names identical. Track the complete lifecycle-managed file set. Delete only previously managed Drive files that are absent locally; never delete unrelated Drive documents. Unexpected duplicate managed names fail the gate.
-
Verify the refresh with a real Drive read. List/search and download/read the destination after upload. Record every local and Drive relative name,
modifiedTime, and SHA-256 content digest in a receipt. The completion command independently walks--local-root, hashes every regular file, and rejects a receipt that omits or changes any canonical local entry.DRIVE_FILESET=PASSrequires the Drive names to equal that derived inventory with no duplicates.DRIVE_FRESHNESS=PASSrequires every Drive digest to match its local source and every DrivemodifiedTimeto be at least as new. Missing or unverifiable content isFAIL. -
If the project has a NotebookLM notebook (see
/gemini-research), add updated replacement files first:source_add(notebook_id, source_type="file", file_path="updated-context.md", wait=True) -
Verify the replacements are indexed and readable, then delete the stale sources:
source_delete(source_id=stale_source, confirm=True) source_list_drive(notebook_id)Record the replacement IDs returned by
source_add, the stale source IDs, and the final indexed source IDs returned by readback.NOTEBOOKLM_FRESHNESS=PASSrequires every expected replacement ID to exist and every stale source ID to be absent; a barefresh: trueclaim does not pass. -
Update notebook instructions:
chat_configure(notebook_id, goal="custom", custom_prompt="Context files have been updated as of {date}. Previous findings about {X} are now implemented.")
Remember NP3: .py/.json/.swift/.yaml files must be renamed to .txt for NotebookLM upload.
GEMINI RESEARCH PROMPT PREFLIGHT — BLOCKING
Before emitting any Gemini research prompt, require exactly one # Grounding block. That block must contain either a Drive document referenced by name or the exact line None — web-only research. Never instruct Etan to attach or upload Drive documents; his connected Drive workspace pulls named documents itself.
Run the executable gate against the prompt file. It checks the block structure and invokes the shared no-attach gate:
PROMPT=/path/to/R{NN}-prompt.md
node skills/golem-powers/research-lifecycle/scripts/lifecycle-gate.mjs \
preflight --prompt "$PROMPT"Any non-zero result means GEMINI_PREFLIGHT=FAIL: do not emit or fire the prompt. Add the missing named-document grounding or the explicit web-only line, then rerun the checks.
LIFECYCLE COMPLETION GATE — BLOCKING
Write the verification evidence to a receipt, then run the same executable gate:
{
"driveRoute": {"canonical": true, "resolvedWith": ["/drive-usage", "/braindrive"]},
"driveAuth": {"callSucceeded": true, "authed": true},
"accountVerification": {
"callSucceeded": true,
"drive_account": "research-account@example.com",
"notebooklm_account": "research-account@example.com",
"expected": "research-account@example.com",
"match": true,
"drive_only": false
},
"localFiles": [
{"name": "01-context.md", "sha256": "<64 hex chars>", "modifiedTime": "<ISO-8601>"}
],
"driveFiles": [
{"name": "01-context.md", "sha256": "<64 hex chars>", "modifiedTime": "<ISO-8601>"}
],
"notebooklm": {
"exists": true,
"expectedReplacementIds": ["source-new"],
"indexedSourceIds": ["source-new"],
"staleSourceIds": ["source-old"]
}
}LOCAL_ROOT=docs.local/claude-web/projects/PROJECT
node skills/golem-powers/research-lifecycle/scripts/lifecycle-gate.mjs \
completion --receipt /path/to/lifecycle-receipt.json --prompt "$PROMPT" \
--local-root "$LOCAL_ROOT"The lifecycle may be marked complete only when the command exits 0 and every row passes:
| Check | PASS criterion |
|---|---|
DRIVE_ROUTE | Receipt names the canonical destination resolved through /drive-usage and /braindrive |
DRIVE_AUTH | A real authGetStatus call succeeds and returns authed |
DRIVE_ACCOUNT | verify-account.sh succeeds and records the intended active Drive identity |
LOCAL_INVENTORY | Receipt local names/digests/timestamps exactly equal the inventory derived from --local-root |
DRIVE_FILESET | Managed Drive names exactly equal the derived local inventory; no missing, extra, or duplicate managed file |
DRIVE_FRESHNESS | Every Drive SHA-256 matches local content and every Drive modifiedTime is at least as new |
NOTEBOOKLM_FRESHNESS | Explicitly not applicable, or source-ID readback proves expected replacements exist and stale sources are absent |
GEMINI_PREFLIGHT | The next Gemini prompt passes the executable grounding/no-attach preflight |
If the Drive corpus is older than the local context, the lifecycle is NOT complete. Auth failure, account mismatch, missing files, or unverifiable Drive freshness also fail the lifecycle; report the failing row instead of silently skipping it.
WHEN TO TRIGGER
| Trigger | Action |
|---|---|
| Sprint merged PRs that address research findings | Run full lifecycle (Steps 1-5) |
| Before writing a new R-number research prompt | Run Steps 2-5, then the Gemini prompt preflight |
| Nightly/project maintenance runs | Check if context files are stale (Step 3 at minimum) |
| Context file count > 10 | Run Step 2 (condense) |
| Local context changed | Run Step 5 (Drive refresh is blocking) |
| NotebookLM notebook exists | Run the NotebookLM portion of Step 5 |
STALENESS DETECTION
A context file is STALE when:
- It describes a problem that's been fixed — e.g., "FTS5 is 96.9% desynced" after PR fixing it
- Its benchmark numbers are outdated — e.g., "675 tests" when there are now 720
- Its architecture claims are wrong — e.g., "Python MCP" when it's now Swift BrainBar
- It references PRs as "open" that are merged — check via
gh pr view - It's >2 sprints old and never updated — age alone signals staleness
Quick staleness check:
# Find context files older than 7 days with no updates
find docs.local/claude-web/projects/PROJECT/research-context/ -name "*.md" -mtime +7INTEGRATION
| Skill | How Research Lifecycle Uses It |
|---|---|
| Claude/Gemini research runs | Create research results → lifecycle manages them afterward |
/drive-usage | Select the canonical Drive folder and stable artifact names |
/braindrive | Resolve current Drive corpus locations and verify Gemini-facing files |
/gemini-research | Enforce Drive grounding preflight and NotebookLM mirroring rules |
| Nightly/project maintenance | Should check research context staleness during sweeps |
/never-fabricate | Verify claims in description.md against actual code before updating |
/orc W5 | Claude Web research prompts consume these context files |
EXAMPLE: Post-R75 Lifecycle
R75 sprint fixed FTS5 sync, implemented detect_entities_in_prompt, improved search.
- NEWEST: Create
95-R75-sprint-results.mdwith: FTS5 3.1%→100%, entity detection implemented, search hybrid mode live - CONDENSED: Merge
91-swift-python-root-cause.md+92-brainbar-ux-current-state.md→condensed-pre-R75.md(update "FTS5 broken" → "FTS5 fixed in PR #198") - UPDATED: Refresh
description.md— chunk count, entity count, test count, remove "FTS5 broken" from known issues - ARCHIVED: Move
R38-knowledge-graph.md(fully implemented) toarchived/brainlayer/ - MIRRORED: Push the current local corpus to Drive, verify Drive freshness, then replace stale NLM sources
Best Pass Rate
100%
Opus 4.6
Assertions
5
3 models tested
Avg Cost / Run
$0.2848
across models
Fastest (p50)
2.5s
Haiku 4.5
Behavior Evals
Phase 2 baseline — skill quality on ClaudeBehavior Baseline
| Assertion | Opus 4.6 | Sonnet 4.6 | Haiku 4.5 | Consensus |
|---|---|---|---|---|
| completion-refused | 3/3 | |||
| drive-route-required | 3/3 | |||
| real-auth-required | 2/3 | |||
| grounding-required | 3/3 | |||
| no-attach-instruction | 2/3 |
Token Usage
Cost per Run
| Model | Input Tokens | Output Tokens | Cost / Run | Cost / 1K Runs |
|---|---|---|---|---|
| Opus 4.6 | 8,313 | 8,400 | $0.7547 | $754.70 |
| Sonnet 4.6 | 5,076 | 5,352 | $0.0955 | $95.50 |
| Haiku 4.5 | 2,606 | 2,857 | $0.0042 | $4.20 |
Response Time (p50)
Response Time (p95)
| Model | p50 | p95 | Overhead |
|---|---|---|---|
| Opus 4.6 | 4.6s | 8.6s | +88% |
| Sonnet 4.6 | 3.0s | 5.0s | +63% |
| Haiku 4.5 | 2.5s | 4.5s | +78% |
Last evaluated: 2026-03-12 · Data is generated from skill assertions (real cross-model benchmarks coming soon)
Changelog entries are derived from eval runs and skill version updates. Full cascading changelog (Phase 4D) coming soon.
Best Pass Rate
100%
Assertions
5
Models Tested
3
Evals Run
7
- +Initial release to Golems skill library
- +5 assertions across 7 eval scenarios
- +Eval fixtures included