# 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`](./SPEC.md) (the authoritative spec). > **Status: Increment 1 — monorepo scaffold + read-only `pull` + Phase-0 > round-trip harness.** Continuous two-way sync is not implemented yet; see the > phased plan in `SPEC.md`. It reuses the sibling project **docmost-mcp** as a library: the `DocmostClient` REST client and the lossless ProseMirror ↔ Markdown converter are extracted into this monorepo (so changes can be backported file-by-file). ## Layout This is an npm-workspaces monorepo: - **`packages/docmost-client`** (`docmost-client`) — the Docmost REST client and its `lib/` (converter, markdown-document, collaboration, …). Its source layout mirrors `docmost-mcp/src/` 1:1 so diffs can be backported by copying files. Sync-specific REST methods are added under clearly marked `docmost-sync additions` banners. - **the repo ROOT** — the sync engine app (`src/`, `test/`, `build/`, `data/`). It depends on `docmost-client` and holds the config (`src/settings.ts`), filename sanitization (`src/sanitize.ts`), the Phase-0 round-trip idempotency harness (`src/roundtrip.ts`), and the read-only `pull` (`src/pull.ts`). ## Install & build Requires Node >= 20. For local (non-Docker) runs a system `git` binary must also be on `PATH` — the vault state store shells out to it for every operation (the daemon fails fast at startup if `git` is missing). ```sh npm install # links the workspace packages npm run build # builds docmost-client, then compiles the app into build/ ``` `docmost-client` must build before the app (the app consumes its built output); the root `build` script builds the lib first, then runs `tsc`. ## Configuration Copy [`.env.example`](./.env.example) to `.env` and fill in real values. The config is read through [`src/settings.ts`](./src/settings.ts). | Variable | Required | Meaning | | ------------------- | :------: | -------------------------------------------------------- | | `DOCMOST_API_URL` | yes | Base URL of our Docmost instance. | | `DOCMOST_EMAIL` | yes | Docmost service-user login email. | | `DOCMOST_PASSWORD` | yes | Docmost service-user login password. | | `DOCMOST_SPACE_ID` | yes | Which Docmost space to mirror. | | `VAULT_PATH` | no | Local vault directory (default `data/vault`). | | `GIT_REMOTE` | no | Optional git remote the vault pushes to. | | `POLL_INTERVAL_MS` | no | Poll interval in ms (default `15000`). | | `DEBOUNCE_MS` | no | Debounce window in ms (default `2000`). | | `LOG_LEVEL` | no | `debug` \| `info` \| `warn` \| `error` (default `info`). | **Real secrets go in `.env`, which is git-ignored — never commit them.** The git remote grants access to the whole vault, so protect it no less than Docmost itself (SPEC §12). ## Running ### Round-trip idempotency harness (Phase 0, SPEC §11) Verifies that `export → import → export` is byte-stable. Runs offline against a fixture (the default for CI) — **no Docmost credentials needed**: ```sh npm run build node build/roundtrip.js --fixture test/fixtures/sample-doc.json ``` Or against a live page (needs `.env`): ```sh node build/roundtrip.js --page ``` Exit code is 0 when the markdown is byte-stable, 1 on a markdown divergence (CI-able). A document-level divergence after stripping block ids is a known SPEC §11 finding and does not fail the run. ### Pull (Docmost → filesystem mirror, SPEC §6) Read-only mirror: walks the configured space's page tree and writes one `.md` per page under `/<…ancestors>/.md`. **Requires a `.env` with real Docmost credentials** — it makes live REST calls and does not touch Docmost state (read-only this increment): ```sh npm run pull ```