Markup language
Mudlark uses a simple system: start any line with a special character to tell it what that line is. You write in the left pane, and the right pane builds the organized note from those prefixes. You can change which characters do what in Settings.
[[ ]] for note links and { } for media, timers, and inline metadata, sit alongside the prefixes. Toggle individual types on or off in Settings.on this page
Start here
Five prefixes cover most notes on day one.
# Project Notes
+ Buy groceries
! Demo is at 3pm
* Bring the good coffee
- buy gr ← checks off “Buy groceries”
# starts a section. + adds a task. ! marks a line as important. * makes a bullet point. - checks a task off by name, and a few letters of each word are enough.
Every prefix needs a trailing space before its content. # Heading is a heading. #FFF is plain text. The same rule applies inside action lines: _ + task removes a task named “task”, while _ +task is plain text.
The other everyday prefixes (", @) are in the next section. All 20 prefixes are in the reference table at the end of this page.
The basics
These eight prefixes cover ordinary note-taking.
| Prefix | Type | Description | Example |
|---|---|---|---|
# | Heading | Creates a section heading. Everything below it groups under that heading on the right. |
→ Project Notes |
+ | Task | Adds an unchecked task. Tasks float to the top of their section on the right. |
→ ☐ Buy groceries |
- | Done | Checks off a task by fuzzy-matching its name. Content after the space is the task name to match. Use _ to remove items of any other type. |
→ ☑ Buy groceries |
! | Highlight | Marks a line as important. Rendered bold and prominent on the right. |
→ Demo is at 3pm |
" | Quote | Wraps a line in a styled blockquote with a left border. |
→ “Simple things should be simple” |
* | Bullet | Creates a bullet point. Multiple bullets form a list under the nearest heading. |
→ • Bring the good coffee |
% | Numbered | Creates a numbered list item. Auto-numbered on the right side. |
→ 1. First step |
@ | Media | Embeds an image or video from a file path, URL, or dropped file. |
→ [image: photo.jpg] |
Inline formatting
Within any line, you can add bold, italic, and inline code formatting. This works inside any text-bearing prefix type.
*italic text*
**bold text**
***bold and italic***
`inline code`
Inline code uses single backticks and renders in a monospace font with a subtle tinted background. Code spans never process formatting inside, so `*literal*` stays literal. Escape a delimiter with a backslash: \*, \`, or \\.
Formatting markers are stripped in the rendered view and in fuzzy matching, so **bold** matches bold when checking off tasks or searching.
Lists and indentation
Bullet lists use *, numbered lists use %. To nest a list, indent two spaces per level. Up to five levels of nesting are supported.
* First item
* Nested item
* Deep nested
* Second item
Escaping and comments
Two prefixes keep Mudlark from interpreting a line. \ makes the rest of the line plain text, so \ + Not a task renders as the literal text “+ Not a task”. / marks a comment, a private note that stays in the left pane and never appears in the rendered note.
Acting on what you wrote
These prefixes act on what you already wrote: check a task off, remove an item, move it somewhere else, search it. They all find their target the same way, so smart matching comes first.
Smart matching
When you check off a task with - or move something with >, you don’t need to type the full name. Each word you type just needs to match the beginning of a word in the original, in order.
+ go get groceries
- go g ← matches (“go” → “go”, “g” → “get”)
+ go get groceries
- go gr ← matches (“go” → “go”, “gr” → “groceries”, skips “get”)
This also works with filenames and paths. A file like images/daisy-pants-stereo.jpg is broken up at slashes, dots, and dashes, so _ @ pants is enough to match it.
The editor colors the line live as you type: green when it finds exactly one match, yellow when more than one item matches (ambiguous, so nothing happens), and red when nothing matches.
Checking off tasks
- looks for a matching task and marks it done. Content after the space is the task name to match.
+ Buy groceries
- buy gr ← checks off “Buy groceries”
In the rendered pane, clicking a task checks it off by writing a matching - line. Clicking again clears it. Cmd-click copies the task text instead.
Removing items and sections
To remove any other kind of item, use _ followed by the type’s prefix. Works with Heading, Task, Highlight, Quote, Bullet, Numbered, Media, Code, Math, Timer, Table, Footnote.
! Ship by Friday
_ ! ship ← removes the highlight
@ images/photo.jpg
_ @ photo ← removes the media
Use _ # name to remove an entire section and everything in it.
# Old Ideas
+ some task
! some highlight
_ # old ← removes the section and all its contents
Moving things around
The > character moves content between sections.
Move an item here
Add a type prefix and a fuzzy match. The matched item moves into the current section.
> + fix ← moves a task matching “fix” here
Send an item to a heading
Add @ and a destination heading.
> + fix @ Home ← moves the task to the “Home” section
Relocate a whole section
Use the heading prefix # inside the move to target a heading by name. Without a destination, the matched heading and its contents re-parent into the current section. With @ destination, they re-parent under that heading instead.
> # Backlog ← moves the “Backlog” heading-block into the current section
> # Backlog @ Active ← moves the Backlog heading-block under “Active”
A fourth form moves a whole named block. See Acting on a whole block.
Writing to another section
The . character creates a new item under another heading without moving your cursor. Write the content, then @ and the destination heading. An optional type prefix sets the item type; without one, the line is written as plain text.
. + eggs @ Shopping ← adds the task under the “Shopping” heading
. call the plumber @ Today ← adds plain text under the “Today” heading
> moves an existing item. . creates a new one. Without an @ destination, nothing is created.
Finding and replacing
The , character searches everything above it. Add a pipe to replace matches, a type prefix to target a specific type, or @ heading to scope the search to a specific section.
, search ← highlights all matches
, search | replace ← replaces all matches
, + search | replacement ← only searches tasks
, search | replace @ Notes ← scoped to the “Notes” section
, \+groceries ← backslash escapes the type prefix, so it searches for the literal text “+groceries”
Rules as barriers
The ~ character draws a horizontal rule. Add a label to center text on the rule: ~ Chapter 2. A rule is also a barrier. Completions and moves cannot cross it: a - task below a rule cannot check off a task above it. Use one to fence off finished work.
Blocks
Blocks group several lines into one unit: a task list with a title, a code snippet, a table.
Opening and closing a block
Double a block-capable prefix to open a block. Use the same doubled prefix again to close it. Single-prefix lines stay as typed-line shortcuts.
!!
Ship the feature
Update the docs
Tell the team
!!
Block-capable types: ++ !! "" ** %% `` == :: && // ^^.
Named blocks
Give a block a title by writing the doubled prefix followed by a name. Named blocks show up as groups on the right side, and you can check off, remove, or move the whole group at once.
++ Shopping List
milk
eggs
bread
++
-- Shopping marks all items done. > ++ Shopping moves the entire block.
Acting on a whole block
A single type prefix targets one item. Doubling the inner prefix targets a whole named block.
- milk ← completes one task
-- Shopping ← completes the whole Shopping block
The same doubling works inside action lines. _ + milk removes one item and _ ++ Shopping removes the block. > + milk moves one item and > ++ Shopping @ Home moves the block under “Home”.
These commands look upward from where you type and stop at the nearest ~ rule. If two blocks with the same name are both in reach, Mudlark does nothing rather than guess.
Composite blocks like code, tables, and math can only be targeted this way: by name, with the doubled form.
Container and composite blocks
Blocks come in two kinds. Inside a container block (++, **, %%), every line is still its own item. You can check off one task inside a ++ block with a plain - milk.
A composite block (!!, "", code, math, tables, media) is one unit. Its inner lines cannot be targeted on their own. To complete, move, or remove it, use its name with the doubled form.
Code blocks
A code block can carry both a language hint and a title. Write the language right after the doubled backtick (no space), then a space, then the title.
``swift Login flow
let user = signIn()
user.persist()
``
The language drives syntax highlighting. The title renders as a header on the rendered block. A bare ``swift opens an unnamed block. A bare `` opens an unnamed, untyped block.
Block hints
A few block prefixes accept a hint glued to the opener, with no space between them. Code takes a language: ``swift Login flow. Math takes an aggregator: ==sum totals. Tables take a format: &&csv. Other prefixes accept the bare doubled form with an optional name only.
Inside a code block or a tab-separated table opened with &&tsv, pressing Tab inserts a literal tab character. Inside any && block table, Tab moves to the next cell. Everywhere else, Tab indents and the line-type prefixes stay in charge of structure.
Tables
Start a line with & and use pipes to separate columns. The first row becomes the header, and additional & rows form the body.
& Name | Age | City
& Alice | 30 | London
& Bob | 25 | Paris
Consecutive & rows are grouped into a single table on the right side. A heading above the table gives it a title.
A bare & row splits on the separator from your Default table format setting, so CSV, TSV, and semicolon split accordingly (the default is mudlark pipes). An explicit hint on a doubled opener always wins: &&csv, &&tsv, &&markdown, or &&semicolon.
Cells evaluate inline embeds. A pipe inside an embed or a [[Note|Alias]] link stays in one cell.
Table formulas
Table cells can use formulas that read columns and rows. See the table formulas section for column totals, row lookups, conditions, dates, and editor help.
Math and units
The = prefix evaluates an expression. It needs a space before the expression, as in = 5 km to mi. A doubled== opens a math block, and {= 1 + 1} places a result inside a line.
See the math and formulas guide for operators, units, functions, variables, math blocks, inline calculations, and table formulas.
Timers
The : character starts a timer. A duration after the prefix counts down. A mode word glued to the prefix changes what the clock does: :repeat starts over, :alarm waits for a time or a date, and :since counts up from one. Mudlark can notify you when a timer ends. That is a setting, and it is off until you turn it on.
Only these three mode words are recognized. Anything else after the prefix, like :D haha or :wq, is plain text, and so is a mode word with nothing after it. The words stay English when you remap the timer prefix in Settings.
Countdowns
Write a duration after the prefix. Units are hours, minutes, and seconds, in long or short form, and a bare number is minutes. Text after the duration names the timer.
: 25m ← counts down from 25:00
: 5 standup ← five minutes, named standup
A timer can run several phases in a row. Separate them with commas and give each an optional name: : 25m work, 5m rest. In the rendered pane, clicking a timer resets it and starts it again.
Repeating timers
:repeat starts the timer over each time it finishes and cycles forever. Glue a count from 1 to 9999 to the word and it stops after that many cycles. While it runs, the rendered pane shows the cycle beside the phase name, as in 2 of 4.
:repeat 5m ← restarts every 5 minutes
:repeat4 25m work, 5m rest ← four cycles of work and rest, then stops
The count has to touch the word. With a space, as in :repeat 4 5m, the 4 is read as part of the duration.
Alarms
:alarm waits for a time of day, a date, or both. Until the last hour it shows the target in the muted style. During the last hour it counts down, and for a minute after firing it shows 0:00. A time on its own means the next time the clock reads that, today or tomorrow, so the alarm comes back every day. A date fires once, at the start of the day unless you add a time, and afterwards shows its target struck through.
:alarm 15:30 standup ← today at 15:30, or tomorrow once that has passed
:alarm 2026-12-25 ← the first moment of that day
:alarm 2026-12-25 09:00 Retro ← that morning at 9:00, named Retro
Clicking an alarm does nothing, and Restart timers leaves it where it is.
Counting up from a date
:since counts up from a date, a time, or both. With a date alone it shows Day N, and the anchor day is Day 1. With a time it shows the hours and minutes that have passed, and after 24 hours it shows the days as well. A time on its own means the most recent time the clock read that, today or yesterday.
:since 2026-06-01 ← Day 1 on June 1, Day 2 on June 2
:since 2026-06-01 09:00 Coffee ← hours and minutes since 9:00 that day, then days
:since 9:15 ← counts from the most recent 9:15
A since line never notifies and never brings up the full-pane timer view. A date or time in the future is an error.
Writing dates and times
Alarms and since lines take a date as YYYY-MM-DD, a time as H:MM on the 24-hour clock, or both with a space between, then an optional name. Nothing else is accepted in a note. Words like 3pm and tomorrow, and a time that does not exist, like 25:99, show an error in place of the clock that names the accepted shape.
The capture bar, the mudlark:// URL scheme, and the Shortcuts actions accept relative words and write the absolute form into the note. :since now becomes today’s date and the current time, and :alarm tomorrow 3pm standup becomes tomorrow’s date, 15:00, and the name. In the editor, typing :since and a space offers the current date and time as a completion.
Timer blocks and inline timers
Doubled :: opens a timer block, with an optional name: :: Workout. The mode words work on blocks too: ::repeat Workout, ::repeat4 Tabata, ::alarm Meetings, and ::since Habits. Each line inside is one timer, written without the prefix: a duration in a countdown or repeat block, a date or time in an alarm or since block. Every kind closes with a bare ::.
::alarm Meetings
15:30 standup
2026-12-25 09:00 Retro
::
Inside a sentence, the same forms are {: 5m}, {:repeat 1hr}, {:repeat4 30s}, {:alarm 15:30}, and {:since 2026-06-01}. See Inline embeds.
Notifications
Notifications are off by default. Turn on Notify when a timer finishes or an alarm fires, under Timers in Appearance settings. macOS asks for permission once. If you decline, the setting shows a link to System Settings, where you can allow notifications for Mudlark later.
A countdown notifies when it reaches zero, with Restart and Open note buttons. An alarm notifies at its time, once for a date and every day for a time on its own, with an Open note button. A repeat with a count notifies once, when its last cycle ends. A repeat without a count and a since line never notify. When the note is on screen in the front window, you hear the sound and no banner appears. Clicking a notification opens the note.
Links, embeds, and footnotes
Three features live inside lines of text rather than at the start of them: links to other notes, inline embeds, and footnotes.
Note links
Write [[Title]] anywhere inside a line to link to another note in the same vault. Typing [[ opens an autocomplete of vault titles. Pick one and the closing ]] is inserted for you.
See [[Project Notes]] for the latest scope.
In the editor, the link shows as a compact chip. Move your caret into it and it turns back into the raw [[Title]] text for editing. In the right pane the chip is clickable and jumps to the linked note.
A note link on its own line renders as a preview card in the right pane. The layout follows the link: [[Title]] previews the whole note, [[#Heading]] previews that heading in the current note, and [[Title#Heading]] previews the heading in another note. A fragment that matches no heading falls back to the whole-note preview.
Renaming or moving a note auto-rewrites every [[ ]] reference across the vault, so links stay valid without manual cleanup. On export, each link resolves to the destination’s native note-link form (a Markdown link by default, a wiki-style link for Obsidian, an internal link for Notion, and so on). See the export guide for the per-destination behavior.
Inline embeds
The { … } notation embeds something live inside a sentence: an image, a calculation, a code snippet, or a timer. The first character inside the braces is the same prefix you would use to open that item on its own line. Four types embed:
| Inline | Type | Example |
|---|---|---|
{@ } | Media | {@ photo.jpg} |
{= } | Math | {= 100 km to mi} |
{` } | Code | {`swift let x = 1} |
{: } | Timer | {: 25:00 Focus}, {:repeat 5m} |
The trip is {= 1240 km to mi}, leaves on {@ lisbon-balcony.jpg}, and runs for {: 25:00 Focus}.
Inline math
{= expression} places a calculated value inside a line. See the math and formulas guide for expressions, units, functions, and table formulas.
Inline code
{`code} renders monospaced code inline. Glue a language hint to the backtick for syntax highlighting: {`python def f()} highlights as Python. Inline code is for short snippets that want richer treatment than the backtick-wrapped `text` inline-formatting shortcut.
Inline media
{@ filename} drops a piece of media into the sentence. Typing {@ opens an autocomplete of vault media. Local images render in place, sized to the column, with rounded corners, an accessibility label from the filename, and a click action (click to open, Cmd-click to copy). Remote URLs load asynchronously. Videos play inline. A click starts or pauses playback.
For a gallery, open a media block with @@ and put one media reference per line. The right pane lays the items out in a mosaic of justified rows sized from each image’s aspect ratio, with runs of tall images stacked so they sit beside shorter neighbors. Nothing is cropped or squeezed to a uniform tile.
Inline timers
{: 25:00 Focus} for a countdown, {:repeat 5m} for a repeating timer, {:repeat4 30s} for one that stops after four cycles, {:alarm 15:30} for an alarm, and {:since 2026-06-01} for a day counter. The rendered pane shows an icon and the clock, ticking in real time. Bare numbers can carry a phase name, so {: 25 Focus} reads as 25 minutes. Inline timers are for when a timer wants to live inside a sentence. Full-line timers are covered in Timers.
Where embeds work
Embeds and [[note links]] work inside prose: headings, tasks, highlights, quotes, bullets, numbered items, footnote definitions, and custom callouts. They also work in table cells: math evaluates, note links and inline code render, and inline timers count down live. Media and metadata embeds in a cell stay as source text. A pipe inside an embed or a [[Note|Alias]] link does not split the cell. Inside code blocks, full-line math, media lines, and comments, the braces stay literal text. Braces that do not form an embed stay ordinary text, and inline formatting still works inside them. To keep an embed-shaped span literal, escape the opening brace with \{.
Footnotes
Put a ^ at the end of a word, with no space, to mark a footnote. Then define the note on its own line with ^ text.
The cat sat on the mat.^
^ The cat was orange.
The first marker pairs with the first definition, the second with the second, and so on. In the rendered pane this becomes “The cat sat on the mat.¹” with a numbered footer below the section. Unpaired markers render as ˣ.
For longer notes, open a footnote block with ^^.
Important note.^
^^
First paragraph of the footnote.
Second paragraph continues here.
^^
A footnote block renders as a callout in the right pane. The footnote number sits in the block’s header, so the body reads on its own. Escape a marker with \^ to render a literal caret. In Settings → Markup, you choose where footnote definitions appear: in the body, next to the reference, or in a footer at the end of the section.
Custom callouts
Beyond the two built-in callouts (! highlight, " quotation), you can define your own. Each custom callout has a prefix character, a name, an SF Symbol icon, a color, a font weight (regular or medium), and an italic toggle. Configure them in Settings → Markup.
A custom callout supports the same forms as a built-in one: a single line, a multi-line block (named or unnamed), and a typed removal target (_ <prefix> name). Toggle a custom callout off in Settings to make its prefix render as plain text again. You can also change which character any built-in type uses in the same Settings pane.
Earlier versions shipped a built-in question type on ?. That prefix is unassigned now. To get question-styled lines back, create a custom callout on ?. It behaves the same way, block form included.
Metadata
The $ character at the start of a line attaches metadata to a note. Rows shaped like key=value become a chip block at the top of the rendered pane. A $ line without an = is a free-form note, rendered verbatim. Reserved keys like tags, due, and priority get typed values and route to native fields on export.
$ tags=lisbon, trip ← tag chip, matches in note browser filters
$ source=https://example.com/article ← clickable source link
$ remember the shipping address ← free-form note, rendered verbatim
See the metadata guide for the full set of reserved keys, value types, destination-scoped pairs, and metadata scoped to a section or item.
Prefix reference
All 20 prefixes in one table. The first eight are the everyday set from The basics.
| Prefix | Type | Description | Example |
|---|---|---|---|
# | Heading | Creates a section heading. Everything below it groups under that heading on the right. |
→ Project Notes |
+ | Task | Adds an unchecked task. Tasks float to the top of their section on the right. |
→ ☐ Buy groceries |
- | Done | Checks off a task by fuzzy-matching its name. Content after the space is the task name to match. Use _ to remove items of any other type. |
→ ☑ Buy groceries |
! | Highlight | Marks a line as important. Rendered bold and prominent on the right. |
→ Demo is at 3pm |
" | Quote | Wraps a line in a styled blockquote with a left border. |
→ “Simple things should be simple” |
* | Bullet | Creates a bullet point. Multiple bullets form a list under the nearest heading. |
→ • Bring the good coffee |
% | Numbered | Creates a numbered list item. Auto-numbered on the right side. |
→ 1. First step |
@ | Media | Embeds an image or video from a file path, URL, or dropped file. |
→ [image: photo.jpg] |
` | Code | A line of code. Add a language hint right after the prefix for syntax highlighting. |
→ console.log("hello") |
= | Math | Evaluates a math expression inline. Unit-aware arithmetic across lengths, weights, times, and temperatures. Variables and constants (pi, e) included. |
→ 62.14 mi |
: | Timer | Starts a countdown timer. Phases separate with commas, as in 5m work, 5m rest. A mode word glued to the prefix changes the clock: :repeat starts over each time it finishes, :repeat4 stops after four cycles, :alarm 15:30 waits for a time or a date, and :since 2026-06-01 counts up from one. Mudlark can notify you when a timer ends, if you turn that on in Settings. |
→ 25:00 ▶ |
& | Table | Creates a table row. Use | to separate columns. First row becomes the header. |
→ Name | Role | Status |
> | Move | Re-parents an item to the current section by type and fuzzy match. Requires a type prefix. Add @ to send to a specific section (e.g. > + fix or > + fix @ Home). Double the type prefix (> ++ name) to move a whole named block instead of one item. |
→ [moved: fix bug] |
. | Write-to | Creates a new item under an @ destination heading (e.g. . + milk @ Shopping). An optional type prefix sets the item type; without one, the line is written as plain text. |
→ [added to Shopping] |
_ | Remove | Removes an item or section by type and fuzzy match (e.g. _ ! ship or _ # old). The inner type prefix needs its own trailing space. Double the inner prefix (_ ++ name) to remove a whole named block. That is the only way to target composite blocks like code, tables, or math. |
→ [highlight removed] |
/ | Comment | A private note that only appears on the left side. Never rendered on the right. |
→ (hidden) |
~ | Rule | Draws a horizontal rule. Completions and moves cannot cross it. Add a label to center text on the rule. |
→ ——— Chapter 2 ——— |
, | Find | Searches content above. Add | replacement to replace all matches. Add @ heading to scope to a section. |
→ [3 replaced] |
^ | Footnote | Defines a footnote. Drop a bare ^ at the end of a word (no space) to attach a sentinel. On its own line, ^ text defines the footnote. Sentinels and definitions pair by source order. |
→ ¹ The cat was orange. |
\ | Escape | Makes the rest of the line plain text. Bypasses all prefix parsing. |
→ + Not a task |
$ | Metadata | Per-note metadata surfaced as a chip in the rendered pane. Use key=value rows like $ tags=trip, $ source=https://… or free-form notes like $ remember the shipping address. |
→ [tags: lisbon, trip] |