KiwiFS: a markdown filesystem that agents can read and write
Markdown filesystem for agents and teams.
At a glance
- What is it?
- KiwiFS wraps a folder of markdown files in a searchable, versioned server with MCP, REST, NFS, S3, WebDAV and FUSE front ends. It is a good fit when agents and humans edit the same notes; it is the wrong tool if you want a plain static site or cannot accept a BSL 1.1 licence.
- Who is it for?
- Adopt KiwiFS if your agents need to write to a knowledge base that humans also edit, and you are comfortable running a single Go binary plus, optionally, a pgvector sidecar. Do not adopt it if you only need static markdown rendering, or if BSL 1.1 licensing is a blocker for your organisation.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What KiwiFS adds to a folder of markdown files
A directory of .md files is easy to write and hard to query. There is no full-text index, no record of who changed what, and no way for an agent to ask a structured question such as which pages lack an owner field. KiwiFS sits in front of that directory and turns it into a server. The README states the design position plainly: files are the source of truth, and everything else is a derivative index you can rebuild.
The audience is narrow and specific. On one side are AI agents that need to read and write durable notes rather than ephemeral sandbox state. On the other are teams that already keep markdown in a wiki or an Obsidian vault and want programmatic access without exporting everything into a database. The README frames the alternatives it rejects: databases agents cannot read, read-only retrieval layers agents cannot write to, and proprietary SaaS you cannot self-host. KiwiFS is aimed at people who find all three unsatisfying.
Files on disk, indexes beside them
The architecture diagram in the README shows two clients, an agent working through cat, grep and echo, and a human working through a web UI with wiki links and a graph view. Both sides meet at markdown files on disk. Below that line sit three derived services: git versioning for an audit trail, an FTS5 plus vector search index, and SSE events for live updates.
That layout has a practical consequence. Because the file tree is authoritative, you can inspect and edit it with ordinary tools, and you can delete the indexes and rebuild them. The README describes every write as an atomic commit, which is what makes blame, diff and point-in-time restore possible. Search combines BM25 through SQLite FTS5 with a pluggable vector store; the README lists OpenAI, Ollama, ONNX and Cohere as embedder options, and sqlite-vec, Qdrant, pgvector and Pinecone on the storage side.
Six access protocols (REST, MCP, NFS, S3, WebDAV, FUSE) all flow through one storage layer, so the choice of protocol does not change what the data looks like. The web UI is embedded in the binary through go:embed, which is why the README can claim one binary and zero config.
Installing KiwiFS and writing your first page
The README gives three install paths. Homebrew is the shortest on macOS and Linux, and the install script is the fallback. Both are shown in the project's own quickstart.
brew install kiwifs/tap/kiwifs
# or: curl -fsSL https://raw.githubusercontent.com/kiwifs/kiwifs/main/install.sh | shInitialize a knowledge root and start the server. The README's example uses the knowledge template and the default port.
kiwifs init --template knowledge --root ./knowledge
kiwifs serve --root ./knowledge
# REST API on :3333, web UI at http://localhost:3333After this the web UI should be reachable at http://localhost:3333. The Docker route skips the CLI install entirely:
docker run -p 3333:3333 -v ./knowledge:/data ameliaanhlam/kiwifsTo write from an agent, the README uses a PUT request with an X-Actor header. The header value becomes the git commit author.
curl -X PUT 'localhost:3333/api/kiwi/file?path=pages/auth.md' \
-H "X-Actor: my-agent" \
-d "# Authentication\n\nOAuth2 + JWT..."On REST, the scoped-token and OIDC middleware overwrite X-Actor with the authenticated identity, so a client cannot forge it. That is the detail worth understanding before you expose the port.
The WebDAV identity gap
KiwiFS has a real trust asymmetry between its protocols, and the README documents it rather than hiding it. On REST, the fallback actor when X-Actor is missing is anonymous, and authentication middleware replaces any client-supplied value. On WebDAV, authentication is a single shared API key that carries no identity at all, so KiwiFS takes X-Actor at face value. Anyone holding that key can attribute a write to any actor.
The README's own recommendation is to terminate authentication at a gateway that sets X-Actor itself and strips any client-supplied value before forwarding. If you are evaluating KiwiFS for a multi-user deployment, that sentence should decide whether WebDAV is exposed at all. The header is normalized before it reaches git, with control characters stripped and the value capped at 256 characters, but normalization is not authentication.
This is not a flaw unique to KiwiFS. It is the shape of WebDAV when you bolt identity onto a protocol that was not designed for it. The point is that the REST path and the WebDAV path do not offer the same guarantees, and the documentation says so.
Where KiwiFS is the wrong tool
If your markdown is published, not edited, KiwiFS adds a server you do not need. A static site generator reads the same files and produces output with no runtime, no database and no auth surface. The README's own framing assumes writes are the interesting operation.
If you want a hosted product with a support contract, this is not that. Self-hosting is the premise, and the docker-compose.yml shows what that means in practice: a KiwiFS service, an optional pgvector sidecar, and a volume you point at a local folder. The compose file also notes that the image should be built from the repo Dockerfile so the embedded UI stays in sync with the backend, which is a build step rather than a pull.
The licence is the other boundary. The repository's licence identifier is NOASSERTION while the README badge says BSL 1.1. Those two signals disagree, and the README does not explain the terms. If your organisation has rules about source-available licences, resolve that discrepancy before you build anything on top of it.
How KiwiFS differs from a static knowledge base
The closest comparison is a plain markdown vault plus a static site generator, which is what many teams use today. That stack gives you files and rendering. It does not give you a write API, a commit per edit, or a query language over frontmatter.
KiwiFS adds all three. Writes go through REST, MCP, NFS, S3, WebDAV or FUSE and land as git commits. DQL runs SQL-like queries over frontmatter with TABLE, LIST, COUNT, WHERE, SORT and GROUP BY. Schema validation enforces JSON Schema on writes, which is the mechanism that keeps agent-generated pages structurally consistent. The README also lists 19 data importers covering Postgres, MySQL, MongoDB, Notion, CSV and Obsidian, so migration from an existing vault is a supported path rather than a rewrite.
The trade is operational weight. A static generator is a build command. KiwiFS is a long-running process with a search index, a git repository per space, and optional vector infrastructure. You are buying query and write capability, and paying for it in surface area.
Maintenance, releases and upgrade cost
The repository is not archived. The last push was on 2026-08-20, and the most recent release on that date was v0.19.62, following v0.19.61 on 2026-08-18 and v0.19.60 on 2026-08-18. The patch-level versioning and the frequency of releases suggest steady incremental work rather than long-stable milestones, and the README lists a ROADMAP document, which implies features are still arriving.
For upgrades, the practical question is where state lives. Files and git history are on disk under the root you pass to --root. Search indexes are derivatives the README says you can rebuild. If that holds for the vector store as well, an upgrade means replacing the binary and reindexing rather than migrating data. The repository includes release-please-config.json and .release-please-manifest.json, so releases are automated from conventional commits, which is a reasonable signal about how changes are tracked.
The embedded UI is the one upgrade detail that catches people. Because the frontend is compiled into the binary through go:embed, a binary built without a fresh ui/dist will serve stale assets. The Makefile separates build (which runs the UI build first) from go-build (which reuses the existing ui/dist), so the distinction is deliberate and worth respecting in your own pipeline.
Editorial conclusion
Adopt KiwiFS if your agents need to write to a knowledge base that humans also edit, and you are comfortable running a single Go binary plus, optionally, a pgvector sidecar. Do not adopt it if you only need static markdown rendering, or if BSL 1.1 licensing is a blocker for your organisation. Before committing, verify the licence terms against your use case, check that the vector provider you want is listed in the [search.vector.embedder] section of .kiwi/config.toml, and confirm whether you need WebDAV at all, because its shared API key carries no identity and lets any key holder attribute writes to an arbitrary actor.
Frequently asked questions
How do I install KiwiFS?
The README lists Homebrew as brew install kiwifs/tap/kiwifs, an install script at https://raw.githubusercontent.com/kiwifs/kiwifs/main/install.sh, go install github.com/kiwifs/kiwifs@latest, and a Docker image at ameliaanhlam/kiwifs. The Docker form maps port 3333 and mounts a local folder at /data.
Does KiwiFS require an external database?
No. The docker-compose.yml marks the pgvector service as an optional sidecar that is only used when [search.vector] is enabled in .kiwi/config.toml with provider = "pgvector", and notes that leaving the related environment variables unset runs the server without semantic search.
Which protocols can agents use to talk to KiwiFS?
The README lists six: REST, MCP, NFS, S3, WebDAV and FUSE, all flowing through one storage layer. The default serve command exposes the REST API and the web UI on port 3333; the docker-compose.yml comments show NFS on 2049, S3 on 3334 and WebDAV on 3335 as opt-in flags.
How does KiwiFS record who wrote a page?
Writes take the actor from the X-Actor request header and use it as the git commit author. On REST, the scoped-token and OIDC middleware overwrite the header with the authenticated identity; on WebDAV, the README states that a shared API key carries no identity and X-Actor is taken at face value.
What is the KiwiFS licence?
The repository's licence identifier is NOASSERTION, while the README badge reads BSL 1.1. The README does not explain the terms, so the two signals should be reconciled against the LICENSE file before adoption.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/kiwifs-kiwifs)