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.
Go to file
Wesley R. Elsberry dc6ada6f43 Added missing import; pytest succeeds thereafter 2025-10-09 12:15:04 -04:00
code Added missing import; pytest succeeds thereafter 2025-10-09 12:15:04 -04:00
.gitignore Initial commit 2025-10-07 17:05:51 -04:00
LICENSE Initial commit 2025-10-07 17:05:51 -04:00
README.md Revised README.md 2025-10-07 19:12:41 -04:00

README.md

PyOrgPatcher

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 dont 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:

python3 -m venv venv
source venv/bin/activate
pip install pytest

2. Clone or Copy the Tool

git clone https://git,cns.fyi/welsberr/PyOrgPatcher.git
cd PyOrgPatcher/code

You can also copy just orgpatch.py to any project — its self-contained and requires no external libraries.


🧩 Example Org File

example.org demonstrates the types of elements PyOrgPatcher understands:

* 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:

./orgpatch.py list example.org

Replace a section body:

./orgpatch.py replace example.org --section "** My Section" --from section.txt

Replace a named block or table:

./orgpatch.py replace example.org --name code-snippet --from code.py

Or from standard input:

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

[
  {"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)

./orgpatch.py sync example.org --map mapping.json --direction in --backup

Export Org Elements to Files (Org → files)

./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 test suite is included:

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 couldnt 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:

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:

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:

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.”


---