Omar Yazeedi107 downloadsTwo-way sync with your self-hosted Graphite (Life Planner) server: pull Spaces into any vault as Markdown, edit in Obsidian, push back through a validate-first merge. Sync panel with per-file status, destination-vault routing, optional auto-push.
Graphite Sync connects your Obsidian vaults to Graphite in one of two ways, chosen in the plugin settings under Where Graphite is:
How This device works. The plugin never connects to anything in this mode. In the Graphite app, Settings → Data & server → Data locations, choose your vault. Whenever the app is opened it writes your spaces into the vault as notes, and takes in what you changed there while it was closed: a record's text, a tick, a new task line. In Obsidian the plugin looks for what the app wrote and tells you when it last wrote and which notes you have changed since. Nothing runs in the background, so a change you make in Obsidian reaches Graphite the next time you open the Graphite app, and the plugin does not call it synced before then. Pull, push, capture and the other features that need a server are not available in this mode, and say so. It works on a computer; on a phone the plugin can read a vault that a computer keeps, but the Graphite app on a phone does not write into an Obsidian vault yet.
Pull a Space as a folder of notes — one command turns any Space (tasks, notes, calendar, expenses, checklists, and 15+ other module types) into an index note plus a note for each module, linked to each other and carrying the module’s own tags. This is the default, because it is what makes the mirror a vault rather than an archive:
Projects/
Projects.md index — overview, your prose, links to every module
Tasks — Backlog.md one module, one note
Notes — Journal.md
Or one file per Space (Settings → Vault layout) — the whole Space as
a single server-canonical .md, for a vault kept as an archive rather than
worked in. Existing notes keep the layout they were pulled with until you
pull them again.
Each module note carries the module's own tags as Obsidian properties and
links back to the index (space:), so the graph, backlinks and tag panes
see your Graphite structure as ordinary vault structure. Every note pushes
on its own — editing one module never touches another. Rename a module in
the app and its note is renamed, not duplicated; remove a module and its
note is left alone in the vault, just no longer synced.
Pick the destination vault — pulling asks which vault the Space lands in. Route different Spaces to different local vaults; the target vault's plugin is configured automatically so it can push and pull on its own from then on.
Validate-first push (Push the current file back to Graphite) — edits go through the server's merge importer. Errors come back with line numbers and nothing is written; on success the file is rewritten to the server's canonical form, so vault and app never drift.
Sync panel (Open the sync panel) — a sidebar view with your connection status (who you're
signed in as, server version), and every synced Space with its notes and
their live state: ✓ in sync, ● local edits, or ⚠ file missing — plus
Push / Check per note and Pull / Push all / Forget per Space.
Check server — one click tells you whether a Space changed on the server since your last sync, before you decide to pull or push.
Selective sync (optional) — a second pull command, Pull a space into THIS vault, choosing modules, lets you tick exactly which modules travel into the file. Unticked modules never enter the vault, and pushes never touch them.
Auto-push on save (optional, off by default) — tracked files push a couple of seconds after you stop typing.
Status bar + test button — a permanent connection indicator, and a one-click "Test connection" in settings (and Test the server connection on the palette) that tells you exactly why a token or URL doesn't work.
Connected devices and servers (Settings, at the bottom) — every browser, app and API token signed in to your account, each with when the server last saw it in use; and every Graphite server the vaults on this computer are set up against, each with when it last answered. It is what the servers recorded, not a live view: the plugin never shows a device as online or as typing.
Freeform notes survive sync — every pulled note has a marked region the sync never regenerates: your own prose lives alongside the mirrored data and is kept across pulls and pushes. In the folder layout each module note has its own block, so prose sits next to the records it is about.
Native tags — record tags arrive as #slug tokens, so Obsidian's
tag pane reads your Graphite data natively, and a #tag you type on a
record's line reaches the record on the next push. That holds for
comments and votes as well as tasks and the rest: a comment's line and a vote's heading
carry the record's id (hidden by this plugin, like the other ids), and a
tag typed there lands on that comment or that vote. Only the tag is read
from those two: who wrote a comment and when, and a vote's options,
counts and decision, belong to Graphite and a change to them in the note
is not applied. A tag on a vote's option line is not read either, since an
option is not a record — put it on the question. A module note's own tags
are its tags property: change them in the Properties panel and they
reach the app on the next push.
Records you can link to — task, reminder, checklist and recipe lines
carry a block anchor, so any note can link to one
([[Projects/Tasks — Backlog#^…]]). The index note's Links table shows
how records are joined up, and each end is a real link, so the graph and
backlinks panes follow them.
Links panel (Open the links panel) — a side panel listing the links of the record under the cursor. Link this line to a Graphite record asks for the kind of link first, then the module, then the record, and writes it; the server refuses what it does not allow, in its own words.
Capture from any note (optional, off by default) — choose a
Capture inbox in settings, then run Capture tasks from this vault into Graphite:
every - [ ] … line in a note that is not a synced one becomes a task
there, with its tags, and the line is marked so capturing again never
makes it twice. Two more switches, both off by default, capture tagged
lines that are not tasks — Capture any tagged line as a note, and a list
of tags (st takes #st/IS-07). Such a line becomes a note in the
inbox's space. Frontmatter and code blocks are never captured.
Create a space from a note — write a space as markdown (a # Name
heading and ## Module: sections), run Create a Graphite space from
this note, and it is created in the app and pulled back in as synced
notes. Nothing is created if the file does not pass the import check —
the first problem comes back with its line number. Your note is left as
it is.
Add a module — Add a module to a Graphite space asks which space (the one the open note is synced to, or a list), which kind of module and what to call it. The module is created in the app and its note is pulled into the vault.
Settings in a note (optional, off by default) — turn on Keep
settings in a note and the settings also live in Graphite/Sync settings.md as properties: change one there and the settings screen
follows, and the other way round. To set up another device, copy the note
into its vault and turn the switch on there. Write settings to the
settings note and Read settings from the settings note do either by
hand. The API token, passwords and the encryption passphrase are never
written to it.
Note sync (off by default; being built) — carries the whole vault between devices through a CouchDB server, in place of LiveSync. Every file is sealed on the device (AES-GCM-256, under a key derived from a passphrase typed on each device) and stored as one document per file in a database of its own, so the server holds neither the notes nor their names. Changes go up shortly after the vault sits still, and arrive live or on Sync notes now. A file deleted on another device moves to the vault trash; a file changed on two devices keeps both, the other version written beside it as a conflict copy, and says so. Hidden files, plugin settings and files over 50 MB never travel. Not yet: merging edits that do not overlap, and Graphite own sync as the server.
One vault, one space and the spaces under it (Settings → This vault's space) — each vault has its own identity and is linked to one space with its subtree. Anything the vault writes — a push, a capture, a new module — lands inside that subtree or is refused, and the notice says why. A vault that is not linked yet writes nothing.
Route a line with >> — type >> anywhere in a line and pick a space
(or space / module) from the list under the cursor; the same list is on
Route this line to a Graphite space and can be bound to a hotkey. The
cursor decides the scope: a line, a heading's section, or the whole note
from its properties. Make these tasks turns the selected bullets into
checkboxes.
The Graphite bar — a row of buttons above any note that is not a synced Graphite file (below it on a phone or tablet, with targets of at least 44px): Start a list, Task, Due, Assign, Priority, Tag, Send to and Capture now. It wears Obsidian's own colours, each button is also a command (Graphite bar: Capture now captures the note you are in; on a device with no sign-in it says your PC does that once the sync brings the note over), and Show the Graphite bar in the settings hides the row.
Pickers on a tablet with no sign-in — while the plugin is connected (a PC), it writes the spaces, their Tasks and Notes modules, the people of each space and the tags in use to Graphite/Toolbar lists.json in the vault, only when they changed. A tablet that has the plugin but no token reads that file, brought over by your vault sync, and every picker works there; capture stays the PC's job. The file holds names only, never a token, a server address or a password. Share the picker lists with other devices in the settings turns it off, and Publish the picker lists for devices with no sign-in writes it now.
Start a list — Graphite bar: Start a list asks what you are writing (a task list or notes; calendar events and the rest are shown as later), then where it goes: the note's own space is offered first, else the capture inbox, then every Tasks or Notes module in the vault's space. The heading words are editable (Actions to start with) and kept. It inserts ## Actions >> Space / Module and a first box with the cursor on it, over a blank line or below the current one.
The Graphite bar's pickers — each is a command, so a phone or tablet
can put it on Obsidian's own mobile toolbar. Graphite bar: Task makes
the line an open task (or starts the next one below). Graphite bar: Due
offers day chips counted from the note's own date, a month calendar and
times, and always writes | due: YYYY-MM-DD with an optional HH:MM.
Graphite bar: Assign offers the people of the space the line is going
to and writes | assigned: with the exact name. Graphite bar: Priority
writes | priority: low, normal, high or critical. Graphite bar: Tag
appends a tag already in use, or a new one, to the line's words.
Graphite bar: Send to is the >> list. They write onto the line as
text and change nothing in Graphite until the line is captured; they
decline a line that is already captured, and a synced Graphite file.
Proposals you approve — a line written in italics with a proposal marker is a suggestion, not yet yours: it is shown washed and labelled until you approve it, and nothing is created in Graphite before then. Approve with Approve the proposal on this line, Approve every proposal in this note, the panel, or by ticking or un-italicising the line; what is created is the line as you left it.
A contract for your own agent (optional, off by default) — if you
use an AI agent of your own to turn prose into proposals, Publish the
routing list and agent brief for your agent writes two notes into the
vault's Graphite/ folder: the closed list of spaces, modules and tags it
may use, and the format it must write. Graphite never sees your notes for
this; the list is checked again when you approve.
Ticks travel both ways — once a capture inbox is chosen, ticking a captured line finishes its task in Graphite, and finishing the task in the app ticks the line. Status only: the words and fields are never changed. Sync ticks between this vault and Graphite runs it on demand.
Vault census for the morning sweep (optional, off by default) — Send the vault census to the morning sweep sends counts and dates only (per note: its path, its date, how many task lines are open, done or proposed, its tags and links), never a line's words, so the sweep can point out to-dos nobody filed and meetings with no note.
Any number of Spaces, any number of vaults — every vault keeps its own server, token, and file mappings, fully independent.
https://graphite.example.com) or it is run for you. The spaces you
want in the vault must be kept on that server. Spaces kept only on your
devices, or shared between them through the relay, are not reachable (see
the top of this page).Pull writes the server's canonical export of a Space into the vault. Push sends your edited file through a validate-first merge: the server only touches records present in the file (absence never deletes — deletions are explicit), and on success the file is canonicalized back. The sync panel's state badges are computed from content hashes, so "in sync" means the file is byte-identical to the last agreed state.
Proprietary - all rights reserved. The source is published so that it can be
read and reviewed; it may not be copied, modified or redistributed. You may
install and run the plugin, unmodified, against a Graphite server you are
entitled to use. See LICENSE.
What the community-plugin policies ask a plugin to say about itself.
/health, no token sent)..obsidian/plugins/graphite-sync/ folder, so that vault can sync by itself.
It does none of this unless you pick another vault, and none of it on a
phone.data.json), as
other plugins store theirs. Treat a shared vault folder accordingly, and
revoke the token in the app whenever in doubt.main.js in each release is built from the source in this repository, not
minified or obfuscated, and the plugin never installs or updates itself.cd tools/obsidian-plugin
npm ci
npm run build # writes main.js
npm run typecheck
main.js is an esbuild bundle of src/main.ts; building it from this source
gives the file attached to the release. The source imports a few shared
grammar files from apps/api/src/spaces/, which this repository carries
alongside it for that reason.
Questions and problems: open an issue in this repository's Issues tab.