Skip to main content

OpenHands Markdown Document Tool - Structural editing and formatting for markdown documents

Project description

OpenHands Markdown Document Tool

CI PyPI version Python versions License: MIT

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 integration
  • pydantic>=2.0.0 - Data validation
  • mdformat>=0.7 - Paragraph rewrapping
  • pymarkdownlnt>=0.9 - Linting and auto-fixing
  • rich>=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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

oh_markdown_tool-0.2.1.tar.gz (65.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

oh_markdown_tool-0.2.1-py3-none-any.whl (26.4 kB view details)

Uploaded Python 3

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

Hashes for oh_markdown_tool-0.2.1.tar.gz
Algorithm Hash digest
SHA256 025311dff64c4fffcb0413e60fe35f7d618a1e5669245a83dce2d2da7c844903
MD5 23c0de9ef79ee5d57b611684777c1bcf
BLAKE2b-256 474ea8492a45af7b11b29497ce44fe7e20672e374d01a522d1b05400414e6857

See more details on using hashes here.

Provenance

The following attestation bundles were made for oh_markdown_tool-0.2.1.tar.gz:

Publisher: release.yml on jpshackelford/oh-markdown-tool

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file oh_markdown_tool-0.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for oh_markdown_tool-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bac22a32815532467844748b79cbbae9f70d258ad4f00e44de775256a3bfef8d
MD5 d6cbdc87658c8f8e95e9e85f5a06ab0a
BLAKE2b-256 fa93fcaa997bbebefab531d1f4b293d39ecd646eae4d71ccb84d9a3c8c732f51

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page