From 3ce860f021a8151fb8650ff0c6daf90304e4154e Mon Sep 17 00:00:00 2001 From: Miles Date: Fri, 28 Aug 2026 22:22:53 +0000 Subject: [PATCH 1/2] docs: add quick-start and comparison pages API-verified against v0.5.3. Adds docs/ directory with: - quick-start.md: five-minute walkthrough for AI agent developers - comparison.md: factual comparison vs orgparse and organice Timed to support Show HN (Sep 2) and the r/emacs post (Aug 28). --- docs/comparison.md | 110 +++++++++++++++++++++++++++++++++++ docs/quick-start.md | 139 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+) create mode 100644 docs/comparison.md create mode 100644 docs/quick-start.md diff --git a/docs/comparison.md b/docs/comparison.md new file mode 100644 index 0000000..0a430c5 --- /dev/null +++ b/docs/comparison.md @@ -0,0 +1,110 @@ +# org-workspace vs orgparse vs organice + +> A factual comparison for developers who work with org-mode files in Python. + +All three libraries solve different problems. This page helps you pick the right one. + +--- + +## TL;DR + +| Capability | orgparse | organice | org-workspace | +|-----------|---------|---------|---------------| +| Parse org files | ✅ | ✅ (via JS) | ✅ (via orgparse fork) | +| Write / mutate org files | ❌ | ✅ (in-browser) | ✅ | +| Python library | ✅ | ❌ (JS/TS) | ✅ | +| Multi-file workspace | ❌ | ❌ | ✅ | +| Atomic task claiming | ❌ | ❌ | ✅ | +| Concurrency primitives | ❌ | ❌ | ✅ | +| GTD query layer | ❌ | ❌ | ✅ | +| Dependency DAG (Plan) | ❌ | ❌ | ✅ | +| AI agent integration | ❌ | ❌ | ✅ | +| Round-trip safe serialization | ⚠️ partial | ✅ (JS) | ✅ | + +--- + +## orgparse + +[orgparse](https://github.com/karlicoss/orgparse) is a mature, well-tested Python parser for org-mode. It's the right choice if you want to **read** org files and don't need to write back. + +**Strengths:** +- Battle-tested and widely used +- Clean, Pythonic API for reading headings, properties, and text +- Good performance on large files + +**Limitations:** +- Read-only: no write support in the upstream library (PR #77 adds it but hasn't merged) +- No multi-file workspace concept +- No query layer for GTD patterns +- No concurrency support + +**When to use:** Reporting, analytics, read-only tooling over org files. + +org-workspace includes a vendored fork of orgparse with write support from PR #77. If your project already depends on orgparse for reading, org-workspace is a compatible upgrade path. + +--- + +## organice + +[organice](https://github.com/200ok-ch/organice) is a web application for editing org-mode files in a browser, with sync support for Dropbox, WebDAV, and Nextcloud. It's a frontend tool, not a Python library. + +**Strengths:** +- Clean mobile and desktop web interface +- Real org-mode support including agenda, TODO states, and tags +- Sync integrations with common file storage services + +**Limitations:** +- JavaScript/TypeScript only — no Python API +- Designed for human editing, not programmatic access +- No agent integration, task claiming, or batch operations + +**When to use:** You want a Dropbox-synced org agenda in a browser. + +--- + +## org-workspace + +org-workspace is a **Python library for AI agents and automation** that need to read, write, and reason over org-mode files. It was built to let autonomous agents safely coordinate over a shared task system without stepping on each other. + +**Strengths:** +- Full read/write Python API +- Multi-file workspace with dirty-file tracking +- Concurrency primitives for multi-agent coordination (TaskClaim, OptimisticLock, FileLock) +- GTD query layer (agenda, deadlines, overdue, next_action, ai_tasks) +- Dependency DAG with topological sort (Plan) +- Round-trip safe serialization: unmodified files are never rewritten +- GTD and nightshift state configurations out of the box +- Content-addressed ID generation with dedup detection + +**Limitations:** +- Newer project (v0.5.3, Beta) — fewer real-world deployments than orgparse +- No standalone CLI +- No browser or sync interface + +**When to use:** Building AI agents, automation pipelines, or developer tools that need to read and write org-mode task lists programmatically. + +--- + +## Feature deep-dive: write safety + +One reason to choose org-workspace over rolling your own orgparse wrapper: write safety is surprisingly hard. + +The naive approach — read → modify in-memory → serialize → write — routinely causes subtle bugs: property drawers getting duplicated, timestamps reformatted, tags reordered, or entire lines truncated on long values. These bugs don't fail loudly; they corrupt your files silently. + +org-workspace's serializer is designed around the round-trip invariant: a file that's loaded and immediately saved must produce byte-identical output for unchanged nodes. This is validated in the test suite on real org files. The `CatastrophicShrinkError` guard will refuse to write a file that's significantly smaller than the original, catching serializer regressions before they reach disk. + +--- + +## FAQ + +**Can I use org-workspace alongside orgparse?** +Yes. org-workspace vendors its own copy of orgparse internally, so there's no conflict. You can use the upstream orgparse for reading and org-workspace for writing if needed. + +**Does org-workspace work with Emacs's org-mode?** +Yes — org-workspace produces valid org-mode syntax. Files modified by org-workspace open correctly in Emacs without reformatting. + +**What Python versions are supported?** +Python 3.10–3.13. + +**Is it production-ready?** +It's at Beta stability (v0.5.3). The core API is stable; the advanced concurrency and Plan features are in use in Datacore's own autonomous agent pipeline. diff --git a/docs/quick-start.md b/docs/quick-start.md new file mode 100644 index 0000000..bbc7ba4 --- /dev/null +++ b/docs/quick-start.md @@ -0,0 +1,139 @@ +# org-workspace Quick Start + +> From install to your first AI-readable task list in under five minutes. + +## Install + +```bash +pip install org-workspace +``` + +## Your first five minutes + +Assume you have at least one org-mode file. If not, create a minimal one: + +``` +~/org/inbox.org: + +* TODO Write my first task + :PROPERTIES: + :ID: abc123 + :END: + This is what org-workspace can read and write. +``` + +Now open Python: + +```python +from pathlib import Path +from org_workspace import OrgWorkspace, Query + +# Point at your org directory (or a single file) +ws = OrgWorkspace(roots=[Path.home() / "org"]) + +# Find all tasks tagged for AI execution +q = Query(ws) +for task in q.ai_tasks(states=["TODO"]): + print(task.heading, task.tags) + +# Create a task programmatically +new_task = ws.create_node( + file=Path.home() / "org" / "inbox.org", + heading="Summarise my meeting notes", + state="TODO", + tags=["AI", "research"], + body="Use the attached notes in ~/org/notes/2026-07-meeting.org", +) + +# Save — only modified files are written, unchanged files are left alone +ws.save() +print("Task created:", new_task.id) +``` + +That's it. You've loaded a workspace, queried it, created a task, and saved safely. + +## What just happened + +**`OrgWorkspace`** loads and indexes all your org files. It tracks which files are dirty and guarantees round-trip safety — if you read a file and write it back unchanged, the bytes on disk don't change. + +**`Query`** is a stateless query layer on top of the workspace. `ai_tasks()` finds any heading tagged `:AI:` — the convention Datacore uses to hand work to autonomous agents overnight. + +**`create_node()`** inserts a new heading with a unique content-addressed ID. It will never silently overwrite an existing node. + +## The key primitives + +| Primitive | What it does | +|-----------|-------------| +| `OrgWorkspace` | Load, index, and safely write org files | +| `Query` | Read-only queries: agenda, deadlines, AI tasks, next action | +| `NodeView` | Stateless view of a single node; detects staleness automatically | +| `TaskClaim` | Atomic task claiming — prevents two agents running the same task | +| `OptimisticLock` | Hash-based conflict detection for concurrent writes | +| `Plan` | Parse `DEPENDS_ON` into a dependency DAG, topological sort | + +## Common patterns for AI agents + +### Claim a task before executing + +```python +from org_workspace import OrgWorkspace, Query +from org_workspace.concurrency import TaskClaim + +ws = OrgWorkspace(roots=[Path.home() / "org"]) +q = Query(ws) +tc = TaskClaim(ws) + +for task in q.ai_tasks(states=["TODO"]): + if tc.claim(task, agent_id="my-agent"): + # Only one agent gets here; others skip this task + ws.transition(task, "EXECUTING", agent="my-agent") + ws.save() + # ... do work ... + ws.transition(task, "DONE", agent="my-agent") + tc.release(task, "my-agent") + ws.save() +``` + +### Find overdue tasks + +```python +overdue = q.overdue() +for task in overdue: + print(f"{task.heading} — deadline: {task.deadline}") +``` + +### Build a dependency plan + +```python +from org_workspace import Plan + +# Plan wraps a project subtree — find the root node first +roots = q.by_property("ID", "your-project-id") +if roots: + plan = Plan(roots[0], ws) + for task in plan.ready_tasks(): + print("Ready to run:", task.heading) + for task, blocker in plan.blocked_tasks(): + print("Blocked:", task.heading, "(waiting on:", blocker, ")") +``` + +## GTD states + +org-workspace ships with a default GTD state sequence and an extended nightshift sequence for autonomous execution: + +```python +from org_workspace import StateConfig + +# Default GTD: TODO → NEXT → WAITING → DONE +config = StateConfig.default() + +# Nightshift: adds QUEUED, EXECUTING, REVIEW, FAILED for agent pipelines +config = StateConfig.nightshift() +ws = OrgWorkspace(roots=[...], state_config=config) +``` + +## Where to go next + +- [GitHub](https://github.com/datacore-one/org-workspace) — source, issues, discussions +- `pip install org-workspace` then `python -c "from org_workspace import OrgWorkspace; help(OrgWorkspace)"` +- Issues and feature requests welcome on GitHub From b1f586ac4211c3f5b98c286c0431f1ad16af5037 Mon Sep 17 00:00:00 2001 From: Miles Date: Fri, 28 Aug 2026 23:09:25 +0000 Subject: [PATCH 2/2] docs: fix missing Path import in TaskClaim example Co-Authored-By: Claude Sonnet 4.6 --- docs/quick-start.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/quick-start.md b/docs/quick-start.md index bbc7ba4..7fcd873 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -76,6 +76,7 @@ That's it. You've loaded a workspace, queried it, created a task, and saved safe ### Claim a task before executing ```python +from pathlib import Path from org_workspace import OrgWorkspace, Query from org_workspace.concurrency import TaskClaim