Skip to main content

POU to Markdown Converter

CI Python Versions License: MIT

A modular Python tool that converts Beckhoff TwinCAT 3 .TcPOU files into Mermaid diagrams embedded in Markdown (.md) documents.

Features

  • Class Diagrams (classDiagram): Automatically extracts IEC 61131-3 declarations (PROGRAM, FUNCTION_BLOCK, FUNCTION) with variable sections (VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, VAR), types, and initial values.
  • Continuous Function Chart (CFC): Reconstructs the signal flow graph (flowchart LR) from <CFC> XML structures, resolving pins, operators, function blocks, program calls, and wiring.
  • Function Block Diagram (FBD): Recursively parses <NWL> trees, resolving nested calls, pass-through assignments, and negated inputs.
  • Ladder Diagram (LD): Automatically detects LD view mode, formatting contacts (┤├), coils (( )), and jump labels (▶ Label).
  • Structured Text (ST): Embeds the original IEC 61131-3 source code in an iecst code block alongside the declaration class diagram.
  • Minimal Runtime Dependencies: Uses only the Python standard library on Python 3.11+; Python 3.10 installs tomli for TOML configuration support.

Architecture

pou2md/
├── __init__.py
├── __main__.py          # CLI entry point
├── converter.py         # Main conversion orchestrator
├── model/
│   ├── declaration.py   # PouDeclaration, VarGroup, Variable dataclasses
│   └── flow_graph.py    # FlowNode, FlowEdge, NetworkDiagram, FlowGraph dataclasses
├── parser/
│   ├── declaration.py   # IEC 61131-3 CDATA declaration parser
│   ├── nwl_parser.py    # Network List parser (FBD & LD)
│   ├── cfc_parser.py    # Continuous Function Chart parser
│   └── st_parser.py     # Structured Text parser
├── renderer/
│   ├── class_diagram.py # Mermaid classDiagram generator
│   └── flowchart.py     # Mermaid flowchart LR generator
└── writer/
    └── markdown.py      # Markdown document generator

Installation & CLI Setup

Install the package using pip (editable mode is recommended during development):

# Editable install (recommended)
pip install -e .

# Or standard install
pip install .

Once installed, the CLI tool can be executed from any terminal or directory using pou2md (or via Python's -m switch):

# Global CLI command
pou2md [input] [options]

# Standard Python module syntax
python -m pou2md [input] [options]

CLI Reference

Command Syntax

pou2md [input] [-o OUTPUT] [-r] [-u] [--single-folder] [--copy-folder-structure] [--exclude PATTERN] [--dry-run] [--clean] [--stdout] [-w] [--curve {step,stepAfter,linear,basis,none}] [--no-bifurcate] [--repeat-inputs]

Options & Arguments

Argument / Flag Value Type / Choices Default Description
input (positional) Path (file or folder) . (Current dir) Path to a single .TcPOU file or a directory containing .TcPOU files.
-o, --output Path (folder or .md file) None Destination directory (e.g. docs/) or specific file path (e.g. docs/system.md). Required for directory input unless --stdout is set.
-r, --recursive Flag False Recursively scan subdirectories for .TcPOU files.
-u, --unified Flag False Merges all converted POUs into a single Markdown document separated by horizontal dividers (---).
--single-folder Flag Automatic Also generate individual Markdown files. This is enabled by default unless --unified is used alone.
--copy-folder-structure Flag False Generate individual Markdown files under matching source subdirectories instead of flattened names. Also enables individual output.
--exclude PATTERN Pattern None Exclude matching filenames or relative paths; repeat the option for multiple patterns.
--stdout Flag False Prints generated Markdown directly to stdout instead of writing to disk.
--curve step | stepAfter | linear | basis | none step Mermaid flowchart wire routing style. step generates orthogonal right-angle wires entering blocks horizontally (>).
--no-bifurcate Flag (Bifurcation enabled) Disables bifurcation junction nodes ((( ))), drawing independent wires from the source pin to each destination pin.
--repeat-inputs Flag False In CFC diagrams, duplicates input variable blocks next to each connected pin to eliminate long cross-sheet wires.
-w, --watch Flag False Continuously watches the input file or directory and regenerates Markdown after changes. Press Ctrl+C to stop.
--poll-interval Seconds 1.0 Watcher polling interval.
--debounce-delay Seconds 0.25 Delay after a detected change before conversion.
--retry-count Integer 3 Conversion attempts for transient save or network errors.
--retry-delay Seconds 0.5 Delay between conversion attempts.
-v, --verbose Flag False Enable diagnostic logging.
--quiet Flag False Suppress normal status messages while preserving errors.
--log-format text | json text Select human-readable or machine-readable logs.
--dry-run Flag False Show planned outputs without writing Markdown or a manifest.
--clean Flag False Remove stale outputs previously recorded in the output manifest. Requires -o.
--config FILE TOML file None Load default arguments from a project configuration file. Command-line values override config values.
--version Flag - Print the installed package version.
-h, --help Flag - Display CLI help message and exit.

Output Resolution Rules

The destination path depends on the input type and flags provided:

Input Type Flags Destination Behavior
Single .TcPOU file No -o or --stdout Prints generated Markdown directly to stdout.
Single .TcPOU file -o path/to/dir/ Creates path/to/dir/<POU_NAME>.md.
Single .TcPOU file -o path/to/custom.md Writes directly to path/to/custom.md.
Directory -o path/to/dir/ Generates individual <POU_NAME>.md files inside path/to/dir/.
Directory -r -o path/to/dir/ Recursively scans subfolders; outputs flattened names: parent--subfolder--<POU_NAME>.md.
Directory -u -o path/to/dir/ Combines all POUs into path/to/dir/unified.md.
Directory -u -o path/to/custom.md Combines all POUs into the exact specified file path/to/custom.md.
Directory -u --single-folder -o path/to/dir/ Writes both individual files and unified.md.
Directory -r --copy-folder-structure -o path/to/dir/ Writes individual files under matching subdirectories.
Directory -u --copy-folder-structure -o path/to/dir/ Writes both nested individual files and unified.md.
Any Input --stdout Emits Markdown to terminal stdout without creating any files on disk.

When both individual and unified output are requested with -o path/to/file.md, the unified document uses that exact path and individual files are written to its parent directory.

Continuous Watching (-w)

Use -w to perform an initial conversion and then keep the process running while watching for added, modified, or removed .TcPOU files. The watcher polls the input path, debounces editor save operations, and releases its lock file when stopped with Ctrl+C.

# Watch a directory and update individual generated files
pou2md MyPlcProject/ -r -w -o docs/generated/

# Watch a directory and rebuild one unified document
pou2md MyPlcProject/ -r -u -w -o docs/complete_system_manual.md

# Watch one file and print each generated document to stdout
pou2md POUs/FB_Motor.TcPOU -w

For directory input, specify -o/--output or --stdout, just as with a one-time conversion. When a source file is removed, its generated individual Markdown file is removed as well; unified output files are rebuilt instead.

Output mode combinations are:

Flags Output
(none) Individual files in one output folder
--unified Unified file only
--single-folder Individual files in one output folder
--unified --single-folder Both individual files and unified file
--copy-folder-structure Individual files in matching subfolders
--unified --copy-folder-structure Both nested individual files and unified file

The default polling interval is one second, followed by a 250 ms save debounce. This is normally suitable for mapped drives and SMB shares, but network latency can make detection slower and a temporarily unavailable share is skipped until the next poll. The watcher uses an atomic lock-file claim, so two processes started for the same target cannot both watch it; the second process exits with an error. Different output targets intentionally use separate locks.

Parsing errors are reported to stderr and do not terminate the watcher. This allows editors to save an incomplete XML document temporarily: the watcher waits and retries that file after the next change. The same behavior applies to an incomplete file present when the watcher starts.

Generated Markdown is written through a temporary sibling file and atomically replaced into place, preventing readers from seeing partially written output. Use --exclude to ignore backup or generated sources, for example:

pou2md MyPlcProject/ -r -w -o docs/ --exclude "Backup/*" --exclude "*_old.TcPOU"

Use --verbose for diagnostic status logging or --quiet to suppress normal status messages while retaining errors. Watcher timing can be tuned with --poll-interval, --debounce-delay, --retry-count, and --retry-delay.

Dry runs, cleanup, and manifests

Use --dry-run to inspect the output plan without creating files:

pou2md MyPlcProject/ -r --copy-folder-structure --dry-run -o docs/

When writing to an output directory, the converter maintains .pou2md-manifest.json containing the generated Markdown paths. --clean removes only stale paths recorded in that manifest; it never scans for or deletes untracked files:

pou2md MyPlcProject/ -r --clean -o docs/

Use JSON logs for automation:

pou2md MyPlcProject/ -r -w -o docs/ --log-format json

Project configuration

Arguments can be saved in a committed pou2md.toml file:

input = "POUs"
output = "docs"
recursive = true
unified = true
copy_folder_structure = true
exclude = ["Backup/*"]

Run it with:

pou2md --config pou2md.toml

Built-in defaults are overridden by the TOML file, and explicit command-line arguments override the TOML values.

Use pou2md --version when reporting issues so the exact installed converter version is known. Invalid XML errors include the source filename and XML location, while the watcher preserves the last valid output.


Practical CLI Recipes

1. Quick Inspection & Terminal Piping

Inspect generated Markdown or pipe directly into tools like bat, glow, or clipboard utilities:

# Print POU markdown directly to stdout
pou2md POUs/FB_Motor.TcPOU --stdout

# Pipe output to a markdown viewer (bat, glow, etc.)
pou2md POUs/FB_Motor.TcPOU --stdout | bat -l md

# Copy markdown directly to clipboard (Windows PowerShell)
pou2md POUs/FB_Motor.TcPOU --stdout | Set-Clipboard

2. Single File Conversion

Convert an individual POU into a specific output directory or custom filename:

# Save to an output directory (produces output/FB_Motor.md)
pou2md POUs/FB_Motor.TcPOU -o output/

# Save to a specific custom filename
pou2md POUs/FB_Motor.TcPOU -o docs/motor_controller.md

3. Batch Directory Conversion

Convert all .TcPOU files located directly inside a folder:

pou2md POUs/ -o docs/pous/

4. Recursive Project Conversion (-r)

Recursively scan complete TwinCAT PLC project structures. The converter flattens nested folder hierarchies into distinct, clash-free filenames:

pou2md MyPlcProject/ -r -o docs/generated/

Example name mapping:

  • MyPlcProject/Motion/Axes/FB_Axis.TcPOU → docs/generated/Motion--Axes--FB_Axis.md
  • MyPlcProject/Diagnostics/FB_Logger.TcPOU → docs/generated/Diagnostics--FB_Logger.md

5. Unified Single-Document Generation (-u)

Merge your entire PLC library or project into a single Markdown document. Perfect for single-page project wikis, Obsidian vaults, or MkDocs:

# Save as default unified.md in target directory
pou2md MyPlcProject/ -r -u -o docs/

# Save with a custom documentation filename
pou2md MyPlcProject/ -r -u -o docs/complete_system_manual.md

# Stream the entire unified manual to stdout for downstream processing
pou2md MyPlcProject/ -r -u --stdout > complete_system_manual.md

Diagram Layout & Styling Customization

pou2md provides dedicated flags to fine-tune the look and layout of Mermaid flowcharts to match industrial PLC schematics:

Wire Routing (--curve)

Select how signal connection lines are interpolated:

# Default: Orthogonal right angles entering nodes horizontally (industrial CAD style)
pou2md POUs/FB_Controller.TcPOU -o docs/ --curve step

# Smooth cubic splines (fluid curves)
pou2md POUs/FB_Controller.TcPOU -o docs/ --curve basis

# Direct point-to-point straight lines
pou2md POUs/FB_Controller.TcPOU -o docs/ --curve linear

# Standard Mermaid default curve interpolation
pou2md POUs/FB_Controller.TcPOU -o docs/ --curve none

Output Bifurcation Junctions (--no-bifurcate)

When an output pin connects to multiple downstream blocks:

  • Default (Bifurcation enabled): Splits wires using a clean junction dot ((( ))), preventing duplicate pin labels and visual clutter.
  • --no-bifurcate: Draws separate, independent wires directly from the output pin to every target node.
# Disable bifurcation junctions
pou2md POUs/FB_Controller.TcPOU -o docs/ --no-bifurcate

CFC Input Variable Duplication (--repeat-inputs)

In large Continuous Function Charts (CFC), multiple blocks often share common inputs (e.g. bEnable or stConfig):

  • Default (False): Creates a single node for each input variable and connects it across the diagram.
  • --repeat-inputs: Creates an input variable block next to each block pin it feeds, eliminating long feedback loops and wires crossing through the middle of the sheet.
pou2md POUs/CFC_PlantControl.TcPOU -o docs/ --repeat-inputs

CI / CD & Automation Integration

GitHub Actions Workflow Example

Automatically generate up-to-date Markdown diagrams whenever PLC files are pushed:

name: Generate PLC Documentation
on: [push, pull_request]

jobs:
  docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - name: Install converter
        run: pip install .
      - name: Build documentation
        run: pou2md src/ -r -u -o docs/plc_architecture.md
      - name: Upload documentation artifact
        uses: actions/upload-artifact@v4
        with:
          name: plc-docs
          path: docs/plc_architecture.md

Shell Automation Scripts

PowerShell (Windows):

# Convert all POU subdirectories into separate documentation folders
Get-ChildItem -Directory "src/PLC/*" | ForEach-Object {
    pou2md $_.FullName -r -o "docs/$($_.Name)"
}

Bash (Linux / macOS):

# Compile documentation for each PLC subsystem
for dir in src/PLC/*/; do
  name=$(basename "$dir")
  pou2md "$dir" -r -u -o "docs/${name}.md"
done

Exit Codes

For CI/CD scripts and automated tools, the CLI returns standard status codes:

  • 0: Execution completed successfully.
  • 1: Error encountered (e.g. input path does not exist, or directory input without -o / --stdout).

Running Tests

Run the test suite using Python's standard unittest module:

python -m unittest tests/test_converter.py -v

Disclaimer & AI Disclosure

License

This project is licensed under the MIT License.

Metadata

Release files for pou2md 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pou2md 0.1.0
File Size Uploaded Provenance Actions
pou2md-0.1.0.tar.gz 41.4 kB With provenance Details for pou2md-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pou2md 0.1.0
File Interpreter ABI Platform Actions
pou2md-0.1.0-py3-none-any.whl Python 3 none any Details for pou2md-0.1.0-py3-none-any.whl

Total release size: 77.5 kB

Release files / pou2md-0.1.0.tar.gz

Download URL pou2md-0.1.0.tar.gz
Size 41.4 kB
Tags Source
SHA-256 checksum
How to use checksums
e062ec93afb17c28251d3e35c0cd35f85defefb795010e998c97d0261b7d975d
BLAKE2b-256 checksum
How to use checksums
912a3ad2e486a4df4297a765ecf9dfb0cb5c6edba940fcfdbbea6ab8fac88186
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / pou2md-0.1.0-py3-none-any.whl

Download URL pou2md-0.1.0-py3-none-any.whl
Size 36.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e6bac086111d6063cd16323bae15bfb17c21467e6adc788cb071e622a1f417b5
BLAKE2b-256 checksum
How to use checksums
baf634feceeab2e68f3d4497b6757864856675a935920bd388f19792441cf765
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Security for pou2md 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pou2md-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page