Tooling reference

This page covers the practical Org2 tooling surface today. For the product framing around compiler-style corpus checks, see Maintenance and health workflows.

The CLI is the shared backend for editor integrations and automation. You can use it directly or through VS Code commands.

Core command families

Run npm run org2 -- --help for current top-level usage. AI architecture, job design, draft artifacts, and provider boundaries are documented separately in AI processing architecture, AI job manifests, AI draft artifacts, and AI adapter interface so the deterministic CLI surface stays clear.

Main workflows:

  • agenda

  • todo

  • plan

  • capture

  • archive, refile

  • fmt

  • search, id, query, backlinks

  • render-chart

  • roam ...

  • crypt ...

  • export html

  • publish

  • lint

  • ai validate-job

  • lsp

Command conventions and stability

Audit summary for CLI consistency: most commands already use --dir for corpus roots, --recursive for traversal, --format for alternate output, and --apply for mutating writes. The lowest-risk cleanup is to make JSON output easier and consistent across commands.

Conventions:

  • Prefer --format json for stable machine-readable output; --json is a shorthand alias where JSON output is supported.

  • Preview is the default for mutating commands. Pass --apply to write files.

  • Use --dir DIR with --recursive for corpus-wide scans, or --file FILE / --files FILE ... for bounded scans.

  • Text/report output is human-facing and may evolve; JSON output is the integration surface.

Examples:

npm run org2 -- agenda --dir ~/notes --recursive --json
npm run org2 -- lint --dir ~/notes --recursive --format json
npm run org2 -- roam node new --dir ~/notes --title "Acme Corp" --apply --json

Agenda

Purpose: query scheduled/deadline items across Org files.

npm run org2 -- agenda --dir ~/notes --recursive --from 2026-03-01 --to 2026-03-31

Important behavior:

  • Includes both SCHEDULED: and DEADLINE: rows in-range.

  • Supports broad filter/sort/group dimensions in CLI + VS Code integration.

  • Normalizes common TODO aliases into stable status buckets (including wait/hold/pause-style states).

TODO + planning edits

npm run org2 -- todo toggle --file notes.org2 --line 42 --apply
npm run org2 -- todo set --file notes.org2 --line 42 --status in_progress --apply
npm run org2 -- plan set --file notes.org2 --line 42 --kind scheduled --date 2026-03-25 --apply

Capture / archive / refile

npm run org2 -- capture --file inbox.org2 --title "Quick note" --template note --apply
npm run org2 -- archive --file notes.org2 --pos 120:0 --apply
npm run org2 -- refile --file notes.org2 --pos 120:0 --to-file projects.org2 --to-pos 40:0 --apply

Archiving moves the selected subtree to a companion archive file (by default FILE_archive for .org and .org2 files, otherwise FILE.archive). Archived subtrees receive a property drawer with ARCHIVED_AT, ARCHIVE_SOURCE, ARCHIVE_SOURCE_LINE, ARCHIVE_HEADING_PATH, and ARCHIVE_ORIGINAL_ID when the original subtree had an ID. Use --format diff to preview the exact removal/append operation, or --format json for editor/agent integrations.

Formatter

Canonical formatting for Org2 files.

npm run org2 -- fmt --dir ~/notes --recursive --check
npm run org2 -- fmt --dir ~/notes --recursive --apply

Chart rendering

org2 render-chart renders an SVG artifact from #+chart: / #+plot: metadata or an adjacent fenced ```chart block attached to an org2 table. This gives editor clients a shared backend instead of making each extension reimplement table parsing and chart semantics.

npm run org2 -- render-chart --file report.org2 --block-id quarterly_revenue --out /tmp/quarterly-revenue.svg
npm run org2 -- render-chart --file report.org2 --line 42 --format json

The first renderer supports deterministic bar, line, and bucketed histogram charts with x and y column mappings. New hand-written examples should prefer fenced chart blocks when they are easier to scan:

| bucket | fetches |
|--------+---------|
| 0-10   | 14      |
| 11-50  | 32      |

```chart histogram
x: bucket
y: fetches
sort: y-desc
source: previous-table
```

For data-backed reports, a chart block can also point at a named materialized result table 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
```

Add sort: x-asc, sort: x-desc, sort: y-asc, or sort: y-desc when a chart preview should be ordered independently of the table rows. JSON output includes ok, format, artifact, source, diagnostics, and svg so VS Code, Vim, or agent tooling can show useful errors for missing columns, unsupported chart types, missing chart sorts, missing named source tables, or missing chart blocks.

Local data queries

org2 query-data is the first DuckDB-backed bridge for local/ad hoc datasets described in org2 notes. It scans fenced ```dataset blocks, creates DuckDB views for explicit csv, parquet, or json paths/URLs or named org2 tables, optionally creates reusable SQL views from ```sql view=NAME blocks, then runs a fenced ```sql results=NAME block and materializes the returned rows.

```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
```

Reusable SQL views can sit between datasets and the final materialized result:

```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
```

Read-only HTTP(S) or file: URLs can be recorded with url: when DuckDB can read the source 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
```

Named org2 tables can also become local DuckDB views without an intermediate CSV export:

#+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
```
npm run org2 -- query-data --file report.org2 --results fetches_by_state
npm run org2 -- query-data --file report.org2 --line 42 --format json
npm run org2 -- query-data --file report.org2 --inspect --include-script
npm run org2 -- query-data --file report.org2 --results fetches_by_state --out views/fetches_by_state.org
cat report.org2 | npm run org2 -- query-data --stdin --results fetches_by_state

The default output is a named org table with #+name: fetches_by_state so it can be pasted or written into the note and consumed by render-chart via source: fetches_by_state. Materialized tables also include a compact #+query-data: provenance line with the result id, row count, optional artifact reference, optional freshness token, selected SQL hash, full DuckDB script hash, and ran_at timestamp so refreshed results can be compared without embedding the full script in the note. Add artifact=PATH to a SQL result block to record the intended materialized output; when --out FILE is used, the actual written artifact path is stamped instead. Add freshness=24h, ttl=24h, or max-age=24h to a SQL result block when editor, agent, or dashboard clients should know how long a materialized result can be treated as fresh. SQL result ids must be unique within the note; duplicate result ids are reported as diagnostics instead of selecting an arbitrary block. Dataset ids and SQL view ids also share DuckDB's relation namespace, so a SQL view cannot reuse a dataset name. URL and table datasets may also include metadata-only credential: or auth: references and config: or profile: references such as env:SCARF_API_TOKEN or profile:product-analytics; inline bearer tokens and passwords are rejected, and these references are not injected into the generated DuckDB SQL. JSON output includes diagnostics, dataset metadata, SQL view metadata, available SQL result block metadata, provenance hashes/artifact/freshness/run timestamp, rows, and the generated org table; --include-script also includes the DuckDB setup SQL for debugging. Use --inspect to emit parsed JSON metadata, structural diagnostics, and selected-query provenance without running DuckDB; add --include-script to preview the generated DuckDB SQL for the selected result in the same dry run. Editor and agent clients can pass an unsaved buffer with --stdin and select the SQL result block containing or after the cursor with --line N; file-backed dataset paths are then resolved relative to the current working directory, while URL datasets are passed through as declared. The command expects a local DuckDB CLI on PATH for execution, or a custom path via --duckdb.

Corpus lint

Lint is the first compiler-style health pass for artifact metadata and corpus structure. It belongs to the broader maintenance and health workflow alongside formatter checks, graph queries, publish previews, and ID/index repair passes.

npm run org2 -- lint --dir ~/notes --recursive

Current checks include:

  • invalid or missing ORG2_ARTIFACT_ROLE on generated outputs

  • missing/invalid provenance, generator, and generated-at metadata

  • duplicate IDs and unresolved provenance references

  • stale generated artifacts when provenance file mtimes or ORG2_SOURCE_HASHES no longer match

  • unresolved id: links, unresolved wiki links, and ambiguous wiki links/aliases using the same graph index as roam workflows

  • conventional corpus-flow checks when you organize notes as raw/ -> notes/ -> compiled/ -> views/ -> publish/

See Corpus flow for the canonical zone model, artifact roles, and generated-output trust boundaries.

AI job manifest validation

org2 ai validate-job validates repeatable AI workflow manifests without calling a provider or loading secrets.

npm run org2 -- ai validate-job --job examples/jobs/weekly-summary.org2-ai.json
npm run org2 -- ai validate-job --job examples/jobs/weekly-summary.org2-ai.json --format json

Use this in CI or editor workflows before a future AI runner consumes a job. The validator checks corpus input selection, task type, symbolic adapter names, generated output targets, provenance/review requirements, and common accidental secret leaks. See AI job manifests for the schema and examples.

org2 ai run writes a reviewable generated draft artifact from a validated job. The current implementation is provider-free and uses manifest input.files as deterministic source material, including simple glob patterns. It stamps ORG2_PROVENANCE, ORG2_SOURCE_HASHES, prompt/template, adapter/model, generated-at, and ORG2_REVIEW_STATUS metadata. Without --apply it previews the draft.

npm run org2 -- ai run --job examples/jobs/weekly-summary.org2-ai.json --out views/weekly-summary.org2
npm run org2 -- ai run --job examples/jobs/weekly-summary.org2-ai.json --out views/weekly-summary.org2 --apply

org2 ai suggest-links ranks compiler-provided roam/linkify candidates with the deterministic mock adapter. It scans the graph, aliases, exact linkify matches, represented-node semantic suggestions, and title-case entity mentions, then emits review-only suggestions with confidence, reasons, source context, and citations. It never edits canonical notes directly; --apply only writes the suggestion report when --out is provided.

npm run org2 -- ai suggest-links --dir ~/notes --recursive --format json
npm run org2 -- ai suggest-links --dir ~/notes --recursive --out views/link-suggestions.org2 --apply

org2 ai promote is the safe acceptance path. It refuses drafts until ORG2_REVIEW_STATUS is reviewed, then appends the reviewed body to a canonical note only when --apply is present and marks the draft promoted.

npm run org2 -- ai promote --file views/weekly-summary.org2 --to-file notes/weekly-summary.org2 --apply

See AI draft artifacts for the full format, review checklist, and VS Code command-palette entry points.

Compiled corpus artifacts

org2 compile corpus emits a stable, schema-versioned knowledge artifact that LLM tools, search indexes, and other automation can consume. Org2 only compiles local plain-text notes into structured data; it does not call an LLM or require any hosted AI service.

npm run org2 -- compile corpus --dir ~/notes --recursive --out compiled/corpus.json
npm run org2 -- compile corpus --dir ~/notes --recursive --format jsonl --out compiled/corpus.jsonl

The JSON form includes:

  • standardized artifact metadata: role, generator, generated-at timestamp, source provenance, source hashes, and review status

  • files with relative paths, absolute paths, SHA-256 hashes, line counts, titles, and IDs

  • file and heading nodes with source ranges for citations

  • heading TODO state, priority cookies, tags, planning timestamps, explicit properties, inherited inheritedProperties, overlaid effectiveProperties, IDs, and aliases

  • links and resolved backlinks for explicit id: links and unambiguous wiki links

  • text snippets suitable for previews or retrieval pipelines

Use JSONL for larger corpora when downstream tools prefer one record per line; the first JSONL record carries the same artifact metadata header as the JSON form. If you wrap compiled artifacts in Org files, stamp the wrapper with the same ORG2_ARTIFACT_*, ORG2_SOURCE_HASHES, and ORG2_REVIEW_STATUS fields and keep using org2 lint for generated-output health checks.

Search + cited query

Use search for literal, case-insensitive full-text lookup over .org and .org2 files, and query when you want cited context suitable for answering factual questions from notes. Directory scans are non-recursive unless --recursive is set. The External LLM consumer pattern page shows how provider-agnostic agents can turn this JSON into cited model context without adding LLM calls to Org2 core.

npm run org2 -- search "Chris Martin" --dir ~/notes --recursive --context 3 --sort date-desc
npm run org2 -- query "Chris Martin" --dir ~/notes --recursive --subtree --sort date-desc --format json
npm run org2 -- query "Sentra" --dir ~/notes --recursive --format json

Useful flags:

  • --context N includes surrounding source lines.

  • --limit N caps returned matches.

  • --sort date-desc is useful for “when did I last...” style questions over date-named daily files and heading timestamps.

  • --subtree deduplicates matches to cited heading/subtree sections with sourceRange, headingAncestry, matchedLines, and full subtree context.

  • --answer-context adds a plain subtree text block for downstream local LLM prompts.

  • --date-from / --date-to and --file-zone narrow results by local corpus zones and source dates.

  • --format json returns machine-readable file, line, heading, snippet, source range, and context fields.

Roam workflows

npm run org2 -- roam db-sync --dir ~/notes --recursive --apply
npm run org2 -- roam node new --dir ~/notes --title "Acme Corp" --apply
npm run org2 -- roam backlinks --id 123e4567-e89b-12d3-a456-426614174000 --dir ~/notes --recursive --format json
npm run org2 -- roam linkify --dir ~/notes --recursive
npm run org2 -- roam graph --dir ~/notes --recursive --format report
npm run org2 -- roam graph --dir ~/notes --recursive --format json

Org2 supports both title-based wiki links and explicit id: links, with backlinks across both forms. Linkify and graph reports are intended as compiler-style maintenance passes: preview references, strengthen links deliberately, and inspect corpus connectivity without leaving plain files. org2 roam linkify --format json reports exact title/alias replacements plus review-only represented-node suggestions with confidence, evidence tokens, and source ranges for headings or multi-line paragraphs; --apply only writes exact safe replacements, never semantic suggestions. org2 roam graph --format report emits a human-readable maintenance view with graph summary, orphan/high-degree nodes, alias/title collisions, unresolved or ambiguous links with file/line citations, and linkify suggestions; --format json includes the same maintenance payload for scripts and CI.

Org-crypt

Org2 keeps the existing Org-style :crypt: convention and encrypts at the subtree boundary. A subtree can be encrypted symmetrically with a passphrase, or to multiple public-key recipients so the same private note can be opened by your user key, another device key, and an agent key without sharing one password around.

# Passphrase/symmetric mode
npm run org2 -- crypt decrypt --file secrets.org2 --line 42 --passphrase 'your-passphrase' --apply
npm run org2 -- crypt encrypt --file secrets.org2 --line 42 --passphrase 'your-passphrase' --apply

# Multi-recipient public-key mode
npm run org2 -- crypt encrypt --file secrets.org2 --line 42 \
  --recipient user@example.com \
  --recipient agent@example.com \
  --apply

# Public-key recipient files are useful for keys that are not in your keyring
npm run org2 -- crypt encrypt --file secrets.org2 --line 42 \
  --recipient-file keys/agent-public.asc \
  --apply

# Or make sharing per-entry with an Org property drawer
# Relative recipient-file paths resolve from the current note's directory.
* Private note shared with an agent :crypt:
:PROPERTIES:
:CRYPT_RECIPIENT_FILE: keys/agent-public.asc
:END:
Only the entries with this property are encrypted to that agent.

# Migration: decrypt an existing block, then re-encrypt it for the new recipients
npm run org2 -- crypt reencrypt --file secrets.org2 --line 42 \
  --passphrase 'old-passphrase-if-needed' \
  --recipient user@example.com \
  --recipient agent@example.com \
  --apply

Per-entry recipient properties let one corpus mix private-only and shared-with-agent notes without a global editor setting. :CRYPT_RECIPIENT: / :CRYPT_RECIPIENTS: add GPG recipient identifiers, while :CRYPT_RECIPIENT_FILE: / :CRYPT_RECIPIENT_FILES: add armored public key files. Multiple values can be separated with commas. Relative recipient-file paths are resolved relative to the Org2 file that contains the subtree, so they work across machines when the key file lives in the synced project.

Export + publish

npm run org2 -- export html --file README.org --out README.html --apply
npm run org2 -- export html --dir docs/site --recursive --out-dir site --apply
npm run org2 -- publish docs-site --config org2.json

Useful export options include TOC, heading numbering, stylesheet injection, and Org-file-link rewrite to HTML targets.

LSP

Start language server:

npm run org2 -- lsp

Current implemented capabilities include:

  • definitions/references/hover/completion/signature help

  • rename + linked editing for IDs/file links

  • file-rename link updates

  • formatting (document/range/on-type)

  • semantic tokens, inlay hints, code lens, call hierarchy

For full details, see: