Getting your content out

By the end of this you will have a clone of a workspace on your own machine and a backup file that contains everything, and you will know precisely what each of the two does and does not hold.

Clone the repository

Each workspace is one git repository, and it is the source of truth rather than an export of one. Clone it and you have every document as a Markdown file, with the ordinary git history, readable with the ordinary tools.

git clone <workspace-repository> knowledge

What you get:

knowledge/
  grundsaetze.md
  bewertung/
    sicherheiten.md
    diagram.png.asset

Every .md file is a document, front matter and body, exactly as it was written. Nothing needs converting and nothing needs an API.

What a clone does not contain

The uploaded files themselves. diagram.png.asset is a pointer — a small text file recording the upload's name, size, type, and checksum. The bytes live outside the repository.

That is a deliberate design decision rather than an oversight. Git cannot forget a binary once it is committed: history cannot be rewritten without invalidating every clone anyone holds. An upload is far more likely than a typed document to contain somebody else's personal data, and being able to answer an erasure request means being able to actually destroy the bytes.

So a hand-rolled copy of the repositories alone silently misses every upload. For everything at once, take a backup.

Take a backup

One workspace, or all of them:

pnpm --filter @md-platform/core backup <workspaceId> ./backup.tar
pnpm --filter @md-platform/core backup --all ./backup.tar

The file is a single tar containing a manifest, the PostgreSQL records, one git bundle per workspace, and the uploaded files that are not in those bundles. It is the thing that holds documents and uploads together.

Writes to a workspace being copied wait for the duration, so the repository and the records agree with each other. On a busy workspace that means a short delay for writers rather than an inconsistent backup.

The file is not encrypted. It holds customer content in full, plus password and token hashes. It is as sensitive as the database it came from — treat it accordingly.

Read it back before you rely on it

pnpm --filter @md-platform/core restore ./backup.tar --dry-run

This verifies the checksums and reports what the file would do, writing nothing:

Backup taken 2026-08-09T12:58:33.113Z
  format    : 1
  workspaces: 01KZB223QDQP0F7MBN1Q9Z24H2
  checksums : 2 verified

Dry run: nothing was changed.

Worth running on any backup you intend to depend on. A backup nobody has ever read back is a hypothesis, not a backup.

Restoring

pnpm --filter @md-platform/core restore ./backup.tar

Restoring is the most destructive operation here and is usually run by somebody who has just lost something, so it refuses a workspace that already has documents:

Workspace 01KZB2… already has 5 document(s). Restoring would replace them. Pass --force to proceed.

Checksums are verified before anything is staged and the swap happens only after that succeeds, so a corrupt file fails without having touched the target.

Rebuilding the index

Not an export, but the same underlying property and worth knowing: PostgreSQL holds a projection of the repositories and can be reconstructed from them.

pnpm --filter @md-platform/core rebuild-projection <workspaceId>

Because git is the source of truth, this cannot lose a document that has been committed. It is also the recovery path if a projection write ever fails after a commit has landed.

What "done" looks like

You have a clone whose .md files you can read in any editor, and a --dry-run that verified your backup's checksums. Between them, leaving is a copy rather than a project.

Getting your content out — md-platform