Set up the project structure per the new-project guide, adapted from the Python skeleton to the Node/TS stack fixed in SPEC.md (reuses docmost-mcp). Scaffold only — the sync engine is not implemented yet. - src/settings.ts: single config layer on zod, schema keyed by real ENV names; credentials and own-service address have no default (fail fast). - src/config-errors.ts: loadSettingsOrExit — clear startup message naming the missing/invalid env var instead of a raw stack trace; exit(1). - src/index.ts: thin entry point that validates config and logs (stub). - test/: vitest unit tests for settings parsing and config errors (10 tests). - Makefile (install/env/build/test/run/dev/clean), strict tsconfig, vitest. - Dockerfile (single-stage, no EXPOSE, prunes dev deps), docker-compose (daemon, volume on /app/data, watchtower), ghcr CI with build needs test. - .env.example, .gitignore/.dockerignore, AGENTS.md, README.md. - Pinned deps (dotenv, zod) + committed package-lock.json.
docmost-sync
Bidirectional sync between Docmost articles and a local Markdown git vault — the
git repository is the state store. For the full design and the phased
implementation plan, see SPEC.md.
Status: scaffold only — the sync engine is not implemented yet.
src/index.tsvalidates configuration and exits. The engine described inSPEC.mdis out of scope for this scaffold.
It reuses the sibling project docmost-mcp as a library (DocmostClient, ProseMirror ↔ Markdown converter, collab-write).
Configuration
All config comes from ENV / .env (see .env.example), read
through the single settings layer in src/settings.ts. A missing required
variable fails at startup with a clear message that names it.
| Variable | Required | Default | Meaning |
|---|---|---|---|
DOCMOST_API_URL |
yes | — | Base URL of our Docmost instance (used for /auth/login). |
DOCMOST_EMAIL |
yes | — | Docmost login email. |
DOCMOST_PASSWORD |
yes | — | Docmost login password. |
DOCMOST_SPACE_ID |
yes | — | The Docmost space to mirror. |
VAULT_PATH |
no | data/vault |
Local git vault path (kept under data/ for the volume). |
GIT_REMOTE |
no | (unset) | Optional git remote the vault pushes to; empty = local-only. |
POLL_INTERVAL_MS |
no | 15000 |
How often to poll Docmost for changes (ms). |
DEBOUNCE_MS |
no | 2000 |
Debounce window for local file changes (ms). |
LOG_LEVEL |
no | info |
One of debug, info, warn, error. |
Credentials and the address of our own Docmost instance have NO default — they
go ONLY into .env, never into code or inline command-line env vars.
Quick start
make install # install dependencies (npm ci)
make env # create .env from .env.example, then fill it in
make test # run the test suite (vitest)
make run # build and run
make dev # run in watch mode (tsx)
make (or make help) lists all targets.
Deploy
Production runs a prebuilt image from ghcr.io (no build on prod):
docker-compose.yml pulls ghcr.io/vvzvlad/docmost-sync:latest, mounts a
volume at /app/data, and watchtower
auto-updates the container when a new image is published. CI (GitHub Actions)
builds and pushes the image; the build job runs only after test passes.