Support and documentation
How the platform works in detail: the ontology, the knowledge library, agents, governance and how to run it. This guide covers version 0.2.0, an open beta. The source, issues and releases are on GitHub.
Overview
Curltale AI keeps two kinds of knowledge apart because they are governed differently, and connects them because agents need both.
A small group of modellers and publishers owns the meaning of the data. Changes go through a draft, a review and a publish.
Editors add documents and interviews. A model drafts, another checks, and people review what is doubtful.
Nothing from a document ever enters the ontology. A topic can point at an entity, and that pointer is stored inside the collection that holds the document. If you cannot read the collection, you never see the link, and nothing in the model is left dangling.
Overview
The ontology answers "what does this data mean and how do I query it". The knowledge base answers "what do we know, and where does it say so". Both are indexed for search; neither is copied into the other.
| Layer | What it is | How it is made | Indexed as |
|---|---|---|---|
| Original text | The text of a document, with its places (page, slide, sheet). | Extracted and cut into passages that fit the embedding model. No AI needed. | Passages: vectors and words |
| Source wiki | A standalone page written from one document; every version is kept. | A writer model drafts it, a checker verifies it claim by claim against the document (with the whole text or search tools), the writer corrects it; doubtful pages wait for a person. | Every version chunked: vectors and words |
| Topic | A page by subject, merged across every document about it, following the type's template. | An analyzer decides which topics a verified wiki creates, updates or complements; the topic writer writes from the full wiki and can read other sources' wikis. | Every version chunked; the topic itself embedded with its title, aliases, summary and claims |
| Claim | One atomic fact of a topic with its exact quote. | Extracted by the analyzer; kept only if the quote is word for word in the wiki. Records the wiki version and passage. Superseded, never deleted. | Each claim embedded |
| Relationship | A typed link between topics (governs, part of, depends on…) with why they relate. | Proposed by the analyzer with the collection's relation types; new types wait for the manager. | Each link embedded with its context |
| Bridge | A topic's link to a data-model entity (about, governs, instance of, uses). | Suggested by the analyzer with a confidence; doubtful links wait for a person. | Stored in the topic's collection |
| Ontology | Entities, fields, definitions, filters, relationships, sensitivity, examples. | Drafted, reviewed and published by the data team, versioned. | Search index of the published version |
Overview
Sixteen read-only tools: six for the data and ten for the documents. On the document side, chunks are how the system finds and whole pages are what it returns. Search everywhere combines meaning (vectors) and words (full text) by reciprocal rank, so exact codes and paraphrases are both found.
| Document step | Tool | What the agent receives |
|---|---|---|
| Answer from the documents | library_context | Per collection: the full Markdown of the best topics with the section that matched (sources cited as [s1], [s2]... with one legend), the graph of linked topics, typed relationships that match the question, answerable and the size in tokens. |
| Discover | library_search | Titles, summaries and the best matching chunk, without page bodies. |
| Prove | library_topic_claims, library_topic_sources | Each claim with its quote, source, wiki version and passage; the documents behind a topic and whether their wiki is still current. |
| Explore | library_topic, library_traverse | One page with its links and sources; the graph from one or more topics. |
| Drill down | library_source_search, library_source | The verified source wikis: searched across the collection, read whole, around a passage or searched inside; the original text on request. |
| Data step | Tool | What the agent receives |
|---|---|---|
| Know your access | get_access | Who the caller is, which sensitivity classes it may see, whether it may query data, and the SQL dialect. Whatever is not granted is absent from every answer. |
| Find in the model | search | The best matching entities, fields, calculated fields, filters, relationships and query examples for words or exact codes. |
| Look up | describe | Anything by name: an entity with its fields, allowed values, filters, checks and examples, a field, a calculated field or filter, or a word only the documents know, with the related topics. |
| Connect | join_path | The best path between two entities with exact join conditions, how far each link can be trusted, an all-confirmed alternative and fan-out warnings; or every entity directly linked. |
| Plan | plan_query | Everything for one statement: tables, the useful columns with meaning and allowed values, the named filters the question matches, a runnable skeleton without fan-out, and the topics that concern these entities. |
| Run | query_data | Rows of one read-only statement, after it is parsed, checked against the caller's entitlements and rebuilt; with notes on truncation, masked columns and ambiguous matches. |
Only what is served is searched: the approved version of a source wiki and the published version of an active topic. A held change is invisible to agents until a person approves it. Every result names its collection and carries its usage tag.
Ontology
Only the structured meaning of your data. Everything an agent or a person needs to build a correct query is one of these.
| Concept | What it is |
|---|---|
| Entities | The business things: a customer, an order, a contract. Each has a business name, domain, kind (master, reference, transaction, fact...), a definition, the table that holds it, its keys, synonyms and the things it is often confused with, and example questions. |
| Fields | Columns, and calculated fields that are computed from the data. Each has a meaning, a type, a role, allowed values with labels, a sensitivity class, an agent-access level and a review status that tells agents how settled the definition is. |
| Relationships | How entities connect: the verb, the exact join, the cardinality, and how far the link can be trusted (confirmed, optional or unreliable). Join planning prefers reliable links and warns when a path would fan out. |
| Filters | Words turned into conditions. Open order is closed_at IS NULL, with synonyms and a status that says whether the team agreed it. Agents receive filters pre-filled instead of guessing values. |
| Checks | Data-quality rules in plain words, optionally with SQL that counts violations. The model check runs them. |
| Query examples | Worked queries with parameters. Each is run on real rows by the model check, and agents get the ones that apply to their question as patterns. |
| Custom properties | Anything else you track, such as an owner, a source system or a ticket number. It is kept, shown, searchable and given to agents. |
SQL in the model is written once in PostgreSQL syntax and translated for whichever database is connected.

Ontology
The model is versioned like code. Agents only ever see the published version.
An optional four-eyes rule means whoever changed a draft cannot publish it. After a publish, the instructions agents receive are rebuilt and every tool reads the new version.
Ontology
A template with a sheet per concept, required columns marked, dropdowns for closed lists. The file is checked before anything is created, with every problem reported by sheet, row and column. Any extra column becomes a custom property. Export and re-import lose nothing.
PostgreSQL, MySQL, MariaDB, ClickHouse, SQLite and DuckDB, read-only, with timeouts and row limits. Read the structure and generate a first draft: entities from tables, fields from columns, relationships from keys, and sensitivity guessed from column names on the safe side.
Everything generated is marked needs review. It is a starting point to which your team adds meaning, filters and calculated fields.
Ontology
Every entity, field, relationship, filter, check and example is a chunk of text. Three rankings are merged: vector similarity, keyword search and exact-code matching. The embedding model runs inside the container, so no key is needed.
Do the columns exist, do the joins hold, do the quality rules pass, do the examples return rows? Every result carries the SQL that produced it and shows counts and statuses, never values.
No data yet? Build a demo database generated from your published model, with keys, links and allowed values respected, to try everything before connecting the real one.
Knowledge
A collection is the unit of isolation. Its documents, passages, topics, statements, links, vocabulary and jobs belong to it alone, and nothing is ever combined across collections.
Public may be shared with customers. Internal is for the agent's own understanding and must not be quoted. The tag travels with every result, every tool description and the server instructions. It is guidance, and the grants below decide access.
Per user or per API token. Read searches and reads. Write ingests, edits and approves. Manage grants access, changes settings and exports. Writing also needs the editor role, and tokens only ever read.
A collection you hold nothing on does not exist for you. Admins see that it exists so they can fix access, and can read content only after a logged self-grant.
Turn it off and the collection is still stored and searchable by words and meaning, with the embedding done locally, but no model ever sees it.
Turn it off and Alfred and MCP clients are kept away from the collection entirely, whatever the grants say.

Knowledge
PDF, Word, PowerPoint, Excel, CSV, HTML, Markdown, text, JSON, XML and images. Scanned pages are read by a vision model. The same bytes cannot be added twice to a collection.
Public addresses only, with the resolved address pinned, every redirect re-checked and private networks refused. Refresh captures again, and only changed content is read again. An optional isolated browser handles pages built by JavaScript.
When the knowledge is not written down, an interviewer model asks questions one at a time and keeps the facts it hears. See Interviews.
Places are kept so passages can be cited: page 3, slide 2, sheet "Costs". Web pages lose their menus, footers and cookie banners, and spreadsheets are read row by row with their column names.
Knowledge
Each source goes through the same pipeline. Models see only the one document of the job, with tools filtered to its collection.
A different model can do each job (writer, checker, analyzer, topic writer, interviewer, image reader), or one model can do all of them. If the topic writer fails, a plain page is built from the candidate so nothing is lost. A claim found again in another source attaches to the existing one, so numbers stay stable. A topic a source no longer mentions gets a surgical rewrite that removes only what no remaining source supports.

Knowledge
Most updates publish at once. What is doubtful waits in the collection's queue, and agents see nothing of it until a person decides.
| Waiting item | What you do |
|---|---|
| Contradiction: new evidence disagrees with a statement on the page | See the published page beside the page as it would become, with the quotes. Approve (the old statement is superseded), reject, or leave it. |
| Probable duplicate: a new topic very close to an existing one | Approve, reject, or merge it into the existing topic. |
| Source page with objections | Approve as it is, or have it written again. |
| Suggested model link | Accept or reject in place. |
| Unreadable document | Retry or remove. |
| Vocabulary proposal | The collection's manager accepts or rejects. |
The queue belongs to the collection, not to a person, so whoever is free picks it up. Readers do not see it, because held changes are unpublished. Two held changes on one topic never build on each other's unapproved work.


Knowledge
A topic is a page by subject, not by document. Two documents about the same product end up on one page.
A claim is kept only if its quote appears word for word in the verified source wiki, and it records the wiki version and passage it came from. Pages cite their sources as chips, and the evidence panel shows each claim with its quote and the wiki passage.
Every collection starts from a rich starter ontology: topic types with a meaning and a page template, relation types such as governs, depends on, part of, replaces, with their inverse. When nothing fits, the analyzer proposes a new kind and the manager decides.
Original text, every source wiki version, every topic version, claims, topic identities and typed relationships are chunked or embedded and searched by meaning and by words together.
A question is matched against chunks of the published topic pages, and the agent receives the whole page with the matched passage and the related topics, so it reads the full argument, not a fragment.


Knowledge
A topic can say what it is about. The Pro plan is a kind of Product. The refund policy governs Invoice.

Knowledge
Some of the most useful knowledge has never been written down. The interviewer captures it the way a curious colleague would.
Knowledge
Merge a topic into another. Statements are renumbered, titles become aliases, links and sources move, and the old address redirects.
Remove or re-read a source and what only it supported is withdrawn. A job asks the writer to soften what rested on it and keeps the rest, citations included.
Held changes, failed sources, isolated topics, links to archived topics, quotes that vanished after an edit, and pairs of topics that may be one subject.
A collection exports as one zip: the original files, every source page with its versions and checks, each topic as Markdown with its statements and evidence as JSON, the links, the vocabulary and a manifest. It is a handover format, and nothing from any other collection can be in it.
Agents
One endpoint for any MCP client that speaks streamable HTTP with a bearer token. Ten read-only tools, and the server explains itself, so there is nothing to prompt-engineer.
claude mcp add --transport http curltale https://<your-host>/mcp \
--header "Authorization: Bearer <token>"
| Tool | What it does |
|---|---|
get_access | Who the caller is, what it may see, whether it may query data, and the SQL dialect. |
search | Entities, fields, filters, relationships and examples for words or exact codes. |
describe | Anything by name, with its fields, values, filters, links, examples and related documents. Also finds a word only the documents know. |
join_path | The best path between two entities with exact joins, reliability, an all-confirmed alternative and fan-out warnings. |
plan_query | Everything for one SQL statement: tables, columns, pre-filled filters, a runnable skeleton without fan-out, and the relevant topics. |
query_data | Runs one read-only statement under the caller's entitlements, with notes before the rows. |
library_context | Start here: full topic pages for a question with the matched passage, related topics and relationships, and whether the documents answer at all. |
library_search | Lightweight topic discovery: titles, summaries and the best matching passage. |
library_topic | One full topic page with its links, sources and model entities. |
library_topic_claims | Every claim of a topic with its exact quote, source and source wiki version. |
library_topic_sources | The documents behind a topic and the wiki version used. |
library_traverse | The topic graph from one or more topics, up to three steps. |
library_source_search | Search the verified source wikis. |
library_source | Read a source wiki whole, around a passage or searched inside; or the original text. |
library_vocabulary | Topic types and relation types. |
library_collections | The collections the caller may read, with their usage tags. |
The ten library_ tools only appear to a token that holds a grant on at least one collection. A token without grants sees six tools and no trace of the library.
Instructions that teach it to read a question: understand the words through the ontology, route to the documents, the data or both, answer with evidence. Tool descriptions that stand on their own for clients that hide the instructions, a next hint in every result, a guide resource, four prompts (explore the model, a data question, a documents question, a question that needs both) and read-only annotations so clients can approve the tools automatically.
A data question uses plan_query and query_data. A question about what the business says goes to library_context. When both apply, plan_query hands over the relevant topics.
Agents
The built-in assistant. It uses the same tools and the same rules as an external agent, under the signed-in person's own access.
library_context, which returns whole topic pages, and goes to claims, related topics or the verified source wikis only for a detail a page lacks. If the documents do not cover a question, it says so.
Governance
| Class | Typically | Who sees it |
|---|---|---|
| internal | the structure and meaning of the model | everyone |
| confidential | financial and other business-sensitive values | holders of the class |
| personal | names, emails, phone numbers | holders of the class; others get hashes where the field is masked |
| restricted | identity numbers, credentials | only holders of the restricted entitlement, granted explicitly and logged |
Masked values come back as a stable hash, so they can still be counted, grouped and joined but never filtered or compared. None means never readable and left out of search entirely.
Every query is parsed, every column traced to its real table through aliases and subqueries, and checked against the caller's rights. The statement that runs is rebuilt from the checked tree, never the text that was sent.
The database account is read-only with timeouts and row limits, and a connector can forbid agents from reading rows at all while still allowing them to plan.
Governance
Governance
| Role | Can |
|---|---|
| viewer | Explore, search, browse data, use Alfred and the SQL console under their entitlements. |
| modeller | Also edit drafts, upload Excel, re-run the model check. |
| publisher | Also publish and discard drafts. |
| admin | Also manage users, tokens, connectors, settings and the activity log. |
| editor | A separate role for documents. With a write grant it allows ingesting, editing and approving. |
Passwords are stored with scrypt and need at least 12 characters. Sign-in locks after repeated failures, a password set by an admin is temporary, and changing your password ends your other sessions. Every assistant conversation and agent session is recorded step by step, with tokens, cost, timing and the response returned.
Run it
Docker with Compose v2 and about 2 GB of memory. Two containers to start: the app and PostgreSQL with pgvector.
git clone https://github.com/curltale/curltale.git && cd curltale
cp docker-compose.example.yml docker-compose.yml
cp .env.example .env # fill in the required values
docker compose up -d # open http://localhost:8080
.env.Run it
Everything beyond the core is an overlay file you add with -f. They combine freely.
| Service | Adds | Use it when |
|---|---|---|
Workerdocker-compose.worker.yml | A container for the library's background work. The web app stops doing it. | You have many or large documents, or several people uploading at once. Scale with --scale worker=3. |
Browser servicedocker-compose.fetcher.yml | An isolated Chromium for pages built by JavaScript. No database, no files, no app secrets, and every request it makes goes through the address guard. | You capture single-page sites. Plain pages work without it. |
S3 bucketdocker-compose.storage.yml | A self-hosted S3-compatible store plus a one-shot job that creates the bucket. | You want original files outside the data folder. Any S3 service works the same way without this file. |
Demo databasesdocker-compose.demo.yml | PostgreSQL, MariaDB and ClickHouse with the same synthetic data. | You want to try the connectors. |
docker compose -f docker-compose.yml \
-f docker-compose.worker.yml -f docker-compose.fetcher.yml -f docker-compose.storage.yml \
up -d --build
Choose the storage before the first upload. Files already stored are not moved when the driver changes.
Run it
OpenRouter, a LiteLLM gateway, Ollama, vLLM. A model per library job if you like. Reasoning and temperature are settings.
They run inside the container with no key. Choose a remote model and any vector size pgvector stores.
Tabs for General, AI, Ontology and data, Library, Web capture, Storage, Limits, Connectors and Maintenance. Changes apply with no restart, are audited, and win over .env. Teams that prefer files can lock the page.
Behind a proxy, the app reads the real client address from a forwarded header only when the request comes from a trusted proxy. It also sets its own security headers and rate limits, so it is safe with no proxy in front.
Run it
-f files. Schema changes apply at startup and missing embeddings fill in the background.Under the hood
One PostgreSQL database with pgvector holds the model, its versions, the library, the search indexes and the app's own data. No separate graph or vector store is needed at this scale.
Under the hood
What it does not do yet, stated plainly.