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, add an optional hint and tags, hit ⌘⏎. The organizer handles the rest.

  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. Build the server and CLI

git clone https://github.com/wiztools/knowledged.git
cd knowledged
go build -o knowledged ./cmd/knowledged
go build -o kc          ./cmd/kc

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
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, parses a strict-JSON decision, applies refactors, writes the file and updated index.
  4. Store makes one atomic git commit: store(<jobID>): path.

Read path

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

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. Returns 202 with a job_id.

PUT
/content

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

GET
/content?path=… | query=… | tag=…

Read by path, query (raw or synthesized), or tag.

GET
/jobs/{id}

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

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.