Skip to the document

Changelog

Notable changes, newest first. Dates are when the change landed.

Unreleased

  • The vault is a folder like any other now, so its name at the top of the sidebar opens its own page, blank until you write on it, the way a folder's name opens the folder's page. The front page used to be a row of its own pinned above the folders, which couldn't be renamed or moved and was called "INDEX" when it had no heading. That row is gone, and in a vault titled like its front page the name no longer shows twice. The page is still the INDEX.md at the vault root, it still opens first once it's written, and existing vaults need no change.

  • With no heading of its own, the vault's page goes by the vault's name, as a folder's page goes by the folder's.

  • The vault name's menu has Delete page, which removes what was written on the vault's page and leaves a blank one.

  • On an exported site the vault's name is the link to the front page and is marked while that's the page being read. The front page is no longer repeated as the first row under it.

  • A link to another document prints as ordinary text in a PDF, set like the words around it. It used to stay a link, and the address it carried was the app's own on the computer that made the PDF (http://127.0.0.1:52515/print?doc=…). Nothing answers there once the export is done, so every one of those links was dead in a PDF you'd sent, and the file showed a local address to whoever looked. That went for a markdown link, a [[wikilink]], a link to a file in the vault and every row of a children block. A link to another site still opens, and a link to a heading in the same document still jumps to it, which [[#Heading]] now does too. The Paginated layout keeps all of them as links, because there a click opens the document. Export a PDF again and the old links are gone. See Exporting PDFs.

  • Moving a document or a folder in the sidebar rewrites the links to it, so they go on working. Every [[wikilink]] and every relative markdown link that pointed at the old path is respelt to reach the new one, in a document's text and in the markdown inside a block. Only the part of the link that names the file changes: its text, its #heading and its |alias stay as written, a link that still finds the document isn't touched, and each file keeps its line endings. A document that moves to another folder has its own relative links and pictures rewritten from there. Before, a move only renamed the file, and every link to it stopped resolving. See Finding your way around, and Documents for exactly what's rewritten.

  • Linked from, at the foot of a document, counts a link written in a block that sits inside another block's markdown, a callout inside a card, say. Those links worked on the page but were missing from the list.

  • Each block that comes with Plicine has a page of its own in the docs, under Blocks: Table of contents, Child pages, Image, Callout, Card, Columns and Page break. Each shows the block live on the page, a picture of its form or editor taken from the app, what every option does in plain words, and how it prints. The Blocks page moved from app/blocks.html to app/blocks/index.html on the site to make room for them.

  • Joining the closed beta is a short form at the foot of plicine.com now, where it used to be an email you had to write. The site has a privacy notice that says what the form asks, why, and when the answers are deleted. Writing to beta@plicine.com still works.

  • A block's form shows an image or a link in a markdown field the way the page does. In the form of a card, a callout or a columns block, ![Chart](../assets/chart.svg) was a broken image, [Prices](pricing.md) pointed at the pricing.md at the top of the vault rather than the one beside the document, and [[Prices]] named the path it spelled instead of finding the file. A card nested inside the same field already found its links. See Links between documents.

  • A link to another document written inside a block, [Getting started](app/getting-started.md) in a card, a callout or a columns item, opens that document, as the same link in the page's own text does. A click used to take the window to an address the app doesn't serve, and an exported site kept the link pointing at a .md file that isn't there. [[links]] already worked in those places. See Links between documents.

  • plicine export-site warns when a page still has a relative link to a .md file once it's written, so --strict fails on it rather than letting a dead link go live. A block's own HTML can write one.

  • An image written the markdown way inside a block, ![Chart](../assets/chart.svg) in a card, a callout or a columns item, shows up, as the same image in the page's own text does. It used to be a broken image in the app, in a PDF and on an exported site, where a file that only a block's markdown named wasn't copied across either. ![[chart.svg]] already worked in those places. See Images.

  • An image whose address has percent signs that spell no character, ![Chart](a%ff.png), is shown as a broken image and nothing more. One such address anywhere in a vault used to stop the vault's documents being listed, and the document holding it from opening.

  • The sidebar shows a document's file name after its title where the two differ, so cli.md titled "CLI reference" no longer hides what the file is called. Capitals, hyphens and punctuation don't count: getting-started.md titled "Getting started" shows the title alone.

  • A document's menu in the sidebar has Rename and Rename file, and a folder's has Rename folder. Rename changes the title, and a file named after its title follows it, written the way its name already is (getting-started.md retitled "Quick start" becomes quick-start.md). Rename file changes the file's name alone. Either way, the links to a file that gets a new name are rewritten, as they are when it's moved. Name file after title shows on a document whose file is called something else, and offers a name made from the title.

  • A document's file can't be renamed to something a new document couldn't be called (a name starting with a dot, or containing :), and a name can now be changed in its capitals alone on a disk that ignores them.

  • The docs open on three doors, one for each kind of reader. Use Plicine is for everyone: what's on screen, with no terminal, no code and no file formats. Getting started begins it, written for someone with the installed app: get the beta, open a folder, write a page, send it as a PDF. Under the hood is for technical people: how a page is kept as a text file (markdown, with settings in YAML), and the plicine command. Build for Plicine is for developers and their agents, making blocks and themes. Pages that mixed the two, such as exporting PDFs, templates and sharing, are now a plain page and a technical one. Everything in the docs can be done with only the app installed: Writing a theme starts from an empty folder, and the pages about Plicine's own source code are gone from the site.

  • A block someone writes for a vault can have its text edited on the block. Markdown from the new plicine module renders a prop as markdown, and a click on it opens the editor the page's own text has, inside the block: markdown symbols at the caret, a copy that takes what's rendered, Copy as markdown on a right-click. It works in both layouts: on the pages the editor opens over the block's printed output. A one-line prop, a title or a lead-in, takes inline. The note block does this now, and so does the block plicine create-block starts you with. See The .block package.

  • A block can add buttons of its own to its toolbar with useToolbar, and write its own props with update. It can write nowhere else: only into its own fence, checked against its schema first.

  • A card and a callout block are edited where they sit, the way an item of a columns block is. A card opens inside its box. A callout opens as the > [!type] Title markdown it stands for, so the type and title can be changed from its first line.

  • A copy from an item of a columns block takes what the selection renders as, like a copy anywhere else on the page, and its right-click menu has Copy as markdown. It used to copy the markdown.

  • A block's prop that holds a line of three backticks (a code sample in a markdown field) no longer ends the block's fence early when it's saved, which spilled the rest of the value into the document. The fence grows a backtick instead.

  • The desktop app opens the vault it's started on: a folder passed on the command line (open -a Plicine --args <vault>), or PLICINE_VAULT. It used to open the most recent vault whatever it was given.

  • Write AGENTS.md in the agent picker can be reached with the keyboard. The arrows, Home and End stepped over it, because it carries a tick rather than being a plain command and the menus only walked plain commands, and nothing else could reach it either: Tab closes a menu rather than moving through it, so it was mouse-only.

  • plicine --help lines its commands up in one column, so plicine validate's description no longer sits on a line of its own. The summary is now built from each command's own flag declarations rather than written out separately, so it can't fall behind the flags a command actually takes.

  • Cmd+F (Ctrl+F elsewhere) finds words in the document you're reading: a bar over the top right of the page, every match tinted, Enter and Shift+Enter to step through them and a count of how many there are. It reads the page as it's drawn, so a block's own text is searched too, and it works in both layouts and in Source. Press Cmd+F again, or click All documents, and what you typed moves to the sidebar's search of the whole vault. See Finding words in the document you're reading.

  • About Plicine names the commit the build came from. The panel reads Version 0.1.0 (a1b2c3d), where a build number usually sits, so a bug report can say which code it's about. A copy built without git around it shows the version on its own.

  • Dragging from one element into another selects text across them, in both layouts: part of the first element, everything between (a picture is tinted like the text), part of the last. Before, the drag stopped at the edge of the element it began in. Delete, Backspace, cutting, typing, Enter and pasting replace the selection and join what's left of the first element to what's left of the last, as one change that one undo takes back, and the result opens for editing with the caret at the join. Shift-click with an element open selects from the caret to the click. See Selecting across elements.

  • A selection looks and copies the same inside one element and across several. It shows the markdown of what it touches, faint. Cmd+C/Ctrl+C now copies what the selection looks like, so it pastes as formatted text; copying from an element's editor used to give its markdown. Right-click the selection for Copy as markdown.

  • Hovering an element no longer shades its bottom-left edge in the accent. The grip at its left and the Add block line between elements still show.

  • An image pasted with the caret at the very start of a heading, a paragraph or a list goes in above it. It used to go under it, like a paste from anywhere else in the text. If that puts it first in the document, it offers to become the header image. See Pasting images.

  • The button an image block shows under it (Move into the text, Make it a header) sits in the middle of the block's bottom edge, where it used to be at the left.

  • A header image fills the head of the first page in the paginated layout and in PDFs: it runs up through the top margin to 6mm from the sheet's edge, as it already did at its sides, with square corners. It used to start under the top margin. See image.

  • An image that ends up first in a document offers to become its header. Add one at the top, move one there or delete what was above it, and a Make it a header button shows under it, which sets the block to full width and its picture to crop to fill in one step. Cmd+Z (Ctrl+Z) takes it back. See Editing an image.

  • In the paginated layout, a paragraph or list that runs on to the next page is edited where it sits on both pages. Opening it used to pull all its text on to the first page, over the footer, until it was saved. Text typed on the first page now pushes the rest on to the second as you write.

  • A click on the part of a paragraph that's on the second page puts the caret where you clicked. It used to land near the start of the paragraph.

  • Click an item of a columns block and it opens for editing where it sits, in both layouts, the way a paragraph does. It used to open the block's form in the side panel, which is still where items are added, reordered and removed. Enter starts a new paragraph in the item, / adds a card, a callout or an image to it, and saving an item you've emptied takes it out. See Editing a columns item.

  • columns has two new fields, Row spacing and Column spacing, each a row of buttons like the width's: pictures of two boxes with no room between them, a little, and so on up to a lot. Auto keeps the theme's spacing as before, and Custom takes an exact size such as 12px or 6mm for anyone who wants one. See columns.

  • A block's form can offer named choices as buttons, with an exact value behind Custom, which is how the spacing fields work. A block's schema asks for it with a union of an enum and a string. See Writing a block.

  • Text in a block's form that grows from one line to several is saved as a YAML block (|), each paragraph on its own lines. It used to stay inside its quotes, folded onto indented lines with every break doubled.

  • Vault settings. The settings in .vault/vault.json can be changed in the app, so turning off the "Made with Plicine" line no longer means editing JSON by hand. Vault settings in the vault name's menu, and Settings… in the desktop app's menu on Cmd+, or Ctrl+,, opens a screen with the title, the default theme, the page size, the default layout, the credit line's switch, the public URL and Write AGENTS.md, which stays in step with the agent palette's switch. Changes save as they're made, and the open document follows at once. The file stays yours: only the key that changed is written, the rest keeps its order and indentation, nothing is written on open, and choosing a default again removes the key instead of writing the default. A vault.json that can't be read is shown with its error and never written over, which now holds for the palette's switch and plicine agents-md too. aliases, values and settings are still edited in the file, and the desktop app can show it in Finder or File Explorer. PUT /api/vault/config is new, GET /api/vault gains config, and POST /api/reveal takes "kind": "config". See Vault settings.

  • The Solunify Creations theme is no longer in the repository. It's the brand of the company that makes Plicine rather than part of the product, so its source now lives outside. themes/acme is the example theme in its place, for an invented company: a white page, cobalt blue, Zilla Slab as static fonts under the OFL, a cover and a footer in a margin box. The theme guide and the .theme reference take their examples from it, the fixture vault defaults to the built-in theme with one document that picks theme: acme, and every screenshot baseline was recorded again. A vault that says theme: solunify keeps working as long as its own .vault/themes/solunify.theme is there; without that file its documents fall back to the built-in theme, with the warning Theme "solunify" not found; using the default theme.

  • The gantt reference block (1.1.1) has a new description. Nothing about the chart changed.

  • Themes can round the corners of pictures. A new token, --fx-image-radius, sets the corner radius of image blocks and markdown images on screen, in print and on an exported site. The built-in theme sets it to 3px and Acme to 2px. A theme that leaves it out gets 3px too, so pictures under a theme written before this now have slightly rounded corners; set --fx-image-radius: 0 in its tokens.css to keep them square. Logos in a theme's cover, header and footer templates aren't touched. See the token list.

  • Every --fx-* token has a default, so a theme only sets what it changes. A theme that left a token out used to get the browser's default for it in places (Times for the body font, no border colour). Now it gets plain values: system fonts, grey ink on white and a link blue, with headings following the theme's body font. The built-in theme's look doesn't come through: a custom theme still starts from neutral, not from Plicine's cream and green. Block frames get the same defaults, so a block's var(--fx-color-accent) resolves under any theme. The defaults are listed in the token list.

  • An image block is edited on the image. Clicking one opens a small editor under it, in both layouts, with the caption, the text for screen readers, the alignment, a width and Replace…; it saves as you go, and More options opens the block's form in the panel. With the image clicked, Backspace or Delete removes the block. See Editing an image.

  • Images can be pasted. Pasting a copied image, a screenshot or an image file onto a document adds an image block at the end with its editor open, and into an empty paragraph it becomes an image block there. Pasted into text that's being written it goes in as a block under that text, which offers Move into the text: pointing at the button shows a second caret where the image was pasted, and clicking it swaps the block for an embed there, ![[assets/name.png]]. Dropping an image file on the editor does the same. The image block's form has a Choose… button beside src and takes a dropped or pasted image too. The files go into assets/, screenshots named after when they were pasted, and the same image pasted twice is kept once. An image block with no src yet says so instead of showing a broken picture. POST /api/asset is new. See Pasting images.

  • With an image selected, Cmd+C and Cmd+X (Ctrl elsewhere) copy and cut it. The clipboard holds the picture, for other apps, and the block's markdown, which pastes back into Plicine as the same block without saving the file twice.

  • Cmd+Z and Cmd+Shift+Z (Ctrl+Z, Ctrl+Y) undo and redo changes to the document as a whole: blocks added, moved, deleted or edited, images pasted, text saved. It's one line through every editor: in text being written the keys undo the typing first and then carry on into what was saved before, from whichever paragraph, table or block. It used to work only inside text being written, and stopped there. See Undo.

  • An image block takes a height and a fit, and no longer a width. How wide it is comes from the block's width (narrow, normal, wide or full), like any other block. contain shows the whole picture, at its own size or at the height; cover, fill and none fill the block's width, and a height then crops the picture, stretches it or crops it at its own size, so a full-width block with cover and a height is a banner. The editor on the image has the block's width, a height field, a grip on the picture's top and bottom edges to drag the height in steps of 50 pixels, the picture easing to each, and four icon buttons for the fit; its left, centre and right buttons are icons now too. A width: still written in a block is ignored. See Editing an image.

  • The editor on an image saves as you go and has no Done button. A button, a drag or a new picture is written at once, typing when you pause. Cmd+Z (Ctrl+Z) takes a change back with the editor still open; Enter, Esc or a click away closes it.

  • Dragging an image's picture moves the block, as dragging its handle in the margin does. A click without a drag still opens its editor.

  • An image set to full width at the very top of a document is a header image: in the infinite layout and on an exported site it runs up to the top of the view and out to both sides. See image.

  • Text being edited in place hides its markdown until the caret gets to it. The ** around bold text, a link's brackets and address, backticks and [[ ]] show, faintly, only while the caret or the selection is in or beside that text, and a heading's # and a callout's [!type] only while it's on their line, so an element being edited reads as it does on the page. A list's marker, a rule and a code sample's fence still show, and a table's markdown shows everything so its columns line up. Table cells work the same way. While the mouse is selecting, nothing appears or hides until the button comes up, so the text doesn't move under the pointer.

  • Opening a paragraph for editing no longer reflows it. The editor wrapped a word to the next line when the space after it didn't fit, which the page doesn't, and a line holding inline code came out a pixel taller than on the page, so a long paragraph crept down as it opened. Both match the page now, in table cells too.

  • Text opens for editing as the mouse button goes down on it rather than on the click. A drag that starts on a paragraph that isn't being edited selects in the editor as it opens, so typing straight away replaces what was selected; a table's cells take a drag the same way. Blocks still open when the button comes up. Dragging across the page's text to select it without editing needs a modifier key held now.

  • The bar with Cancel and Save under text being edited floats over whatever comes next and takes no room on the page, so opening an editor moves nothing below it. In the paginated layout, a paragraph opened with Enter at the end of an element now appears under that element; it was drawn where the editor had last been, over the element's first line.

  • A document gets the theme's cover page only when its frontmatter says cover: true. Until now every paginated document and every PDF had one unless it said cover: false, which put a title page in front of notes and one-page documents that never wanted it. Add cover: true to the documents that should keep theirs; a cover: false already in a file does no harm and can go.

  • The built-in theme no longer assumes a client. Its cover and footer read title, subtitle, type, author, date and an optional organisation, and nothing else. The cover's "Prepared for" line and the footer's "Prepared for … ·" are gone, along with the cover's reference, and author is labelled "Author" where it said "Contact". A list of authors prints with commas between the names. A document that set client or reference keeps the keys, which now show nowhere in the built-in theme; write the line as the subtitle, or use a theme of your own, to keep it. PDFs of such documents change. Plicine is for one person's documents as much as a company's, and the docs now say so.

  • Exports say where they were made. A PDF in the built-in theme ends with one small line at the foot of its last page, "Made with Plicine · plicine.com", linked to https://plicine.com/?ref=pdf. It's there once, never on the cover or in the running footer, and it never adds a page: it's placed after the pages are laid out, below the link and QR code when there are any. A site made with plicine export-site has the same line under every page, linked to https://plicine.com/?ref=site. A new credit key turns it off, "credit": false in .vault/vault.json for the whole vault or credit: false in a document's frontmatter for one document, frontmatter winning. It's on by default and turning it off is free. Custom themes don't carry it: a theme opts in with "credit": true in theme.json, which only the built-in theme sets, so documents in the Solunify Creations theme print as before. The infinite layout in the app doesn't show it. A document in the built-in theme exported before this change gains the line when exported again, which changes its bytes unless credit: false is set. GET /api/doc gains credit, GET /api/theme gains credit, and the PDF cache key includes it.

  • Exporting a PDF again after changing values or publicUrl in .vault/vault.json, or the frontmatter of a folder's INDEX.md, renders it again. The render cache's key left out the merged {{placeholder}} values and the document's link, neither of which is in the document's own text, so the export came back from the cache with the old cover, header, footer or QR code. Both are in the key now.

  • The agent palette never takes more than two fifths of the window's height (or a third, whichever is more). The conversation scrolls inside it; the header and the message box keep their size.

  • Folders pass values down. The frontmatter of a folder's INDEX.md sets {{placeholder}} values for every document below it, between the vault's values and each document's own frontmatter, and a folder further in adds to or overrides its parents' key by key. Keys that set up the page itself, such as title and theme, stay the page's own. A folder's values are set in its page's frontmatter, in Source view. The theme's cover, header and footer, templates' defaults in the app and in plicine template, and GET /api/doc's values all read the folder layers.

  • Values for {{placeholders}} can be set for the whole vault and per document, in that order. .vault/vault.json takes a values object, and a document's frontmatter goes over it, objects merging key by key. The theme's cover, header and footer read the merged values, so an organisation's name or a default author can be set once for every document. Filling a template uses the vault's values, then the template's own frontmatter, then the data passed in: those fields become optional, plicine template fields shows their defaults, the schema and example carry them, and the app's form starts from them. GET /api/doc gains values.

  • The agent primer, and so AGENTS.md, explains placeholders, templates and value layers, lists the keys the vault's values set, and gives plicine template fields and plicine template apply, telling the agent to fill a template with the command rather than copy it by hand.

  • The sidebar can be resized by dragging its right edge, between 200px and 480px, and never so wide that the document has less than 480px. The arrow keys move the edge when it has focus and a double-click puts it back to 250px. The width is remembered per vault next to the block panel's, so GET and PUT /api/sidebar carry an optional sidebarWidth. In a window narrow enough for the sidebar to be a drawer, the edge isn't there.

  • The sidebar's menus can duplicate. A document's menu has Duplicate, which writes name (Copy).md beside it, with (Copy) on its title too, and opens the copy, and a folder's has Duplicate folder, which copies the folder with everything in it. In the desktop app, documents, folders and the vault name also have Show in Finder, or Show in File Explorer on Windows. POST /api/duplicate and POST /api/reveal are new.

  • Templates. A document with {{placeholders}} in Mustache syntax can be filled in to make a new document: {{client.name}} for a value, {{#items}}…{{/items}} to repeat table rows, list items or whole blocks for each item of a list, {{^signed}}…{{/signed}} for when a value is missing or false. In frontmatter and block props a placeholder that is the whole value takes the value with its type, so a block's rows can come in as a real list. Code, fenced or inline, is left alone. A Template badge in the sidebar marks such a document, since the documents made from it tend to share its name. Use template in the top bar opens a form built from the placeholders and writes the result as a new document. On the command line, plicine template fields lists what a template needs and prints a JSON Schema and an empty example of its data, and plicine template apply fills it from JSON, an array or JSON Lines (one document per record, named by an --out pattern), --set flags or stdin, checking every record before it writes anything. That JSON is the contract for adapters that feed templates from a spreadsheet or another system. GET /api/doc gains template, and GET /api/template and POST /api/template/apply are new. See Using templates.

  • The top bar runs across the whole window to the right of the sidebar, and a block's panel opens under it rather than beside it from the top of the window. Its buttons get the panel's width too, so they no longer run out of room and slide under the panel.

  • A block's panel can be resized by dragging its left edge, between 320px and 900px, and never so wide that the document has less than 320px. The arrow keys move the edge when it has focus and a double-click resets it. The width is remembered per vault in app data, next to the open folders, so GET and PUT /api/sidebar carry an optional panelWidth now.

  • A block's form no longer shows a vertical scrollbar on a table that has room for all its rows. Where scrollbars take up space, macOS set to always show them for one, the desktop app sized the table's box without its sideways scrollbar, which then covered the last row.

  • The paginated layout keeps its place when the window is resized. As the pages scaled to fit, the scroll position stayed the same number of pixels, so the view landed somewhere else in the document.

  • The app fits narrow windows and phones. Below 1000px wide the sidebar becomes a drawer, opened from a new button at the left of the top bar or with a swipe from the left edge, and when the top bar runs out of room the theme selector and Export PDF move into a menu behind a three-dots button. Below 920px a block's panel opens as a sheet from the bottom that can be pulled up to fill the screen, with the block scrolled into view above it. Below 720px the top bar keeps only the title, with every control in that menu, and the bar under text being edited drops its shortcut hint and grows to a size a finger can hit. On touch screens nothing is shaded on hover, keyboard hints are left out and the sidebar's rows are taller. The desktop window's smallest width goes from 900px to 920px, the last width with the panel beside the document, so the sheet and the phone layout only show in a browser. The window itself no longer scrolls: only the document, the sidebar and a block's panel do, so scrolling one of them past its end can't carry the whole app with it. See Narrow windows and phones.

  • Folders in the sidebar no longer carry a folder icon: the chevron and the name are the row. Clicking a folder whose page is already open closes the folder in the tree, and clicking it again opens it, so the name works like the chevron once the page is showing. The first click still opens the page.

  • With a block's panel open in a narrow window, the top bar's controls no longer spill over the panel's title. They pass behind the panel instead, and Export PDF no longer wraps onto two lines.

  • A block's panel closes when anything else on the page is opened for editing in place, a paragraph or another block's markdown. It used to stay open showing the earlier block's form.

  • The bar with Cancel and Save under text being edited in place folds down from under the text as the editor opens, like a flap hinged along its top edge, and folds back up when the editor closes, instead of appearing and vanishing at once. It hangs from the text's bottom edge now, at the left, rather than 12px below it at the right. Hovering an element shades that edge in the accent, from its bottom-left corner, in place of the thin line in the left margin. Reduced motion skips the folding.

  • The gantt reference block (1.1.0) fills the width it's given, so setting it wide or full makes the chart wider on screen and on the pages. Its width field is gone; a width: line in an existing document is ignored. The lettering scales with the chart. The agent primer and Writing a block now say a block should lay out to the width it's given rather than a size of its own.

  • A block can be wider or narrower than the text. Ending a fence's first line with {width="wide"} or {width="full"} widens it, {width="narrow"} makes it a fixed 400px against the usual 680px column, as much narrower as wide is wider at its widest, and pointing at a block shows a Narrow, Normal, Wide and Full control on its toolbar that writes the attribute for you; the block's panel has the same control, in both layouts. In the infinite layout and on an exported site, full takes the width the document scrolls in and wide goes halfway there, up to 960px. On the pages and in PDFs, wide reaches halfway into each side margin and full goes out to 6mm from the edge of the sheet. Changing it rewrites only that line, and to any other markdown tool the fence is still an ordinary code block, since they read only the first word as the language. Code samples written the same way widen too. A package block's frame follows the width, and a block's markdown opened in place keeps its width while it's edited. A table, an image or a paragraph takes the same attribute in a comment on the line above it, <!-- {width="wide"} -->, which GitHub, Obsidian and Pandoc hide as an ordinary comment and Plicine hides too; opening one for editing puts the same control in the bar under the editor, and emptying the element removes its comment. A width comment with nothing directly below it shows faintly as its text, in the app only, so it can be clicked and deleted. Themes can set --fx-width-wide, --fx-print-wide-outset, --fx-print-full-outset and --fx-print-edge.

  • A table's markdown, opened with Edit as markdown, takes the full width in the infinite layout through the same rule as a full-width block rather than a script measuring the pane. It looks the same as before.

  • The sign-in cookie no longer holds the session token. A browser sends 127.0.0.1's cookies to every port on it, so any other local web server you opened in that browser received the token and could use it to change the vault. The cookie now holds a separate value that only opens the app's pages, their scripts and files in assets/. The token goes from the sign-in link into that tab's session storage, and the app sends it as a header on every API call. The live update socket carries it in its URL, and Export PDF in a browser opens a link that works for that document for five minutes. A tab opened by typing the address instead of following the link isn't signed in, and says so. Agents aren't handed the token any more either: Plicine's MCP tools take the agent's own secret alone.

  • A symbolic link inside a vault is no longer followed. A link to a document, a folder or an asset outside the vault used to let Plicine read, write, move and delete files there, and serve them from /_vault/, which matters for a vault shared through a sync client. Any path that passes through a link below the vault root is now refused, as are links to somewhere else inside the vault, which the sidebar never showed anyway. The search index skips documents behind a link, and plicine export-site leaves such files out with a warning. Opening a vault through a link still works.

  • A file in a vault's assets/ can no longer run as a page on the local server. An .html or .svg file that a document linked to opened on the app's own origin when clicked, where its script could read the session token and call the API. Every /_vault/ response now carries Content-Security-Policy: default-src 'none'; sandbox and X-Content-Type-Options: nosniff. Images keep their type, so images in documents, the paginated layout and PDFs look the same as before. Opening an SVG as a page downloads it, and so does every other file that isn't an image, HTML and PDF included, sent as application/octet-stream.

  • Tables are edited as a grid. Clicking a markdown table opens its cells in the page's own type instead of its pipes and dashes, each cell showing its markdown the way the text editor does, markup faint and bold in bold: type in a cell, Tab and Enter to move on (past the last cell they add a row), the arrow keys to cross into the next cell at the edge of one, and Backspace in an empty row to take it out. Hovering a row or a column shows a pill-shaped handle whose menu inserts, moves or deletes it, and a column's menu sets its alignment. Pointing at the line between two rows or two columns in the margin, or anywhere along the bottom or right edge, shows a green insert line with a + that adds one there, cells copied from a spreadsheet paste in as cells and grow the table to fit, and Cmd+Z/Ctrl+Z undoes a step at a time. Every change is written back as a tidy markdown table, each column padded to its widest cell so the pipes line up in the file. Edit as markdown in the editor's bar switches to the text, tidied and in a monospaced font so the columns line up, one line per row scrolling sideways; Edit as table switches back, and a table saved from its markdown is tidied as well. Table in the add-block list and the / menu adds a markdown table with two columns and one empty row, its first heading selected.

  • The table core block is gone. A markdown table does everything it did, and a caption is a paragraph under the table. A fence still named table is now an unknown block, and plicine validate, and the block's Unknown block badge on hover, say to write a markdown table instead. The name isn't reserved any more, so a package can take it.

  • An agent no longer starts in the vault folder. The Claude Code and Codex entries fall back to npx -y, and npx runs a package from the node_modules of the folder it starts in before asking npm, so a shared vault carrying its own copy of an ACP adapter could get that copy run as you, with nothing to see, since the sidebar hides node_modules. Every agent process now starts in an empty agent-cwd/ folder in app data, and the vault reaches the agent as the session's folder, which is where agents that follow the Agent Client Protocol already worked, so what an agent can do once it's running is unchanged. Agent commands are also looked up only in PATH's absolute folders, so a relative entry such as node_modules/.bin can't find a copy inside a vault the server was started from.

  • A new workspace package, @plicine/site in site/, holds the landing page for plicine.com: one static page, compiled by bun run site into site/dist, which is the folder that goes up to the web host by hand. The page is written in TypeScript and styled with Tailwind over the brand's own tokens, and it ships the built-in theme's Newsreader and Instrument Sans as woff2 rather than pulling them off a font service. Four pictures under the headline are real: bun run site:screenshots builds a throwaway lorem ipsum vault, drives the app with Playwright the way the scenes in test/visual do, and exports a PDF with plicine export-pdf to render the cover. bun run site also exports these docs into site/dist/docs with --strict and fails on any link on the landing page that leads nowhere, so the one folder is all of plicine.com. The Docs site workflow is now the Site workflow: it runs bun run site:validate and uploads site/dist as the site artifact, where it used to export the docs into site/ itself. site/README.md has the rebuild and upload steps.

  • PDF export no longer needs a browser installed. If it can't find Chrome, Chromium, Edge or Brave, the first export downloads a pinned chrome-headless-shell build from Chrome for Testing into chrome/<version>/ in the app data folder, about 100 MB, once per machine, showing progress in the app and in plicine export-pdf. The archive's SHA-256 is pinned for each platform alongside the version and checked before anything is unpacked; one that doesn't match is deleted and the export fails. The order of preference is PLICINE_CHROME (or PUPPETEER_EXECUTABLE_PATH), then the downloaded renderer, then an installed browser, and nothing is downloaded while one of those answers. plicine chrome status, plicine chrome download and plicine chrome remove manage it by hand; status exits 1 when there's no renderer, for scripts. A failed download names the folder it tried to write and points at PLICINE_CHROME.

  • A conflicted copy from a sync client is handled as one, instead of showing as a second document. Plicine reads the names Dropbox, OneDrive, iCloud Drive and Google Drive give a copy (quote (conflicted copy).md, quote-COMPUTERNAME.md, quote 2.md, quote (1).md), and treats the two numbered ones as a conflict only when the copy reads differently from the document beside it. A copy sits under that document in the sidebar, marked "Conflict", and the folder's count leaves it out. Opening the document shows a bar: Keep mine deletes the copy, Keep theirs writes the copy over the document and then deletes it, and Open both opens the copy, which carries the same bar with a way back. Both deletions ask first, nothing is ever merged, and keeping theirs is refused if the document changed after the bar appeared. GET /api/vault now reports conflicts, and POST /api/doc/conflict does the work. Sharing a vault has the names and the exceptions.

  • Search and backlinks. The sidebar has a search box, on Shift+Cmd+F or Ctrl+Shift+F, which looks through every document's title, headings, text, block names and block props, and its path. Results show a line of text around the match with the words marked in it, and where it was found; clicking one opens the document scrolled to the element that matched, in both layouts, with a brief tint on it. Under every document is a Linked from list of the documents that link to it, counting [[wikilinks]], markdown links to a .md file and links inside a block's markdown, hidden when nothing links there. It belongs to the app rather than the document, so it never reaches the printed pages or a PDF.

  • The server keeps a search index per vault in vaults/<vault-hash>/index/documents.json in the app data folder, built as it starts and updated a document at a time from the folder watcher, renames and deletions included. A document whose file hasn't changed since it was indexed isn't read again. GET /api/search and GET /api/backlinks answer from it.

  • Your agent gets three tools from Plicine: validate_doc checks a document and answers with the same JSON as plicine validate --json, render_preview gives back PNG images of the pages as they print, so a block's Print output stops being guesswork, and pack_block checks a block checkout and writes it into the vault, refusing rather than packing anything broken. A block packed this way still waits for your approval. The Agent Client Protocol has no way to hand an agent tools, so Plicine runs a small Model Context Protocol server on its own local server, behind the session token and a secret of its own, and names it when it opens a session. An agent that doesn't speak MCP over HTTP carries on without them, and the agent menu says which tools a session got.

  • An opt-in AGENTS.md at the vault root gives an agent working from a terminal the same primer the palette sends, with Plicine closed. Turn it on with Write AGENTS.md in the agent menu or plicine agents-md <vault> --write, which sets agentsMd in .vault/vault.json; --remove turns it off and deletes the file. It's rewritten only when its content would actually change, the way blocks.lock is, and an AGENTS.md you wrote yourself is never overwritten. It isn't a page: it stays out of the sidebar and out of [[link]] resolution, and Plicine's own write to it doesn't register as a document changing.

  • Vault and document validation moved out of the CLI into packages/core/src/validate.ts, so plicine validate, the check plicine block push runs before writing, and the new validate_doc tool all report the same problems in the same shape.

  • plicine export-site <vault> --out <dir> writes a whole vault out as static HTML: one page per document in the infinite layout, in the theme's own CSS, with every block's Print output already in the page, a sidebar tree of the vault beside it, and every link relative, so the folder reads the same opened from file:// as it does from a web host. INDEX.md becomes index.html at each level, a folder without one gets a page listing what's in it, assets/ and anything else a page points at come across, and nothing is written into the vault. No browser is involved: the pages render in the CLI process, a block runs only if it's approved on that machine, and its Print HTML is stripped of anything that could run, load or take input. Two exports of one vault are the same folder byte for byte. These documents are the first site: a new Docs site workflow exports them on every push to main and uploads the folder, and publishing it to plicine.com is a manual step for now.

  • Enter starts a new paragraph. What sits after the caret moves into it, and at the end of an element it opens an empty paragraph that isn't written until you type in it. A list, a quote, a table and a code sample carry on as they did, and Shift+Enter is the line break inside an element. Backspace in an empty paragraph takes it out and carries on at the end of the element above, or opens that block's form.

  • Writing works more like Notion. Clicking below the last element, or anywhere on a blank page, starts a new paragraph at the end (after the last element on that page, in the paginated layout). Typing / at the start of an empty line in the editor opens the add-block list under the slash: keep typing to filter it, pick with the arrow keys and Enter, or press Esc to keep the slash as text. A text choice turns the line into that markdown, a block with a form goes in with its defaults and opens in its form, and a card opens as an empty fence to type into. An empty editor says to type /, and a new paragraph left holding only markup (## , - ) adds nothing. Text being edited in place no longer has a green ring around it, and a block open in its form no longer has a green outline; a ring only appears when a save fails. Hovering a paragraph or a block shows a thin green line in the margin to its left instead of an outline around it, in both layouts, and nothing on the page shifts when it appears. It shows while an editor is open too. In the paginated layout, an editor taller than what it's editing (a callout with its title line, a card's fence, a paragraph that grows) pushes the rest of the page down instead of covering it. Clicking another paragraph or block while one is open saves the first and opens the second with a single click, in both layouts; it used to take two.

  • Switching documents in the Document view animates. The page stays on screen while the next document loads underneath. If that one is ready within 150ms the page fades into it; otherwise the page turns back on its left edge and the next one turns in once it's ready, which in the paginated layout means once its pages are laid out. Reduced motion skips it. While a document loads, the top bar's title and controls wait for the document and its theme's colours and then fade in together, and "Loading…" or "Laying out pages…" shows, centred, only when loading takes more than a moment. In the desktop app on macOS, a paginated document's pages no longer show through the sidebar while they lay out, and no longer jump sideways or flash a scrollbar as they appear.

  • The desktop app remembers which folders are open in the sidebar. They were kept in localStorage, but the desktop app's server takes a new port every launch, which gives the page a new origin and empty storage, so every folder came back closed. The server now keeps them per vault in vaults/<vault-hash>/sidebar.json in the app data folder, read and written with GET and PUT /api/sidebar. Folders saved in a browser's localStorage before this aren't carried over.

  • A children core block lists the pages below the one it's on, as links. On a folder's INDEX.md that's everything in the folder; on any other document it's the folder with the document's name, so plans.md lists plans/. Subfolders come first, as in the sidebar, and depth reaches further down. Every row is a link, a subfolder opening its INDEX.md as it does from the sidebar, and a subfolder with pages under it folds with an arrow; collapsed: true starts them folded. The list is read from the vault whenever the page renders, in the Document view, the paginated layout and PDFs.

  • steps isn't a core block any more. A vault that uses it needs a steps block package of its own. The .fx-steps class hooks are gone from doc.css and from both themes.

  • The agent palette's first-run note stays dismissed. The desktop app showed it on every launch, because its server takes a new port each time, which gives the page a new origin and empty localStorage. The server now keeps the dismissal in agent-palette.json in the app data folder, set with POST /api/agent/coach.

  • The sidebar can make documents. The vault name's menu and every folder's menu have New document above New folder: type a name, press Enter, and the document is written as <name>.md with the name as its heading, then opens. A name that's taken, or that a folder couldn't have either, is explained under the box. POST /api/doc does the writing and refuses to overwrite a file.

  • A folder is a page. Clicking a folder in the sidebar opens its INDEX.md (index.md works too), the way a page with children opens in Notion, and the chevron in front of the name is what opens and closes the folder. A folder without one opens as a blank page; the file is written into the folder the first time something is put on the page, and until then nothing touches the disk. A folder's INDEX.md no longer shows as a row of its own inside the folder, the folder's count leaves it out, and the folder's menu gets Delete page while it has one. A blank page in the Document view says so and starts a paragraph when clicked. A folder's INDEX.md with no title of its own is named after the folder rather than "INDEX".

  • The print cover starts at the top of the page. The organisation line comes first, then the kicker, title, subtitle and "Prepared for", then the date, reference and contact row straight under them, and the rest of the page is left empty, in both the built-in and the Solunify Creations themes. Before, the title block was pushed to the foot and most of the page sat empty between the organisation line and the title. In the built-in theme, a document without organisation no longer keeps a blank line for it at the top.

  • Editing markdown in place happens in the page's own type instead of a monospaced text box. A heading stays a heading and a quote keeps its bar, the markdown shows faintly where it sits (##, **, -), and the caret starts where you clicked. Enter continues a list or a quote. The editor measures a hidden copy of the element rendered by the theme, so every theme works with it in both layouts, and save and cancel sit in a small bar below the text rather than a panel around it.

  • The Solunify Creations theme sets bold at 600 wherever its type is Playfair Display: # and ## headings, pull quotes and a quote callout's body. It asked for 500 there, which Playfair doesn't ship, so bold fell back to the regular face and didn't show.

  • The agent primer says how blocks are drawn, so an agent stops proposing things the sandbox rules out. Interactive runs in a frame sized to its content, and a tooltip or popover the block draws can't spill past it; browser storage, nested frames, workers and popups are blocked, and so is the network without the capability; only the modules Plicine provides can be imported without a lockfile; and the paginated layout and PDFs use Print as sanitised static HTML, where hover and clicks do nothing. The provided modules and the tags stripped from Print HTML come from the constants the compiler and the sanitiser use.

  • scripts/pack-vault.ts removes the .block and .theme files it didn't pack from docs/ and test/fixtures/vault, printing a removed line for each, before it refreshes blocks.lock. A block or theme whose source folder is deleted no longer leaves its archive in every checkout, where the agent palette's primer would still hand its BLOCK.md to your agent. Other vaults keep every archive unless you pass --prune.

  • Obsidian [[links]]: name a document instead of its path, with | for the text to show and # for a heading. Resolution follows Obsidian's, nearest match first and case-insensitive, .md optional, and a link that matches nothing renders grey and dotted rather than as a working link. ![[chart.svg|420]] embeds an image from assets/. Links work the same in a document's own text and in a block's markdown, on screen, in the paginated layout and in PDFs, and plicine validate warns about the ones that match nothing. GET /api/doc now carries the vault's linkable files, and the watcher's changed event says when that set changed.

  • The agent palette: a bar at the bottom of the document that opens a conversation with your own coding agent over the Agent Client Protocol. It finds Claude Code, Kiro, Gemini CLI and Codex on PATH and takes any other agent from agents.json in the app data folder. It shows the agent's plan, tool calls and reply as they arrive, queues follow-ups, lists Plicine's commands and the agent's slash commands under /, switches the agent's mode and model, remembering the model you pick for each agent, and asks you about anything the agent wants permission for, with a diff for edits. A conversation's first message carries a short primer about the vault and a link to the open document. An agent that isn't signed in, or whose login expires mid-turn, gets a card offering to sign it in, either over the protocol or by opening a terminal on its own sign-in command. Cmd+K or Ctrl+K opens it, clicking the document folds it, the agent's name and status sit at the foot of the sidebar, and a note points it out once. The desktop app adds View > Agent Palette.

  • The server runs the agent as a child process in the vault folder and pushes the conversation to every tab as agent events, with GET /api/agent and POST /api/agent/* to drive it. Which command runs comes only from the built-in list and agents.json, never from a vault. Tests drive a scripted ACP agent through a real server.

  • The agent primer now carries what an agent needs to work with blocks: the core blocks' props, generated from their schemas; every block package the vault can use, with its version, where it came from, whether you've approved it and its BLOCK.md; and the plicine commands for checking documents and for checking out, pushing and inspecting blocks, naming the command that runs this build. It also tells the agent that approving blocks is yours to do.

  • The code uses the product's name, Plicine: the @plicine/* packages, the plicine command, PLICINE_DATA_DIR and PLICINE_CHROME, the x-plicine-token header, globalThis.plicine.storage for blocks, the app data folder (~/Library/Application Support/plicine on macOS) and the desktop identifier uk.co.solunify.plicine. Nothing moves across by itself. Trust decisions, the library, block storage and recent vaults stay in the old folders until moved by hand, and the old packages/ and inline/ caches shouldn't be moved at all, since blocks compiled there look for the old global.

  • The built-in theme is Plicine's own (2.0.0, still id default): a cream page, ink text, kraft hairlines and pleat green #0f6e64 for links, kickers and emphasis in titles. Titles and ## headings are Newsreader, body text and labels Instrument Sans, both static fonts under the OFL. It now has a cover page with a band of pleats along the foot, a footer with the title, client and page count, and the same markdown mapping as the Solunify Creations theme: standfirst, kickers, pull quotes, and restyled callouts, cards and steps.

  • The app's interface, the desktop launcher and the app icon use the same palette. The icon is a strip of paper folded into four pleats on a green tile. In dark mode the accent lightens and text on accent buttons turns dark, since white on the lighter green was unreadable.

  • The built-in theme's fonts are type: "file" imports, which bun build --compile embeds in the desktop sidecar, so builtinTheme() is async.

  • The Solunify Creations theme ships Playfair Display in a 600 italic, so emphasis in a title (for *Lorem Ipsum Ltd*) uses a real face instead of one the browser fakes from the 400 italic, which came out too thick and looked doubled. Headings also turn off weight synthesis, so a missing face renders at the nearest real weight rather than a fake bold.

  • An item of a columns block fills its row, so cards in a row share one height however much text each holds. stagger: true deals the items into one stack per column instead: every column starts at the top, each item is only as tall as its content, and the columns end ragged.

  • A markdown field is a small page editor: a columns item, a callout's body or a step's detail renders as it will look, an element opens for editing where it sits, and a + between elements adds text or a block, so a card is built inside a column the same way anything is built in a document. Markdown shows the raw text and Expand opens either in a modal. A list of markdown items shows one editor per item, with reorder and remove. Markdown fields are tagged contentMediaType: "text/markdown" in the JSON Schema the form is built from.

  • Obsidian callouts: a quote starting with [!note], [!warning], [!quote] and the rest of Obsidian's types (aliases included) renders as a coloured box with an icon and a title, on screen and in print; + and - make it collapsible, and clicking a folded callout's title opens or closes it rather than starting an edit. The new callout core block is the same thing as YAML, with a form.

  • Core blocks have ids in the reserved @core scope (@core/toc, @core/callout), usable in fences, vault.json aliases and frontmatter pins; manifest.json and create-block refuse the scope.

  • card, columns and steps are core blocks now, compiled with the app. card is markdown in a box: its fence body is markdown, like a ts-block's is code, and it has no form. columns is a grid of markdown items, filled row by row or column by column. Markdown inside any core block can hold fenced core blocks, so a grid of cards is a columns block whose items are card fences, which replaces @solunify/cards. @solunify/terms is gone: its two-column run is a columns block and its note box is the new @solunify/note reference package, which looks exactly as it did. Text fields are markdown; the Solunify theme restyles the core blocks through class hooks. Core blocks are one module each under packages/app/src/client/blocks/core/, exporting Interactive and Print like a package block.

  • Four screenshot scenes cover callouts (light and dark) and the layout blocks in both layouts.

  • Blocks in the Document view no longer sit on a white box in dark mode. The app's color-scheme: light dark left each block's iframe dark while the frame document inside stayed light, and browsers paint an opaque canvas behind a frame when the two disagree. Block frames are now pinned to color-scheme: light.

  • A newline inside a paragraph renders as a line break, on screen and in PDFs, instead of folding into a space. Enter in the in-place editor puts the next line on its own line; a blank line still starts a new paragraph. A paragraph hard-wrapped in another editor now shows those wraps. Screenshot tests cover the line break in both layouts.

  • Screenshot tests (test/visual.test.ts) compare six screens of the app with PNG baselines in test/screenshots/ and fail on any changed pixel, leaving the new screenshot and a diff in test/screenshots/failed/. bun run test:visual:update re-records them; committing the new PNGs puts the before and after in the pull request.

  • The sidebar can make folders and delete documents and folders, from a three-dots menu on each row (and one on the vault name for top-level folders). Deleting asks first and doesn't go through the trash. Folders with no documents now show in the tree. /api/vault lists folders, and POST /api/folder, DELETE /api/folder and DELETE /api/doc do the work.

  • The Read and Print views merged into one Document view with an Infinite/Paginated switch. A document's layout (infinite, the old Read, or paginated, the old Print, now editable) is a frontmatter key, with a vault-wide default in .vault/vault.json; clicking Infinite or Paginated writes it for you. Old ?mode=read and ?mode=print links open the Document view.

  • Markdown is editable in place, in both layouts: click a paragraph, heading, list, quote, table, rule or plain code block to edit its raw markdown, and click a block to open its form or, without one, its fence as markdown. ts-block code, YAML errors and unapproved or unknown blocks no longer need Source to edit.

  • Resting the pointer between two elements shows an Add block line. It opens a searchable picker of text elements (paragraph, heading, lists, quote, code, divider), the built-in blocks and the vault's installed blocks, and adds the choice at that spot with blank lines around it. /api/vault now lists installed blocks, and POST /api/doc/insert does the writing.

  • Vault config, blocks and themes moved under .vault/ (.vault/vault.json, .vault/blocks/ with blocks.lock alongside, .vault/themes/); a vault from before .vault/ is left alone with a warning rather than migrated automatically. Documents always live at the vault root now, and an INDEX.md there is the vault's front page: shown first in the sidebar and opened automatically instead of falling back to the first document.

  • The Solunify Creations theme (2.0.0) follows the Solunify Creations brand: Playfair Display, Inter and Manrope, warm charcoal on paper, terracotta accents. Its typography moved to type.css, imported from tokens.css so the Read view and print share one file, and plain markdown now maps onto its document components: standfirst, numbered section labels, pull quotes. The footer carries "Page n of total", density: compact in frontmatter tightens the printed type, the header template is gone, and the logo is outlined paths rather than a wordmark set in Helvetica.

  • The Print preview shows a theme's @page background. It used to paint every page white over it, so only the exported PDF had the right colour. The preview also sits on the same backdrop as Read in light and dark mode, and its pages have 4px rounded corners on screen; exported PDFs keep square corners.

  • New reference blocks for Solunify Creations documents: @solunify/cards, @solunify/steps, @solunify/terms and @solunify/gantt.

  • The sidebar shows documents as a folder tree, with document counts, open folders remembered per vault and the current document's folders opened automatically.

  • Desktop app (packages/desktop): a Tauri 2 shell with a launcher, recent vaults, a native folder picker and menus. It runs the server as a compiled sidecar (plicine open --desktop), keeps native commands away from vault pages and saves exported PDFs to Downloads.

  • The built-in theme and print-base.css are embedded in the code instead of read from disk, and the server can use prebuilt browser bundles.

  • Sign-in links return a small page that sets the session cookie and moves on, instead of a 302. Browsers withhold a SameSite=Strict cookie set on a redirect when the navigation started on another site, which left the desktop app on the 401 page. PDF export sets the cookie in headless Chrome directly.

  • A vault opens on its index.md or README.md when it has one, rather than the first file alphabetically.

  • On macOS the desktop window has no visible title bar: the page fills the window, the window buttons float over the sidebar, and the top bar, sidebar strip and panel header move the window. Vault pages are granted only the window drag and zoom permissions this needs.

  • Native controls follow dark mode: the app declares color-scheme: light dark, and the theme selector and buttons take the app's text colour instead of the browser's black.

  • vault.json has a title (replacing name), shown in the sidebar, the browser tab and the desktop window title, and in the launcher's recent vaults. It falls back to the folder name, updates live when vault.json changes, and an old name key produces a warning.

  • Documentation moved into docs/, which is now a Plicine vault opened with bun run docs.

  • The example vault moved to test/fixtures/vault; scripts/build-example.ts became scripts/pack-vault.ts, which defaults to docs/.

  • Image paths resolve correctly in vaults whose markdown sits at the root rather than in docs/.

  • Code fences whose content isn't valid YAML (ASCII diagrams, for instance) no longer print as error boxes in PDFs.

  • Approvals made with plicine trust while the app is running now show up on the next document load.

  • The Chrome lookup error names the environment variable that actually pointed at a missing file.

  • Removed the unused themes and build entries from the app data paths.

  • The trust prompt says "changed since you approved" when a block's content changes without a version bump.

0.1.0 (12 September 2026)

First version: the Phase 0 slice and most of P0.

  • Vaults: folder layout, vault.json, plain folders of markdown, a recursive watcher with 150 ms debounce.
  • Documents: CommonMark with YAML frontmatter, block fences with YAML bodies, exact source line ranges, heading ids, doc links and vault assets, raw HTML escaped.
  • Blocks: .block packages with manifests, deterministic packing, content hashes, resolution across vault, library and community with frontmatter pins, blocks.lock, conflicted-copy detection.
  • Compilation: extraction per hash, dependency install keyed by lockfile with scripts disabled, Bun.build with host-provided React and zod, import containment and a macro ban.
  • Trust: approval per content hash per user, update detection, capabilities for network and storage, placeholders for pending and denied blocks.
  • Sandbox: opaque-origin iframes with per-frame CSP, a MessagePort protocol, worker frames for print, validation and schemas.
  • App: sidebar, Read, Source (CodeMirror with diagnostics) and Print views, theme switcher, trust panel, schema-generated block forms with live preview and minimal-diff saves, conflict detection, live reload.
  • Core blocks: page-break (with named pages), toc (with page numbers in print), image, table, ts-block.
  • Reference blocks: @solunify/quote-table 2.1.0 and @solunify/iso 1.0.0.
  • Themes: .theme packages with tokens, screen and print CSS, cover, header and footer templates; built-in default theme; Solunify Creations theme with static Inter and Source Serif 4.
  • Print and PDF: Paged.js pagination, sanitised block Print output with scoped styles, QR links, headless Chrome export, PDF normalisation for byte-identical output, render cache.
  • Server: local-only binding, session token and SameSite=Strict cookie, Host header check, WebSocket change events.
  • CLI: open, export-pdf (with --frozen and --strict), validate for vaults, docs and block folders (with --json), create-block, pack, trust, lock, install.
  • Tests: 60, covering parsing, YAML patching, zips, resolution, compile containment, form helpers, server access control, sandbox CSP, minimal-diff saves, vault byte-identity and PDF determinism.