Iota Syntaxis Specification

Version 1.0 RC5 (July 11, 2026)

Iota Syntaxis is a lightweight annotation syntax orthogonal to most text formats (Markdown, HTML, LaTeX, plain text). A text is any file or string carrying Iota Syntaxis constructs.

This document is normative.

The renderer layer (how parsed Iota Syntaxis constructs are transformed into host-format markup) is specified separately in jotr. Parser conformance (this document) and renderer conformance are independent.

The key words MUST, SHOULD, and MAY are used as defined in RFC 2119.

Part I: Syntax & Semantics

1 Design Principles

  1. Format-agnostic. Every construct works identically in .md, .txt, .tex, and .html files.

  2. Doubled sigils. Every core construct uses a doubled ASCII punctuation character.

  3. Unicode identifiers. Sigils use ASCII characters available on most keyboards. Identifier character sets follow Unicode XID_Start / XID_Continue (plus underscore as an honorary XID_Start); see the ASCII-only Jot Syntax variant for the portability-first counterpart.

  4. Inline and unobtrusive. Constructs appear within prose without disrupting human readability.

  5. Orthogonal to tooling. This specification defines syntax and parser output; renderer behavior is specified separately in jotr. Storage, indexing, querying, and rendering beyond the renderer output rules are out of scope.

  6. No escaping. Implementations MAY offer parsing-control flags (§9) to disable individual construct families.

2 The Doubled-Symbol Family

Iota Syntaxis comprises eight core constructs:

Sigil Name Example
.. Tag ..project
:: Category ::work::projects
-- ID Reference --meeting_notes, --work--42
// File Reference //notes.md, ///work/notes.md
;; Resource ;;report.pdf
?? Todo ??review proposal
== URL ==https://example.com
!! Bookmark !!introduction

Each sigil is immediately followed by its payload. No whitespace is permitted between the sigil and the payload.

In addition, three suffix forms attach to references and resources:

Suffix Name Example
:N, :N-M, :N+L Line fragment specifier --42:10-20
#name Bookmark specifier --42#intro
##a,b Bookmark range specifier --42##intro,summary

3 Construct Boundaries

Every construct is delimited by a left and a right boundary. These rules apply uniformly unless a per-construct exception is noted.

3.1 Left Boundary

A construct’s sigil MUST be preceded by either start-of-line or whitespace (space or tab). Any other preceding character — including punctuation — is not a valid left boundary.

Invalid Corrected
(--42) (see --42) or ( --42)
"--42" "see --42" or " --42"
--42/--43 --42 / --43
foo..bar foo ..bar

3.2 Right Boundary

A construct’s payload ends at the first of:

  1. whitespace (space or tab),

  2. end of line, or

  3. a trailing punctuation character from the set . , ; : " \' ! ? ) ] }.

Trailing punctuation is not consumed as part of the payload.

Input Payload Trailing
See --42. 42 .
Check --42, --43, and --44. 42, 43, 44 ,, ,, .
(see --42) 42 )
Read ..meeting, then continue. meeting ,

Per-construct exceptions.

Suffix introducers before whitespace.

A suffix or specifier introducer appended to a construct is treated as construct syntax only when payload content follows. When an introducer composed of trim-set characters (:, ::, .., ;;) is immediately followed by whitespace or end of line, it is not a suffix attempt: the construct ends before the introducer, and the introducer’s characters are ordinary trailing punctuation. See --42: the discussion emits the bare reference --42 with : as trailing punctuation; --42:: at end of line likewise emits --42. The bookmark-specifier introducers # and ## are not trim-set characters; followed by whitespace or end of line they remain parse errors (§13). This rule concerns introducers appended to a construct; a free-standing sigil at a construct boundary with no payload is an empty payload parse error (§11).

Trim-then-validate.

The right boundary is determined in two steps: the construct’s grammar consumes greedily, then a maximal run of trim-set characters extending to whitespace or end of line is trimmed as trailing punctuation. Any remaining character the grammar cannot consume — an internal trim-set character (..meet!ing) or a character outside the trim set (--42$ref) — invalidates the whole candidate span: the parser MUST report the full span as a parse error (Jots/Parsing/InvalidPayloadChars, or a more specific canonical code where one applies — §11) and MUST NOT silently emit a shorter valid prefix. ..meeting! is therefore a clean tag (the ! run reaches whitespace and is trimmed), while ..meet!ing and --42$ref are parse errors.

URL right-boundary examples:

Input URL payload Trailing
==https://example.com. https://example.com .
(see ==https://example.com) https://example.com )
==https://example.com/p?q=1. https://example.com/p?q=1 .
==https://example.com/a.b) https://example.com/a.b )

4 Constructs

4.1 Tags (..)

Syntax.

..NAME or ..NAME..NAME2..NAME3...

A tag is two periods immediately followed by one or more identifier characters (Unicode XID_Start + XID_Continue, plus underscore).

Adjacent tags MAY be chained without intervening whitespace; each ..NAME segment in the chain is a separate tag.

Semantics.

Optional extension.

Implementations MAY accept #word as an alternate tag form when the parse\_hashtags\_as\_tags flag is enabled. The hashtag payload MUST begin with a letter (§7.9): #2026 and #_draft are not matched, although ..2026 and .._draft are. This extension is disabled by default.

Example.

A tagged meeting note:

Met with the design team today ..meeting ..urgent

4.2 Categories (::)

Syntax.

::NAME or ::NAME::SUB::SUBSUB...

A category is two colons immediately followed by one or more ::-separated word segments (each segment is one or more identifier characters — Unicode XID_Start + XID_Continue, plus underscore).

Semantics.

Example.

A categorized project note:

Project kickoff notes ::work::projects::alpha

4.3 ID References (--)

ID references link between texts. An ID is one or more identifier characters (XID_Start + XID_Continue, plus underscore);

its meaning is determined by the host tool.

Forms.

Form Syntax Example
Same-space --ID --42, --meeting_notes
Cross-space --SPACE--ID --work--42

Semantics.

Examples.

ID references in a sentence:

See --42 for the previous discussion.
Related to --work--42 in the work journal.

4.4 File References (//)

File references identify another text by file path rather than ID.

Forms.

Form Syntax Example
Same-space //FILEPATH //notes.md
Cross-space ///SPACE/FILEPATH ///work/notes.md

FILEPATH is a /-separated sequence of filename segments, where each segment follows the <filename> grammar (§7.6).

Semantics.

Examples.

File references in a sentence:

See //notes.md and //subfolder/architecture.md.
Diagram in ///design/assets/layout.svg.

4.5 Resource References (;;)

Syntax.

;;FILENAME

A resource reference identifies an auxiliary file associated with a text (e.g., an attachment, an embedded image, a bibliography file).

Filename grammar.

A valid filename is one or more identifier characters (Unicode XID_Start / XID_Continue, plus underscore),

period (.), hyphen (-), tilde (~), comma (,), at-sign (@), exclamation mark (!), and parentheses ((, )), subject to:

The exclusions of whitespace, shell metacharacters (+* ? [ ] |  ‘+), URI-sensitive characters (% + # & =), :, and ; apply uniformly. The full grammar is in §7.6.

Portability.

File and resource references intentionally support a portable subset of path syntax (identifier characters plus a small punctuation set).

Implementations targeting hosts with arbitrary filesystem path conventions (Windows backslash paths, paths containing spaces or non-ASCII characters, NFC/NFD normalization, etc.) SHOULD provide a host-specific mapping layer that translates the portable syntax to and from native paths, rather than extending the grammar.

Semantics.

Examples.

Resource references in a sentence:

See the attached ;;report.pdf for details.
Diagram in ;;architecture.png.

4.6 Todo Items (??)

Syntax.

A todo item is composed of:

??[.][<importance>][<blockers>]<action>[<due>][<cat>][<tag>]...[ <description>]

A todo item begins with ?? and is terminated by end of line. Throughout this specification, <cat> denotes a full sigil-inclusive category suffix (::path) and <tag> denotes a full sigil-inclusive tag suffix (..word); the leading sigil is part of the placeholder.

Components.

@L2.1cmL4.0cmL0.8cmL6.6cm@ Component & Syntax & Req. & Example
Done marker & . immediately after ?? & No & ??.review, ??.!!review, ??.(draft)implement
Importance & ! (1–3 times) & No & ??!, ??!!, ??!!!
Blockers & (<entry>(,<entry>)*) — see Blockers below & No & ??(draft)implement, ??(draft::spec..john)review
Action & <word> & Yes & ??buy, ??review
Due date & @YYYY-MM-DD or @YYYY-MM-DDTHH:MM[TZ] & No & ??send@2026-03-01
Annotation & [<cat>][<tag>]... & No & ??review::work..important
Description & : free text or free text & No & ??buy: milk and eggs

Semantics.

Examples.

Active todos, done todos, and todos with completion timestamps:

??buy milk
??!send@2026-03-01 quarterly report
??!!review@2026-03-15T09:00-05:00 architecture doc
??review::work..important
??.review proposal
??.!!(draft::spec)merge::work..urgent
??.send quarterly report .@2026-03-02
??.review architecture doc .@2026-03-15T17:45-05:00

Description-form classifier.

The forms below are all valid and parse to action buy with description milk:

Input Action Description
??buy milk buy milk
??buy: milk buy milk
??buy : milk buy milk
??buy:milk buy milk

When a due date or annotations are present, the optional colon may attach to whichever of them is last:

??send@2026-03-01: quarterly report
??review::work..important: architecture doc

Todo span and nested constructs.

A todo claims everything from ?? to end of line. Tags, categories, references, file references, resource references, inter-jot resources, and URLs that appear inside that span — whether in the annotation slot or post-scanned from the description — are emitted into the enclosing todo, not the text’s top-level lists. See §5.2. For tags and categories this means the annotation-slot form (??buy..groceries milk) and the description form (??buy milk ..groceries) are equivalent: both yield a todo whose tags includes groceries.

Bookmark declarations (!!name) are the one exception: a !!name inside a todo span is not extracted as a bookmark and is not attached to the todo. The parser MUST drop the declaration from output and SHOULD emit a diagnostic (§14). To anchor the line that carries a todo, place the bookmark before the ??:

!!followup ??review proposal

Because bookmarks are line-level (§4.8), this anchors the entire line — todo included — without entangling the bookmark with the todo’s span.

Blockers.

A todo MAY declare one or more blockers — patterns identifying other todos whose completion must precede this one. The blocker slot appears in parentheses between the optional importance prefix and the action. Each entry is structured as an action plus optional <cat> and <tag> constraints:

??(draft)implement
??(draft::spec)review
??(draft..john)review
??(draft::spec..john)review
??(review,typeset)publish
??!(review)merge

Entry grammar.

Each entry takes one of two shapes:

Within an entry, <cat> MUST precede the <tag>s, mirroring the annotation-slot ordering rule. At most one <cat> per entry, with zero or more <tag>s. No importance, due date, or description fragments are permitted inside a blocker entry.

Multiple entries are comma-separated and combine conjunctively (all must complete):

??(draft::spec,review..urgent)merge

Parse errors.

Canonical diagnostic codes for these conditions are listed in §11.

Resolution is application-defined.

The parser MUST NOT attempt to resolve a blocker entry to any todo. Each entry is emitted on the todo’s blockers field as a structured object (§8); matching it to a real todo — within the same text, across texts, against an external index, or not at all — is the responsibility of the consuming application.

4.7 URLs (==)

Syntax.

==URL, ==(LABEL)URL, or ==[LABEL]URL

Semantics.

Examples.

Bare and labeled URLs in prose:

Check out ==https://example.com for more info.
See ==(project homepage)https://github.com/example/project for source.
See ==[docs (internal)]https://example.com/docs for details.

4.8 Bookmarks (!!)

Syntax.

!!NAME

A bookmark declares a named anchor at the line containing the declaration.

Semantics.

Example.

A bookmark declaring an anchor for the line it sits on:

!!introduction
This is the introduction section.

4.9 Bookmark Specifiers (#name)

A #name suffix appended to an ID reference, file reference, or resource reference links to the named anchor in the target.

Form Example
Same-space ID reference --42#introduction
Cross-space ID reference --work--42#summary
Same-space file reference //notes.md#conclusion
Cross-space file reference ///work/notes.md#overview
Standalone resource ;;report.pdf#chapter1
Inter-jot resource --42;;report.pdf#chapter1

A bookmark specifier is mutually exclusive with a line fragment specifier (§4.11) and with a bookmark range specifier (§4.10): a reference MAY carry at most one specifier.

When a bookmark specifier is used on a resource whose type does not support named anchors (e.g., a plain CSV file), implementations SHOULD emit a resolution warning (§14).

4.10 Bookmark Range Specifiers (##)

A ## suffix selects the content between two bookmarks.

@L3.2cmL2.6cmL7.4cm@ Form & Syntax & Meaning
Start to bookmark & ##,name & From the beginning of the text/resource up to (but excluding) !!name
Bookmark to end & ##name, & From immediately after !!name to the end of the text/resource
Between bookmarks & ##name1,name2 & From immediately after !!name1 up to (but excluding) !!name2

Semantics.

Where it applies.

ID references, file references, resource references, and inter-jot resources (on the resource filename, not on the locator prefix).

Examples.

Bookmark range specifiers on each construct family that accepts them:

--42##intro,summary
--work--42##,conclusion
//notes.md##intro,summary
;;data.csv##header,footer
--42;;report.pdf##intro,conclusion

Host format support.

No widely deployed host format natively supports range selection between named anchors. Implementations SHOULD pass ## syntax through into rendered link targets unchanged.

Parser representation.

Parsers expose a bookmark_range object with start_bookmark and end_bookmark (each +string | null+). start_bookmark is null for the ##,name form; end_bookmark is null for the ##name, form. Resolution to byte offsets occurs at render time, not at parse time.

4.11 Line Fragment Specifiers

A line fragment specifier narrows a reference or resource to a specific line or line range, by numeric position.

@L2.2cmL2.5cmL5.6cmL3.2cm@ Form & Syntax & Meaning & Example
Single line & :LINE & One line; shorthand for :LINE-LINE & //notes.md:42
Range & :START-END & Lines START through END inclusive & --42:10-20
Offset+length & :START+LENGTH & Line START plus LENGTH additional lines & --42:10+5

Where it applies.

ID references, file references, resource references, and inter-jot resources (on the resource filename, not on the locator prefix). Line fragment specifiers also appear in inline include constructs defined in jotpp.

Semantics.

Examples.

Line fragments combined with annotations:

--42:10-20::work..draft
//notes.md:100-120..review
;;data.csv:1-50::import..urgent

5 Inter-Jot Resources

Reference and resource constructs compose to denote resources owned by other texts:

@L6.7cmL7.5cm@ Syntax & Meaning
;;file.pdf & Resource on the current text
--42;;file.pdf & Resource on text 42 (same space)
--work--42;;file.pdf & Resource on text 42 in space work
//notes.md;;file.pdf & Resource on file-text notes.md
///work/notes.md;;file.pdf & Resource on file-text notes.md in space work
--42;;data.csv:1-50 & Lines 1–50 of data.csv on text 42
--42;;report.pdf##intro,conclusion & Bookmark range on report.pdf on text 42

Disambiguation rule.

When multiple construct patterns could match overlapping spans of input, the longest match takes priority. Among matches of equal length, the more specific construct wins: inter-jot resource references take priority over standalone references or standalone resources; cross-space forms take priority over same-space forms; and annotated references take priority over bare references.

Locator vs. resource.

In an inter-jot reference, the prefix (--42, --work--42, //notes.md, ///work/notes.md) serves only as a locator. Annotation suffixes and specifiers MUST NOT appear between the locator and the ;; separator (§12). They MAY appear after the filename:

--42;;report.pdf..draft
--42;;report.pdf::work
--42;;data.csv:1-50
--42;;report.pdf##intro,conclusion

These suffixes annotate the resource edge, not the current text’s own tag or category lists.

5.1 Malformed Tokens

When the input begins a candidate token with a recognized sigil and the following characters introduce suffix, specifier, or inter-jot syntax, the parser MUST validate the entire candidate token against the grammar before deciding what to emit. If the token violates an ordering or mutual-exclusion constraint defined in this specification, the parser MUST emit a single diagnostic covering the full candidate span and MUST NOT silently emit a shorter valid prefix.

For example, given the input --42..tag;;file.pdf, a parser MUST NOT emit --42..tag as a tagged ID reference and treat the remainder as inert text. The presence of ..tag;;file.pdf makes the whole token a candidate inter-jot resource reference; the annotation suffix between the locator and ;; violates §12. The parser MUST report the entire --42..tag;;file.pdf span as a parse error.

The same rule applies to specifier composition: given --42:10;;file.pdf, the parser MUST report the entire span as a parse error per §12 rather than emitting --42:10 as a same-space reference with a line fragment specifier.

5.2 No Construct Nesting

Constructs do not nest. Once the parser consumes a span as part of a matched construct, no other construct is emitted from within that span. Specifically:

6 Annotated References

ID references and file references MAY carry tag and category suffixes that annotate the relationship (edge) from source to target, not the current text itself.

6.1 Tagged References

A reference MAY be followed by one or more tag suffixes (..word):

--42..next
--42..important..draft
--work--42..next
//notes.md..draft
///work/notes.md..urgent

Tags on references follow the same case-folding rules as free-standing tags: case-insensitive, stored in canonical lowercase.

6.2 Categorized References

A reference MAY be followed by a single category suffix (::path):

--42::work
--42::work::projects
//notes.md::review

Only one category MAY appear per reference. Categories on references follow the same case-folding rules as free-standing categories.

6.3 Combined Suffixes

When both a category and tags are present, the category MUST precede the tags:

--42::work..important
--work--42::projects::alpha..next..urgent
//notes.md::review..draft

--42..important::work is not valid and MUST NOT be matched as an annotated reference (§12).

6.4 Semantics

6.5 Annotated Todos

Todos accept the same suffix system as references. A todo’s suffixes classify the todo item itself, not the current text.

??review..accounts
??review..accounts..overdue
??review::work
??review::work::projects..urgent..draft
??!send::finance..quarterly

The category-before-tags ordering constraint is mandatory (§12). The annotation slot accepts at most one category and zero or more tags. Description post-scan (§5.2) MAY contribute additional categories and tags; the slot and post-scan sources are merged and deduplicated into the todo’s categories and tags lists. None of these contribute to the text’s own tag or category lists.

6.6 Annotated Resource References

Resource references accept the same suffix system as ID and file references. Suffixes annotate the resource edge from the current text to the resource.

;;report.pdf..draft
;;report.pdf::work
;;report.pdf::work..draft..urgent
--42;;report.pdf..draft
--work--42;;report.pdf::work..draft..urgent
///work/notes.md;;file.pdf..tag

The category-before-tags ordering constraint is mandatory (§12). On inter-jot resource references, suffixes MUST appear after the filename, not between the locator and ;;12). Suffixes do not add to the text’s own tag or category lists.

7 Formal Grammar

The following grammar defines Iota Syntaxis in BNF. All productions are applied as a global, multiline scan of the input text.

7.1 Common Productions

<word-char>          ::= <letter> | <digit> | "_"
<word>               ::= <word-char>+
<letter>             ::= "A" | "B" | ... | "Z" | "a" | "b" | ... | "z"
<digit>              ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<uint>               ::= <digit>+
<ws>                 ::= " " | "\t"
<line-terminator>    ::= "\n" | "\r\n" | "\r"
<line-start>         ::= (* zero-width assertion: start of input, or
                            position immediately after a
                            <line-terminator> *)
<line-end>           ::= (* zero-width assertion: end of input, or
                            position immediately before a
                            <line-terminator> *)
<construct-boundary> ::= (* zero-width assertion: position preceded by
                            beginning of line or whitespace; equivalent
                            to the regex lookbehind (?<=^|[ \t]) with
                            multiline ^ *)

In the Iota Syntaxis variant, <word-char> is widened so that <letter> ranges over Unicode XID_Start and <word-char> additionally admits XID_Continue code points. The enumeration above is written for the ASCII Jot Syntax variant; both variants share the rest of the grammar verbatim.

<construct-boundary>, like <line-start> and <line-end>, is a zero-width assertion: it constrains position but does not consume input.

A line is the maximal run of input characters between two <line-terminator> matches (or the bounds of the input). LF (U+000A), CRLF (U+000D U+000A), and CR (U+000D) are all recognized as terminators; CRLF is consumed as a single two-byte unit, never as two adjacent CR + LF terminators. Implementations MUST handle mixed-terminator input without splitting CRLF, and SHOULD preserve the original terminators verbatim when emitting raw substrings.

7.2 Tags

<tagstring> ::= <construct-boundary> <tag-tail>
<tag-tail>  ::= ".." <word> ( ".." <word> )*

A <tagstring> is one or more ..word segments chained without intervening whitespace; each segment is emitted as a separate tag. The <tag-tail> production is also reused by annotated reference and annotated todo suffixes (§7.11, §7.12).

Matched tags are case-folded to lowercase and deduplicated.

7.3 Categories

<category>      ::= <construct-boundary> "::" <category-path>
<category-path> ::= <word> ( "::" <word> )*

Matched categories are case-folded to lowercase and deduplicated.

7.4 ID References

<id-locator>       ::= <construct-boundary> "--" <word>
<cross-id-locator> ::= <construct-boundary> "--" <word> "--" <word>

<same-ref>  ::= <id-locator>       ( <line-fragment-specifier> | <bookmark-specifier> | <bookmark-range-specifier> )?
<cross-ref> ::= <cross-id-locator> ( <line-fragment-specifier> | <bookmark-specifier> | <bookmark-range-specifier> )?

<line-fragment-specifier> is defined in §7.13. <bookmark-specifier> and <bookmark-range-specifier> are defined in §7.14.

ID identifiers and space identifiers are case-sensitive. ID references are emitted in document order, one parser-output object per matched occurrence. Deduplication, indexing, and cross-text reconciliation are the responsibility of the consumer, not the parser.

7.5 File References

<file-ref-locator>       ::= <construct-boundary> "//" <filepath>
<cross-file-ref-locator> ::= <construct-boundary> "///" <word> "/" <filepath>
<filepath>               ::= <filepath-segment> ( "/" <filepath-segment> )*
<filepath-segment>       ::= <filename>

<same-file-ref>  ::= <file-ref-locator>       ( <line-fragment-specifier> | <bookmark-specifier> | <bookmark-range-specifier> )?
<cross-file-ref> ::= <cross-file-ref-locator> ( <line-fragment-specifier> | <bookmark-specifier> | <bookmark-range-specifier> )?

Filepaths and space identifiers are case-sensitive. File references are emitted in document order, one parser-output object per matched occurrence. Deduplication is the consumer’s responsibility.

7.6 Resource References

<resource-ref>     ::= <construct-boundary> ";;" <filename> ( <line-fragment-specifier> | <bookmark-specifier> | <bookmark-range-specifier> )? <annotations>?
<filename>         ::= <fname-segment> ( "." <fname-segment> )*
<fname-segment>    ::= <fname-start-char> <fname-char>*
<fname-start-char> ::= <word-char> | "~" | "," | "@" | "!" | "(" | ")"
<fname-char>       ::= <fname-start-char> | "-"

<annotations> is defined in §7.11.

A <filename> MUST NOT begin with - or .. Consecutive periods (..) within a filename are not producible under this grammar.

After the greedy <filename> / <filepath> match, trailing trim-set characters are stripped repeatedly and treated as following punctuation, per the right-boundary exception in §3.2.

7.7 Todo Items

<todo>            ::= <construct-boundary> "??" <todo-body>
<todo-body>       ::= <todo-content> <todo-terminator>
<todo-terminator> ::= <line-end>
<todo-content>    ::= <done-marker>? <importance>? <blockers>? <action> <due-date>? <annotations>? <description>?

<done-marker>     ::= "."
<completion-time> ::= <construct-boundary> ".@" <iso-date>
<blockers>        ::= "(" <blocker-entry> ( "," <blocker-entry> )* ")"
<blocker-entry>   ::= <word> <category-suffix>? <tag-tail>?
                    | "*" <category-suffix> <tag-tail>?

<category-suffix> ::= "::" <category-path>
<importance>      ::= "!" | "!!" | "!!!"
<action>          ::= <word>
<due-date>        ::= <ws>* "@" <iso-date>
<description>     ::= ":" <free-text>
                    | <ws>+ ":"? <free-text>

<iso-date>        ::= <date-only> | <datetime>
<date-only>       ::= <digit> <digit> <digit> <digit> "-" <digit> <digit> "-" <digit> <digit>
<datetime>        ::= <date-only> "T" <time> <timezone>?
<time>            ::= <digit> <digit> ":" <digit> <digit> ( ":" <digit> <digit> )?
<timezone>        ::= "Z" | ( "+" | "-" ) <digit> <digit> ":" <digit> <digit>

<free-text>       ::= (* any characters except newline *)

<annotations> is defined in §7.12; the category-before-tags ordering constraint is mandatory. The <due-date>, when present, MUST precede the annotations.

A <done-marker> is positional: a literal . MUST appear at the single position immediately after ??, and only there, to mark a done todo. The parser MUST consume <done-marker> before attempting any of the productions that follow; a . in any other position within <todo-content> does not satisfy <done-marker>. Done todos are extracted by the same parse\_todos flag and emitted with the same object schema as active todos, but routed to a separate done_todos list (§8).

<completion-time> is recognized only during description post-scan (§5.2) of a done todo (one whose <todo-content> began with <done-marker>). In an active todo’s description, in non-description regions of a todo, or in input outside any todo span, the .@ sequence is not a recognized sigil. When matched, the parsed date is emitted on the done todo’s completed field (§8) and the matched span remains textually present in description. At most one <completion-time> MAY contribute to a single done todo’s completed field; the first match in document order wins, and each subsequent match raises Jots/Validation/DuplicateCompletionTime13).

Extracted todos are trimmed of leading/trailing whitespace. Todos are emitted in document order, one object per matched occurrence, within their respective list.

The <bookmark> production (§7.14) is suppressed inside <todo-content>: a !!name between ?? and the todo terminator is not matched as a bookmark and produces a diagnostic per §14. All other constructs in the description body are post-scanned per §5.2.

7.8 URLs

<url-construct>       ::= <construct-boundary> "==" <url-payload>
<url-payload>         ::= <labeled-url> | <bare-url>
<labeled-url>         ::= <paren-labeled-url> | <bracket-labeled-url>
<paren-labeled-url>   ::= "(" <paren-label-text> ")" <http-url>
<bracket-labeled-url> ::= "[" <bracket-label-text> "]" <http-url>
<bare-url>            ::= <http-url>
<paren-label-text>    ::= (* any characters except ")" *)
<bracket-label-text>  ::= (* any characters except "]" *)
<http-url>            ::= ( "http://" | "https://" ) <non-ws>+

URLs are emitted in document order, one object per matched occurrence.

7.9 Hashtag Tags (Optional Extension)

<hashtag> ::= <construct-boundary> "#" <letter> <word-char>*

Requires parse\_hashtags\_as\_tags to be enabled. The payload MUST begin with a <letter>: hashtag payloads are a strict subset of .. tag payloads (#2026 is not matched). Matched hashtags are case-folded to lowercase, merged with .. tags, and deduplicated.

Extension freeze.

Hashtag tags are the only sanctioned extension to Iota Syntaxis 1.0. A conforming implementation MAY support this extension and MUST NOT define additional construct families, sigils, suffix forms, or specifier syntaxes beyond those in this specification. Implementations are free to add tooling, output formats, indexing strategies, or storage models around the parser output; the syntax surface itself is closed for 1.0.

7.10 Inter-Jot Resources

<inter-jot-ref> ::= <cross-id-locator>       ";;" <filename> ( <line-fragment-specifier> | <bookmark-specifier> | <bookmark-range-specifier> )? <annotations>?
                  | <id-locator>             ";;" <filename> ( <line-fragment-specifier> | <bookmark-specifier> | <bookmark-range-specifier> )? <annotations>?
                  | <cross-file-ref-locator> ";;" <filename> ( <line-fragment-specifier> | <bookmark-specifier> | <bookmark-range-specifier> )? <annotations>?
                  | <file-ref-locator>       ";;" <filename> ( <line-fragment-specifier> | <bookmark-specifier> | <bookmark-range-specifier> )? <annotations>?

Annotation suffixes and specifiers MUST NOT appear on the locator prefix. They appear only on the resource side, after <filename>.

7.11 Annotated Reference Suffixes

<annotated-ref>   ::= <ref-base> ( <line-fragment-specifier> | <bookmark-specifier> | <bookmark-range-specifier> )? <annotations>
<ref-base>        ::= <id-locator> | <cross-id-locator> | <file-ref-locator> | <cross-file-ref-locator>
<annotations>     ::= <category-suffix> <tag-tail> | <category-suffix> | <tag-tail>

<tag-tail> is as defined in §7.2; <category-suffix> is as defined in §7.7. The category-before-tags ordering constraint is mandatory.

7.12 Annotated Todo Suffixes

<annotated-todo> ::= <construct-boundary> "??" <done-marker>? <importance>? <blockers>? <action> <due-date>? <annotations> <description>? <todo-terminator>
<annotations>    ::= <category-suffix> <tag-tail> | <category-suffix> | <tag-tail>

<tag-tail> is as defined in §7.2. The category-before-tags ordering constraint is mandatory; the <due-date>, when present, MUST precede the annotations.

7.13 Line Fragment Specifiers

<line-fragment-specifier> ::= ":" <uint>
                            | ":" <uint> "-" <uint>
                            | ":" <uint> "+" <uint>

The three forms normalize to a (start, end) pair as described in §4.11. In a reference or resource context, a single : (i.e., not ::, which always introduces a category suffix) that is immediately followed by at least one non-whitespace character introduces a line fragment specifier; the characters that follow are validated against the productions above. If those characters do not form a valid <uint>, range, or offset, the malformed-token rule (§5.1) applies and the entire reference or resource span is reported as a parse error per §13. The parser MUST NOT silently emit the bare reference and treat the : and what follows as inert text. A : immediately followed by whitespace or end of line is not a specifier attempt: the bare reference is emitted and the : is ordinary trailing punctuation (§3.2) — See --42: the discussion emits the bare reference --42.

The grammar admits zero as a line number (--42:0, --42:0-5), but zero is not a valid line number: such fragments are matched and emitted by the parser, then flagged as validation errors per §13. Permissive matching ensures the diagnostic carries the offending construct’s loc and raw for accurate reporting. A zero offset (:START+0) is well-formed and equivalent to :START — it normalizes to (START, START).

7.14 Bookmarks

<bookmark>                 ::= <construct-boundary> "!!" <word>
<bookmark-specifier>       ::= "#" <word>
<bookmark-range-specifier> ::= "##" <word>? "," <word>?

A <bookmark-range-specifier> MUST have at least one of the two <word>? slots non-empty; ##, alone is not valid.

Bookmark names in declarations and specifiers are case-sensitive. Bookmark names within a single text MUST be unique. Bookmark declarations are extracted in document order.

The <bookmark> production is suppressed inside <todo-content>7.7); see §14.

<line-fragment-specifier>, <bookmark-specifier>, and <bookmark-range-specifier> are mutually exclusive on a given reference or resource: at most one of the three may be matched.

Part II: Parser

8 Parser Output

The parser accepts source text and optional configuration flags and returns structured metadata. It does not modify the input text.

Output fields.

@L3.3cmL2.3cmL8.1cm@ Field & Type & Description
tags & list of strings & Canonical (lowercase) free-standing tag names outside any todo span
categories & list of strings & Canonical (lowercase) free-standing category paths outside any todo span
references & list of objects & Same-space ID references outside any todo span
cross_references & list of objects & Cross-space ID references outside any todo span
file_references & list of objects & Same-space file references outside any todo span
cross_file_references & list of objects & Cross-space file references outside any todo span
inter_jot_resources & list of objects & Inter-jot reference–resource pairs outside any todo span
resources & list of objects & Standalone resource references outside any todo span
todos & list of objects & Parsed active todo items (no done marker)
done_todos & list of objects & Parsed done todo items (??. form); same todo object schema as todos
urls & list of objects & Parsed URL constructs outside any todo span
bookmarks & list of objects & Bookmark declarations in this text (case-sensitive, document order; on duplicate declarations the first wins, §4.8)
diagnostics & list of objects & Diagnostics raised during parsing; per-object shape per §10.1

Object structures.

Every construct object listed below additionally carries loc (an object locating it in the source) and raw (the exact matched source string). These two fields are omitted from the per-object field lists for compactness; they are normative and MUST be present on every object emitted in references, cross_references, file_references, cross_file_references, inter_jot_resources, resources, todos, done_todos, urls, and bookmarks, unless suppressed by the emit\_loc flag (§9). The nested fragment and bookmark_range sub-objects do not carry their own loc / raw.

@L3.1cmL11.1cm@ Object & Fields
reference & id, fragment, bookmark, bookmark_range, category, tags
cross_reference & space, id, fragment, bookmark, bookmark_range, category, tags
file_reference & filepath, fragment, bookmark, bookmark_range, category, tags
cross_file_reference & space, filepath, fragment, bookmark, bookmark_range, category, tags
inter_jot_resource & space, id, filepath, filename, resource_fragment, resource_bookmark, resource_bookmark_range, category, tags
resource & filename, fragment, bookmark, bookmark_range, category, tags
fragment & start (integer), end (integer), raw (string)
bookmark_range & start_bookmark (+string | null+), end_bookmark (+string | null+)
blocker & action (string), cat (+string | null+), tags (list of strings)
todo & importance (integer), blockers (list of blocker objects), action, categories, tags, due (+string | null+), completed (+string | null+), description, references, cross_references, file_references, cross_file_references, inter_jot_resources, resources, urls
url & url, label (+string | null+)
bookmark & name (string)

Field rules.

Example.

Given the input:

Met with design team ..meeting ..urgent ::work::projects
See --42..next for context. Related to --work--42::review..urgent..draft
Check ;;report.pdf and --42;;slides.pdf and --work--99;;deck.pdf
See //notes.md..draft and ///work/design.md::review
??!review@2026-03-15::work..important architecture doc
??.draft initial outline .@2026-03-10
==(docs)https://docs.example.com
!!introduction

the parser returns the structure shown below. For brevity the loc and raw fields are elided from each emitted construct object; they are nonetheless required on every entry of references, cross_references, file_references, cross_file_references, inter_jot_resources, resources, todos, done_todos, and urls.

{
  "tags": ["meeting", "urgent"],
  "categories": ["work::projects"],
  "references": [
    { "id": "42", "fragment": null, "bookmark": null, "bookmark_range": null, "category": null, "tags": ["next"] }
  ],
  "cross_references": [
    { "space": "work", "id": "42", "fragment": null, "bookmark": null, "bookmark_range": null, "category": "review", "tags": ["urgent", "draft"] }
  ],
  "file_references": [
    { "filepath": "notes.md", "fragment": null, "bookmark": null, "bookmark_range": null, "category": null, "tags": ["draft"] }
  ],
  "cross_file_references": [
    { "space": "work", "filepath": "design.md", "fragment": null, "bookmark": null, "bookmark_range": null, "category": "review", "tags": [] }
  ],
  "inter_jot_resources": [
    { "space": null,   "id": "42", "filepath": null, "filename": "slides.pdf", "resource_fragment": null, "resource_bookmark": null, "resource_bookmark_range": null, "category": null, "tags": [] },
    { "space": "work", "id": "99", "filepath": null, "filename": "deck.pdf",   "resource_fragment": null, "resource_bookmark": null, "resource_bookmark_range": null, "category": null, "tags": [] }
  ],
  "resources": [
    { "filename": "report.pdf", "fragment": null, "bookmark": null, "bookmark_range": null, "category": null, "tags": [] }
  ],
  "todos": [
    {
      "importance": 1, "blockers": [], "action": "review", "categories": ["work"], "tags": ["important"],
      "due": "2026-03-15", "completed": null, "description": "architecture doc",
      "references": [], "cross_references": [],
      "file_references": [], "cross_file_references": [],
      "inter_jot_resources": [], "resources": [], "urls": []
    }
  ],
  "done_todos": [
    {
      "importance": 0, "blockers": [], "action": "draft", "categories": [], "tags": [],
      "due": null, "completed": "2026-03-10", "description": "initial outline .@2026-03-10",
      "references": [], "cross_references": [],
      "file_references": [], "cross_file_references": [],
      "inter_jot_resources": [], "resources": [], "urls": []
    }
  ],
  "urls": [
    { "url": "https://docs.example.com", "label": "docs" }
  ],
  "bookmarks": [{ "name": "introduction" }],
  "diagnostics": []
}

Description post-scan example.

Given the input:

??review proposal ..draft ;;contract.pdf before signing

the todo emits:

{
  "importance": 0, "blockers": [], "action": "review", "categories": [], "tags": ["draft"],
  "due": null, "completed": null, "description": "proposal ..draft ;;contract.pdf before signing",
  "references": [], "cross_references": [],
  "file_references": [], "cross_file_references": [],
  "inter_jot_resources": [],
  "resources": [
    { "filename": "contract.pdf", "fragment": null, "bookmark": null, "bookmark_range": null, "category": null, "tags": [] }
  ],
  "urls": []
}

Note that ..draft and ;;contract.pdf remain textually in description, but are also extracted into the todo’s tags and resources. Neither appears in the text’s top-level tags or resources lists.

The specifier sub-objects, by example:

With loc and raw included, the first entry of references in the example above (from a parser using UTF-8 byte offsets) is:

{
  "id": "42",
  "fragment": null,
  "bookmark": null,
  "bookmark_range": null,
  "category": null,
  "tags": ["next"],
  "loc": { "unit": "byte", "start": 61, "end": 71 },
  "raw": "--42..next"
}

and the introduction entry of bookmarks is:

{
  "name": "introduction",
  "loc": { "unit": "byte", "start": 373, "end": 387 },
  "raw": "!!introduction"
}

9 Parsing Control Flags

Configuration sources, in decreasing priority:

  1. Environment variablesJOTS\_* prefixed variables.

  2. Local project file.jot.toml in the current working directory or any parent directory (searched upward).

  3. User-level file$HOME/.jot.toml.

A higher-priority source overrides a lower-priority source for the same key. Keys not specified in any source use the defaults below. Implementations that expose CLI flags for these keys (e.g., --no-loc for emit\_loc) SHOULD give them precedence over all three sources.

The JOTS\_* prefix, the .jot.toml file name, the output field names (§8), and the Jots/... diagnostic layer (§10.1) are shared verbatim by the Jot Syntax and Iota Syntaxis variants; none of them vary with the variant.

@L3.3cmL4.1cmL1.0cmL5.4cm@ Key & Env var & Default & Controls
parse\_tags & JOTS\_PARSE\_TAGS & true & ..tag extraction
parse\_categories & JOTS\_PARSE\_CATEGORIES & true & ::category extraction
parse\_references & JOTS\_PARSE\_REFERENCES & true & --id and --space--id extraction
parse\_file\_references & JOTS\_PARSE\_FILE\_REFERENCES & true & //filepath and ///space/filepath extraction
parse\_resources & JOTS\_PARSE\_RESOURCES & true & ;;file extraction
parse\_todos & JOTS\_PARSE\_TODOS & true & ??todo extraction
parse\_urls & JOTS\_PARSE\_URLS & true & ==url extraction
parse\_bookmarks & JOTS\_PARSE\_BOOKMARKS & true & !!name bookmark extraction
parse\_hashtags\_as\_tags & JOTS\_PARSE\_HASHTAGS\_AS\_TAGS & false & #word..word synonym
emit\_loc & JOTS\_EMIT\_LOC & true & Emission of loc and raw on construct objects (§8)

When parsing is disabled for a construct family, matching text remains inert: it is not extracted, indexed, or transformed by the renderer.

When emit\_loc is false, parser output omits the loc and raw fields from every construct object. All other fields are unchanged. Implementations SHOULD expose this as a --no-loc CLI flag (or equivalent) for compact output when only structured metadata is wanted.

9.1 Flag Interactions

Several flags govern more than one production. The interactions below are normative.

Part III: Error Conditions

This part enumerates error conditions that may arise when parsing or rendering Iota Syntaxis.

10 Severity Levels

@L2.3cmL5.2cmL5.9cm@ Severity & Meaning & Recommended behavior
Parse error & Input violates the grammar and cannot be matched as a construct. & Text is left as inert content. No entry is emitted in parser output.
Validation error & Input is grammatically valid but violates a semantic constraint. & Parser SHOULD report via diagnostics. Strict implementations MAY reject; lenient MAY accept with warning.
Resolution warning & Input is syntactically and semantically valid, but a target cannot be resolved. & Parser emits the construct normally. Renderer SHOULD warn and render the construct as-is (no link target).

Scope of “parse error”.

A parse error covers two distinct situations:

  1. No construct ever matched. The input contains no candidate sigil, or a sigil whose payload is rejected by the grammar before any prefix could be considered a complete construct. The text is inert.

  2. Candidate construct rejected. A construct’s sigil is present and begins consuming characters that would form a payload, suffix, specifier, or inter-jot syntax, but the resulting token violates the grammar’s payload, ordering, or composition rules (including trim-then-validate, §3.2). The parser MUST diagnose the rejected token and MUST NOT silently emit a shorter valid prefix.

For example, ==ftp://example.com is a parse error in the second sense: the == sigil starts a URL construct, but the payload fails the <http-url> rule that requires http:// or https://. No shorter URL match is emitted; the entire ==ftp://example.com token is reported as a single parse error.

10.1 Diagnostic Shape

A conforming implementation MUST expose error conditions through a diagnostics interface. Each diagnostic MUST carry at least the following fields:

@L1.5cmL4.6cmL7.6cm@ Field & Type & Description
code & string & Stable identifier; see naming convention below.
severity & +"parse_error" |++"validation_error" |++"resolution_warning"+ & Maps to a row in §10.
message & string & Human-readable explanation.
loc & + unit, start, end + +| null+ & Source location covered by the diagnostic, using the same shape and unit semantics as parser-output loc8). null for diagnostics that have no source construct (configuration errors, §15).

Implementations MAY add fields (e.g., hint, related_locs, source_label).

Location in parser output.

Implementations conforming to §8 MUST surface diagnostics in the top-level diagnostics array of the parser output. CLI implementations MAY additionally render a human-readable summary on stderr; the structured array is the contract.

Emitting component.

Parse and validation diagnostics are emitted by the parser from the input text and configuration alone. Resolution-tier diagnostics (Jots/Resolution/...) additionally require resolution context — knowledge of which texts, files, resources, and bookmarks exist. They are emitted by whichever component performs resolution (typically the host tool or renderer) and appear in the parser-output diagnostics array only when the parser is invoked with such context. A parser operating on input text alone emits no resolution warnings.

Code naming convention.

Diagnostic codes are slash-separated PascalCase identifiers shaped <Layer>/<Tier>/<Name>. The layer segment identifies the producing component:

The tier segment identifies severity:

Codes in this section are therefore all Jots/<Tier>/<Name>. The shape is deliberately distinct from the upper-snake-case JOTS\_PARSE\_TAGS env-var family (§9) and the lower-snake-case parse\_tags config-flag family.

Canonical codes.

Each row of §11–§16 carries a Code column giving the canonical code for that condition. Conforming implementations MUST emit the canonical code when reporting the listed condition, and MUST NOT re-purpose a canonical code for a different condition. The canonical-code list is append-only within a major spec version: new conditions add new codes; removed or renumbered conditions leave their codes retired (codes are never reused).

When more than one canonical condition describes the same rejected span, the most specific condition’s code is emitted. Jots/Parsing/InvalidPayloadChars is the generic fallback: it fires only when no more specific row matches.

Diagnostic location.

For each canonical-code condition in §11–§16 other than the configuration errors (§15, whose diagnostics carry loc null), loc covers the full matched construct — from the sigil through the construct’s right boundary per §3.2, including any specifier and annotation suffixes. This matches the loc extent the construct would carry on its parser-output object had it parsed cleanly. Extension-code diagnostics MAY use any loc extent appropriate to the condition they report.

Determinism.

For a given (input, configuration) pair, a conforming parser MUST emit a deterministic sequence of canonical-code Jots/Parsing/... and Jots/Validation/... diagnostics: every conforming parser produces the same canonical diagnostics in the same order, agreeing on each diagnostic’s code, severity, and loc. Resolution-tier diagnostics are excluded from this guarantee — they depend on resolution context (see Emitting component above), not on the input alone. The message field is human-readable and MAY vary across implementations; consumers comparing parser outputs across implementations MUST ignore message and MUST filter out extension-code entries (<Layer>/<Tier>/X/<Name>, defined below) before comparison. Within the canonical subset, diagnostic order is ascending loc.start, then ascending loc.end, then code lexicographically. Diagnostics with loc null (configuration errors) precede all located diagnostics and are ordered by code lexicographically.

Extension codes.

Implementations MAY emit additional diagnostics for conditions not listed in §11–§16 using the reserved extension namespace <Layer>/<Tier>/X/<Name> — i.e., a fixed X segment between the tier and a vendor-defined PascalCase name (for example, Jots/Parsing/X/VendorFoo). Extension codes are implementation-defined and need not be portable across parsers; consumers route them by severity.

Unknown-code handling.

Consumers MUST tolerate unrecognized codes in the standard Jots/Parsing/... / Jots/Validation/... / Jots/Resolution/... namespace — these may originate in a future spec revision — by routing on severity and falling back to the human-readable message. Codes in the <Layer>/<Tier>/X/<Name> extension namespace MAY be ignored by consumers that don’t recognize the emitting implementation.

Retired codes.

Codes assigned to conditions that have since been removed from the spec are listed below for historical reference. Conforming implementations MUST NOT emit retired codes, and the codes are never reassigned to a different condition (the canonical-code list is append-only — see Canonical codes above).

@L4.3cmL2.5cmL1.5cmL5.0cm@ Code & Originally & Retired in & Reason
Jots/Parsing/InvalidLeftBoundary & §11 (parse error; pre-1.0 row 3.2.1) & 2026-04-30 & Left-boundary application per §3.1 is silent skipping by design, not a reportable error condition.

One further condition was removed before canonical codes were assigned and therefore has no code to retire: a zero-length offset validation error (:START+0; pre-1.0 row 3.4.3). The form is now well-formed and equivalent to :START7.13).

Condition numbering.

Condition rows in §11–§16 are numbered section.row and renumber with the document; the stable identifier for a condition is its canonical code, never its row number. (Documents predating 1.0 numbered these rows 3.2.1–3.7.7.)

11 Structural and Grammar Violations

One row originally listed here (pre-1.0 row 3.2.1) was retired; see Retired codes in §10.1.

@L0.65cmL2.9cmL1.25cmL1.5cmL3.55cmL3.7cm@ # & Error condition & Severity & Reference & Example & Code
& Empty payload — sigil with no content following & Parse error & §7.2–§7.8 & .. , :: , -- , ?? & Jots/Parsing/EmptyPayload
& Invalid payload characters — candidate span contains characters the production cannot consume that are not trailing punctuation (trim-then-validate, §3.2) & Parse error & §3.2, §7.1–§7.8 & ..meet!ing, --42$ref & Jots/Parsing/InvalidPayloadChars
& Empty category segment — consecutive :: separators with no word between them & Parse error & §7.3 & ::work::::projects & Jots/Parsing/EmptyCategorySegment
& Filename starts with - or . — forbidden by <fname-start-char> & Parse error & §7.6 & ;;-report.pdf, ;;.hidden & Jots/Parsing/InvalidFilenameStart
& Consecutive dots in filename — not producible under <filename> & Parse error & §7.6 & ;;report..pdf & Jots/Parsing/ConsecutiveDotsInFilename
& Invalid filename characters — characters outside the allowed set & Parse error & §4.5, §7.6 & ;;file[1].pdf, ;;report#2.pdf & Jots/Parsing/InvalidFilenameChars
& URL missing scheme== followed by a URL without http:// or https:// & Parse error & §7.8 & ==ftp://example.com, ==example.com & Jots/Parsing/UrlMissingScheme
& Unmatched or stray label delimiter — label opened with ( / [ but not closed before end of line, or content between the closing delimiter and the URL scheme & Parse error & §4.7, §7.8 & ==(label, ==(label)text)https://... & Jots/Parsing/UnmatchedLabelDelimiter
& Todo missing action?? (optionally followed by .) followed immediately by whitespace, due date, or end of line & Parse error & §7.7 & ?? @2026-03-01, ??, ??. & Jots/Parsing/TodoMissingAction
& Malformed due date@ introduces a due date whose characters do not form a valid <iso-date> & Parse error & §7.7 & ??send@2026-3-1 & Jots/Parsing/MalformedDueDate
& Empty blocker list() with no entries & Parse error & §4.6, §7.7 & ??()action & Jots/Parsing/EmptyBlockerList
& Empty blocker entry — leading, trailing, or doubled comma in the blocker list & Parse error & §4.6, §7.7 & ??(,a)action, ??(a,)action, ??(a,,b)action & Jots/Parsing/EmptyBlockerEntry
& Invalid wildcard blocker entry — wildcard * without the REQUIRED <cat> constraint & Parse error & §4.6, §7.7 & ??(*)action, ??(*..tag)action & Jots/Parsing/InvalidWildcardBlocker
& Whitespace in blocker slot — whitespace inside the parens, between ) and the action, or between the importance prefix and ( & Parse error & §4.6, §7.7 & ??(draft, review)merge, ??(draft) merge & Jots/Parsing/WhitespaceInBlockers

12 Ordering Constraint Violations

@L0.65cmL2.9cmL1.25cmL1.5cmL3.55cmL3.7cm@ # & Error condition & Severity & Reference & Example & Code
& Tags before category on annotated reference & Parse error & §6.3, §7.11 & --42..next::work & Jots/Parsing/TagsBeforeCategoryRef
& Tags before category on annotated todo & Parse error & §6.5, §7.12 & ??review..important::work & Jots/Parsing/TagsBeforeCategoryTodo
& Tags before category on annotated resource reference & Parse error & §6.6 & ;;report.pdf..draft::work & Jots/Parsing/TagsBeforeCategoryResource
& Annotation suffix between locator and ;; in inter-jot resource reference & Parse error & §5, §7.10 & --42..tag;;file.pdf, --42::work;;file.pdf & Jots/Parsing/AnnotationBeforeInterJotSep
& Specifier on locator prefix of inter-jot resource reference & Parse error & §5, §7.10 & --42:10;;file.pdf, --42#intro;;file.pdf & Jots/Parsing/SpecifierOnInterJotLocator

13 Specifier Errors

@L0.65cmL2.9cmL1.25cmL1.5cmL3.55cmL3.7cm@ # & Error condition & Severity & Reference & Example & Code
& Start greater than end in range:START-END where START > END & Validation error & §4.11 & --42:20-10 & Jots/Validation/RangeStartAfterEnd
& Zero line number — line numbers are 1-based & Validation error & §4.11 & --42:0, //notes.md:0-5 & Jots/Validation/ZeroLineNumber
& Non-numeric fragment content: followed by non-whitespace content that does not form a valid fragment & Parse error & §7.13 & --42:abc & Jots/Parsing/NonNumericFragment
& Multiple mutually exclusive specifiers on same reference & Parse error & §4.9, §4.10, §7.14 & --42:10-20#intro, --42#intro##a,b & Jots/Parsing/MutuallyExclusiveSpecifiers
& Integer overflow in line fragment specifier & Validation error & §4.11 & --42:99999999999999 & Jots/Validation/FragmentIntegerOverflow
& Empty bookmark range## with no bookmark names or no comma & Parse error & §4.10, §7.14 & --42##,, --42## & Jots/Parsing/EmptyBookmarkRange
& Empty bookmark specifier name# on a reference or resource followed by whitespace or end of line & Parse error & §4.9, §7.14 & --42#, //notes.md# & Jots/Parsing/EmptyBookmarkSpecifier
& Same bookmark in range##name,name where both names are identical & Validation error & §4.10 & --42##intro,intro & Jots/Validation/SameBookmarkInRange
& Todo with semantically invalid ISO 8601 date — grammar matches but date is invalid & Validation error & §4.6, §7.7 & ??send@2026-02-30 & Jots/Validation/InvalidDate
& Done todo with semantically invalid completion date.@<date> matches grammar but date is invalid & Validation error & §4.6, §7.7 & ??.send report .@2026-02-30 & Jots/Validation/InvalidCompletionDate
& Multiple completion timestamps on a single done todo — more than one .@<iso-date> in description & Validation error & §4.6, §7.7 & ??.send report .@2026-03-01 .@2026-03-02 & Jots/Validation/DuplicateCompletionTime

14 Bookmark Errors

@L0.65cmL2.9cmL1.25cmL1.5cmL3.55cmL3.7cm@ # & Error condition & Severity & Reference & Example & Code
& Duplicate bookmark names within a text & Validation error & §4.8 & Two !!introduction declarations & Jots/Validation/DuplicateBookmark
& Bookmark specifier referencing a nonexistent bookmark & Resolution warning & §4.9 & --42#missing where text 42 has none & Jots/Resolution/BookmarkNotFound
& Empty bookmark name!! followed by whitespace or end of line & Parse error & §7.14 & !! & Jots/Parsing/EmptyBookmarkName
& Bookmark declaration inside a todo span!!name between ?? and end of line & Validation error & §4.6, §5.2 & ??buy milk !!followup & Jots/Validation/BookmarkInTodoSpan

15 Configuration Errors

@L0.65cmL2.9cmL1.25cmL1.5cmL3.55cmL3.7cm@ # & Error condition & Severity & Reference & Example & Code
& Invalid boolean value for parsing control flag — value is not true/false & Validation error & §9 & JOTS\_PARSE\_TAGS=maybe & Jots/Validation/InvalidFlagValue
& Invalid template — unrecognized placeholder name or unbalanced {/} & Validation error & §3, §4 & ref_target = "jot://{unknown}" & Jots/Validation/InvalidTemplate

16 Resolution Warnings

@L0.65cmL2.9cmL1.25cmL1.5cmL3.55cmL3.7cm@ # & Error condition & Severity & Reference & Example & Code
& ID reference to nonexistent text & Resolution warning & §4.3 & --99999 & Jots/Resolution/JotNotFound
& File reference to nonexistent file & Resolution warning & §4.4 & //deleted.md & Jots/Resolution/FileNotFound
& Cross-space reference to nonexistent space & Resolution warning & §4.3 & --nonexistent--42 & Jots/Resolution/SpaceNotFound
& Resource reference to nonexistent resource & Resolution warning & §4.5 & ;;missing.pdf & Jots/Resolution/ResourceNotFound
& Inter-jot resource where the text exists but the resource does not & Resolution warning & §5 & --42;;deleted.pdf & Jots/Resolution/InterJotResourceNotFound
& Bookmark range referencing nonexistent bookmark(s) & Resolution warning & §4.10 & --42##missing,also_missing & Jots/Resolution/BookmarkRangeNotFound
& Bookmark range with start after end!!a appears after !!b in the target’s document order & Resolution warning & §4.10 & --42##summary,intro & Jots/Resolution/BookmarkRangeStartAfterEnd

17 Severity Classification Summary

Severity Conditions
Parse error [cond:empty-payload][cond:whitespace-in-blockers], [cond:tags-before-category-ref][cond:specifier-on-inter-jot-locator], [cond:non-numeric-fragment], [cond:mutually-exclusive-specifiers], [cond:empty-bookmark-range][cond:empty-bookmark-specifier], [cond:empty-bookmark-name]
Validation error [cond:range-start-after-end][cond:zero-line-number], [cond:fragment-integer-overflow], [cond:same-bookmark-in-range][cond:duplicate-completion-time], [cond:duplicate-bookmark], [cond:bookmark-in-todo-span], [cond:invalid-flag-value][cond:invalid-template]
Resolution warning [cond:bookmark-not-found], [cond:jot-not-found][cond:bookmark-range-start-after-end]

Conformance

A tool or library conforms to the Iota Syntaxis parser specification if it:

  1. Locates all eight core constructs from input text using the grammar in §7.

  2. Provides a parser interface that returns structured metadata per §8.

  3. Applies the disambiguation rule in §5: longest match wins; among equal-length matches, inter-jot resources take priority over standalone references; cross-space takes priority over same-space; annotated forms take priority over bare.

  4. Case-folds tags and categories to canonical lowercase, and preserves case for IDs, spaces, filepaths, filenames, and bookmark names.

  5. Deduplicates extracted free-standing tags and categories after case-folding, and enforces bookmark-name uniqueness within a text (§4.8). References, resources, inter-jot resources, todos (active and done), and URLs are emitted in document order with one parser-output object per matched occurrence; deduplication of these constructs is the consumer’s responsibility.

  6. Enforces left-boundary rules (§3.1) for free-standing constructs, and applies trim-then-validate right boundaries (§3.2): trailing trim-set runs are trimmed, and any other unconsumable character rejects the full candidate span.

  7. Parses annotation suffixes on references, resource references, and todos (§6), enforces the category-before-tags ordering, and keeps edge annotations separate from the text’s own tag and category lists.

  8. Recognizes the todo done marker (??. form, §4.6) only when the . immediately follows the ?? sigil, and routes done todos to done_todos rather than todos in parser output (§8). The two lists share an identical object schema. On done todos only, post-scans the description for an optional completion timestamp (.@<iso-date>) and emits the parsed date on the todo’s completed field, applying the same timezone-completion behavior as for due. The .@<iso-date> syntax MUST NOT be recognized in active todo descriptions or outside any todo span.

  9. Parses line fragment, bookmark, and bookmark range specifiers (§4.9–§4.11), enforces their mutual exclusivity, normalizes line fragments to (start, end) pairs, and exposes them in parser output per §8. Specifiers MUST NOT appear on the locator prefix of an inter-jot resource reference.

  10. Parses bookmark declarations (§4.8), enforces bookmark-name uniqueness within a text, and preserves bookmark name case.

  11. Parses inter-jot resource references (§5), including annotation suffixes and specifiers on the resource portion.

  12. Classifies error conditions per Part III and reports parse errors, validation errors, and resolution warnings through a diagnostics interface. Each diagnostic MUST expose at minimum the fields defined in §10.1 (code, severity, message, loc). Implementations MAY offer a strict mode that promotes validation errors and resolution warnings to fatal errors.

A tool MAY implement the optional hashtag extension (§7.9) without affecting conformance.

Renderer-side conformance — default output templates, host-format patterns, escaping, bookmark and inter-jot resource rendering — is defined separately in the Conformance section of jotr. The two surfaces are independent: a tool MAY conform to either, both, or different host-format subsets of either.