- Other repositories. Connecting an assistant used to tie it to one
repository for good. The consent screen now has Also let it use my other
repositories (ticked to begin with): the repository you pick stays the
default, and the assistant uses another when you name it — "add this to my
work repository". A newlist_repositoriestool shows which it can use.
Connections made before this keep to their one repository and say how to
reconnect. - No more notes in random places. A new note goes beside related notes, in
inbox/when you did not say where, or at the top. A folder that does not
exist is refused, with the list of folders there are, unless you asked for a
new one. - It says where. Every write answers with the repository, the full path and
a link to the note, and the assistant is told to pass that on.
Changelog
What changed, and when
Every notable change to ForkLeaf, newest first. 104 changes across 13 releases. The same record lives in CHANGELOG.md, and the commit history is the full one.
- Not yet released
8 changes
Import, at the top of the notes list (or ⌘K → Import Markdown files),
brings.mdfiles into a repository: pick files, pick a folder, or drop them on
the dialog. Choose which connected repository and which folder they go into,
see where each note will land, then import. They come across exactly as
written, with pictures beside them copied too; a name already taken gets a
number, and the dialog says which. Obsidian vaults and Notion exports are the
other two options in the same dialog.The diagram canvas works more like a whiteboard:
- Arrows meet the middle of a side. They used to leave a box wherever the
line between two centres happened to cross its edge. Each now attaches to the
middle of the side facing the other box, leaves it square-on and curves
smoothly into the other — and re-routes as boxes move. Two arrows on the same
side sit a little apart rather than merging. - Lines you can see. Outlines and arrows are drawn close to text colour
instead of in the faint border grey. - Less on screen. The eight labelled shape buttons are a floating bar of
icons at the bottom of the canvas; the strip of eight hints is behind a
?; the four connection dots show only on the box under the pointer or the
selected one; a selected box gets a soft halo. - While dragging a new arrow onto a box, the preview is the connector that will
be made.
Tidy up on the diagram canvas handles loops now. A "No → try again" arrow
used to push the step it returns to below everything else, so the main arrow
into that step ran through every box in between. Loops are drawn as an arrow
going back instead; each row is ordered to cross as few arrows as it can; boxes
of different widths are centred on one line; and bottom-to-top and
right-to-left diagrams are laid out that way round.The diagram editor opens on the diagram alone now, not on a column of Mermaid
source beside it. Diagram, Both and Source at the top switch
between the three — one choice rather than two toggles that could not both be
off.Sign in and Continue with GitHub go straight to GitHub now. The sign-in
page that used to sit in between — two permission cards, each with what it
covers, what it never does and a caveat — is one card with one button. Keeping
to public repositories only is still a link under it, and the documentation
still explains both.Panel, card, field and dialog edges were drawn in a grey barely different from
the background — in the dark theme,#1f1f1fon black — so the layout had to
be found by squinting. Every border is stronger now, in both themes, and the
stronger hairline used for hover and dividers moved up with it.The changelog is a dated timeline now, newest first, at Changelog in every
page's footer — each day's changes beside its date, labelled New, Fixed or
Security. It is rendered fromCHANGELOG.md, which is laid out the same way. - Arrows meet the middle of a side. They used to leave a box wherever the
- 29 September 2026
7 changes
A note or a folder can now be sealed for a list of people, each opening it with
their own key, instead of for one shared passphrase that can never be taken
back. Each person's key pair is made in the browser and the private half is
only ever stored sealed with their passphrase. Fingerprints are checked, and a
reader whose key changes blocks sealing until the change is confirmed.Builds a GitHub Action for the notebook's own repository that counts the days
since anything was written. Two weeks before the limit it opens an issue as a
reminder; at the limit it does what was chosen, once — publishes a folder to
GitHub Pages, and/or opens an issue naming someone trusted. It never deletes a
note, and deleting the workflow file turns it off.Say it instead listens and writes each finished phrase into the answer,
still editable by hand, and the comparison works as it does for typed answers.
Where the browser has no speech recognition, there is no button.⌘K → This note's family finds the notes that share passages with this one —
a meeting note split in three, a draft pasted into the final version — with how
many words each shares and the passages themselves.Where did this paragraph come from? has a second shading, Times
rewritten, marking each paragraph "settled" or "rewritten N×" from the note's
own history.When an edit reverses what a note said — one thing named for another, a
negation put in or taken out — the note's header offers to record why, as one
dated line in the note itself. Typo fixes and rewrites from scratch are left
alone.SecuritySecurity and privacy, tightened
- The assistant consent screen says where access will be delivered, not only
the name a client gave itself. - Server-side fetches are pinned to the address that was checked.
- Rate limits and one-time codes hold across server instances.
- MCP batches and the public badge are bounded; decks publish only into decks.
- Note names are kept out of analytics: addresses are reduced to origin and
path before they reach any analytics service. - CI runs with a read-only token.
- The assistant consent screen says where access will be delivered, not only
- 28 September 2026
10 changes
NewEchoes
One sentence from what you wrote a day, a week, a month and a year ago, on the
dashboard, with one question: is it still true?Every note gets a forgetting curve from the days you open it, and the dashboard
lists the notes you came back to that are fading now. Visits are kept on this
device only.Every time a note is sent to an assistant or the flashcard writer, a receipt
records when, to which provider and model, and how much of which note. ⌘K →
See what the AI has read lists them. Kept in this browser only.Search learns which words keep company across your notes, so "customers
leaving" finds the note about churn. Built in the browser from your own notes —
nothing downloaded, nothing sent.A template with a
schedule— daily, weekdays, weekly, monthly, or a day such
asfriday— makes its note the first time ForkLeaf is open in that period.
Never back-filled, so a month away does not leave thirty empty stand-ups.⌘K → This note, then and now shows the note as it was a month, six months
or a year ago beside today's, with what was added and let go.⌘K → Write this note's map of contents writes a
## Map of contentssection
of ordinary[[wikilinks]]: what the note links to, what links here, and what
shares its tags. Running it again replaces only that section.⌘K → Present this note shows it full screen, one slide at a time, split at
---lines or, without them, at its##sections.$…$inline and$$…$$block maths render with KaTeX in the preview, the split
view and published pages. Prices such as "$5 and $10" stay prices.- Study in one click, and every card option under
/cards. - Make a card from selected text, from a passage in a PDF, or from the
diagrams in a note — or have your own model write them from the note. - Type the answer before seeing it; tap to turn a card over and swipe to grade.
- Schedule with FSRS if you choose it; find the cards that keep slipping.
- A study streak, and a grid of the days you studied.
- Import decks from Anki, and export them back.
- Study in one click, and every card option under
- 20 September 2026
1 change
Next.js and other vulnerable dependencies were patched, and the key the rate
limiter counts by was hardened. - 17 September 2026
1 change
Clicking "1 change stopped trying — click to see why" opened nothing, because
the status bar clipped the panel that opens out of it. The panel opens, wraps
and scrolls again. - 16 September 2026
2 changes
A model in a column beside the note you are writing — Claude, OpenAI, Gemini,
or one on your own machine, with your own key. Open it with ⌥⌘A, the sparkle in
the header, or ⌘K. The open note travels with the question unless you hold it
back, and any answer is one button from being part of the page.- A plan limit is told apart from a busy queue, and failed questions no longer
stack up. - The model picker offers the model that works rather than a list to guess in.
- The assistant can write into the note.
The status bar fits on one line, help explains setting up Claude, and pictures
survive being copied from one note to another. - A plan limit is told apart from a busy queue, and failed questions no longer
- 14 September 2026
1 change
A bulleted list copied from a web page became one "Plain text" code block,
because indentation counted as a sign of code. Lines that read as sentences no
longer do, and pasted HTML with lists or headings is kept as written. - 13 September 2026
39 changes
Connect AI assistant now sits in the editor's bottom bar and opens the MCP
setup for Claude Code, Claude Desktop, Cursor and VS Code; the site footer links
to the MCP guide too. It was only reachable from ⌘K before.⌘K or
/→ What I learned this month writes a journal page from the month's
new notes, flashcard progress and the decisions made in decision blocks and
meetings — ready to add a few thoughts to and publish as a page.A README badge for a notes repository — broken links, stale notes and the
flashcard review streak — served by/api/badgefor public repositories and
added to a note with/→ Notebook health badge. It never shows as a broken
image: a repository it cannot read gets a grey badge saying why./→ Decision lays out options with weighed pros and cons and a score for
each, then keeps the chosen option with a dated history of every choice and
change of mind — as plain lines in a```decisionblock in the note.⌘K or
/→ Check claims in this note underlines, as you write, sentences
that state something nothing in your other notes, saved sources or highlights
backs — and says which note and line backs the ones that are. On per note,
remembered on this device, and the note's text is never touched./→ Map this note builds a canvas of the note and every note it links with
— links out on the right, links in on the left, arrows following each link — laid
out automatically and placed in the note, one or two links deep./→ Hands-free review reads a note's cards aloud, listens for the answer,
says the right one when it was missed, and grades each card — with "repeat",
"skip", "I don't know" and "stop" by voice — for studying while walking./→ Shared deck shares a note's cards as a public GitHub repository
(after asking, and with only the card lines), copies someone's shared deck into
a note, and later pulls in a newer version — adding, changing and removing
cards while keeping any card you rewrote or added. Progress stays private in
your own schedule./→ Course from a folder turns a folder's notes into lessons ordered by how
they link, with an index note first, ticks for what is done, a progress bar and
the next lesson, flashcards counted per lesson, and a quiz at the end drawn from
all of them — in the note, with progress kept in the note's```course
block.With both side panels open, a wide window still leaves a narrow column for the
note, but the header chose its labels by the window's width. Search and All
tools were drawn in full, the last buttons were pushed past the edge, the open
note tabs shrank to nothing, and the whole column scrolled sideways whenever a
button in it took focus. The header now sizes its labels by its own width.A note that ended in a canvas, a flashcard, a spaced-reading block or a diagram
had nowhere to type after it once it was taller than the screen: the space
under the last block belongs to the page around the editor, and clicks there
were never seen. Clicking below the last block now puts a line there, and
clicking below text puts the caret at its end.Highlights were made and never seen again.
/→ Spaced reading puts a
block in the note that brings back a few passages a day — PDF highlights, saved
quotes, and highlights on saved pages — on the flashcard schedule, in your own
repository. Each is sent back soon, later, or never, and says when it returns.⌘K or
/→ Explain it back hides the note where it was and asks for what
you remember of it, then compares the two side by side: each sentence of the
note marked remembered, partly or missed, the words left out named, a score for
the key ideas recalled, and anything written that the note does not support
flagged. Stemmed word matching on the device — no account, no upload.A
Question :: Answerline stayed a line of text, with nothing to say it was a
card or how to study it. It now turns into a card the moment Enter is pressed —
and every such line is drawn as one when a note opens. Click to turn it over,
grade it in place, and it says when it is next due; the grade goes into the same
reviews/flashcards.mdthe review session uses. Edit changes it in place.
The file keeps the plain line. The preview draws the same lines as cards that
open to their answer.Use std::vector hereis no longer read as a card.A canvas made from
/opened in a window over the note and left nothing on the
page, so a diagram you drew could not be seen where you were writing./→
Canvas now draws the board in the note itself, stored as a```canvas
block of JSON Canvas. A board's Delete and Enter keys only act while the board
has focus, so they no longer take Backspace from the paragraph below.
.canvasfiles still open on their own.Flashcards opened straight into a review with no explanation, so there was no
way to tell what a card was, how to make one, or why cards came back./→
Flashcards now opens a home: how many cards are waiting, a three-step How
flashcards work, Add a card with question and answer fields (no syntax),
Cards from this note — definitions the open note already holds, ticked and
added under## Flashcards— and Decks, one per note, each studied or
practised on its own. Grades say what they mean (Forgot it, Barely, Knew it,
Too easy) and when the card comes back, and a session ends with a way back.Double-clicking a card made a new empty card under it instead of opening the
card: pressing a card captures the pointer on the board so it can be dragged,
and the browser then sends the double-click to the board. Double presses are
now timed on the card itself, so double-clicking writes in a card or renames a
group, double-clicking empty space adds one, and a selected card also opens with
Enter or the new Edit button.NewCanvases
/→ New canvas opens a board for placing cards, notes, links and groups
freely and joining them with arrows. Cards are added from the toolbar or by
double-clicking, moved by dragging (Shift-click for several), resized from the
corner, connected by dragging a card's edge dot onto another, coloured with the
six JSON Canvas presets, and deleted with their arrows; a group carries the
cards inside it. The board pans and zooms around the cursor, and Fit shows
all of it..canvasfiles open from the sidebar and ⌘K.Boards are saved a moment after each change as JSON Canvas 1.0, tab-indented as
Obsidian writes it, keeping fields this app does not read. A file that is not a
canvas is reported and never opened as an empty board, so it cannot be
overwritten.The store now saves and opens files that are not markdown exactly as written:
it used to stampupdatedandgeneratorfront matter onto every file, which
would have put YAML at the top of a JSON file. The GitHub tree lists.canvas
files beside notes and PDFs.Every dialog moved focus back to its first field whenever the page behind it
re-rendered — after a save, a sync, a grade in a flashcard review — because it
treated each new close handler as a new dialog. It now sets focus once, when it
opens, and still closes with the newest handler.The extension now loads in Firefox 121 and later, from the same folder as in
Chrome:about:debugging→ Load Temporary Add-on… →manifest.json. The
manifest declares bothbackground.service_worker(Chrome) and
background.scripts(Firefox), which each browser ignores the other of, and a
Gecko add-on id. It still asks for no access to any site; a test holds the
manifest to all three./or ⌘K → Ask your notebook answers a question with the passages in your
notes that answer it: paragraphs and list items, ranked by how much of the
question they cover with rare words counting for more (BM25-style), quoted with
the note, the heading and the line, matching words highlighted, at most two
from one note. Open at line N opens the note there — the line in Split and
Source, the paragraph in Rich text. No model writes anything, so it cannot say
what your notes do not, and nothing leaves the device./→ Start meeting notes makes a dated note inmeetings/. Pull out
decisions and to-dos reads the notes — or a voice note's transcript — for
Decision:, "we agreed",Action:, "@Sam will", "Leo will review",Question:
and speaker labels, and writes a Summary at the end: decisions, action items as
to-dos with owner and date, and open questions. The summary sits under its own heading, so running it again replaces it, and it is never read back in.Cards written in the rich editor came out wrong. The editor escapes what it
saves, so2 * 3 :: 6was asked as "2 * 3",[[links]]kept escaped
brackets, formatting marks showed raw, and every line ending inside a paragraph
left a backslash on its answer.Question::Answerwithout spaces made no card.Cards are now shown as a person reads them, and the spellings Obsidian's
spaced-repetition plugin reads all work:::with or without spaces (a tight
card needs a question that reads like one, sostd::vectorstays code),:::
for a card each way, a line holding only?or??to split a card over
several lines, and==highlights==as fill-in-the-blank cards in notes tagged
flashcards.::inside inline code is not a separator, a card written twice
is asked once, and the review keeps multi-line answers' line breaks and says
when a card is reversed or a blank.A few older notes come back each day — in the document panel and through
/→
Open a note worth revisiting — each with the reason it was chosen: linked to
the open note and untouched for a month, written on this day in an earlier year,
or among the longest forgotten. The choice holds for the day. Templates, the
flashcard schedule and encrypted notes are never suggested.The weekly review runs the notebook check over the same notes and adds Worth
a look: notes pointing at files or notes that no longer exist, then notes it
thinks have gone out of date, each with the reason. Notes that are merely old
are left out, so the section stays short enough to read.- The
/menu holds every feature. Blocks and the app's tools are listed
together under headings — Text, Lists, Insert, Study, Plan, Templates,
Capture, See, Protect, History, Help, Formatting — and one search covers all
of them, by name, keyword or group. Flashcards, dated to-dos, voice notes,
the graph, board and table, encryption and history were reachable only
through ⌘K before. A tool appears only when its command can run, and running
it is running the command, so the two cannot disagree. A flashcard and a
dated to-do are typed straight in. The same list works in Source view. - The menu no longer covers what is being typed. It was positioned against
the editor's box while drawn inside a padded container, so it landed a line
too high, over the/it was answering. It is now fixed at the caret — below
the line, or above it near the bottom of the window — follows scrolling, and
repeats the query at the top. - Code that asks for input works. A run's standard input comes from a
file written beside the script, soinput(),readandprocess.stdinget
answers instead of an immediate end-of-file. Pressing Run on a program that
reads input opens a Program input box first; a run that still stops for
want of input reopens it and says why. The interpreter and script reach bash
as arguments, never as shell text. The input is not written into the note. - Saves have their own repository. The extension, bookmarklet and share
sheet now open/save, which files each save into a private
forkleaf-savesrepository —pages/,quotes/,links/,images/, each
by year and month, with the date first in every name — and rewrites
INDEX.md(by month and kind, newest first) andindex.jsonin the same
commit. Saving the same page twice says when it was saved before. Signed out,
the page offers to sign in (the request survives the trip) or to keep the
save in this device's inbox. Everything I saved shows both, and opens a
repository save on GitHub. An old/editor?save=1address redirects. - Connecting an AI assistant is one address and a sign-in.
/api/mcpis a
remote MCP server (Streamable HTTP) with OAuth 2.1: the assistant registers
itself, opens a ForkLeaf page where the person chooses the repository —
optionally a folder, a branch and read-only — and gets tokens it keeps and
renews. Nothing is stored on the server: registrations, codes and tokens are
sealed with the session secret and carry their purpose, and each assistant
gets a GitHub grant of its own, since GitHub refresh tokens can be spent only
once. Codes need the PKCE verifier and last five minutes. All tools →
Connect an AI assistant has a copy-ready step for Claude Code, Claude
Desktop and claude.ai, Cursor and VS Code. The localpackages/mcpserver
remains for people who want to run it themselves. - A documentation page for every feature, in a new Everyday features
section: the/menu, templates and journal, to-dos, flashcards, views,
saving from the web, running code with input, voice notes, encrypted notes
and importing. The MCP and extension guides are rewritten for the above. future-implementations.mdtracks what is done and what is next.- The All tools button and the extension and MCP guides, which were pushed
after #69 was merged, are included here.
- All tools in the editor header opens every command as a clickable button,
grouped, filterable, with its shortcut beside it. Until now many features were
reachable only through ⌘K or a shortcut, which is invisible to anyone who has
not read about them. It is the same list the palette runs, so nothing can be
in one and missing from the other. - /docs/browser-extension and /docs/mcp, under a new Connect section
of the documentation: installing Save to ForkLeaf step by step, and connecting
Claude Code, Claude Desktop or Cursor with a fine-grained token, including
what to do when it does not connect. Reachable from All tools, ⌘K, and a
Step-by-step setup link on both cards of the features page.
⌘K → Import notes from Obsidian or Notion reads a folder picked from disk,
shows what will come across — how many notes and files, how many links were
updated, what was left out and why — and imports only when asked, into a folder
of its own so a mistaken import is one folder to delete.- Obsidian vaults keep their folders and front matter.
![[picture.png]]
embeds, which Obsidian resolves by filename anywhere in the vault, become
ordinary markdown images pointing at where the picture landed, so they
render here and on github.com;![[Note]]embeds become[[Note]]links.
.obsidian,.trashand other hidden folders are left behind. - Notion exports (Markdown & CSV, unzipped) lose the 32-character id Notion
appends to every page and folder name, and their URL-encoded relative links
are rewritten to the cleaned paths. Database tables come out of Notion as CSV
and are skipped with that reason.
Nothing already in the notebook is overwritten. Pictures, PDFs and recordings
are copied through the same queue as a pasted image; anything else, and any
file over the 3 MB a commit carries, is listed as left out. Up to 2,000 notes
at a time. The notes are saved and then added to the sidebar in one step — one
update per note would have kept only the last of them.NewVoice notes
⌘K → Record a voice note records in the browser, lets the recording be heard
back and redone, and Add to note saves it inassets/beside the note — like
a pasted picture, so it goes through the same queue, the same commit and the
same history — with a Listen to the recording link at the end of the note.That link is the whole format. A paragraph that is only a link to a recording in
the repository now renders as an audio player in the preview and on published
pages, and stays a plain link to the file on github.com. Only repository files
play: a link to audio on another site stays a link, because playing it would
mean the page fetching from that site. The player is built after sanitising,
from a link the sanitiser has already passed, and a recording that is not on this
device stays a link rather than becoming a broken player.Recordings are WebM or Ogg with Opus where the browser can, MP4 in Safari, and
stop at ten minutes, which keeps them inside the 3 MB a single commit carries.
Audio joins the allowlist the commit and raw-file routes share, and the content
security policy gainsmedia-src 'self' blob:so a recording not yet pushed can
play from this device.A transcript is optional, off by default, and says before it is switched on that
the browser does it — Chrome sends the audio to Google. Refusing microphone
permission is explained rather than failing silently, and a failed save keeps
the recording. Recording is not offered in an encrypted note, whose audio would
be stored in the clear.packages/mcpis a Model Context Protocol server. Added to Claude Code, Claude
Desktop or another MCP client, it lets the assistant search the notebook
(search_notes), list notes (list_notes), read one with the notes that link to
it (read_note), create or replace a note (write_note) and add to today's
journal note (append_to_daily_note).It reads and commits to the notes repository with a GitHub token the person
gives it, directly — nothing passes through ForkLeaf. Writes are ordinary
commits markedforkleaf:, so each one is in the history. It refuses anything
that is not a.mdor.mdxnote, anything in a hidden folder such as
.github, any path that climbs out with..(checked before normalising, which
would otherwise quietly drop it), and anything outsideFORKLEAF_DIRwhen that
is set. Encrypted notes are neither shown nor overwritten — the server has no
passphrase, so writing one could only destroy it.FORKLEAF_READ_ONLY=true
removes the two writing tools entirely. Configuration mistakes are reported as a
sentence naming the variable to set.The protocol is written by hand, like the GitHub client: newline-delimited
JSON-RPC over stdio, with a malformed request answered as a JSON-RPC error and a
tool that could not do what it was asked answered withisError, so the
assistant can read why.The stale-notes check that lived only in the editor now runs in CI.
docs/workflows/notebook-check.ymlis a workflow to copy into a notes
repository: on a pull request it asks ForkLeaf to read the notes at that
commit, puts the report in the job summary, marks each broken reference on its
file, and fails the check when a note points at a file that is not there or a
[[link]]matches no note. Notes whose claims may have aged are listed as worth
re-reading and never fail anything. If ForkLeaf is unreachable the step warns
and passes, so an outage elsewhere does not block a merge.Behind it is
GET /api/gh/notebook-check?owner=&repo=&ref=, which reads every
markdown file at one commit — so a push landing mid-check cannot produce a
report mixing two versions — runs the same survey as the editor, and returns
the findings and a ready-made markdown report. It answers without signing in for
public repositories. A private repository needs a token: the signed-in session,
or an explicitAuthorization: Bearerheader, which the workflow sends only when
FORKLEAF_SEND_TOKENistrueand which is used for that request's reads and
nothing else. It reads at most 400 notes and skips any over 512 KB, saying how
many it skipped, and is rate limited.Shipped as a template in
docs/rather than switched on for this repository:
enabling it here would fail ForkLeaf's own pull requests against a production
deployment that does not have the route yet.⌘K → Encrypt this note… seals a note so that only its passphrase can read
it — in ForkLeaf, on github.com, in a clone on somebody else's machine. The
words, the title and the tags all go inside; the file keeps nothing about the
note but the fields ForkLeaf stamps on every note. It is still one ordinary
.mdfile, which explains on github.com what it is and carries the sealed
text, with the parameters needed to open it written beside it: AES-256-GCM,
the key derived from the passphrase with PBKDF2-SHA256 at 600,000 iterations.Opening an encrypted note shows a passphrase box where the editor would be, so
the sealed text is never on screen as if it were the note. Once opened it edits
like any other note until the tab closes or ⌘K → Lock this encrypted note;
typing is sealed again after a short pause, reusing the key derived when it was
opened, with a fresh IV every save. Remove encryption from this note writes
it back as plain text, after asking. A passphrase that is wrong, and a file that
has been tampered with, both fail rather than showing garbage.What it does not hide, said before encrypting: the filename. What it cannot do:
recover a forgotten passphrase — nobody holds a copy, ForkLeaf included. If a
newer version of an open note arrives from another device, the note locks
again instead of this tab overwriting it with what it remembered.-
Save to ForkLeaf, a Chromium extension in
apps/extension. The toolbar
button (or Alt+Shift+S) saves the page, or the selection as a quote; the
right-click menu saves a page, a selection, a link or an image. It opens
ForkLeaf's save address in a new tab rather than writing anything itself, so
it needs no account, holds no token, asks for no host permissions, and every
save still goes through ForkLeaf's confirmation. A selection too long for an
address is cut to fit and marked as cut. The decisions — what to save for each
menu, which addresses count, where ForkLeaf is — are plain modules with tests. -
Everything you saved. ⌘K → Show everything I saved lays the inbox out
as a grid of what each thing is: quotes set as quotes, pictures shown, links
with their site and date. Filter by kind, search across titles, text, sites
and tags, open the note, or open the original. Pictures are fetched through
ForkLeaf's image proxy rather than by the browser, so browsing the inbox does
not tell every site in it that you looked; one that will not load is hidden
rather than drawn broken.
Things worth keeping are mostly found somewhere other than a notes app. There
are now three ways to send them here, and all of them arrive the same way.- The share sheet. Installed ForkLeaf registers as a share target, so
Share → ForkLeaf works from any app on a phone. - A bookmarklet. ⌘K → Copy the Save to ForkLeaf bookmarklet gives a
bookmark that saves the page you are on, or the text you selected as a quote. - An address,
/editor?save=1&kind=…&url=…&title=…&text=…, for anything
else — the browser extension will use the same one.
What is saved is a note in
inbox/— a blockquote with its source for a quote,
a link for a page, the picture for an image — withtype,url,siteand
savedas properties. Nothing is fetched to make it; the words are the ones
that were shared.It always asks first. A link to that address can be put on any website, so
arriving at it is not consent to write into somebody's repository. A dialog
shows exactly what will be saved, with Save focused so it is still one tap from
the share sheet; declining writes nothing. The address is cleared afterwards, so
a reload cannot save twice. Onlyhttpandhttpsaddresses are kept —
javascript:anddata:are dropped — control characters are stripped, lengths
are capped, and parentheses in an address are escaped so they cannot break the
link. Saving the same link again says where the first copy is.⌘K → Write this week's review makes
journal/2026-w37.md: the notes started
this week (and how many words they came to), the notes worked on, the notes
deleted, the to-dos that are overdue and the ones due in the next seven days —
each with a link to its note — and an empty Looking back heading for the part
only you can write. Running it again the same week opens the note rather than
writing a second one.Read from the notes themselves — their
createddates and when they were last
saved — so it works offline and in a notebook with no repository. On a
connected repository, notes deleted this week are found the same way Bring
back a deleted note finds them. To-dos are copied as plain lines rather than
boxes, so a review does not add a second copy of every task to the to-do list.
Weeks are ISO weeks, starting on Monday.NewFlashcards
A line written
Question :: Answerin any note is a flashcard, and ⌘K →
Review flashcards goes through the ones due today: the question, the answer
when asked for, then Again, Hard, Good or Easy (or 1–4 on the
keyboard). The gap before a card returns grows as it is remembered — SM-2, the
schedule most flashcard apps descend from — and each button says what that gap
will be. A forgotten card comes round again before the session ends.The schedule lives in
reviews/flashcards.mdas a table, one row per card, and
each grade is written to it straight away: it syncs, it has history, and
deleting a row starts that card over. A card is identified by its note and its
question, so editing the answer or the rest of the note keeps its progress.
::in code blocks, indented code, tables, headings and inline code is never
read as a card. The spelling is the one Obsidian's spaced-repetition plugin
reads, so the cards are not a ForkLeaf format.-
Graph. ⌘K → Show the graph of my notes draws every note as a dot and
every[[link]]between two notes as a line. It opens on the notes within two
links of the one you are in; Whole notebook shows everything, and notes
with no links are hidden until asked for. Scroll to zoom, drag to move, point
at a note to light up its neighbours, type to find one, click to open it. The
layout is computed here rather than by a library, and is deterministic — the
same notebook draws the same picture every time, so where things are can be
learned. -
Board. ⌘K → Show this folder as a board puts the folder's notes in
columns by theirstatusproperty — or any other property you pick. Drag a
card, or use the menu on it, and that note'sstatuschanges; moving it to
No status removes the property. Columns come from the values the notes
already use, with To do / Doing / Done offered when the folder uses those or
nothing yet. -
Table. ⌘K → Show this folder as a table lists the folder's notes with
a column for every property they have. Click a header to sort (numbers as
numbers, empty cells last), type to filter, click a cell to edit it. A
property keeps the shape it had: a list stays a list and a number a number.
Add gives every note a new, empty property column to fill in.
Neither view stores anything of its own. The board and the table are rebuilt
from the notes' front matter each time they open, so they cannot disagree with
the files, and every change is an ordinary edit to one note. A note locked on
this device is not changed, and the view says so.- ⌘⇧F in the source view entered focus mode and opened the editor's
find-and-replace bar underneath it. The shortcut is now taken before the
editor sees it. - The Leave focus button sat under the "only on this device" banner. The
banner steps away in focus mode with everything else. - A new day's note began with an empty
- [ ], which the rich editor showed
as a bullet reading "[ ]". It begins with the headings alone now.
⌘K → Bring back a deleted note compares the notebook as it stood a week, a
month, three months or a year ago with the notebook now, and lists the notes
that have gone. Each can be read before deciding, and Bring it back writes
it at the path it had, properties included, as an ordinary new change. When a
file with the same name has appeared elsewhere since, the row says the note was
probably moved rather than deleted. Nothing new on the server: the comparison is
the time machine's read of an earlier day. When something new already lives at
the old path, the note comes back beside it instead of over it.Four things every notes app is expected to do, which ForkLeaf did not. Each one
is ordinary files and ordinary markdown, so nothing here works only inside
ForkLeaf.-
Templates are files in
templates/. Every markdown file there appears in
⌘K as New note from template, and Save this note as a template makes
one from what you have open.{{title}},{{date}},{{time}},
{{weekday}},{{yesterday}}and{{tomorrow}}are filled in; any other
braces are left alone, in case they are yours. A template's tags come along;
its own title and creation date do not, or every meeting note would claim to
have been written the day the template was. -
Today's note. ⌘K → Open today's note opens
journal/2026-09-12.md,
making it first if needed — fromtemplates/daily.mdwhen there is one, and a
plain dated page with a to-do list when there is not. "Today" is the writer's
own day, not UTC's. -
Every open to-do, in one list. A
- [ ]written in Tuesday's meeting
note was invisible from Wednesday's. ⌘K → Show every open to-do lists
every unticked box in the notebook, soonest due first, and ticking one there
ticks it in its note — one character, synced and in history like any edit.
Due dates are📅 2026-09-14(the Obsidian Tasks spelling) or
due: 2026-09-14. Boxes inside code blocks and templates are not tasks. When
a note has changed since the list was read and the line cannot be found
unambiguously, nothing is ticked and the list reads again. -
Focus mode. ⌘⇧F puts away the file tree, the tabs, the document panel and
the status bar, and brings back exactly the layout you had when pressed again.
- The
- 6 September 2026
1 change
Three places in ForkLeaf could tell you that something had changed and then
leave you to work out how on your own. All three can now show you.-
A rewrite, beside the original. Trying a rewrite already gave you a copy
to work in and two buttons — keep it, throw it away — with nothing in between
to base the choice on. The bar now has a third: Compare puts the two
versions in two columns with the changed words picked out.Compared against the commit the rewrite grew from rather than the original's
current tip. If anything landed on the original while the rewrite was being
written, comparing against the tip would report that work as something the
rewrite deletes — and talk you out of keeping a rewrite that deletes nothing.
When the original has moved on, it says so instead. -
Two versions of a paper, page beside page. Comparing two versions of a
PDF said which pages changed, compared as words rather than bytes. Picking
one of those pages now draws it from both files at once, so "page 12 changed"
becomes the paragraph that changed. The arrow beside it still takes the
reader there. -
A suggestion, read where you accept it. A correction sent back from a
published page could be accepted here but only read on github.com — three
context switches to approve the one-word fixes that most of them are. The
note before and after is now in the list itself. Discuss on GitHub stays,
for the half that genuinely belongs there: replying to whoever sent it.
-
- 2 September 2026
11 changes
Two problems with one answer.
A scan is a photograph of a page. There is no text in it, so there is nothing
to search, nothing to quote and nothing to check a citation against — the
reader said so honestly and then there was nowhere to go. And a paper that
does carry its text still had it extracted from scratch on every device,
every time, and thrown away at the end.The reader now looks for
<name>.text.mdbeside a document and uses it when
the document has nothing of its own. Recognise a scan's words once — with
ocrmypdf,tesseract, or anything else — commit the file, and search,
quotations, highlights and the citation check all start working on it, on every
device. For a paper that already has text, ⌘K → Keep this document's text
beside it writes the same file from what has already been read.Markdown with a
## Page 1heading per page, deliberately: somebody will make
these by hand and will want to correct a mangled line when they find one, which
means the format has to be something a person can open and read. Correcting a
line there corrects it everywhere.A document's own text always wins. A file beside a paper never silently
replaces what the paper actually says.Recognising the words inside ForkLeaf is still not possible, and that is a
decision rather than an omission — seedocs/ideas.md.Three faults in one action, which together made renaming a folder unsafe.
The links to the pictures were repointed at the old folder. A note's links
are relative to where the note sits, so moving one is normally accompanied by
rewriting them — but when the whole folder moves, the pictures move with it,
andassets/chart.pngwas being rewritten to../../old-folder/assets/chart.png,
which no longer exists. Every image in a renamed folder broke immediately, and
the note looked fine until somebody opened it. Links that point out of the
folder are still rewritten, because those files did not move.The old folder stayed on screen beside the new one. The sidebar corrects
the repository's file list with whatever has not been pushed yet, and it knew
about renames and deletions but not about moves — which is how everything
that is not a note travels, a PDF included. So a folder holding a paper
appeared twice.An open tab kept pointing at the old path. The next keystroke in it saved
the note back to where it used to be, recreating the folder that had just been
renamed with one note inside it. Tabs now follow the rename, and so do the
locks on the notes in them.Between them these explain the duplicate folder people were left deleting — and
why deleting it took real files with it: the duplicate was not a copy, it was
the original.When a friend writes a good note, what people do is copy and paste it. Now
there are two copies, one is already out of date, and neither of you can tell
which. Installing a library solved this for code thirty years ago and nobody
has solved it for the things people know.⌘K → Borrow a note from another notebook takes a repository as
owner/name, lists the notes in it, and writes a link into yours —
[[repo:ada/notes:runbook.md@a1b2c3d]]— pinned to the revision you read.
Theirs stays theirs, nothing is copied here, and the link keeps working after
they change it, because it names the version you actually read rather than
“whatever is there now”. Unpin it if following along is what you
wanted.A paper in your repository has every version of itself kept beside it, which no
other reading app can say. ⌘K → See what changed in this document picks an
earlier version and reports which pages changed — and whether one of them is a
page you quoted.Compared as text, not as bytes: a paper re-exported from the same source
differs in every byte while saying exactly the same thing, and a comparison
that reported four hundred changed pages every time somebody re-saved it would
be one nobody reads twice. Hyphenation across a line break, ligatures and runs
of spaces are not edits.Whether the words you quoted survived is a different question, and one Check
my citations against their documents already answers.A note written from a paper is commentary with the passages set into it, each
linked back to the page it came from. That is the thing worth sharing — not
“here is a PDF” and not “here is an opinion”, but the
argument with its receipts.It did not survive publishing. A citation is written relative to the note,
which is right in the repository and reaches nothing from a page served out of
docs/— so every quotation on a published reading page was a dead link,
silently, which is worse than no link at all because it looks like there is a
source behind it.Citations are now rewritten on the way out, to the document in your repository,
fragment and all. Only the published copy changes: the note keeps its relative
links, because that is what makes it readable on github.com and in any other
editor.Everybody else locks a highlight inside the PDF — a binary annotation only a
PDF reader can see — or inside their own app, where you can never get it out.
Both mean the marks you made on a paper are worth nothing away from the tool
you made them in, which is a strange fate for the part that is actually yours.Select a passage and press Highlight. It becomes a line in
attention.highlights.md, committed beside the document, and is drawn in green
over the page when you read it. The file renders on github.com, opens in
Notepad, greps and diffs.The PDF is never touched. And because each line records the words rather than a
page number, a highlight made against last year's version of a paper is still
drawn in the right place after the author adds a figure to page 4 — one that has
genuinely gone is simply not drawn, rather than drawn somewhere wrong.Rewriting a note you care about is a small act of courage: the old version goes
into the history, where you have to know it exists and how to get it back. In
practice people either do not try, or paste the original into a second note
calledrunbook-old.md.⌘K → Try a rewrite of this note gives you a copy of the notebook to
experiment in, and a bar at the top that says so and never goes away. Keep
it puts the rewrite back onto the branch it came from as one change; Throw
it away deletes the experiment and leaves the original exactly as it was.It is a git branch — named
try/<branch>/<what>, so the name itself says what
it is and where it has to land, and a second device picks the experiment up
knowing both. Nothing is written down anywhere else, because anything written
down anywhere else is the thing that gets lost.Programmers have had “here is a fix for what you wrote” for twenty
years and call it a pull request. Nobody has ever offered it to people writing
notes: a published page is something you read, and that is where it ends.- Every page you publish now carries Suggest an edit. A reader who spots a
mistake follows it, fixes the note in GitHub's own editor, and their change
becomes a suggestion — GitHub does the forking and the pull request, and
neither of you has to say those words - ⌘K → See what other people have suggested lists what has come in: who,
what, and when. Read what changed opens the diff and the conversation on
GitHub, which is a thing GitHub does very well; Accept merges it into your
notes from here, and the next sync brings it down to this device
The link points at the note in the repository it came from, never at the
published copy — a suggestion against a copy is one you could not accept
without hand-copying it back.Read a document beside a note and the two follow each other: move the cursor
past a citation and the document turns to that page; turn to a page and the
note scrolls to what you wrote about it. This is what people open two windows
to fake.Nothing is guessed. Every citation already records the page it came from, so
the mapping is the notebook's own. Above the first citation nothing follows —
a cursor in a heading is not a statement about any page. ⌘K → Stop the
document following the note switches it off; it works in Split and Source
view, where there is a cursor to follow.A ForkLeaf citation was always an ordinary Markdown link — a relative path plus
the#page=fragment every PDF reader has understood for twenty years, with the
W3C Web Annotation text selector spelled into a query string. That is only
useful to anybody else if it is written down, so it now is:
the citation link format, field by field, with what a
tool has to do to read one.Copy link on a selected passage puts exactly that form on the clipboard, for
pasting into anything that is not ForkLeaf.Ten features have gone in lately and the help dialog had not heard of any of
them. It now covers every one, in the same three beats: what it is in one line,
the exact words to press, and what happens when you do. Two new topics —
Papers & PDFs and Checks & history — and the existing ones gained the
resizable columns, the search that weighs what you are working on, diagram boxes
that are notes, and what to do about an image too big to send. - Every page you publish now carries Suggest an edit. A reader who spots a
- 31 August 2026
8 changes
Show me my notebook as it was on… in the palette takes the whole notebook
back to a date: the files that existed that day, and any of them readable as it
stood. The per-note history answers "how did this page come to be?"; this
answers "what did I know when I made that decision?", which is a question about
the shape of the notebook rather than about one file in it.Read-only, deliberately. Restoring one note is something the history panel does
well; a button that rolled a whole notebook back to March would be the most
dangerous control in the app.Nothing new is stored. Git already holds every version of every file — a tree
read at an old commit is the same call as a tree read at the newest one.Pointing at a paragraph in the blame view now shows the wording it replaced,
taken from the revision before the commit that last changed it. A paragraph you
rewrote in March is one you changed your mind about, and what you changed it
from is usually the most interesting thing on the page.Nothing is shown for a paragraph that was added rather than rewritten, or for a
change older than the history that can be read — those are different facts, and
inventing a previous wording for them would be a lie.Write a
[[wikilink]]in a box's label —A["[[Deploy runbook]]"]— and the
box becomes the way to that note. The label reads as the words you wrote, and
clicking it in the preview opens the note.It stays plain text in the file: an ordinary mermaid label, so the diagram
still renders on github.com and in every other mermaid tool, showing the
brackets exactly as a[[wikilink]]in prose does there. Aliases work
([[deploy/runbook|The runbook]]), and so do anchors.In the rich editor a click on a diagram still opens it for editing, which is
what a click there has always meant — but the labels read correctly there too,
and in exports and published pages.The freshness panel beside a note answers the question for the note you happen
to have open. Check which of my notes have gone stale answers it for all of
them: notes pointing at a file that is not in the repository,[[links]]
matching no note, and datable claims — version numbers, CVEs,
“currently” — in a note nobody has touched in a long time.The first two are facts and are labelled as such; the third is an inference and
is reported as one. Nothing is changed: every row opens the note and gets out
of the way. It is fine takes a note off the list until it is edited again.Write about this in the reader makes a note that is already about the
document: its title, its author and the date it was published in the
frontmatter, and its own table of contents as the note's headings — each one
linked to the page that section starts on. The document then moves aside and
sits beside the note you are writing.Nothing is invented. A paper with no contents list of its own gets a single
"Notes" heading rather than a structure somebody would have to argue with.⌘K now weighs which notes are connected to the one you are in. Searching
"setup" in the middle of a project finds that project's setup rather than the
other five. A note you linked to and a note that linked to you count the same,
and the effect fades with distance — but it never beats a better kind of match,
so a note actually called what you typed still wins.Every other tool stores a page number, and a page number quietly stops being
true: the author adds a figure to page 4 and every citation after it points one
page short. Nothing tells you. A ForkLeaf citation records the sentence, so the
question has an answer — and now there is somewhere to ask it.- Check my citations against their documents in the palette reads every
paper you have quoted and reports what it found: quotations that have moved
to another page, quotations that matched only loosely, and the ones that are
no longer in the document at all - A moved quotation can have its page number corrected in place, one press per
citation. The words, the context and the path are left exactly as they were —
it is the page hint beside them that had gone stale - A document that could not be read is reported as unread, never as a document
full of broken citations
The reader has always extracted every page's text — that is what makes
find-in-document work through hyphenation and ligatures — and then threw it
away when the document closed. It is now kept beside the notebook, so ⌘K
searches the papers as well as the notes and jumps straight to the page. A
document is indexed the first time it is opened, and by the citation check. - Check my citations against their documents in the palette reads every
- 30 August 2026
8 changes
Signing out and signing in as a different GitHub account on the same browser
left the previous account's workspaces and notes in place: their repository
names, their folder structure, the full text of every note they had opened,
and an editor willing to let the new arrival type into them.GitHub itself was never exposed — every request is authorised server-side by
the session cookie, which is why a repository the new account could not read
reported "Not Found" rather than handing over its contents. What leaked was the
local cache, which is where the words are.A repository workspace now records the account that connected it and is listed
for nobody else, across the editor, the dashboard and the profile page. Nothing
is deleted: a notebook is hidden from other accounts and comes back intact when
its own account signs in. Being offline is treated as "could not ask" rather
than "signed out", so a notebook still opens without a network.NewReading PDFs
ForkLeaf opens PDFs, beside the note you are writing from them.
- A reader in its own pane: page rendering, the document's own table of
contents, and find-across-the-document that matches through line breaks,
hyphenation and ligatures — so searching for "find" matches a page that
really contains "find" - Open one by dragging it onto the window, from the command palette, from a
.pdfin the repository file tree, from an ordinary markdown link in a note,
or from the operating system's "Open with" list - Quote into note turns a selected passage into a blockquote and a link.
Nothing bespoke lands in the file:[On Attention, p. 12](paper.pdf#page=12…)
renders on github.com and opens the right page in every other PDF reader - Citations record the sentence, not the page. Clicking one finds those words
in the document as it is now — so a citation still points at the right
paragraph after the author adds a figure to page 4, and says so plainly when
the passage has genuinely gone - Nothing is ever written back to the PDF. The file in your repository stays
exactly as it was committed
- Clicking a PDF in the file tree now opens it here, in the middle of the
editor, with the document's contents pinned open on the right. It used to
throw you into a second browser tab, which is a strange thing for a notes
app to do with a file that lives in the notebook you are looking at - The contents column is a real column: Contents and Find as two tabs
of it, and a seam you can drag. Documents with no table of contents of their
own say so rather than showing an empty list - Where PDFs open is now a choice of three rather than a toggle — in this
window, beside the note, or in a browser tab — and the command palette shows
all three with the current one marked, so it answers "where do they open
now?" as well as changing it
When an image cannot be pushed — a screenshot is larger than GitHub will take
in one request — the panel offered exactly one way out: remove it. The picture
was fine; there was simply more of it than the wire would carry.- Resize now sits beside Remove for any PNG, JPEG or WebP that is stuck.
Pick how small — as large as will still send, 1 MB, or 500 KB — and the
picture is re-encoded, replaces the copy on this device, and is pushed again.
Your notes keep showing it, at the same path, in the same format - Quality comes down before size does, so a photograph stays full-size where it
can; a screenshot comes down in scale, which is what actually makes it small - Animated GIFs are not offered: a canvas holds one frame, so "resizing" one
would silently throw away every frame but the first
Remove took the file out of the queue and off this device and left the
markdown in place, so a note that used to show a chart showed a broken-image
icon instead — with no file left anywhere to put back. It now takes the image
out of every note that used it, in every form a reference can take. A link to
the file keeps its words and loses the link; a line that held nothing but the
image goes with it.Open a PDF from your repository and the contents column has a third tab:
every note that quotes this document, each one showing the passage it took and
the page it came from, in the document's own order. Click the passage to go to
that page, or the note to open it.Nothing new is stored to make this work. ForkLeaf already writes a citation as
an ordinary markdown link, so the notebook always knew which notes quote which
paper — it had no way of being asked. Months after reading something, that
list is the useful artefact: your own argument, assembled out of notes written
weeks apart, with the paper's words set into it.Every panel in the editor was a width somebody chose once. Each seam between
panels is now a handle: drag it and the column follows, double-click it and it
goes back to where it started. The widths are remembered on this device.The handles are real separator widgets, so arrow keys move them, shift moves
them further, and Home and End take them to their limits. Nothing moves for
anyone who never touches a seam — the defaults are the widths the panels
already had.- A PDF from your repository now opens in its own tab, full width. Half a
laptop screen is not a width anybody reads a typeset page at. The tab is a
real link — bookmark it, open two side by side, or send it to somebody with
access to the same repository - Reading beside the note is still there and is now a choice rather than the
only option: Open beside this note on a PDF in the sidebar for once, or
Open PDFs beside the note instead in the palette for good - Save to notebook commits a PDF opened from your desktop into a
papers/
folder beside the note you are reading it with, so its citations become real
links. Documents too large for a browser commit say so rather than failing - Opening a PDF has a button beside New Note — it used to be reachable only
from the command palette, which meant only by people who already knew - The reader's contents and find panels now slide over the page in a narrow
window instead of taking a column from it, which had left about a hundred and
sixty pixels for the document - The header wraps rather than pushing Close off its own right edge
- Fitting to width uses the document's most common page size rather than its
widest, so one fold-out no longer shrinks every ordinary page to suit it
- A reader in its own pane: page rendering, the document's own table of
The first release.
ForkLeaf is a local-first Markdown workspace whose storage is a GitHub
repository you already own. Every note is a plain.mdfile committed to your
repo: real version history, no database to be locked out of, and nothing to
export because there was never anything to import.NewWriting
- Three editing modes per note — rich text, split source/preview, raw markdown
- Slash commands, a command palette (
⌘K), and a properties panel that edits
the note's YAML frontmatter directly - Enter makes a line, not a paragraph, so the rich and source views agree about
what the file contains - Code blocks with syntax highlighting and a language picker; pasted code is
detected and fenced with the language it appears to be in - Document outline, word count, reading time, task progress
[[Wikilinks]]in the Obsidian dialect, resolved by path, filename or title- Backlinks that quote the line they were written on
- Full-text BM25 search across every note, in the browser, offline
NewDiagrams
- A Mermaid studio: pick a diagram type, drag shapes onto a canvas, or write
the source with autocomplete and plain-language errors - 14 templates; six types drawable rather than typed
- Stored as ordinary
```mermaidblocks, so they render on github.com too
- Local-first: edits land in IndexedDB immediately and push in the background
- Rapid edits coalesce into one commit rather than a thousand autosaves
- Offline-safe queue, conflict prompts, branch switching from the status bar
- Every version of every note read from the repository's own commit log
- Propose changes as a pull request against a repository you cannot push to
- Notes refresh themselves when someone else commits, without a reload
- Publish a note as a self-contained page committed to
docs/and served by
GitHub Pages - Export to PDF, Word, HTML, Markdown, plain text or JSON — one note or the
whole workspace, rendered in the browser
NewDesktop
- Installs as an app and registers as a Markdown editor:
xdg-open note.md
opens it, and⌘Swrites back to the file it came from
NewKnown limits
- No real-time multiplayer editing
- Editing files on your machine needs a Chromium-based browser (File System
Access API); everything else works everywhere
Looking for what it does rather than what changed? Every feature.