Docs Open org

aegent Markdown

The file format for pages, generated from the specification, with the Org mode mapping.

Every page in org is an aegent Markdown file: ordinary Markdown with Org mode's features added in ways that still read well anywhere else. This reference is built from the specification each time the docs are built, so it always matches what org parses.

aegent Markdown is CommonMark 0.31 + GFM (tables, task-list checkboxes, strikethrough, autolinks, footnotes) plus the extensions below. Files use the .md extension and UTF-8 with LF line endings. It supports every Org-mode feature. Where a convention already exists, it reuses it: Org timestamps, Obsidian wikilinks, embeds, block IDs, callouts and comments, Dataview key:: value fields, and Pandoc footnotes, citations, attributes and fenced divs.

Frontmatter

YAML between --- lines at byte 0. The recognised keys are shown below. Unknown keys are page properties.

---
title: Car                      # the page title (otherwise the first H1, otherwise the file name)
aliases: [Vehicle]              # link aliases (Org radio targets)
tags: [admin]                   # page tags (Org FILETAGS), inherited by every entry
todo:                           # TODO sequences for this page (Org #+TODO). See §7.1
  - ["TODO(t)", "NEXT(n)", "WAIT(w@/!)", "|", "DONE(d!)", "CANCELLED(c@)"]
priorities: {highest: A, lowest: C, default: B}
category: Car                   # the agenda category (Org CATEGORY)
tz: Europe/London               # a fixed time zone for this page's timestamps (the default is floating)
startup: overview               # overview | content | showall | show2levels … (Org STARTUP)
id: a78                         # the page's short ID (written by aegent)
archive: "Archive/Car"          # the archive target (Org ARCHIVE)
bibliography: refs.bib          # citations
csl: harvard.csl
macros: {version: "1.2"}        # {{version}}
export: {toc: true, numbered: false, author: true}
database: …                     # makes this page a database (§10)
views: …                        # saved views on a database page (§10)
---

Headings and entries

## TODO [#A] Renew car insurance #admin #money [1/3]

Grammar (after the ATX #{1,6} marker):

heading   := [KEYWORD " "] [PRIORITY " "] TITLE [" " TAGS] [" " COOKIE]*
KEYWORD   := one of the in-scope TODO keywords (§7.1), case-sensitive
PRIORITY  := "[#" LETTER "]"          (A–Z, within the configured range)
TAGS      := ("#" TAG) (" #" TAG)*    trailing tags only, where TAG := [\p{L}\p{N}_/-]+, not all digits
COOKIE    := "[" n "/" m "]" | "[" n "%]"   (statistics, which may sit anywhere in the title)
  • A heading is a task if and only if it starts with a keyword.
  • Deeper than 6 levels: write ###### with the metadata line level:: N (N ≥ 7). The outline treats it as level N. Default.
  • The subtree of a heading runs to the next heading of the same or a higher level.
  • An inline task is a list item whose text starts with a keyword: - TODO Call Sam. Its metadata lines are indented to the item's content column. Inline tasks have no children.
  • Checkboxes (- [ ], - [x], - [-]) are checklist items, not tasks. They're counted by cookies and are clickable. - [-] means partially done.

Metadata lines

These are contiguous lines immediately after a heading (or indented under an inline task), each matching:

^[a-z][a-z0-9_]*:: .*$
  • They hold Org's planning line and property drawer.
  • The first non-matching line ends the block.
  • Keys are lowercase snake_case, and values are raw text, typed by the key.
  • Duplicate keys are an error on write. On read, the last one wins and a diagnostic is raised.
  • Canonical order on write: scheduled, deadline, closed, id, then the keys in the order listed below, then custom keys in their existing order.
  • New keys are appended in canonical position.

Reserved keys:

Key Type Meaning
scheduled timestamp when you plan to do it (Org SCHEDULED)
deadline timestamp when it must be done (Org DEADLINE)
closed inactive timestamp when it was completed (written automatically)
id short ID the entry's identity (written by aegent when it's first projected)
custom_id text a human anchor (Org CUSTOM_ID)
owner handle @user, @agent or @team
depends short IDs a78, b12: blocked by these
ordered bool children must be completed in order
noblocking bool children don't block this entry
effort duration 30m, 1h30m, 2d (Org EFFORT)
category text agenda category
acceptance text what "done" means (§7.6)
review auto, required, none review policy (§7.6); the UI labels auto Review agent completions
agent text plain-language guidance for agents (§7.9)
agent_allow list a subset of research, draft, contact, spend, irreversible, code
agent_ask list the same vocabulary: ask the human first
budget money £450, $20, 100 EUR
secrets short IDs secrets usable while working this task (§14.4)
style habit habit tracking (§8.6)
habit_min / habit_max duration through the repeater .+2d/4d instead
last_repeat inactive timestamp written when a repeater advances (Org LAST_REPEAT)
archived bool archived in place (Org ARCHIVE tag)
archive_page, archive_path, archive_time, archive_category, archive_state text origin, written when archiving to another page
export bool false excludes the entry from export (Org COMMENT)
level int the outline level when it's deeper than 6
created inactive timestamp written when an entry is created through the API
source / external_id text import provenance (§16.6)
reminders list extra reminders: -15m, -1d, <2026-10-11 Sun 18:00> (§17.1)
rows pages, headings database row source (§10)

Any other key is a custom property, inherited if it's listed in inherit_properties.

Timestamps

These are Org's syntax, verbatim.

active     := "<" body ">"
inactive   := "[" body "]"
body       := DATE [" " DAYNAME] [" " TIME ["-" TIME]] (" " MODIFIER)*
DATE       := YYYY "-" MM "-" DD
DAYNAME    := [A-Za-z]{2,9}               (ignored on read, and regenerated in English on write)
TIME       := H?H ":" MM                  (24-hour)
MODIFIER   := REPEATER | WARNING | TZ
REPEATER   := ("+" | "++" | ".+") N UNIT ["/" N UNIT]    (the /max form is for habits)
WARNING    := ("-" | "--") N UNIT          (on a deadline: warning period; on scheduled: delay)
TZ         := "@" IANA_ZONE                (a fixed zone; without it the time is floating)
UNIT       := "h" | "d" | "w" | "m" | "y"
range      := active "--" active | inactive "--" inactive
special    := "<rrule:" RFC5545_RRULE [" " TIME ["-" TIME]] [" " TZ] ">"
            | "<yearly:" DATE ">"          (anniversary; the agenda shows the count of years)
            | "<rrule:" RRULE ";DTSTART=" DATE ">"
  • Active timestamps anywhere in an entry's title or body are appointments (§8.4). Inactive timestamps are just records.
  • The <…> form isn't HTML (it starts with a digit, r or y plus a colon). Parsers treat it as literal text, so it renders literally in CommonMark.
  • The canonical writer emits <2026-10-12 Mon>, <2026-10-12 Mon 09:00>, and modifiers in the order repeater, warning, TZ.
  • Diary sexps from Org are replaced by rrule: and yearly:. Converters MUST map diary-float to BYDAY with BYSETPOS, diary-anniversary to yearly:, and diary-cyclic to rrule:FREQ=DAILY;INTERVAL=n.

Special fenced blocks

The language tag decides the meaning. Each of these is folded by default in the editor.

Fence info Meaning
logbook the entry's LOGBOOK (§5.7). It MUST come directly after the metadata lines, or after the first body paragraph
drawer NAME a generic Org drawer
results [NAME] Babel results for the preceding code block (or a named one)
encrypted an age-armoured ciphertext of a Markdown fragment (§5.12)
agenda a custom agenda command definition (YAML, §9.5)
query a live query with results rendered inline (YAML, §9.4)
clocktable a clock report, rendered live (YAML, §8.7)
columns a column-view definition for the parent subtree (YAML, §10.3)
capture capture template definitions (YAML, §11.5)
example, verse, export FORMAT Org example and verse blocks, and raw export blocks

Pandoc fenced divs ::: verse, ::: center and ::: {.class} are supported for Org's #+BEGIN_VERSE, #+BEGIN_CENTER and special blocks. Callouts > [!note] Title (Obsidian) cover #+BEGIN_NOTE, warnings and so on.

Logbook

A fenced logbook block is one entry per line, using Org's wording.

- State "DONE" from "TODO" [2026-10-09 Fri 18:02]
- Note taken on [2026-10-08 Thu 12:00] \\
  Called broker, waiting on quote.
- Rescheduled from "[2026-10-05 Mon]" on [2026-10-04 Sun 10:00]
- New deadline from "[2026-10-10 Sat]" on [2026-10-04 Sun 10:00]
- Claimed by @planner [2026-10-08 Thu 09:00]
- Released by @planner [2026-10-08 Thu 09:40] \\
  Handoff: quotes collected in [[Car#^quotes]]; need a human to choose.
- Submitted by @planner [2026-10-08 Thu 11:00] \\
  Evidence: paid, policy PDF attached ![[policy-2026.pdf]]
- Approved by @daniel [2026-10-08 Thu 12:00] \\
  Checked the policy number.
- Rejected by @daniel [2026-10-08 Thu 12:00] \\
  Wrong start date.
- Cancelled by @daniel [2026-10-08 Thu 12:00]
- Reopened by @daniel [2026-10-08 Thu 12:00] \\
  Requirements changed.
- Decision by @daniel via claude (verified) [2026-10-08 Thu 10:00] \\
  Q: Switch provider to Admiral at £398? A: Yes
CLOCK: [2026-10-08 Thu 09:00]--[2026-10-08 Thu 09:40] =>  0:40
CLOCK: [2026-10-08 Thu 13:00]
  • \\ at the end of a line starts an indented continuation note.
  • New lines go at the top (newest first), as Org does by default (org-log-states-order-reversed). A page setting can flip that.
  • An unclosed CLOCK: line is the running clock.
  • Clock durations use Org's H:MM form with two spaces after =>.
  • A CLOCK: line may end with @handle naming who clocked (CLOCK: [..]--[..] => 0:40 @planner, or CLOCK: [..] @planner while running). aegent always writes it. Without one, the clock is the owner's.
  • Unknown lines are preserved.
Syntax Meaning
[[Page]], [[Page|label]] wikilink by title or alias, within the space, then the org
[[Page#Heading]], [[Page#^block]], [[#Heading]], [[#^block]] a heading or block in a page, or in the current one
[[a78]], [[a78|label]] a short ID link to any entity (it resolves through aliases)
[[acme/a78]] a cross-org short ID link (it resolves only if the viewer has access)
[text](https://…), <https://…> external links
[text](Page.md), [text](Page.md#heading) relative file links (the folder-sync form)
![[Page]], ![[Page#Heading]], ![[a78]] transclusion (Org #+INCLUDE)
![[file.pdf]], ![[image.png|300]], ![alt](url) attachments and images
^block-id at the end of a paragraph or list item a block target (Org <<target>>)

Unresolved wikilinks render as "create page" links. Renaming a page updates the wikilinks that point at it (if the user opts in, which is the default).

Tables and formulas

GFM tables. A formula line is a tblfm:: line directly after the table's last row:

| Item  | Qty | Price | Total |
|-------|-----|-------|-------|
| Tyres | 4   | 80    | 320   |
| MOT   | 1   | 55    | 55    |
| Total |     |       | 375   |
tblfm:: $4=$2*$3::@>$4=vsum(@2..@-1)
  • The language is Org's table formula language without Emacs Lisp or Calc internals:
    • references: $N, @N, @N$M, $name (a named column through an optional | ! | name | row), @> (last row), @< (first), @-1, @I/@II (horizontal-rule groups)
    • ranges a..b
    • the operators + - * / ^ % and comparisons
    • the functions vsum vmean vmin vmax vcount vmedian round floor ceil abs if concat
    • format suffixes ;%.2f, ;N, ;T
  • Recalculation happens on demand (the editor's "Recalculate", the API, or the CLI ae org tblfm). It's never automatic on read.
  • The editor aligns columns when you press Tab.

Code blocks (Babel)

```python {#fetch-rates tangle=scripts/rates.py exports=both results=output session=rates}
print(sum([1, 2, 3]))
```

```results fetch-rates
6
```
  • Attributes use Pandoc syntax after the language: #name, .class, and key=value (Org header arguments: tangle, exports, results, var, session, dir, noweb, cache, eval).
  • Noweb: <<name>> inside a block expands to the named block when tangling or executing (if noweb=yes).
  • Execution happens only in the CLI and desktop app, on the user's machine, after a per-block confirmation (unless eval=yes has been approved for the page on that device). The server and web app never execute code. Results replace the following results block.
  • Tangling: ae org tangle <page> writes blocks to their tangle paths, relative to the current directory or --dir.

Other syntax

Feature Syntax
Footnotes [^1] with [^1]: text, and inline ^[text]
Maths $x^2$, $$ … $$ (KaTeX)
Comments %% not rendered or exported %%, inline or as a block
Macros {{name}} and {{name(arg1, arg2)}}, defined in frontmatter macros:. Built-in: {{date}}, {{time}}, {{title}}, {{author}}, {{modification-time}}
Citations [@key], [@key, p. 4], [-@key], @key, with bibliography: and csl: in frontmatter. Bare @key, and bracketed citations with a prefix ([see @key]), are citations only on pages with a bibliography: (otherwise they are handles or text)
Horizontal rule --- (not at byte 0)
Callouts > [!note] Title, with the types note, tip, warning, danger, info, quote and todo. [!note]- makes it folded

Encrypted blocks

```encrypted
-----BEGIN AGE ENCRYPTED FILE-----
…
-----END AGE ENCRYPTED FILE-----
```
  • The plaintext is an aegent Markdown fragment. It's encrypted to a passphrase (age scrypt recipient) on the client: web (age-encryption JavaScript), desktop or CLI (age crate).
  • The server stores ciphertext only, and never indexes it or shows it to agents.
  • The editor shows a locked placeholder with "Unlock", which decrypts in memory only.

Org to aegent Markdown mapping (normative)

Org aegent Markdown
* Heading … ****** Heading # … ###### (deeper levels through level::)
#+TITLE, #+FILETAGS, #+TODO, #+SEQ_TODO, #+TYP_TODO, #+PRIORITIES, #+CATEGORY, #+STARTUP, #+ARCHIVE, #+BIBLIOGRAPHY, #+MACRO, #+OPTIONS frontmatter title, tags, todo, todo, todo, priorities, category, startup, archive, bibliography, macros, export
TODO/DONE keyword the same, after the hashes
[#A] [#A]
:tag1:tag2: #tag1 #tag2
SCHEDULED:, DEADLINE:, CLOSED: scheduled::, deadline::, closed::
:PROPERTIES: drawer key:: value lines (lowercased keys)
:ID: id:: (the short ID). A UUID from Org is kept in org_id:: for back-references
:LOGBOOK: drawer a ```logbook block
other drawers ```drawer NAME
<2026-10-12 Mon +1w -2d> the same
%%(diary-…) <rrule:…> or <yearly:…>
- [ ], - [X], - [-] - [ ], - [x], - [-]
[1/3], [33%] the same
[[id:…][desc]] [[a78|desc]]
[[file:x.org::*Heading][d]] [[x#Heading|d]]
[[https://…][desc]] [desc](https://…)
<<target>> ^target
<<<radio>>> frontmatter aliases
#+BEGIN_SRC lang :tangle x ```lang {tangle=x}
#+RESULTS: ```results
#+BEGIN_QUOTE >
#+BEGIN_EXAMPLE ```example
#+BEGIN_VERSE, #+BEGIN_CENTER ::: verse, ::: center
#+BEGIN_NOTE (special) > [!note]
# comment, #+BEGIN_COMMENT %% … %%
COMMENT heading keyword export:: false
#+TBLFM: tblfm::
#+INCLUDE: ![[…]]
{{{macro(a)}}} {{macro(a)}}
[cite:@key] [@key]
[fn:1] [^1]
\( … \), \[ … \] $ … $, $$ … $$
:crypt: + PGP body ```encrypted (age, re-encrypted with the user's passphrase during conversion)
:ARCHIVE: tag archived:: true
STYLE: habit style:: habit
Clock tables #+BEGIN: clocktable ```clocktable
Column view #+COLUMNS: ```columns
#+BEGIN: dynamic block ```query

ae org convert --from org <file|dir> implements this table. Conversion is lossless for every row, and anything unmapped is kept in a ```drawer ORG block with a diagnostic.