API setup: Base URL: https://api.hydradb.com. Get your API key at app.hydradb.com.
Goal: Ingest six source types into one HydraDB database, store per-user memory profiles for personalized answers, and answer three query patterns (simple factual lookup, decision provenance, and cross-source synthesis), all through POST /query.
Prerequisites
Required knowledge: Python basics, REST APIs, environment variablesRequired tools:
- HydraDB API key
- Python 3.11 or 3.12 (
python --version) pip install hydradb-sdk
KeyError:
The TypeScript variants use
@slack/web-api, @octokit/rest, axios and openai, and read the same environment variables.
What You’ll Build
By the end of this cookbook, you’ll be able to:- Ingest Slack threads, Gmail, Confluence pages, GitHub issues, and Linear tickets into a single HydraDB database
- Answer cross-source questions like “Why did we move to a monorepo?” that span multiple tools and time periods
- Use
recency_biasandgraph_context: trueto surface the most relevant, connected context across all sources - Store per-user memory so answers are personalized to each employee’s role and project context
The Problem with Per-Tool Search
Every company has knowledge scattered across a dozen tools. The answer to “why did we move from microservices to a monorepo?” is split between a Confluence RFC, a Slack thread in #architecture, a GitHub PR discussion, and an email thread between two VPs. No single tool contains the full answer. Keyword search returns one fragment. The person who knows is usually in a meeting. This cookbook builds a company-wide search engine that works like Perplexity, but over your internal knowledge. Ask any question, get a cited answer that synthesizes across Slack, email, docs, code, and project management. The answer includes provenance: where each piece came from and when it was recorded. The critical capability that makes this possible is HydraDB’s context graph. It automatically links entities across tools: “Project X” in a Slack message is connected to “Project X” in a Confluence page, the GitHub repo namedproject-x, and the Linear project tracking it. A query about Project X surfaces all of these together, ranked by relevance and recency, in a single call.
Architecture Overview
- Ingestion Layer: Connector scripts that format source content and upload to HydraDB via
POST /context/ingestusing multipart form-data. - HydraDB: Stores all sources, automatically builds a context graph linking entities across tools, and ranks results by relevance and recency at query time.
- User Memory: Per-user profiles stored via
POST /context/ingestand retrieved viaPOST /queryto personalize answer depth and format.
Step 1: Create Database
One database for all company knowledge. Usecollection to isolate by source type: "slack", "email", "docs", "github". All created automatically on first write, no setup required. To search across sources, list them in collections on the query; a query with neither collection nor collections reads only the database’s default collection.
Step 2: Ingest Company Knowledge
All connectors use the same endpoint:POST /context/ingest. This endpoint uses multipart form-data, not JSON. database and collection are form fields alongside the file.
Important: Do not setContent-Type: application/json. Pass onlyAuthorizationin headers and let your HTTP client set the multipart boundary automatically.
Pacing: The connectors below upload one file per request with a short pause between uploads. If you batch, keep it to about 20 sources per request and wait 1 second between batches to stay under your plan’s rate limits. Always call GET /context/status before querying newly ingested content.
The upload response for all connectors looks like this (this is the envelope’s data field, result.data in the SDK):
results[0].id; you need it to verify indexing.
2.1 Slack Channels
Combine each thread (parent message + all replies) into one document. HydraDB’s context graph automatically links Slack threads that mention the same project or person to the Confluence pages and GitHub issues that discuss the same entities.2.2 Gmail / Email Threads
Email threads contain decisions that never make it to Confluence. Filter to RFC, decision, and proposal threads; these carry the highest signal density.2.3 Confluence & Notion
Confluence pages are the most structured knowledge context. Upload each page as a separate document so HydraDB can link entities in those pages to Slack threads and GitHub issues that reference the same topics.2.4 GitHub Issues & PRs
GitHub issues contain the full discussion trail around engineering decisions: requirements, objections, alternative approaches, and the final resolution. Include all comments so HydraDB can build graph links between issue discussions and Slack threads that mention the same features.Linear connector: Use the Linear GraphQL API (https://api.linear.app/graphql) with your API key. Format each issue + comments as a plain text file withSource: Linearprepended, and upload withcollection: "linear". The same multipart upload pattern applies.
Step 3: Verify Indexing
After uploading, pollGET /context/status until indexing_status is completed before running any queries. HydraDB indexes asynchronously, typically 10 to 30 seconds per file. A source is searchable at graph_creation, done at completed, and failed at errored.
Note:GET /context/statustakesids,database, andcollectionas query parameters. Pass the collection you uploaded into (slack,docs, orgithub); without it, the lookup searches the default collection and does not find the source. Pass multipleidsto check a batch in one call.
data field):
Step 4: Store User Memory Profiles
Each user gets a persistent memory profile in their own collection, which knowledge queries on the source collections do not read. Your app fetches it with atype: "memory" query (Step 6) and passes it to the LLM to personalize answers: an engineer gets more technical answers with PR citations, a product manager gets decision context and timelines, a new hire gets more background on why things are built the way they are.
data field):
Step 5: Search Interface
Three query patterns cover every internal search use case. All usePOST /query with different parameters. The routing logic is lightweight: keyword detection on the question, not ML classification.
Important: UsePOST /querywith aqueryfield for all three query patterns below. It returns retrieved chunks and graph context; your app can pass that context to an LLM when it needs a synthesized answer.
5.1 Simple Factual Lookup: “What is X?” / “How does X work?”
Use balancedrecency_bias: 0.5 for factual questions where both old and recent context matter equally. Restrict to a collection if the user is clearly asking about a specific tool; otherwise the code lists the source collections in collections. Without either, the query reads only the default collection. A collection exists only after its first write, and listing one that does not exist returns 400, so source_collections() asks HydraDB which ones exist before each search.
5.2 Decision Provenance: “Why did we decide X?” / “What led to Y?”
For provenance questions, usegraph_context: true and read graph_context.chunk_relations from the response: these are the multi-hop entity chains that trace a decision back through Slack, email, Confluence, and GitHub. Pass the chunks and relation chains to an LLM to synthesize a fully cited answer.
5.3 Cross-Source Synthesis: Complex multi-part questions
For questions that span multiple topics or time periods, usemode: "thinking" with a lower recency_bias to surface both old and recent context. HydraDB decomposes the question into sub-queries automatically and ranks results across the source collections.
Step 6: Search User Preferences
To personalize any answer, retrieve the user’s stored memory profile withtype: "memory" before calling the LLM. This is the same response structure as any /query call: an array of chunks inside the envelope’s data field.
Reading the response:/queryreturns the same structure regardless oftype: read the profile fromchunks[0].chunk_content.additional_metadatawill benullfor memory entries; that’s expected.
Step 7: Interfaces
Web API (Flask)
Slack Bot
Step 8: Incremental Sync
Run a nightly sync to keep all sources current. Upserts match on the sourceid (upsert defaults to true), not the filename. The connectors above upload files without an id, so for a re-upload to replace the earlier copy, give each file a stable id in document_metadata, such as the Slack thread ts or the Confluence page ID.
API Reference
All endpoints used in this cookbook. Base URL:https://api.hydradb.com · Header: Authorization: Bearer YOUR_API_KEY
Create Database
Upload Knowledge (form-data)
Do not use Content-Type: application/json. This is a multipart upload.
Verify Processing (query params)
Store User Memory (form-data)
Search User Preferences
Full Search: All Sources
collections fans the query out to each source collection and merges the results. List only collections you have ingested into, or the request returns 400.
Full Search: Scoped to One Source Type
Benchmarks
Tested across a 2-year company knowledge base: 12 Slack channels, 3 Gmail accounts, 4 Confluence spaces, 6 GitHub repos. 400 questions rated by employees across engineering, product, and operations.The 183% improvement on decision provenance reflects HydraDB’s context graph. Naive RAG treats a Slack thread, a Confluence page, and a GitHub issue as three isolated vectors. HydraDB understands they are three pieces of the same decision trail, entity-linked across sources, and surfaces all three together with the relationship chain that connects them.
Benchmark methodology: Figures are based on internal HydraDB testing. See research.hydradb.com/hydradb.pdf for the full methodology. Results will vary by corpus size, content quality, and query distribution.
File Structure
Requirements
Next Steps
- Run
setup.pyto create your database. - Start with one source: ingest a single Slack channel or Confluence space and verify indexing.
- Store profiles for 2 to 3 users via
memory/profiles.py. - Run
python search/qa.pywith a real question to confirm results. - Wire
search/synthesis.pyintointerfaces/slack_search.pyand deploy the Slack bot. - Schedule
sync/nightly.pyvia cron once the initial ingest is complete.
