Obsidian
Some people write in Obsidian and would rather not stop. The GMTales plugin makes a vault a place to write articles for a campaign and push them up when they are ready. It is a writing desk, not a second GMTales: the server keeps the secrets, decides what is valid, renders for readers and links the articles. The plugin asks it.
Everything in this topic assumes you know what a package and a folder sync are. The plugin is that story told for a different client.
What the plugin is, and is not
A vault is a folder of Markdown files that Obsidian opens. A note in the vault is a GMTales article, character for character. There is no front matter, no field the plugin adds, and no transform on the way up or down. The text you see in Obsidian is the text the server parses, so everything in Writing applies unchanged.
The plugin does not hold real secrets. A secret block in your vault is a passage in a file on your disk, readable by anyone with the file. It becomes a secret when it is uploaded and the server records who may read it. The plugin does not enforce a save, and it does not render your articles for other readers. It shows you what your text says; the campaign decides what it does.
Setting up
Install the plugin, then in its settings choose Sign in. Your browser opens GMTales, where you approve the vault under your account. Nothing of your password, and nothing of a Google sign-in, reaches the vault. What the plugin receives is a device token: a credential minted for this vault alone, named after it, which you can revoke at any time under Your account → Devices on the website.
The device token is stored in plain text in the vault, at .obsidian/plugins/gmtales/data.json. Anyone who can read that file can act as you on GMTales until you revoke the token. Revoking it signs the vault out; nothing else about your account moves.
Then choose the campaign this vault writes to, and the folder under which its notes live. One vault binds to one campaign.
Writing
In Live Preview the plugin draws a block's opener as a small header naming the block and its arguments, its closer as a rule, and the lines between with a tint, so a block's extent is visible. A secret block stands apart from the others. Directives are drawn as chips, and a strip above the note gathers every directive in the document into one row, wherever each was written; clicking a chip goes to it. Putting the cursor on a marker's line shows the raw text again. Source mode shows the raw text throughout.
The file on disk is not touched by any of this. Reading view shows the prose with the markers invisible.
Validate
GMTales: Validate this article asks the server for every problem the save would refuse, and shows them in a problems pane and as underlines in the text. The answer is the server's, from the same checks the editor's Render runs.
When the server cannot be asked, because you are offline or no campaign is bound, the plugin checks what it can from the text alone and says so. A local check finds an unknown directive, an unmatched block marker or a wrong argument; it cannot know whether a group, an image or a calendar exists in your campaign. The pane labels a local result as checked locally, and a clean local result as one the server may still refuse.
Who would read this
A secret block's header names its audience by the group's name rather than its key, so <!-- start: secret; nobles, gm --> reads as The Ashen Court, Game Masters. A key no group has is drawn as an error, which is what the save will say too. Inside <!-- start: secret; and <!-- visibility: the plugin offers the campaign's groups as you type.
GMTales: Show this article's audience lists each top-level passage of the note with the audience it comes to: the article's own visibility as the baseline, each secret narrowing its passage within it. Member counts are shown for the groups you belong to; for the others the plugin says the count is unknown rather than guessing. This is what your text says. What a reader receives is decided by the campaign when the article is uploaded, and the server's preview of the article as one of your groups is the answer to check against.
Names as links
GMTales links articles by name, without brackets. The plugin underlines the names of other articles in your campaign as you write them, matched the same way the server matches them, and a relations pane lists what the open note names and which notes in the vault name it. The server also checks that the reader of the naming passage may open the named article, and drops a link that comes to nobody. The plugin shows the match; the server decides whether the link survives.
The suggesters offer the campaign's own values inside a directive: types and labels already in use, article keys for a tree's parent, calendar keys, image names. GMTales: Insert block… writes any block with its required arguments in place, and GMTales: New article writes a title, a key and a type, and nothing else. GMTales: Open the campaign pane lists the folder's notes grouped by type, with their labels and a filter.
Syncing
GMTales: Sync this campaign pushes every note and image under the bound folder to the campaign as a folder sync. Everything lands as drafts: the plugin is not a publishing tool, and nothing the table reads moves until you say so. GMTales: Sync this note pushes the open note alone.
Before the upload the plugin checks each note locally. Problems are listed, and you may sync anyway; the server refuses the offending files itself and reports them as failed rows, with the rest landing as drafts. Pushing everything every time is fine: a file that says what the article already says is reported Unchanged and nothing is written.
When the upload finishes its review opens in the vault, the same review queue the website shows: one row per file with what happened to it. Publish all publishes every draft not in conflict, Publish all, conflicts included takes the conflicts too, and Discard all throws every draft away. Earlier uploads are listed beneath.
Keeping sync.json
The folder's sync.json is what lets an upload report that an article changed on the site while your copy sat in the vault. Seeding writes it; publishing from the review pane updates it with the revisions you published. Keep it in the bound folder, and if it drifts, GMTales: Refresh sync.json fetches the campaign's current one and replaces it. Without the file every upload looks unconflicted, and a co-author's published change would be overwritten without a word.
An article with no key directive is matched by title, which breaks the moment you rename it. The plugin points out notes without a key after each upload.
Seeding a vault
GMTales: Seed this vault from the campaign pulls the campaign's export into the bound folder: your articles as notes, your images and their sidecars in the same layout, and sync.json. It is the way to start writing in Obsidian for a campaign you began on the website, and a seeded folder syncs straight back with every row Unchanged.
Seeding into a folder that already holds notes never overwrites and never deletes. A file already identical to the campaign's is skipped. A file that differs is left alone and named in a summary, with overwriting offered as a second, explicit step. A note the campaign does not hold is exactly what an article you have not uploaded yet looks like, so nothing is removed.