wangru78 downloadsMirror a Git repository into your vault, one-way and read-only. Never commits, never pushes, never touches untracked files.
Bring files into your Obsidian vault — one way. Two modes:
Your server hands you a one-time setup code (it expires quickly and works once). Paste it into Settings → Read-only Git Mirror → Setup code. The plugin exchanges it for a device token and stores only the server address, the token and a device id — not the code. Link each computer separately; every device has its own token and can be unlinked on its own (command palette: Unlink this device, or from the server side).
If the vault was previously used in mirror mode, switching removes the mirrored files you never
edited and the local .git folder; files you edited, and your own notes, stay. A notice says how
many files were removed and kept.
On startup and every 10 seconds:
.part file, renames it into place, reads it back and
checks its SHA-256. Attachments are written before the page that links to them.data.json) and only then confirms receipt.Guarantees:
-<id> suffix..., no absolute paths, no backslashes, no
leading dots, no reserved or control characters.A 401 answer means the token was revoked; the status bar says the device is unlinked and syncing
stops. Files already in the vault stay.
Every request except claim carries Authorization: Bearer <device token>; responses must not be cached.
POST {endpoint}/claim {code, label} -> {token, device_id}
GET {endpoint}/items?limit=50 -> {items: [{id, created_at, files: [{seq, path, size, sha256}]}], more}
GET {endpoint}/items/{id}/files/{seq} -> raw bytes
POST {endpoint}/ack {ids, failed} -> {acked}
GET {endpoint}/device -> device status
POST {endpoint}/device/revoke -> 204
The setup code is base64url of {"v": 2, "endpoint": "https://…", "claim": "…"}.
The setup code and the device token are credentials. Anyone holding them can receive your items.
By default the mirror is strictly read-only: a tracked file you delete comes back on the
next sync. If the publisher runs an endpoint for it, set Deletion report URL (and its
token): the plugin then reports what you deleted (POST JSON {paths, reporter, user, host},
Authorization: Bearer <token>), and files the server answers with in accepted stay
deleted — the plugin keeps them suppressed until the remote repository drops them too. Files
the server does not accept are restored, and a notice says so. A report that gets no answer
within 30 seconds counts as failed, and a sync that hangs for more than five minutes is abandoned
so the next one can run. user and host are your OS
user name and machine name; Your name is an optional label for the audit trail.
In mirror mode this plugin talks to the Git repository URL you configure and, only if you set one, the deletion report URL. In inbox mode it talks only to the inbox server named in your setup code. Nothing else. There is no telemetry, no analytics, and no update mechanism of its own — updates come through Obsidian.
Credentials you enter are stored in this plugin's data.json inside your vault, in plain
text — the same way a Git remote URL with an embedded token would be. Use a read-only
token.
Administrators can also hand out a link that configures everything in one click:
obsidian://readonly-git-mirror?config=<base64url of the setup JSON>
The setup JSON looks like this:
{
"repoUrl": "https://example.com/team/handbook.git",
"tokenUser": "reader",
"token": "a-read-only-token",
"targetDir": "",
"sparseFile": ".mirror-sparse",
"hidePaths": [],
"deleteReportUrl": "",
"deleteReportToken": "",
"reporterName": ""
}
targetDir empty means the vault root (a dedicated vault); a folder name puts the mirror in
that subfolder of whichever vault the plugin runs in.
That link contains the token. Treat it as a credential — anyone who gets it can read the repository.
If the repository contains files meant for tooling rather than readers, it can ship a
sparse list (default file name .mirror-sparse) in Git non-cone format:
/*
!/AGENTS.md
!/build/
Top-level paths listed with ! are not written to disk. The file name is configurable
via sparseFile, and hidePaths supplies a fallback list for repositories that do not
ship one. Adding a path to the list later removes it from disk on the next sync.
depth: 1); history is not available locally.npm install
npm test # unit + integration tests
npm run build # produces dist/main.js and dist/manifest.json
MIT