Skip to content

org-press/org-press

Repository files navigation

Org-Press

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.

FeaturesQuick StartUsageConfigurationFAQ


Features

  • 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)

Quick Start

# Install
npm install org-press

# Create content/index.org
mkdir content
echo "#+TITLE: Hello World" > content/index.org

# Start dev server
npx orgp dev

Packages

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

Usage

CLI Commands

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 server

Executable Code Blocks

Code 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

Display Modes

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

Server-Side Execution

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

Literate Testing

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 file

Code Quality Tools

npm 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 TypeScript

LSP Support

Org-press includes a language server for editor integration. Currently supported:

Start the language server:

orgp lsp

Configure 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

Configuration

// .org-press/config.ts
import { defineConfig } from 'org-press';

export default defineConfig({
  contentDir: 'content',
  outDir: 'dist',
  base: '/',
  plugins: [],
});

Vite Integration

// 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 exports

Block Plugins

Create 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)};`
    };
  }
};

FAQ

Is this org-mode?

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.

Why org syntax instead of Markdown?

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.

Can I use Markdown for README files?

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.

Is org-press only for Emacs users?

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:

How does this compare to Jupyter notebooks?

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.

Was this built with AI?

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.

Can I contribute?

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.


Documentation

See the docs folder or visit the documentation site.

Acknowledgments

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.

License

GPL-2.0 - Code should be free.

About

Literate computing for the AI era.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors