In a previous post, we examined how GTM Telescope could be used by a single SE to accelerate onboarding. A customer asks a hard question mid-call, and the answer, with its source, is on screen before the silence gets awkward. It ran on a laptop, searched a folder of docs, and kept everything local.
That works for one person. Now make it work for a team of 25.
Each person has their own folder, and each folder has a slightly different version of the battlecard. One SE’s notes say SCIM is on the roadmap. The product spec, updated last month, says it’s generally available. Two SEs give the same customer two different answers in the same week. Static content like battlecards goes stale within about 90 days, and nobody’s index knows.
At team scale, speed is solved. Accuracy becomes the hard part. A wrong answer delivered in 200 milliseconds is still…well, wrong. For this next stage, we’ll look at how we can scale GTM Telescope to make the shared answer the right one.
What Stage 1 Proved
Stage 1 was a proof of value: local hybrid search over an SE’s own documents, cited snippets for live calls, and grounded drafts for follow-ups. It showed that SEs will actually use retrieval in the middle of a conversation, and that it shortens ramp time.
It also showed the limits of a single laptop setup:
- No shared truth. Every rep curates their own corpus, so answers drift apart.
- No sense of authority. A PMM-verified battlecard and a rep’s hallway note rank the same if the words match.
- No sense of time. Last year’s pricing deck stays in the index until someone remembers to delete it.
- No way in for the team. It’s a terminal tool, and most of the GTM org lives in Slack.
Stage 2 addresses all four. Its goal is accuracy: one shared, current, owned body of knowledge, available where the team already works.
The Architecture Shift: From Laptop to Cloud
Stage 2 replaces file-system lookups with event-driven ingestion, a shared Postgres database with pgvector, and Mistral models served through the Mistral API or a private VPC endpoint. The stack is deliberately small: one familiar database and one model vendor, so the thing being proven is the workflow, not a new set of tools.
Real-World Note: I chose Mistral for this project because they provide a suite of different models covering different areas of my use case (not just a generative LLM).
| Component | Stage 1: Local Laptop RAG | Stage 2: Cloud Architecture |
|---|---|---|
| Exact SKU and term search | ripgrep scanning local files | Postgres full-text search |
| Semantic search | Local Jina model | mistral-embed via API or VPC endpoint |
| Storage and scale | Local Markdown and disk cache | Managed Postgres with pgvector |
| Stale content handling | Manual file deletion | Event-driven change capture with versioned retirement |
| Document authority | Flat ranking | Tiered weighting (1.0 vs 0.6) |
| Generation engine | Remote API call to Mistral Large | Dual path: Ministral 8B for live calls, Mistral Large for deal strategy |
| Surfaces | CLI on a laptop | Slack, web, and a live-call assistant |
| Concurrency | Single user | Horizontally scaled API serving hundreds of concurrent reps |
Why Postgres and pgvector, not a dedicated vector database? Postgres already does the three jobs this stage needs, in a single solution. We can use pgvector for storage and searches. Built-in full-text search handles exact terms. And the metadata, permissions and transactions that decide what is allowed to be retrieved live right next to the vectors.

Every source change and every question pass through the same governed Postgres index, so every surface (e.g. CLI or Slack) gets the same answer.
Event-Driven Ingestion
In Stage 1, the index was whatever happened to be in a folder. In Stage 2, the index follows the sources.
- Webhooks, not folders. Google Drive, Notion, Confluence, Slack and Gong send change events to lightweight serverless workers on Cloud Run or AWS Lambda.
- Chunking that keeps structure. Documents are split into 400 to 600 token chunks that preserve their Markdown heading hierarchy, so a chunk knows it belongs to “Security › Encryption at rest.”
- Strict metadata on every chunk. Authority, ownership, timing and status travel with the text:
{
"doc_id": "notion_page_89234",
"chunk_id": "notion_page_89234#chunk3",
"version": 7,
"authority_tier": 1,
"authority_weight": 1.0,
"owner": "product marketing",
"business_unit": "enterprise-na",
"category": "pricing_matrix",
"created_at": 1729180800,
"updated_at": 1729180805,
"last_verified_at": 1729180810,
"is_active": true
}
Write the new version first, then retire the old one. When a source changes, the worker embeds the new version and writes its chunks before touching anything else. Then, in a single database transaction, it marks the new version active and the old version inactive. A cleanup job hard-deletes the retired rows afterwards. Because Postgres commits that swap atomically, there is never a moment when the index holds no pricing, or two prices. When a source is deleted outright, its chunks are marked inactive immediately.
The Data Layer
Each chunk is one row that carries both of the representations Stage 1 used, now in a single table:
- Meaning, for natural questions. Every chunk carries a
mistral-embedvector, a numerical fingerprint of what the text says so search stays fast as the knowledge base grows to millions of chunks. - Exact terms, so specifics never get lost. The same row carries a keyword index built for precision. SKU names, competitor feature codes and internal acronyms are kept exactly as written, so a question about a specific product code returns the document that names it, not one that’s merely similar.
- Hard pre-filters. Every query starts with
WHERE is_activeand a business-unit check. Retired content is never even a candidate. - Business-unit isolation. A
business_unitcolumn, enforced with Postgres row-level security, keeps Enterprise and Commercial, or NA and EMEA, separate inside one database. Company-wide collateral such as security documentation is taggedglobaland visible to everyone.
The Retrieval Cascade
Instead of comparing the query against every chunk, retrieval narrows in stages:
- Hybrid retrieval (top 50). The query is embedded with
mistral-embedand run against the vector index and the keyword index in parallel. The two ranked lists are merged with weighted reciprocal rank fusion, roughly 0.7 for semantic and 0.3 for keyword. Fusing by rank balances intent against exact matches without comparing raw scores that live on different scales. - Authority and freshness rescoring. A PMM-verified battlecard (authority 1.0), for example, outranks unverified Slack tips (0.6). Documents older than 90 days gradually down-rank unless an owner recertifies them, which resets the clock.
- Cross-encoder reranking. A lightweight reranker reads the query and each remaining candidate together, and picks the 3 to 5 best chunks for the model’s context window. However, the reranker can’t supersede the authority of a source.
Two Paths for Generation
- Live calls: Ministral 8B or Mistral NeMo 12B. This is “Edge AI” with models that are small enough to run locally on your laptop in under 200 milliseconds (to first token), generating a response while your customer is still talking.
- Deal strategy and RFPs: Mistral Large. Using the Mistral API or a private VPC endpoint, for multi-product answers and contract exception reviews where depth matters more than speed.
Both paths require every claim to reference a retrieved chunk, and to say so when a question has no documented backing. It’s the same grounding rule as Stage 1, now with authority and dates attached to every citation. We keep mistral-embed handling both sides of the pipeline: embedding documents at ingestion and embedding questions at query time.
Meeting the GTM Team in Slack
For most GTM teams, Slack is the one tool everyone already has open. Stage 2 uses it twice: as a place to ask questions, and as a source of knowledge.
Slack as a Surface
- Just ask questions where you already work (e.g.
/telescope do we support SCIM?) - Limit questions to private conversation or shared channels
- Every answer shows its pedigree, for example Verified · PMM battlecard · updated 12 days ago
- Give feedback in real-time with (emoji) reactions helping the the data owner and the team
Slack covers async questions and the quick query before a call. During the call itself, the same API serves a web view or a live-call assistant running the fast model path.
Slack as a Source
- Selected public channels are ingested at authority tier 2 (weight 0.6). A Slack tip can surface, but it can’t outrank verified collateral.
- When a Slack answer proves right, its owner can turn it into an approved answer card at tier 1. Conversations become official knowledge, with a name attached.
- Only public channels are ingested by default preserving privacy.
Measuring Accuracy, Not Asserting It
With the local setup of Stage 1, the end user (SE) currated the sources so there was a level of assumption that they were accurate. While we originally optimized for speed, now we are optimizing for accuracy. This can be driven across the team as well through: real customer questions, each paired with the document that correctly answers it. Every change to chunking, weights or models runs against that set before it ships to ensure a high accuracy rate. Three numbers matter most:
- Recall@3: how often the right source lands in the top three results.
- Citation accuracy: how often the cited source actually supports the claim it’s attached to.
- Stale-answer rate: how often the top source was out of date or already superseded.
The evaluation set measures accuracy in the lab. Slack measures it in the field. Every thumbs-down with a correction goes to the owner of the source behind it. Repeated misses on the same topic point to missing content, not just weak retrieval, and that tells the team exactly what to write next.
The next time two SEs get the same tough question in the same week, they’ll give the same answer, and it will be the right one.