diff --git a/README.md b/README.md index 215ae43..0828a7c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,275 @@ # PyOrgPatcher -PyOrgPatcher is a Python command-line utility that aid in workflows involving Emacs Org-Mode documents, as used in the PolyPaper project. - -Functions: - - List Org-Mode elements in an Org-Mode file that can be modified or extracted. - - Replace the content of an Org-Mode element with text from STDIN or from a file. - - With a JSON configuration, either extract multiple Org-Mode elements to associated files (without noweb substitution) or update an Org-Mode document's specified elements with the contents of files. - - Dry-run capability. - +**PyOrgPatcher** is a lightweight command-line utility and Python library for **programmatically editing, extracting, and synchronizing parts of Org-mode documents** — all without Emacs. + +It provides a simple way to patch Org files from scripts, CI/CD jobs, or AI agents, making it ideal for: +- Collaborators who work with Org files but don’t use Emacs. +- Reproducible research pipelines using literate programming. +- AI systems (e.g., LangChain, LangGraph, or MCP agents) that maintain structured text and code artifacts. + +All components are under: + +``` + +./code/ +├── orgpatch.py # main tool +├── example.org # demonstration Org file +└── test_orgpatch.py # pytest unit tests + +```` + +--- + +## 🔧 Installation & Setup + +### 1. Requirements + +- **Python 3.8+** +- **pytest** (for testing) + +Install dependencies: + +```bash +python3 -m venv venv +source venv/bin/activate +pip install pytest +```` + +### 2. Clone or Copy the Tool + +```bash +git clone https://git,cns.fyi/welsberr/PyOrgPatcher.git +cd PyOrgPatcher/code +``` + +You can also copy just `orgpatch.py` to any project — it’s self-contained and requires no external libraries. + +--- + +## 🧩 Example Org File + +[`example.org`](./example.org) demonstrates the types of elements PyOrgPatcher understands: + +```org +* Main Title +** Introduction +Some intro text. + +#+NAME: intro-para +This is a named paragraph that will be replaced. + +** Data +#+NAME: mytable +| Item | Value | +|------+-------| +| A | 1 | +| B | 2 | + +** Code +#+NAME: code-snippet +#+BEGIN_SRC python +print("hello world") +#+END_SRC + +** My Section +This section body will be replaced. +``` + +--- + +## 🚀 Basic Command-Line Usage + +List available patch targets: + +```bash +./orgpatch.py list example.org +``` + +Replace a section body: + +```bash +./orgpatch.py replace example.org --section "** My Section" --from section.txt +``` + +Replace a named block or table: + +```bash +./orgpatch.py replace example.org --name code-snippet --from code.py +``` + +Or from standard input: + +```bash +printf "| X | 42 |\n" | ./orgpatch.py replace example.org --name mytable --stdin +``` + +Use `--backup` to create `example.org.bak`. + +--- + +## 🔄 JSON Sync Mode + +Batch operations for multiple elements are defined via JSON mappings. + +### Example: `mapping.json` + +```json +[ + {"name": "code-snippet", "file": "code.py"}, + {"name": "mytable", "file": "table.org"}, + {"section": "** My Section", "file": "section.txt"} +] +``` + +### Apply Updates *into* the Org File (files → Org) + +```bash +./orgpatch.py sync example.org --map mapping.json --direction in --backup +``` + +### Export Org Elements *to* Files (Org → files) + +```bash +./orgpatch.py sync example.org --map mapping.json --direction out --mkdirs +``` + +Options: + +* `--dry-run` — preview only +* `--backup` — create a backup before modifying +* `--mkdirs` — create destination folders automatically +* `--no-overwrite` — skip existing files on export + +--- + +## 🧪 Running Unit Tests + +A complete [pytest](https://docs.pytest.org) test suite is included: + +```bash +pytest -q +``` + +This validates: + +* Parsing of headings and `#+NAME:` blocks +* Section replacement +* Named block/table/paragraph replacement +* JSON mapping synchronization (`sync in` and `sync out`) + +--- + +## 🧠 Integrating with AI Agent Tooling + +### Why It Matters + +Org-mode provides a **hierarchical, semantic structure** perfect for literate programming, documentation, and multi-language code notebooks — but until now, most AI systems couldn’t safely manipulate it without Emacs or brittle regex hacks. + +**PyOrgPatcher** changes that: +It gives AI agents and LLM-based systems a structured interface to read, patch, and synchronize `.org` files, **treating them as composable data artifacts**. + +### Example: Agent Workflow + +Imagine an **AI documentation agent** that: + +1. Reads `mapping.json` to identify relevant files and blocks. +2. Rebuilds code snippets or analyses (e.g., retraining results, data summaries). +3. Calls `orgpatch.py` (or its Python API) to update the corresponding Org blocks. + +This lets an AI system manage “literate” files safely without needing to regenerate the entire Org document. + +### In LangChain / LangGraph + +Within a LangChain or LangGraph workflow, you can use `PyOrgPatcher` as a tool node: + +```python +from langchain.tools import tool +import subprocess, json + +@tool("update_org_block") +def update_org_block(name: str, content: str): + """Update a named Org-mode block in example.org.""" + cmd = [ + "python3", "orgpatch.py", "replace", "example.org", + "--name", name, "--stdin" + ] + subprocess.run(cmd, input=content.encode("utf-8"), check=True) + return f"Updated block '{name}' successfully." +``` + +Agents can then call this tool directly: + +```python +update_org_block("analysis-results", "Mean=42\nStd=7.5\n") +``` + +Similarly, a chain could: + +* Use `sync in` to load generated files into an Org document. +* Use `sync out` to extract tables or code for downstream tasks (e.g., testing, publishing, or compiling). + +### Multi-Component Patch (MCP) Integration + +In MCP-style systems — where AI agents patch **specific parts of multi-file projects** — +PyOrgPatcher acts as the **Org-layer patcher**: + +* `sync in` = inject AI-generated code, results, or summaries. +* `sync out` = extract training data, code snippets, or narrative text. +* `replace` = fine-grained control of a single element in context. + +This makes it ideal for **AI-assisted research notebooks**, **literate AI model reports**, and **collaborative documentation systems**. + +--- + +## 🧰 Python Library Usage + +PyOrgPatcher can also be used as a Python module: + +```python +import orgpatch as op + +lines = op.read_lines("example.org") +new_lines = op.replace_named(lines, "code-snippet", "print('updated via API')\n") +op.write_lines("example.org", new_lines) +``` + +This makes it easy to integrate into scripts or notebooks. + +--- + +## 🧬 Example Use Case: Non-Emacs Collaboration + +Researchers, engineers, or students who use VS Code, Sublime, or other editors can: + +* Edit external files (`.py`, `.csv`, `.txt`) directly. +* Let an automated process update `main.org` via `sync in`. +* Keep the literate record synchronized without ever opening Emacs. + +This lowers the barrier for collaboration in mixed-editor teams. + +--- + +## 🏁 Summary + +| Feature | Description | +| -------------------------- | ---------------------------------------------------- | +| **CLI + Library** | Command-line and Python module usage | +| **Emacs-Free Editing** | Safely patch `.org` files without Emacs | +| **JSON Batch Mode** | Bulk updates and exports | +| **AI/Automation Ready** | Ideal for LangChain, LangGraph, or MCP agents | +| **Fully Tested** | Comprehensive pytest suite included | +| **Collaboration-Friendly** | Perfect for teams mixing Org-mode with other editors | + +--- + +**Author:** Wesley R. Elsberry +**Project:** PyOrgPatcher +**License:** MIT +**Location:** `./code/` + +> “PyOrgPatcher bridges human-readable structure and machine-editable precision — empowering both collaborators and intelligent agents to work fluently with Org-mode documents.” + +``` + +--- +