Skip to content

Create a Knowledge Base Agent

This guide walks you through creating a Knowledge Base agent — an agent that searches an indexed set of your documents and answers with numbered citations back to the source document and page, instead of guessing.

  • Pinchy is running (see Quick Start)
  • You have mounted at least one data directory (see Mount Data Directories)
  • Local Ollama is connected under Settings → AI Provider → Ollama (Local) (see Set Up Local Ollama) — the knowledge base embeds your documents with a fixed local model served by that endpoint
  • You are logged in as an admin

Your agents can chat on any provider you like — the knowledge base always embeds locally. But the local Ollama endpoint itself has to carry two models: the embedding model the knowledge base uses, and one tool-capable chat model. Connecting Ollama (Local) validates that a chat model is there, and refuses an endpoint that only has the embedding model with No models found. Pull a compatible model first. So pull both before you connect, even if none of your agents will ever chat on this endpoint.

Before creating a Knowledge Base agent, make sure the documents you want the agent to access are mounted under /data/ in the Pinchy container. See the Mount Data Directories guide for detailed instructions.

The knowledge base turns your documents into searchable passages using a fixed embedding model, bge-m3, served by the same local Ollama endpoint you configured above. Pull it once — together with a tool-capable chat model, which the Ollama (Local) connection requires:

Terminal window
ollama pull bge-m3
ollama pull qwen2.5:7b

Any tool-capable chat model satisfies the connection check; qwen2.5:7b is the one Pinchy suggests. Pull both before you connect the endpoint: with only bge-m3 present, saving the Ollama URL is refused and the knowledge base has no embedder to reach.

If bge-m3 isn't available when you trigger indexing (see below), the reindex request fails until it's pulled.

In the Pinchy sidebar, click the + button next to "Agents" to open the agent creation form.

Choose Knowledge Base from the template options. This template gives the agent the knowledge_search tool — a search over your indexed documents that returns citable passages, not raw file access.

Give your agent a descriptive name, for example "HR Policy Assistant" or "Engineering Docs". You can also add an optional tagline like "Answers questions about company HR policies". Then click Create.

The agent is created with an auto-generated avatar and you are taken to its chat page. The Knowledge Base template pre-fills operating instructions (AGENTS.md) with cite-then-answer guidelines, but the agent doesn't know which documents to search yet — you scope that in the Permissions tab, then index those documents.

Open the agent's settings by clicking the gear icon, then select the Permissions tab.

Permissions tab with safe tools and directory picker

Under Knowledge Base, the Allowed Directories picker shows all directories found under /data/. Select the directories that contain the documents this agent should be able to search. This is the same folder scope that governs everything the agent can retrieve and cite — an agent can never search or cite a document outside its granted directories.

Click Save to apply the permissions.

Granting a directory doesn't index it automatically — an admin has to trigger indexing. Call the reindex endpoint for the agent:

Terminal window
curl -X POST -b session_cookie "https://pinchy.example.com/api/agents/<agentId>/knowledge/reindex"

This reads the agent's granted folders, extracts text from each PDF, splits it into overlapping chunks, embeds every chunk with bge-m3, and stores the result in Pinchy's own Postgres database (using pgvector) so it can be searched later.

Indexing is idempotent — unchanged files are skipped on the next run, changed files are re-indexed, and files removed from disk are dropped from the index. Re-run reindex whenever documents change — new files, edits, or deletions. There's no automatic file-watcher yet; a scheduled sweep is planned for a later phase.

The request comes back immediately with a job to watch:

{
"jobId": "6f1c2b64-6c3e-4a2f-9c19-5c1d3a1f2e77",
"status": "pending",
"pathCount": 2
}

Indexing itself runs in the background. It has to: every page has to be read, split, and turned into a vector, and on a few thousand documents that's hours of work on a CPU. Nothing about that fits inside an HTTP request, so the request queues the run and hands you its id.

One index run happens at a time, across your whole Pinchy — the index is shared, and embedding is CPU-hungry enough that two runs would only slow each other down. Trigger a second while one is going and you get a 409 naming the run that's in your way, including which agent it belongs to. That may not be the agent you asked about; watch that one instead of retrying.

Ask the same endpoint how it's going:

Terminal window
curl -b session_cookie "https://pinchy.example.com/api/agents/<agentId>/knowledge/reindex"
{
"job": {
"status": "running",
"processed": 340,
"total": 1893,
"counts": null
}
}

total is every document we found across the granted folders, counted before the first one is read — so it doesn't move once the run starts. counts fills in as the run goes, so you don't have to wait until the end to see how it's going:

processed counts whole documents, so a long one holds the number still while we work through it — a 300-page PDF can sit there for minutes. That's the run being slow, not stuck.

FieldWhat it means
indexedAdded or updated, and searchable afterwards.
skippedUnchanged since the last run, left alone.
removedGone from disk, dropped from the index.
unsearchableRead without error, but the file holds no text to search — nearly always a scanned PDF (see Scope in this release).
failedCouldn't be read or parsed at all. The run continues; if an earlier version of the file was indexed, that version stays searchable.

indexed counts documents the agent can actually reach, not documents we processed — that's why a scanned PDF lands under unsearchable instead. If either of the last two numbers is above zero, part of your corpus can't answer questions yet, and it's worth knowing which part before someone asks it something.

A status of failed is a different thing from a failed file: it means something systemic stopped the whole run — the embedding endpoint went away, or the database did — and error says what. A broken file never gets that far; it's counted and stepped over.

If Pinchy restarts mid-run, the run resumes on the next start. Nothing is lost and nothing is done twice: everything already indexed is skipped on the way back through.

Go back to the agent's chat and start asking questions. The agent calls knowledge_search behind the scenes, which runs a hybrid search — semantic (vector) and full-text — over the passages you indexed, then answers using only what it found.

Every grounded answer cites its sources inline, like [1] and [2], and ends with a Sources list mapping each number to its document path and page:

**Sources:**
- [1] /data/handbook/policies/Employee Handbook.pdf — p. 12
- [2] /data/handbook/policies/Employee Handbook.pdf — p. 14

That makes every claim in the answer traceable back to a specific document and page, even though the underlying search results aren't shown in the chat.

Sources are named by their full path, not just the filename. In a real document tree a bare filename is often impossible to act on — you can't tell which of several folders it lives in, and two folders may hold files with the same name. The path is what lets you open the document and check the claim for yourself.

The list resolves exactly the numbers the answer cites — no more and no fewer. A number with no entry would be a dead end, and an entry the answer never cited would make a single source look like several.

Citation accuracy isn't just a goal here — it's tested. Every change to the knowledge base runs against an automated test suite that checks retrieval quality (the right passages come back for a query) and citation integrity (every [N] in an answer resolves to a real, correctly-formatted source, and vice versa). A change that broke either would fail before it ships. We also track groundedness — whether an answer's claims are actually backed by what it cites — against a reference set of questions, so accuracy is measured over time, not just assumed.

If the indexed documents don't contain the answer, the agent says so instead of guessing. If only part of a question is answered by the sources, it answers what's supported and flags what's missing rather than padding the rest.

The agent answers in the language you asked in, even if the source documents are written in a different language.

Phase 1 of the knowledge base is deliberately narrow:

  • Only text-based PDFs are indexed and searchable via knowledge_search. Scanned/image-only PDFs and Office documents (.docx, etc.) are on the roadmap, not indexed today.
  • There's no clickable link from a citation into the PDF viewer yet — citations are text (document path + page), not a jump-to-passage link.
  • Indexing is a manual admin action (step 7). It runs in the background and reports progress, but you still have to ask for it — a scheduled sweep and a progress UI in the app are planned for a later phase.

Every retrieval and every reindex is recorded in the audit trail — each knowledge_search call as retrieval.query with the documents it drew on, and every reindex as two knowledge.reindex entries sharing a jobId: who asked for it, and how it turned out. Both are needed, because the run finishes long after the request that started it. The search query text itself is never stored in plaintext, only a one-way hash.

Beyond permissions, you can customize your Knowledge Base agent through its settings tabs:

  • General — Change the name, tagline, avatar, or model
  • Personality — Choose a personality preset (e.g. The Professor for a formal tone) or write custom personality instructions
  • Instructions — Edit the operating instructions that tell the agent how to cite documents and when to abstain

To add organization-specific context like team structure or terminology, go to Settings → Context. This context is applied to all shared agents, not configured per-agent.

You can update an agent's permissions at any time by returning to the Permissions tab. Add or remove directories, then re-run the reindex step so the index matches the new folder set. Changes take effect after clicking Save.

Under the hood, Pinchy uses an allow-list approach. The agent starts with no capabilities and only gets the tools an admin explicitly enables — here, knowledge_search, scoped by the same folder allowlist as everything else. For a full explanation, see Agent Permissions.