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 and timers, 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 23 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 |
? | Question | Flags a line as a question. Rendered in italics on the right so open questions stay visible. |
→ Should we move the deadline? |
" | 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 |
@ | 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”
Removing items and sections
To remove any other kind of item, use _ followed by the type’s prefix. Works with Heading, Task, Highlight, Question, Quote, Bullet, Media, Numbered, Code, Math, Timer, Loop, Table, Footnote.
? Should we change the deadline?
_ ? deadline ← removes the question
! 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 a pipe 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 pipe, the matched heading and its contents re-parent into the current section. With a pipe, they re-parent under the destination 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 type prefix, the content, then a pipe and the destination heading.
. + eggs | Shopping ← adds the task under the “Shopping” heading
> moves an existing item. . creates a new one. The pipe destination is required.
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. Outside those contexts, Tab still 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.
Math and units
The = character evaluates math expressions. Units flow through every operator, so you can add, subtract, and convert between compatible quantities.
= 42 * 1.21 ← 50.82
= 5 km + 3 mi ← 9.83 km
= 100 km to mi ← 62.14 mi
= x = 5 ← assigns 5 to x
= x * 2 ← 10
Operators and constants
Supports + - * / ^ (power, right-associative), parentheses, and the constants pi and e.
Functions
Take a list of values: sum, avg (also mean, average), min, max, count, median, range. Take a single value: sqrt, abs, floor, ceil, round (with optional precision, e.g. round(3.14159, 2)), product.
Most functions preserve the unit of their inputs. count always returns a unitless number. sqrt and product reject unit-bearing inputs.
= sum(10, 20, 30) ← 60
= avg(85, 92, 78) ← 85
= sqrt(144) ← 12
Math blocks
A doubled == opens a math block. Add a name after the prefix to label it. Variables defined inside are scoped to the block.
== Budget
5000 - 1500
5000 - 2000
==
Aggregating prefix
Glue a function name onto the doubled prefix to roll every line in the block into a single result. The footer shows the function, value, and count.
==sum
100
200
300
==
sum = 600 (3 values)
Combine both forms: ==sum totals labels the block and aggregates it. Any of the list functions above (sum, avg, min, max, count, median, range, product) can be used as an aggregating prefix.
Unit conversion
Use to to convert a quantity between compatible physical units: length, weight, temperature, and duration.
= 100 km to mi ← 62.14 mi
= 5 kg to lb ← 11.02 lb
= 20 °C to °F ← 68 °F
Chained conversions parse right to left, so = 5 km to mi to yd converts to miles, then to yards. A bare scalar with to has no source unit, so = 5 to km is an error.
Timers and loops
The : character starts a countdown timer. Write a duration after the prefix. Mudlark notifies you when it finishes. The ; character starts a looping timer that restarts each time it finishes.
: 25m ← counts down from 25:00
; 5m ← restarts every 5 minutes
A timer can run several phases in a row. Separate them with commas and give each an optional name: : 25m work, 5m rest.
Doubled :: opens a named timer block, like :: Workout. Timers can also live inside a sentence. See Inline embeds.
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.
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. Five types embed:
| Inline | Type | Example |
|---|---|---|
{{@ }} | Media | {{@ photo.jpg}} |
{{= }} | Math | {{= 100 km to mi}} |
{{` }} | Code | {{`swift let x = 1}} |
{{: }} | Timer | {{: 25:00 Focus}} |
{{; }} | Loop | {{; 5:00 Break}} |
The trip is {{= 1240 km to mi}}, leaves on {{@ lisbon-balcony.jpg}}, and runs for {{: 25:00 Focus}}.
Inline math
The same engine that drives full-line = expressions runs inside {{= }}: unit-aware arithmetic across lengths, weights, times, and temperatures, plus any variables you defined earlier in the document. The right pane shows the formatted result, the source survives in the editor.
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 (tap to copy, Cmd-click to open). Remote URLs load asynchronously. Videos show a poster and open in the default app on click.
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 and loops
{{: 25:00 Focus}} for a countdown, {{; 5:00 Break}} for a loop. The rendered pane shows an icon and a formatted duration, ticking down 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 and loops.
Where embeds work
Embeds and [[note links]] work inside prose: headings, tasks, highlights, questions, quotes, bullets, numbered items, footnote definitions, and custom callouts. Inside code blocks, full-line math, tables, media lines, and comments, the braces stay literal text. Put the embed on a prose line if you want it to render. Escape a literal brace pair 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 three built-in callouts (! highlight, ? question, " quote), 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.
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, and destination-scoped pairs.
Prefix reference
All 23 prefix characters 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 |
? | Question | Flags a line as a question. Rendered in italics on the right so open questions stay visible. |
→ Should we move the deadline? |
" | 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 |
@ | Media | Embeds an image or video from a file path, URL, or dropped file. |
→ [image: photo.jpg] |
% | Numbered | Creates a numbered list item. Auto-numbered on the right side. |
→ 1. First step |
` | 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. Notifies when done. Supports multi-phase timers (e.g. 5m work, 5m rest). |
→ 25:00 ▶ |
; | Loop | Starts a looping timer that restarts automatically when it finishes. |
→ 5: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 a pipe 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 an item of a target type under a destination heading. Requires a pipe destination (e.g. . + milk | Shopping). |
→ [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. |
→ [question 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] |