OpenHands Markdown Document Tool - Structural editing and formatting for markdown documents
Project description
OpenHands Markdown Document Tool
A comprehensive tool for structural editing and formatting of markdown documents, designed for use with OpenHands AI agents.
Features
This tool provides AI agents with powerful markdown document manipulation capabilities:
Document Structure
- Overview - Display hierarchical document structure with sections, line numbers, and nesting
- Validate - Check section numbering consistency and table of contents accuracy
- Renumber - Automatically fix section numbering sequentially
Table of Contents
- Generate/Update TOC - Create or refresh table of contents with configurable depth
- Remove TOC - Clean removal of table of contents section
Section Operations
- Move - Relocate sections (with children) to new positions
- Insert - Add new sections at specific locations
- Delete - Remove sections and their subsections
- Promote - Increase heading level (### → ##)
- Demote - Decrease heading level (## → ###)
Formatting
- Rewrap - Normalize paragraph line lengths with smart wrapping
- Lint - Detect markdown formatting issues
- Fix - Auto-fix common markdown problems
- Cleanup - Comprehensive cleanup (rewrap + fix + renumber + update TOC)
Installation
The core library (markdown parsing, numbering, TOC, formatting) has no dependency on the OpenHands SDK:
pip install oh-markdown-tool # or: uv pip install oh-markdown-tool
To use it as an OpenHands agent tool, install the openhands extra. It pulls in
openhands-sdk, which requires Python 3.12+:
pip install "oh-markdown-tool[openhands]"
Usage as an OpenHands agent tool
The tool lives in oh_markdown_tool.tool; importing that module registers it under the
name markdown_document.
from openhands.sdk import Agent
from oh_markdown_tool.tool import MarkdownDocumentTool
# Create an agent with the markdown tool
agent = Agent(
tools=[MarkdownDocumentTool],
# ... other configuration
)
# The agent can now use commands like:
# - "Show me the overview of doc/design.md"
# - "Renumber the sections in README.md"
# - "Update the table of contents in design.md"
# - "Move section 4.3 to after section 2"
On a remote agent-server, reference the tool by its module qualname so the server imports and registers it on conversation creation:
"tools": [{"name": "markdown_document"}],
"tool_module_qualnames": {"markdown_document": "oh_markdown_tool.tool"},
Standalone usage (no agent)
MarkdownExecutor runs the operations directly. It lives in oh_markdown_tool.tool and
therefore needs the [openhands] extra (the action/observation types build on the SDK):
from pathlib import Path
from oh_markdown_tool.tool import MarkdownAction, MarkdownExecutor
# Initialize executor with workspace directory
executor = MarkdownExecutor(workspace_dir=Path("."))
# Get document overview
action = MarkdownAction(command="overview", file="design.md")
result = executor.execute(action)
print(result.content)
# Renumber sections
action = MarkdownAction(command="renumber", file="design.md")
result = executor.execute(action)
print(f"Renumbered {result.sections_renumbered} sections")
# Update table of contents
action = MarkdownAction(command="toc_update", file="design.md", depth=3)
result = executor.execute(action)
print(f"TOC updated with {result.toc_entries} entries")
For SDK-free, lower-level access, import the core classes directly (no [openhands]
extra needed):
from oh_markdown_tool import MarkdownParser, SectionNumberer, TocManager
Document Conventions
Section Numbering
- Document title uses
#(h1) and is unnumbered - Top-level sections use
##(h2):## 1. Introduction - Subsections are numbered hierarchically:
### 1.1 Purpose,#### 1.1.1 Detail
Table of Contents
- TOC section uses
## Table Of Contents(unnumbered, case-insensitive) - Appears after document title, before first numbered section
- Depth is configurable (default: 3 levels)
Section References
Sections can be referenced by:
- Number:
"3.2"(current numbering in document) - Title:
"Implementation Plan"(exact title match)
Available Commands
| Command | Description | Parameters |
|---|---|---|
overview |
Show document structure | file |
validate |
Check structure consistency | file |
renumber |
Fix section numbering | file |
toc_update |
Generate/update TOC | file, depth (default: 3) |
toc_remove |
Remove TOC | file |
move |
Move a section | file, section, position, target |
insert |
Insert new section | file, heading, level, position, target |
delete |
Delete section | file, section |
promote |
Increase heading level | file, section |
demote |
Decrease heading level | file, section |
rewrap |
Rewrap paragraphs | file, width (default: 80) |
lint |
Check for issues | file |
fix |
Auto-fix issues | file |
cleanup |
Full cleanup | file, width, depth |
Architecture
The tool is composed of several specialized components:
oh_markdown_tool/
├── parser.py # Parse markdown into section tree
├── numbering.py # Validate and renumber sections
├── toc.py # Table of contents management
├── operations.py # Section operations (move, insert, delete, etc.)
├── formatter.py # Formatting, linting, and fixing
└── tool.py # OpenHands SDK tool integration
Development
Setup
# Clone the repository
git clone https://github.com/jpshackelford/oh-markdown-tool.git
cd oh-markdown-tool
# Install with dev dependencies
pip install -e ".[dev]"
# Or with uv
uv pip install -e ".[dev]"
Running Tests
pytest
With coverage:
pytest --cov=oh_markdown_tool --cov-report=html
Code Quality
# Format and lint
ruff check .
ruff format .
Dependencies
Core:
openhands-sdk>=1.19.0- OpenHands SDK integrationpydantic>=2.0.0- Data validationmdformat>=0.7- Paragraph rewrappingpymarkdownlnt>=0.9- Linting and auto-fixingrich>=13.0.0- Terminal formatting
License
MIT License - see LICENSE file for details
Credits
Originally developed as part of the lxa project.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Commit Messages
This project uses Conventional Commits and Release Please for automated releases. Please use the following commit message format:
feat: add new feature # New features (minor version bump)
fix: correct bug # Bug fixes (patch version bump)
docs: update documentation # Documentation changes
refactor: improve code # Code refactoring
test: add tests # Test changes
chore: update dependencies # Maintenance tasks
Breaking changes should include ! or BREAKING CHANGE: in the footer:
feat!: redesign API
See PUBLISHING.md for details on the release process.
Automated Code Review
This repository uses OpenHands for automated PR reviews. When you open a PR:
- ✅ Automated review with direct, honest feedback 🔥
- ✅ Code quality critique
- ✅ Best practices enforcement
Reviews are roasted style - expect critical, no-nonsense feedback. See .github/OPENHANDS_REVIEW.md for details.
Development Guidelines
Please see CONTRIBUTING.md for detailed contribution guidelines.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file oh_markdown_tool-0.2.1.tar.gz.
File metadata
- Download URL: oh_markdown_tool-0.2.1.tar.gz
- Upload date:
- Size: 65.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
025311dff64c4fffcb0413e60fe35f7d618a1e5669245a83dce2d2da7c844903
|
|
| MD5 |
23c0de9ef79ee5d57b611684777c1bcf
|
|
| BLAKE2b-256 |
474ea8492a45af7b11b29497ce44fe7e20672e374d01a522d1b05400414e6857
|
Provenance
The following attestation bundles were made for oh_markdown_tool-0.2.1.tar.gz:
Publisher:
release.yml on jpshackelford/oh-markdown-tool
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
oh_markdown_tool-0.2.1.tar.gz -
Subject digest:
025311dff64c4fffcb0413e60fe35f7d618a1e5669245a83dce2d2da7c844903 - Sigstore transparency entry: 2084277367
- Sigstore integration time:
-
Permalink:
jpshackelford/oh-markdown-tool@1c9fdc3ea4e913d0f343cd734c49fc5f60920991 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/jpshackelford
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1c9fdc3ea4e913d0f343cd734c49fc5f60920991 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file oh_markdown_tool-0.2.1-py3-none-any.whl.
File metadata
- Download URL: oh_markdown_tool-0.2.1-py3-none-any.whl
- Upload date:
- Size: 26.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bac22a32815532467844748b79cbbae9f70d258ad4f00e44de775256a3bfef8d
|
|
| MD5 |
d6cbdc87658c8f8e95e9e85f5a06ab0a
|
|
| BLAKE2b-256 |
fa93fcaa997bbebefab531d1f4b293d39ecd646eae4d71ccb84d9a3c8c732f51
|
Provenance
The following attestation bundles were made for oh_markdown_tool-0.2.1-py3-none-any.whl:
Publisher:
release.yml on jpshackelford/oh-markdown-tool
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
oh_markdown_tool-0.2.1-py3-none-any.whl -
Subject digest:
bac22a32815532467844748b79cbbae9f70d258ad4f00e44de775256a3bfef8d - Sigstore transparency entry: 2084277373
- Sigstore integration time:
-
Permalink:
jpshackelford/oh-markdown-tool@1c9fdc3ea4e913d0f343cd734c49fc5f60920991 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/jpshackelford
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1c9fdc3ea4e913d0f343cd734c49fc5f60920991 -
Trigger Event:
workflow_dispatch
-
Statement type: