# Kanwas ships a compose file that publishes Postgres with the password kanwas

> 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.

**kanwas-ai/kanwas** — Kanwas — Shared context board for teams and agents

- Repository: https://github.com/kanwas-ai/kanwas
- Website: https://kanwas.ai/
- Stars: 752 · Forks: 101
- Language: TypeScript
- License: NOASSERTION
- Published: 2026-09-15 · Updated: 2026-09-15 · Language: en
- Canonical page: https://hysenlabs.com/projects/kanwas-ai-kanwas

## 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:

```bash
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 up
```

Every 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/@blocknote__core@0.46.0.patch, 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.

## 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.

## FAQ

### 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.

## Sources

- [Issues](https://github.com/kanwas-ai/kanwas/issues)
- [kanwas-ai/kanwas on GitHub](https://github.com/kanwas-ai/kanwas)
- [Project website](https://kanwas.ai/)
- [README](https://github.com/kanwas-ai/kanwas/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kanwas-ai-kanwas
