Language reference
This is the practical language reference for Org2 v0.
For the normative draft spec, see spec/v0/SPEC.org.
Spec map
Use this mapping when deciding where behavior is defined:
Core syntax and canonical AST: spec/v0/SPEC.org
Roam semantics (IDs, links, backlinks model): spec/v0/ROAM.org
CLI/editor workflow behavior: Tooling reference
Headings
Syntax: one or more stars, a space, then title text.
Example:
* Project
** Subproject
*** Task
Heading level is the number of stars.
Level skips are accepted in v0.
TODO keywords
Headline TODO states parsed into the canonical AST:
TODOIN_PROGRESSDONECANCELLED/CANCELED
Workflow tools may accept aliases such as PROG or WAITING and normalize them to one of the canonical TODO keywords above.
Example:
* TODO Ship docs
* IN_PROGRESS Implement parser tests
* DONE Publish changelog
Priority cookies
Syntax:
[#A]style cookie after TODO keyword (or at headline start when no TODO keyword).
* TODO [#A] Critical task
Tags
Tags are suffixes at headline end:
:tag:or:tag1:tag2:
* TODO Draft docs :docs:website:
Drawers
Property drawers
Drawer delimiters:
:PROPERTIES:...:END:-
Common keys used by Org2 workflows:
:ID::CUSTOM_ID::EFFORT::ROAM_ALIASES:
:PROPERTIES:
:ID: 123e4567-e89b-12d3-a456-426614174000
:EFFORT: 45
:END:
Generic drawers
Generic
:NAME:...:END:drawers are preserved.
Planning lines
Recognized planning keywords:
SCHEDULED:DEADLINE:CLOSED:
SCHEDULED: <2026-02-21 Sat>
DEADLINE: <2026-02-25 Wed>
CLOSED: [2026-02-20 Fri]
Timestamps
Supported timestamp forms:
Active:
<2026-02-21 Sat>Inactive:
[2026-02-21 Sat]With time:
<2026-02-21 Sat 09:30>Ranges:
<2026-02-21 Sat>--<2026-02-23 Mon>Repeaters (agenda projection):
+1w,++1m,.+2d
Lists
Unordered markers:
-,+,*Ordered markers:
1.,1)Checkboxes:
[ ],[X],[x],[-]Checkbox progress cookies:
[n/m]and[p%]may appear in headings or list items; compile output exposes computed checkbox totals and lint reports stale cookies.Nested lists via indentation.
Links
Supported link forms:
Bracket links:
[[https://example.com][label]]Plain URLs:
https://example.comFile links:
[[file:path/to/file.org]]ID links:
[[id:UUID][label]](roam-style link)Wiki links:
[[Node Title]](roam-style link)
Both ID links and Wiki links are first-class in Org2 roam workflows.
Link abbreviations are supported with built-ins, config, and #+LINK directives.
Built-in abbreviations:
gh:→https://github.com/%sgl:→https://gitlab.com/%syt:→https://www.youtube.com/watch?v%s=wiki:→https://en.wikipedia.org/wiki/%s
You can add/override abbreviations in org2.json:
{
"links": {
"linearTeam": "scarf",
"abbreviations": {
"linear": "https://linear.app/scarf/issue/%s",
"gh": "https://github.example.com/%s"
}
}
}
And define file-local abbreviations with Org-compatible syntax:
Define:
#+LINK: linear https://linear.app/scarf/issue/%sUse:
[[linear:APP-3718][APP-3718]]or[[linear:APP-3718]]
Precedence (highest to lowest):
file-local
#+LINKorg2.jsonlinks.abbreviationsbuilt-ins
Org2 expands abbreviation targets when rendering/exporting and for LSP document-link targets.
Inline emphasis
Bold:
*bold*Italic:
/italic/Underline:
_underline_Strike:
+strike+Verbatim:
=verbatim=Code:
~code~
Blocks
Recognized block forms include:
Source blocks:
#+begin_src ... #+end_srcExample blocks:
#+begin_example ... #+end_exampleQuote blocks:
#+begin_quote ... #+end_quoteVerse blocks:
#+begin_verse ... #+end_verseCenter blocks:
#+begin_center ... #+end_centerComment blocks:
#+begin_comment ... #+end_comment
Syntactic sugar / aliases
Org2 supports a friendlier fenced-code alias for source blocks:
```ts
const x = 1
```
This is treated as syntactic sugar for:
#+begin_src ts
const x = 1
#+end_src
Prefer the fenced form for new hand-written examples and docs. The verbose #+begin_src form remains fully supported for compatibility and explicit Org-style interchange.
Fenced source blocks use exactly three backticks for the opener and closer. Four-or-more backticks remain ordinary text in v0, which keeps Markdown examples that quote org2 fences from accidentally becoming executable org2 source, chart, dataset, or SQL blocks.
Tables
Pipe table rows:
| a | b |Horizontal separator rows:
|---+---|Table content is parsed and preserved.
Tables, source blocks, and common blocks can carry adjacent affiliated keyword metadata:
#+name: quarterly_revenue
#+chart: line x=quarter y=revenue
#+dataset: finance.revenue
| quarter | revenue |
|---------+---------|
| 2026-Q1 | 1200 |
Recognized affiliated keys include NAME, CAPTION, PLOT, CHART, DATASET, VIEW, RESULTS, HEADER/HEADERS, and ATTR_* keys. The parser preserves them on the following table or block as affiliatedKeywords for chart renderers, dataset indexes, SQL views, and exporters.
For new chart examples, prefer an adjacent fenced chart block when it is easier to read:
#+name: fetch_buckets
| bucket | fetches |
|--------+---------|
| 0-10 | 14 |
| 11-50 | 32 |
```chart histogram
x: bucket
y: fetches
sort: y-desc
source: previous-table
```
This is ergonomic syntax sugar for chart metadata over the preceding table. Fenced chart blocks may also point at a named table or materialized result elsewhere in the same note:
#+name: package_fetches_result
#+results: query-fetches-by-company
| day | fetches |
|------------+---------|
| 2026-06-10 | 84 |
#+name: package_fetches_chart
```chart line
x: day
y: fetches
source: package_fetches_result
```
The current renderer supports bar, line, and bucketed histogram charts over the previous table or a named table source. Add sort: x-asc, sort: x-desc, sort: y-asc, or sort: y-desc when the visual should order marks independently of the table's source row order.
The CLI can render chart-affiliated tables directly:
npm run org2 -- render-chart --file report.org2 --block-id quarterly_revenue --format svg
Local datasets and SQL views
Org2 can describe local/ad hoc data workflows with fenced dataset and sql blocks. This is intended for notebook-like reports over explicit local files, read-only URLs, and named org2 tables, with DuckDB as the first execution bridge:
```dataset fetches
type: csv
path: ./data/package-fetches.csv
engine: duckdb
```
```sql results=fetches_by_state artifact=views/fetches_by_state.org freshness=24h
SELECT state, count(*) AS fetches
FROM fetches
GROUP BY state
ORDER BY fetches DESC
```
```chart bar
source: fetches_by_state
x: state
y: fetches
```
org2 query-data reads these blocks, creates DuckDB views for csv, parquet, json, URL-backed sources, or named org2 table datasets, creates any declared SQL views, runs a selected SQL result block through the local DuckDB CLI, and materializes the returned rows as a named org table or JSON envelope. Materialized org tables include a #+query-data: provenance line with the result id, row count, optional freshness token, selected SQL hash, full DuckDB script hash, and ran_at timestamp:
npm run org2 -- query-data --file report.org2 --results fetches_by_state --out report.fetches.org
npm run org2 -- query-data --file report.org2 --line 42 --format json
npm run org2 -- query-data --file report.org2 --inspect --include-script
cat report.org2 | npm run org2 -- query-data --stdin --results fetches_by_state --format json
Use --stdin when an editor, agent, or notebook-style client wants to run the current buffer without saving it first. Use --line N to select the SQL result block containing or after the cursor line. JSON output includes resultBlocks with each available SQL result id and source range so clients can populate result pickers or recover from duplicate-id diagnostics without reparsing the file. Use --inspect to return parsed datasets, SQL views, result block metadata, structural diagnostics, and selected-query provenance without running DuckDB; --include-script also returns the generated DuckDB SQL for the selected result. Relative file dataset paths are resolved from the current working directory for stdin input. SQL result ids must be unique within the note so materialized tables and provenance stay deterministic. Dataset ids and SQL view ids must also be distinct because they become DuckDB relation names during execution. Dataset blocks may include metadata-only credential: or auth: references such as env:SCARF_API_TOKEN, secret:analytics-token, or profile:product-analytics and config: or profile: references such as config:dashboard-local; these are exposed as JSON metadata for clients and agents, but are not inserted into the generated DuckDB SQL. Inline bearer tokens, passwords, and other literal secrets are rejected. SQL result blocks can include artifact=PATH to record the intended materialized output in JSON provenance and the #+query-data: line; --out FILE stamps the actual written artifact path. Executed JSON provenance also includes ranAt, and materialized org tables stamp ran_at, so editor, agent, and dashboard clients can compare declared freshness with the actual query run time. Result blocks can also include freshness=24h, ttl=24h, or max-age=24h so clients can decide when materialized rows should be refreshed.
Use sql view=NAME when a report needs a reusable local projection before the final result table:
```sql view=california_fetches
SELECT state, fetches
FROM fetches
WHERE state = 'CA'
```
```sql results=fetches_by_state
SELECT state, sum(fetches) AS fetches
FROM california_fetches
GROUP BY state
```
Use url: instead of path: when DuckDB should read a declared HTTP(S) or file: URL directly:
```dataset remote_fetches
type: csv
url: https://data.example.test/package-fetches.csv
engine: duckdb
credential: env:SCARF_API_TOKEN
config: profile:product-analytics
```
```sql results=remote_fetches_by_state
SELECT state, count(*) AS fetches
FROM remote_fetches
GROUP BY state
```
Use type: table with source: NAME when the source data already lives in a named org2 table:
#+name: raw_fetches
| state | fetches |
|-------+---------|
| CA | 42 |
| NY | 24 |
```dataset fetches
type: table
source: raw_fetches
engine: duckdb
```
```sql results=fetches_total
SELECT sum(fetches) AS fetches
FROM fetches
```
This is deliberately scoped to explicit local/ad hoc data sources. Org2 stores the source path, read-only URL, table/view name, optional column and primary-key metadata, credential/config reference, query, and materialized result/provenance; secrets, bearer tokens, and remote warehouse credentials belong in external tooling, not in notes.
Keyword/directive lines
Org2 parses keyword lines in #+KEY: VALUE form.
Commonly used in export/publish:
#+TITLE:#+SUBTITLE:#+AUTHOR:#+DATE:#+DESCRIPTION:#+KEYWORDS:#+LANGUAGE:#+HTML_HEAD:#+ID:
Unknown directives are preserved for round-tripping.
Comments
Line comments: lines beginning with
#.Comment blocks are also supported (see Blocks).
Losslessness goal
Org2 aims for practical round-tripping of supported constructs. When behavior is ambiguous, defer to the current implementation and spec fixtures.