!! WARNING !! - This is a VIBE SLOP codebase with git integration, so use at your own risk! Highly recommend starting with some dummy tasks to ensure everything mostly works before risking losing real work. Pull requests/forks welcome. This file is designed to be an interactive tutorial. Requires org-edna and claude-code.el https://github.com/stevemolitor/claude-code.el
Any org heading can be an agent session. Press C-c C-x s on a
heading and an AI agent spawns — isolated in its own git worktree,
scoped to that task, with full context from the org tree. When it
finishes, its changes auto-commit on a branch.
The tree is the persistent state. Sessions come and go, headings survive.
Requires claude-code.el for terminal management.
(add-to-list 'load-path "~/repos/org-agent")
(use-package org-agent
:after (org claude-code)
:config
(org-agent-mode 1))Then initialize your project:
M-x org-agent-init-project
The headings below are live tasks. Open this file in Emacs with
org-agent-mode enabled and try the workflow yourself.
First, set up the project:
M-x org-agent-init-project
This creates .org-agent/, installs guard hooks in
.claude/settings.json, and adds .org-agent/ to .gitignore.
After running all three tutorials, clean up the test branches:
git branch -D org-agent/TRY-1 org-agent/TRY-2 org-agent/TRY-3 2>/dev/null
git worktree prune
rm -rf .org-agent/worktrees/TRY-*Create a file examples/hello.sh that prints “Hello from org-agent!”
and is executable (chmod +x).
- Put point on this heading. Press
C-c C-x s. - Watch the agent work in its terminal.
- When it finishes, this heading flips to DONE.
- Press
C-c C-x gto review the diff in magit. - Verify:
bash examples/hello.shprints the greeting.
Dispatch (=C-c C-x s=) — branch + worktree created:
$ git branch * main org-agent/TRY-1 ← forked from main $ git worktree list /you/org-agent [main] /you/org-agent/.org-agent/worktrees/TRY-1 [org-agent/TRY-1]
Agent works — edits happen in .org-agent/worktrees/TRY-1/.
Your main working tree is untouched.
NEXT → DONE — auto-commit on the branch:
$ git log --oneline org-agent/TRY-1 f00cafe [TRY-1] Create examples/hello.sh $ git diff main..org-agent/TRY-1 --stat examples/hello.sh | 3 +++ 1 file changed, 3 insertions(+)
Review (=C-c C-x g=) — magit diff of main..org-agent/TRY-1.
Add a CONTRIBUTORS file listing “Your Name” and a LICENSE file
with the MIT license. These are independent — use parallel children.
- Create two children and dispatch them:
emacsclient -e '(org-agent-add-child "TRY-2" "[TRY-2a] Create CONTRIBUTORS file" "NEXT")' emacsclient -e '(org-agent-add-child "TRY-2" "[TRY-2b] Create LICENSE file with MIT license" "NEXT")' emacsclient -e '(org-agent-dispatch-batch (list "TRY-2a" "TRY-2b"))'
Or: put point on this heading, press
C-c C-x pto let a planning agent decompose it, thenC-c C-x bto batch-dispatch. - Both agents work in parallel. Watch them in the dashboard (
C-c C-x l). - When both are DONE, mark this heading DONE (
C-c C-x sorS-RIGHT). - The hook merges both branches. Press
C-c C-x gto review. - Verify:
cat CONTRIBUTORSandcat LICENSEshow the expected content.
Parent branch created when TRY-2 is dispatched or children fork:
$ git branch * main org-agent/TRY-2 ← parent branch (forked from main)
Children dispatched — each gets its own worktree:
$ git branch * main org-agent/TRY-2 org-agent/TRY-2a ← forked from org-agent/TRY-2 org-agent/TRY-2b ← forked from org-agent/TRY-2 $ git worktree list /you/org-agent [main] /you/org-agent/.org-agent/worktrees/TRY-2a [org-agent/TRY-2a] /you/org-agent/.org-agent/worktrees/TRY-2b [org-agent/TRY-2b]
Two agents, two directories, two branches — simultaneous work.
Children finish (NEXT → DONE) — each auto-commits:
$ git log --oneline org-agent/TRY-2a aaa1111 [TRY-2a] Create CONTRIBUTORS file $ git log --oneline org-agent/TRY-2b bbb2222 [TRY-2b] Create LICENSE file with MIT license
Parent finishes (TODO → DONE) — merges both, cleans up:
$ git log --oneline org-agent/TRY-2 ccc3333 Merge branch 'org-agent/TRY-2b' into org-agent/TRY-2 ddd4444 Merge branch 'org-agent/TRY-2a' into org-agent/TRY-2 bbb2222 [TRY-2b] Create LICENSE file with MIT license aaa1111 [TRY-2a] Create CONTRIBUTORS file $ git worktree list /you/org-agent [main] ← worktrees removed
Child branches deleted. Since TRY-2 is a level-2 heading,
TODO → DONE also merges org-agent/TRY-2 into main.
Merge conflict? If both children had edited the same file:
CONFLICT (content): Merge conflict in README.md org-agent: merge conflict — TRY-2 stays TODO, resolve manually
Resolve, commit on org-agent/TRY-2, then mark DONE again.
Create a VERSION file, then a CHANGELOG.md that references
the version from that file. The changelog depends on the version
file existing first — use a sequential chain.
- Create the chain:
emacsclient -e '(org-agent-add-chain "TRY-3" (list "[TRY-3a] Create VERSION file containing 0.1.0" "[TRY-3b] Create CHANGELOG.md referencing the version from VERSION" "[TRY-3c] Add a test script that checks VERSION matches CHANGELOG.md"))'
- TRY-3a dispatches immediately. TRY-3b auto-dispatches when
TRY-3a finishes — its worktree already contains the
VERSIONfile. - When the chain completes, mark this heading DONE.
- Verify:
bash test-version.sh(or whatever TRY-3c created) passes.
Chain created — org-edna wires the dependencies:
*** NEXT [TRY-3a] Create VERSION file containing 0.1.0
:PROPERTIES:
:TRIGGER: ids(TRY-3b) todo!(NEXT)
:END:
*** TODO [TRY-3b] Create CHANGELOG.md referencing the version from VERSION
:PROPERTIES:
:BLOCKER: ids(TRY-3a)
:TRIGGER: ids(TRY-3c) todo!(NEXT)
:END:
*** TODO [TRY-3c] Add a test script that checks VERSION matches CHANGELOG.md
:PROPERTIES:
:BLOCKER: ids(TRY-3b)
:END:
Only TRY-3a is NEXT. TRY-3b and TRY-3c are blocked.
TRY-3a works and finishes — auto-commit, then rolling merge into the parent branch (this is the key difference from parallel):
$ git log --oneline org-agent/TRY-3 aaa1111 Merge branch 'org-agent/TRY-3a' into org-agent/TRY-3 fff0000 [TRY-3a] Create VERSION file containing 0.1.0
TRIGGER fires → TRY-3b flips to NEXT → auto-dispatches.
Its worktree forks from org-agent/TRY-3, which already has
TRY-3a’s work merged in:
$ ls .org-agent/worktrees/TRY-3b/ VERSION ← written by TRY-3a, available to TRY-3b
TRY-3b finishes — rolling merge again, TRY-3c dispatches:
$ ls .org-agent/worktrees/TRY-3c/ VERSION ← from TRY-3a CHANGELOG.md ← from TRY-3b
Chain complete — full history on the parent branch:
$ git log --oneline org-agent/TRY-3 eee5555 Merge branch 'org-agent/TRY-3c' into org-agent/TRY-3 ddd4444 [TRY-3c] Add a test script ccc3333 Merge branch 'org-agent/TRY-3b' into org-agent/TRY-3 bbb2222 [TRY-3b] Create CHANGELOG.md aaa1111 Merge branch 'org-agent/TRY-3a' into org-agent/TRY-3 fff0000 [TRY-3a] Create VERSION file
Mark TRY-3 DONE → merges org-agent/TRY-3 into main.
- NEXT: execution. Agent gets edit access + worktree isolation.
- TODO: planning/decomposition. Agent gets read-only access.
- DONE: complete. Changes auto-committed, session closed.
org-agent works on whatever org file you open it in. This README,
your project’s TODO.org, a sprint-planning.org — any org file.
Set org-agent-org-filename to control which file org-agent-init-project
creates by default.
# Send a message to an agent's terminal
emacsclient -e '(org-agent-send "TRY-1" "Also add error handling." t)'
# Add a persistent note (survives restarts)
emacsclient -e '(org-agent-add-note "TRY-1" "Needs input validation.")'
# Read another agent's subtree
emacsclient -e '(org-agent-read-subtree "TRY-1")'
# Broadcast to all live agents
emacsclient -e '(org-agent-broadcast "Report status.")'Always pass t as the third arg to org-agent-send.
When a heading reaches DONE, press C-c C-x g to open a magit diff
of everything the agent changed. Falls back to a plain diff buffer
if magit isn’t installed.
For review agents (code review of children’s work): C-c C-x r.
All under C-c C-x in org-agent-mode:
| Key | What it does |
|---|---|
| s | Spawn agent on heading at point |
| b | Batch-spawn all NEXT leaves |
| p | Spawn planning agent (decompose) |
| r | Spawn review agent for DONE children |
| q | Close review/read-only sessions |
| k | Kill session (C-u to also purge) |
| d | Purge session from disk (fresh start) |
| g | Show magit diff for this node |
| l | Open agent dashboard |
| o | Switch to another agent session |
| n | Capture a TODO from any buffer |
| j | Jump to next waiting agent |
Global (when org-agent-global-keybindings is non-nil):
| Key | What it does |
|---|---|
| C-c n | Capture a TODO from any buffer |
| C-c j | Jump to next waiting agent |
(setq org-agent-org-filename "TODO.org") ;; default task file name
(setq org-agent-state-directory ".org-agent") ;; state/sessions dir
(setq org-agent-worktree-directory ".org-agent/worktrees") ;; worktree dir
(setq org-agent-instructions-file ".claude/CLAUDE.md") ;; project instructions;; Rust
(setq org-agent-pre-commit-formatter "cargo fmt"
org-agent-merge-formatter "rustfmt")
;; Python
(setq org-agent-pre-commit-formatter "black .")
;; JavaScript
(setq org-agent-pre-commit-formatter "prettier --write .")
;; None (default)
(setq org-agent-pre-commit-formatter nil)Every agent gets methodology text in its prompt. Override it:
;; Point to a file
(setq org-agent-methodology-file "docs/methodology.md")
;; Or set inline
(setq org-agent-methodology-text "## Our process\n1. Write tests first\n...")
;; Or use the default TDD stub (built-in);; Global default
(setq org-agent-default-backend "anthropic") ;; "anthropic", "codex", "zai"
;; Per-heading (inheritable via org properties)
(org-agent-set-backend "A-1" "codex")Elisp hooks:
| Hook | When it fires |
|---|---|
| org-agent-pre-execute-hook | Before spawning (receives plist) |
| org-agent-post-execute-hook | After agent completion |
| org-agent-state-change-hook | On TODO state change |
Claude Code PreToolUse hooks (shell scripts) enforce workflow rules:
- Edit guard: blocks edits when agent state isn’t NEXT/TODO, or
when writing outside declared
:OWNS_PATHS: - Commit guard: blocks
git commitfor NEXT agents without worktrees (forces the auto-commit path)
Installed by org-agent-install-hooks / org-agent-init-project.
(push '("my-backend" . (:require my-backend-code
:term-make my-backend--term-make
:term-send-string my-backend--term-send-string
:term-configure my-backend--term-configure
:term-setup-keymap my-backend--term-setup-keymap
:term-customize-faces my-backend--term-customize-faces
:event-hook my-backend-event-hook))
org-agent-backend-adapters)All claude-org-* functions are aliased to org-agent-*. Existing
guard scripts and running agents continue to work.
(setq org-agent-state-directory ".claude/tree"
org-agent-worktree-directory ".claude/worktrees"
org-agent-instructions-file ".claude/CLAUDE.md"
org-agent-pre-commit-formatter "cargo fmt")