Skip to main content
App sources are pre-parsed records from business applications: emails, chat messages, tickets, wiki pages, CRM objects, comments, and attachments. Use them when your connector already extracted the item’s text and structured fields. App sources are ingested through POST /context/ingest with the app_knowledge multipart field. The app-source payload is not a generic top-level content object. It uses the same app-native model as v1: kind, provider, external_id, fields, metadata, attachments, comments, and typed relations.
App sources land in the Knowledge store. Query them with POST /query, type: "knowledge" or type: "all", and query_apps: true. Use mode: "thinking" when you want app relation expansion and connected context.

1. What it is

Both paths eventually feed the same Knowledge retrieval stack, but app sources give HydraDB extra structure for app-aware recall: provider IDs, object kinds, actors, threads, parents, and explicit relations.

2. The mental model

Every app-source item becomes one HydraDB Knowledge source. The identity of the item comes from id, kind, provider, and external_id. The searchable app content lives in fields. Do not put the primary app text in a top-level content object for app-native ingestion. Top-level content is the older generic knowledge payload; app sources should put text in the correct typed field:

3. Ingest an app source

Send app_knowledge as a JSON-stringified form value. Each item should include the request-level scope fields inside the item too; if supplied, they must match the form-level database and collection.
Response:
The call returns 202 Accepted; the source is not queryable until GET /context/status reports indexing_status: "graph_creation" or "completed".
Multipart, not JSON. app_knowledge is nested JSON inside a multipart/form-data request. Stringify the object or array before sending it.

4. Incremental ingestion

Use the same endpoint for initial backfill and live updates. The important modeling choice is whether the provider event updates an existing source or creates a new source.
upsert: true replaces the existing source with the same id. Do not upsert a parent ticket/page with only a new comments[] item unless you intend to replace the whole snapshot. For live webhook events, model each new comment as its own kind: "comment" source.

5. Per-app patterns

Slack message with thread reply and attachment

A Slack thread is multiple message sources connected by thread_id, parent_id, and optional explicit relations.
For a reply, ingest a second source. fields.parent_id points to the parent message’s provider external_id; an explicit relation can point to either the parent HydraDB ID or the provider ID.

Jira ticket with linked issues

The ticket body lives in fields.description. Workflow fields belong in fields; scope/filter values like project and environment belong in metadata.

Linear ticket comment

Comments are first-class app sources. Use fields.parent_id for the parent ticket’s provider ID. Use relations[] when you need a cross-provider link or want to declare the relation explicitly.

Notion / Confluence page

A page is one knowledge_base source. Space/workspace/database values belong in metadata, not in external_id.

Gmail email with reply

Each email message is its own email source. Link replies with fields.reply_to_id and, when useful, a reply_to relation.

Salesforce opportunity linked to a support ticket

CRM records usually use kind: "custom". Use fields.parent_id for same-provider hierarchy, and relations[] for cross-app context.

6. Relations

Use relations[] to declare explicit source-to-source connections when the relationship matters for search and cannot be safely inferred from text alone.
The target can use either shape: Useful predicates include:
If you use target.external_id, include target.provider. External IDs are only unique inside a provider namespace.
For app sources, prefer the app-native relations[] shape above. relations.ids is the file/legacy forceful-relation shortcut and does not carry predicate or provider information.

7. Attachments and comments

Attachments and embedded comments[] add searchable child content connected to the app source. Use attachments[].content only when you already extracted the attachment text. HydraDB treats an attachment URL as metadata; it does not fetch arbitrary URLs from app-source payloads.
Use embedded comments[] for full backfill snapshots. For live incremental webhooks, prefer first-class kind: "comment" sources so a single new/edited/deleted comment can be handled without replacing the parent ticket or page.

8. Metadata: scoping vs display

For v2 Knowledge ingestion, metadata is the canonical filterable metadata field and additional_metadata is the canonical free-form metadata field. Legacy aliases are accepted for compatibility in some request shapes: Filterable database metadata keys must be declared in the database schema with enable_match: true. Query-time filters use top-level keys for metadata and nested additional_metadata for free-form fields:
See Scoping using metadata for the full schema and filter rules.

9. How app sources affect query

When query_apps: true, HydraDB runs an app-aware retrieval lane alongside normal semantic and lexical retrieval. It can use app-specific signals that are not available from raw text alone.

Parent and child query

Parent/child query is based on provider-scoped external IDs. When a child source has fields.parent_id, HydraDB can match that value to another source’s external_id under the same provider. At recall time, query_apps: true lets the app-aware lane find an initial source by text, exact ID, actor, provider, or kind. In thinking mode, hierarchy language such as “parent”, “children”, “epic”, “subtask”, “account”, or “deal” can trigger expansion around the matched source.

10. TLDR field reference

Top-level app source fields

email fields

message fields

ticket fields

knowledge_base fields

comment fields

custom fields

Relation fields

Attachment fields


11. Common mistakes