knowledged
open source · Go · SwiftUI

A self-organizing,
Git-backed knowledge base.

Write notes in; an LLM decides where they belong, keeps the folder structure tidy, and commits everything to Git. Query content back as raw Markdown or synthesized answers — from the CLI, HTTP, or a native macOS app.

  • Go 1.22+
  • macOS 14+
  • Ollama · Anthropic · OpenAI · Jan

Why knowledged

A small set of strong defaults that turn a folder of notes into a queryable, audit-friendly knowledge base.

📂

LLM picks the path

On every write, the model reads INDEX.md, decides where the note belongs, and refactors the tree if it has drifted. You stop foldering by hand.

🌿

Git is the source of truth

Every write is one atomic commit with the job ID in the message. Crash recovery scans the log — jobs never run twice.

🔎

Raw or synthesized retrieval

Query by natural language and get an answer with sources cited, or pull the raw Markdown back. By file path, query, or tag.

🔌

Pluggable providers

Ollama, Anthropic, OpenAI (incl. Azure / OpenAI-compatible gateways), and Jan — one llm.Provider interface, four backends, zero lock-in.

🧰

Three surfaces

HTTP server, kc CLI, and a native SwiftUI macOS app. Pick the one that fits the moment — they all talk to the same backend.

🪶

Small, boring core

A single Go binary, a JSON queue file, and go-git. No database to babysit, no vector store to tune.

The Mac app

knowledged-mac is a native SwiftUI client. Post, retrieve, browse tags, edit, and replay recents — all without leaving the window.

  1. 01

    Post

    Paste content, optionally add hint and tags, then use the Title field below Tags only when you want to override the generated title.

  2. 02

    Retrieve by path

    Pull any stored file back with frontmatter, tag chips, and inline rendering.

  3. 03

    Synthesize answers

    Ask a question in plain English; the model drafts an answer and cites the source files it used.

  4. 04

    Browse tags

    Tags are derived from frontmatter and cached. Click a tag to see every note that carries it.

  5. 05

    Recents

    Twenty most recent posts, one click away from re-opening, editing, or jumping to a tag.

Install

Two steps: run the backend, then talk to it from kc, HTTP, or the Mac app.

1. Install the server and CLI

brew install wiztools/repo/knowledged

2. Start the server with the LLM provider you have

ollama pull mistral-small3.1

./knowledged \
  --repo         /path/to/knowledge-repo \
  --llm-provider ollama \
  --model        mistral-small3.1 \
  --port         9090

3. Use it

From the CLI

kc post --content "Goroutines are…" --hint golang --title "Go Goroutines"
kc get  --query   "how does Go handle concurrency?"
kc get  --path    tech/go/goroutines.md
kc tags
kc ask  --question "what is RAII?"

From the Mac app

git clone https://github.com/wiztools/knowledged-mac.git
cd knowledged-mac
./bld.sh   # builds Release and copies to /Applications

Open Settings (⌘,), point at http://localhost:9090, click Test.

Architecture

A single Go binary fronts an HTTP API. Writes funnel through one worker goroutine; reads hit the filesystem directly. Git is the durable store.

Write path

  1. POST /content validates, appends a job to .knowledged/queue.json (atomic rename), returns 202.
  2. The single worker picks the oldest queued job and flips it to processing on disk before any work begins.
  3. Organizer calls the LLM with INDEX.md, content, and any user metadata. User-supplied title/tags are preserved; missing title/tags are generated in the strict-JSON placement decision.
  4. Store makes one atomic git commit: store(<jobID>): path.

Read paths

  • GET /content?path=… — direct file read, no LLM.
  • GET /search?query=… — LLM picks ≤5 relevant paths from INDEX.md, server reads them; returns raw documents.
  • GET /search?tag=… / ?tags=a,b&match=all — derived from a cached tag index rebuilt from frontmatter on staleness; metadata by default, bodies with &mode=raw.
  • GET /answer?query=… — same relevance call as /search, then a synthesis call that answers from those files only.

Crash recovery

On startup the queue scans queue.json. processing jobs are resolved against git log: if a commit contains the job ID, the job is marked done; otherwise it is reset to queued and retried. Commits are atomic — exact-once semantics fall out of git.

Repository layout

<repo>/
├── .gitignore         # ignores /.knowledged/
├── .knowledged/
│   ├── queue.json     # live job queue
│   └── origin-push.json
├── INDEX.md           # auto-maintained
└── <topic>/<sub>/<file>.md

Concurrency model

HTTP GET handlers read the filesystem directly with no locking. POST handlers acquire the queue mutex only to persist the job and signal the worker. The worker goroutine is the single writer of git — no concurrent git writes are possible by construction.

LLM provider interface

type Provider interface {
  Complete(ctx, system, user, opts…) (string, error)
  CompleteStructured(ctx, system, user, schema, opts…) (string, error)
}

One method per provider. The only call option today is WithReasoningBudget(n), forwarded to POST /ask when a non-zero --ask-reasoning-budget is set.

HTTP API at a glance

Full reference lives in the repo README — here is the shape of it.

POST
/content

Enqueue a write with content, optional hint, title, and tags. Empty title/tags are generated by the LLM organizer.

PUT
/content

Replace an existing document's body, title, description, or tags by path.

DELETE
/content

Remove a stored document by path; commit is atomic.

GET
/content?path=…

Fetch a single document by repo-relative path.

GET
/search?query=… | tag=…

LLM-ranked retrieval by query, or tag-index lookup. Always returns an array.

GET
/answer?query=…

LLM-synthesized answer with cited sources, drawn from the most relevant documents.

GET
/jobs/{id}

Poll job status: queued · processing · done · failed.

GET
/posts/recents

Up to 20 most recent posts with tags hydrated from frontmatter.

GET
/tags

Tag inventory derived from note frontmatter.

POST
/ask

Draft a Markdown answer + suggested tags. Stores nothing.

Run it locally in under a minute.

Pick a provider, point --repo at a folder, and start posting.