Kanwas ships a compose file that publishes Postgres with the password kanwas
Kanwas — Shared context board for teams and agents
At a glance
- What is it?
- A self-hostable shared context board where a team and a coding agent work over the same markdown. The setup is a single compose profile, and the defaults it starts with are meant for a laptop rather than a server.
- Who is it for?
- Kanwas fits a team that wants one board where an agent's tool calls sit in the same timeline as human decisions, and that wants the documents in git rather than in a vendor's database. Before you run it anywhere but your own machine, change three values: the Postgres password, the empty Redis password, and the API_SECRET placeholder, all of which the compose and env templates ship as readable defaults on published ports.
- 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 53 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 4, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Postgres starts with kanwas three times over
The database service in the compose file is a stock postgres:18-alpine image with three environment values set to the same word. POSTGRES_USER is kanwas, POSTGRES_PASSWORD is kanwas, and POSTGRES_DB is kanwas, with a healthcheck that runs `pg_isready -U kanwas` every ten seconds. The port mapping publishes 5432 to the host, and a named volume, kanwas_postgres_data, holds the data directory across restarts. A read-only mount of ./dev/postgres-init goes in as the image's entrypoint init directory, so anything in that folder runs the first time the database initialises. Nothing here is unusual for a development stack, and nothing here is safe to leave on a machine that other people can reach.
Redis is published with no password and no auth configured
The second data service is redis:8-alpine on 6379, published to the host the same way Postgres is, with a healthcheck of `redis-cli ping` and five retries at five second timeouts. The interesting part is the absence of configuration rather than its presence: there is no requirepass in the service, and the REDIS_PASSWORD entry in the env template is an empty assignment rather than a placeholder you are meant to replace. So a default run leaves a port-forwarded Redis with no credential at all. It is also worth noticing how the backend waits for its dependencies: both depends_on entries are conditioned on service_healthy and marked required false, so the backend is allowed to start even when Postgres or Redis never become healthy.
The env template ships placeholder secrets in clear text
Four env files have to exist before the stack starts, and the root template is worth reading before you copy it. APP_KEY carries the literal instruction to generate one with node ace, GEMINI_API_KEY is a placeholder for an AI provider key, API_SECRET is described as the secret for authenticating against the Yjs server, and SLACK_WEBHOOK_URL is left empty for notifications. The database block repeats the kanwas values so the app can connect, and the Redis block is the empty password from earlier. The setup copies four templates in sequence, from the root, backend, yjs-server and frontend, so a self-hosted run means four files to fill in, and the four are not interchangeable.
Prerequisites name two providers, the env template asks for a third
The stated prerequisites are Docker with Docker Compose and an Anthropic API key, or an OpenAI key, or both. The env template that follows asks for something else. The variable it asks you to fill is GEMINI_API_KEY, and no Anthropic or OpenAI variable appears in it at all. That gap is the kind of thing that costs an afternoon: the stack comes up, the board renders, and the first agent call fails because the key the template wanted was never the key the documentation described. Treat the env template as the more accurate of the two, and expect to add a variable yourself if you intend to use one of the two providers named in the prerequisites.
One profile starts almost the whole stack
Starting the board is one command, and the interesting part is how much the word profile is carrying:
git clone https://github.com/kanwas-ai/kanwas.git
cd kanwas
# Env files — fill in API keys, APP_KEY, etc.
cp .env.example .env
cp backend/.env.example backend/.env
cp yjs-server/.env.example yjs-server/.env
cp frontend/.env.example frontend/.env
docker-compose --profile app upEvery service declares membership in most of the same list: postgres and redis both tag themselves for postgres, infra, test, backend, frontend and app, and the backend adds backend and frontend on top while depending on both data services. The yjs-server, which provides the collaborative editing layer, is built from its own dev Dockerfile and published the same way. The frontend is what you open, on http://localhost:5173. The practical consequence is that the same file also expresses isolated stacks for testing and for single services, so a profile name is the unit you would edit rather than a flag you would add.
The CLI binds a directory on your first pull
The command line tool exists to move markdown between a workspace and your disk, and it keeps a binding file to remember which workspace a directory belongs to. Install it with `npm install -g @kanwas/cli`, run `kanwas login` to authorize through a browser tab, and the credential is written to a global config at `~/.kanwas/config.json`. Running `kanwas pull` in an empty directory opens an interactive picker and downloads the files there; running `kanwas push` afterwards uploads what you edited. After that first pull the directory carries a `.kanwas.json` and every later pull or push reuses it without asking. Every command also accepts `--id` or `--name` to skip the picker, which is what makes the tool scriptable from CI or from another agent.
Import walks directories but only collects markdown
The bulk import path has five documented shapes and one rule underneath them. A directory can be imported through the interactive picker, a directory can be imported by name in non-interactive mode, a single file can be imported by ID, imports can be placed under a destination subfolder, and an overwrite flag can replace files that already exist. Underneath, the tool walks the source path, picks up every file ending in .md, skips everything else, preserves the directory structure, and creates the files in the target workspace. So attachments, images and data files do not come along. If you are bringing notes out of another tool, the migration is markdown only unless you handle the rest yourself, and the preserve-structure behaviour means the layout of your old notes folder becomes the layout on the board.
BlockNote is pinned by a patch file and three overrides
The workspace root pins the editor stack tightly, which is the clearest signal in the tree about where the difficulty lives. pnpm.patchedDependencies points @blocknote/core 0.46.0 at a local patch file, patches/@[email protected], and pnpm.overrides then holds prosemirror-view at 1.41.4 while @blocknote/core and @blocknote/server-util are both held at 0.46.0. A patched dependency and three overrides on a document editor means the fix lives in this repository rather than upstream. The contributing notes agree, telling newcomers to read the system overview first for the mental model and the project-specific gotchas, and naming Yjs and BlockNote clone semantics and transactions as the things to understand before changing anything.
Editorial conclusion
Kanwas fits a team that wants one board where an agent's tool calls sit in the same timeline as human decisions, and that wants the documents in git rather than in a vendor's database. Before you run it anywhere but your own machine, change three values: the Postgres password, the empty Redis password, and the API_SECRET placeholder, all of which the compose and env templates ship as readable defaults on published ports. Also read the license file yourself rather than trusting the README sentence, since the two do not agree on how the licensing is recorded.
Frequently asked questions
What credentials does Kanwas start Postgres with by default?
POSTGRES_USER, POSTGRES_PASSWORD and POSTGRES_DB are all set to kanwas, and the healthcheck runs pg_isready -U kanwas. The compose file also publishes 5432 to the host.
Does Kanwas require a password for Redis?
Not by default. The redis service declares no requirepass, REDIS_PASSWORD in the env template is an empty assignment, and port 6379 is published to the host the same way 5432 is for Postgres.
Which AI provider key does the Kanwas env template ask for?
The template asks for GEMINI_API_KEY, while the stated prerequisites mention an Anthropic API key and an OpenAI API key. No Anthropic or OpenAI variable appears in the template.
How does the Kanwas CLI remember which workspace a folder belongs to?
After the first kanwas pull, the directory carries a .kanwas.json binding file and later pull or push calls reuse it without asking. Credentials from kanwas login are stored globally in ~/.kanwas/config.json.
What does kanwas import copy from disk?
It walks the source path, picks up every .md file, skips other files, preserves the directory structure and creates them in the target workspace. Overwrite behaviour is opt-in through a flag.
How is the Kanwas license stated?
The README points at an Apache License 2.0 LICENSE file in the repository root, but the license recorded for the project is not a recognised identifier, so the two do not agree and the file itself is the thing to read.
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/kanwas-ai-kanwas)