Literate computing in plain text. Write prose and code together. Everything executes.
Org-press is a static site generator built for literate programming. Write in org syntax and transform your documents into interactive websites with executable code blocks, live previews, and literate testing.
Note: This project was built with AI assistance. Read more about it.
Features • Quick Start • Usage • Configuration • FAQ
- Executable Code Blocks - JavaScript, TypeScript, TSX, CSS blocks run in the browser
- Server-Side Execution - Run code at build time with
:use server - Literate Testing - Write tests alongside documentation with
orgp test - Code Quality Tools - Format, lint, and type-check code blocks
- Block Plugins - Extend with custom visualizations (Excalidraw, JSCad, etc.)
- Hot Module Replacement - Instant feedback during development
- Cross-File Imports - Import blocks between org files
- LSP Support - Language server for editor integration (currently Emacs lsp-mode)
# Install
npm install org-press
# Create content/index.org
mkdir content
echo "#+TITLE: Hello World" > content/index.org
# Start dev server
npx orgp dev| Package | Description |
|---|---|
org-press |
Core library with Vite plugin, parser, and CLI |
@org-press/block-test |
Literate testing with Vitest |
@org-press/fmt |
Format code blocks with Prettier |
@org-press/lint |
Lint code blocks with ESLint |
@org-press/type-check |
Type-check TypeScript blocks |
@org-press/block-excalidraw |
Excalidraw diagram block plugin |
@org-press/block-jscad |
JSCad 3D modeling block plugin |
orgp dev # Start development server
orgp build # Build static site
orgp test # Run literate tests
orgp fmt # Format code blocks with Prettier
orgp lint # Lint code blocks with ESLint
orgp type-check # Type-check TypeScript blocks
orgp lsp # Start language serverCode blocks in org files are automatically executed and their results displayed:
#+begin_src typescript
const greeting = "Hello from TypeScript!";
export default <div>{greeting}</div>;
#+end_src
Control what's displayed with :use:
#+begin_src javascript :use dom | withSourceCode
// Shows both code and result
export default <button>Click me</button>;
#+end_src
#+begin_src javascript :use dom
// Shows only the result (default)
export default <span>Just the output</span>;
#+end_src
#+begin_src javascript :use sourceOnly
// Shows only the code (no execution)
console.log("Documentation only");
#+end_src
#+begin_src javascript :use silent
// Executes but shows nothing
window.myGlobal = "initialized";
#+end_src
Run code at build time for data fetching, file processing, etc:
#+begin_src typescript :use server
const data = await fetch('https://api.example.com/data').then(r => r.json());
return <ul>{data.map(item => <li key={item.id}>{item.name}</li>)}</ul>;
#+end_src
Write tests alongside your documentation:
npm install @org-press/block-test vitest#+NAME: math-utils
#+begin_src typescript
export function add(a: number, b: number): number {
return a + b;
}
#+end_src
#+begin_src typescript :use test
import { describe, it, expect } from 'vitest';
import { add } from './math-utils';
describe('add', () => {
it('adds two numbers', () => {
expect(add(2, 3)).toBe(5);
});
});
#+end_src
orgp test # Run all tests
orgp test --watch # Watch mode
orgp test math.org # Run tests in specific filenpm install @org-press/fmt @org-press/lint @org-press/type-check// .org-press/config.ts
import { fmtPlugin } from '@org-press/fmt';
import { lintPlugin } from '@org-press/lint';
import { typeCheckPlugin } from '@org-press/type-check';
export default {
contentDir: 'content',
plugins: [fmtPlugin, lintPlugin, typeCheckPlugin],
};orgp fmt --check # Check formatting
orgp fmt # Format all blocks
orgp lint # Lint JS/TS blocks
orgp lint --fix # Auto-fix lint issues
orgp type-check # Type-check TypeScriptOrg-press includes a language server for editor integration. Currently supported:
- Emacs with lsp-mode
Start the language server:
orgp lspConfigure in Emacs:
(with-eval-after-load 'lsp-mode
(add-to-list 'lsp-language-id-configuration '(org-mode . "org"))
(lsp-register-client
(make-lsp-client
:new-connection (lsp-stdio-connection '("npx" "orgp" "lsp"))
:activation-fn (lsp-activate-on "org")
:server-id 'org-press-lsp)))The LSP provides:
- Diagnostics from lint, type-check, and test results
- Go-to-definition for cross-file block imports
- Hover information for block references
// .org-press/config.ts
import { defineConfig } from 'org-press';
export default defineConfig({
contentDir: 'content',
outDir: 'dist',
base: '/',
plugins: [],
});// vite.config.ts
import { orgPress } from 'org-press/vite';
export default {
plugins: [await orgPress()]
};Import org files directly in your app:
import { html, metadata, blocks } from './content/post.org';
console.log(metadata.title); // Document title
console.log(html); // Rendered HTML
console.log(blocks); // Code block exportsCreate custom block handlers:
import type { BlockPlugin } from 'org-press';
const myPlugin: BlockPlugin = {
name: 'my-plugin',
languages: ['mylang'],
async transform(block, context) {
return {
code: `export default ${JSON.stringify(block.value)};`
};
}
};No. Org-press uses org syntax (sometimes called "org-down") but is not org-mode. We chose the org format for its expressive block syntax, not to replicate Emacs org-mode functionality.
What we share: The file format. Org syntax provides named blocks, header arguments, and structured markup that's perfect for literate programming. Your .org files are valid org syntax and will render in any org-mode viewer.
What's different: Everything else. Org-mode is a powerful Emacs application with agendas, TODO management, time tracking, spreadsheets, and a vast ecosystem built over decades. Org-press is a web-focused static site generator. We rebuild specific features (like code execution and tangling) from scratch, targeting the browser instead of Emacs.
Think of it like Markdown: many tools use Markdown syntax, but they're not all the same application. Similarly, org-press uses org syntax while being its own tool optimized for web publishing and literate programming.
Markdown's syntax has fundamental limitations for literate programming. We could implement the same features in Markdown, but we'd have to invent non-standard syntax extensions that wouldn't work with any other tool:
<!-- Markdown: no native way to name blocks or add parameters -->
```ts
export function add(a, b) { return a + b; }...
This invented syntax would:
- Not work with any other Markdown tool
- Need to be documented and learned separately
- Feel bolted-on rather than native
**Org syntax has this built in:**
```org
#+NAME: add-func
#+begin_src typescript :use dom | withSourceCode
export function add(a, b) { return a + b; }
#+end_src
The syntax for named blocks and header arguments (:use, :tangle, etc.) is part of the org specification. We leverage existing, documented syntax rather than inventing conventions.
Note on cross-block references: Emacs org-mode uses noweb syntax (<<block-name>>) for referencing other blocks. We chose ES module imports instead:
import { add } from './math.org?name=add-func';This approach provides better IDE support - you get autocomplete, go-to-definition, and type checking across block boundaries. Standard tooling (TypeScript, ESLint) understands imports; they don't understand noweb references.
Trying something new can be rewarding. Markdown tools are everywhere - and they're great. But if you've ever wished your documentation could run, or wanted to test code examples inline, org-press offers something different. Give it a try.
Yes! Use the :tangle parameter to generate Markdown files from your org source:
#+begin_src markdown :tangle README.md
# My Package
This README is generated from the org source.
#+end_src
This keeps your source of truth in org while producing the Markdown files that package registries expect.
No. Org-press is not Emacs org-mode - it's a standalone tool that uses org syntax. You don't need Emacs at all. Org files are plain text with a simple, readable syntax that you can edit in any text editor:
- VS Code: org-mode extension for syntax highlighting
- Vim/Neovim: orgmode.nvim
- Any text editor: Org syntax is human-readable plain text
Both support literate programming. Jupyter is an industry standard and excels at interactive data exploration. Org-press takes a different approach:
Plain text, standard tooling. Org files are plain text - you get real version control diffs, not JSON blobs. Your existing tools (ESLint, Prettier, TypeScript) work out of the box. No special notebook environment required.
Editor-native experience. Because it's plain text with standard imports, you get full IDE support: intellisense, go-to-definition, refactoring across blocks. The editing experience is your normal code editor, not a browser-based notebook.
Open format. Org syntax is a documented, open specification that's been around since 2003. Your content isn't locked into any particular tool or platform.
Yes, and I'm proud of it.
This project went through multiple prototypes over the last 10 years that I never managed to complete and publish. Parsing org blocks, building an LSP, getting Vite integration right - these problems kept stopping me. AI brought back the fun of building it.
Is this AI slop? Probably, I don't know. I spent days going through each file, creating review lists, refactoring across versions, and cleaning the architecture. I didn't type every line or write every loop, but I shaped the architecture, defined the behavior, and wrote the specs. Is it perfect? No. Is it production ready? No.
I built it because it was fun. I built it for me. You're welcome to use it, with the hope it unleashes your creativity like it did for mine.
I believe literate programming has great potential when paired with AI - prose and code together create rich context that AI assistants understand well. This project is both a tool for that workflow and a product of it.
Contributions are welcome, but org-press is currently open source without open development. The code is publicly available under GPL-2.0, and you're free to use, fork, and modify it. Development happens in a private repository and is synced to GitHub.
We're happy to receive bug reports and feature suggestions via issues. Pull requests may take longer to review as open development isn't our current priority, but we appreciate them nonetheless.
As the project matures, we expect to move toward a more open development model.
See the docs folder or visit the documentation site.
Org-press is built on the shoulders of giants:
- Vite - The lightning-fast build tool that powers our dev server and production builds
- Uniorg - The excellent org-mode parser for JavaScript that makes this project possible
- Unified - The powerful content processing ecosystem (rehype, remark, and friends)
- Highlight.js - Syntax highlighting for code blocks
- React - UI components and the JSX transform
Thank you to all the maintainers and contributors of these projects.
GPL-2.0 - Code should be free.