AI-powered Allen-Bradley PLC ladder logic troubleshooter — deterministic L5X trace engine + AI explanation layer. Portfolio/demo project.
Find a file
Alan 4e98744097
Some checks are pending
CI / test (push) Waiting to run
ci: install uv via shell (astral-sh user not redirectable on Codeberg)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 20:13:50 -04:00
.github/workflows ci: install uv via shell (astral-sh user not redirectable on Codeberg) 2026-05-05 20:13:50 -04:00
docs docs: session notes + roadmap update for M5 completion 2026-04-17 22:56:51 -04:00
src/rung_reader m5: docs + bump to 0.5.0 2026-04-17 22:52:44 -04:00
tests m5: add opt-in Ollama integration test for explainer 2026-04-17 22:49:44 -04:00
.gitignore chore: ignore .worktrees directory 2026-04-16 15:08:13 -04:00
CHANGELOG.md m5: docs + bump to 0.5.0 2026-04-17 22:52:44 -04:00
CLAUDE.md docs(claude): link to global end-of-session handoff rule 2026-04-21 23:54:14 -04:00
LICENSE Initial commit: Rung Reader — AI-powered Allen-Bradley PLC ladder logic troubleshooter 2026-04-15 22:19:45 -04:00
pyproject.toml m5: docs + bump to 0.5.0 2026-04-17 22:52:44 -04:00
README.md docs: fix CI badge link target 2026-05-05 18:43:40 -04:00
uv.lock m5: docs + bump to 0.5.0 2026-04-17 22:52:44 -04:00

Rung Reader

CI

AI-powered Allen-Bradley PLC ladder logic troubleshooter. Deterministic L5X trace + LLM explanation + RAG SOP correlator + proactive anomaly detection.

Status: pre-release · v0.5.0 (M5 of 14 milestones complete) · 1140 tests green · demo target v0.13.0

What it does

When a PLC faults on a production line, an operator typically reads ladder logic in Studio 5000, traces back from a failed output through every condition until they find the false rung, then walks the floor checking sensors and wires. Rung Reader automates the trace: given an L5X export and live tag values, it produces the same root-cause analysis a senior maintenance tech would, narrates it in plain English, surfaces relevant SOPs from the plant document corpus, and (optionally) proactively flags anomalies before an operator notices.

The core trace is deterministic — pure-function rung walker on the L5X AST. The LLM only narrates what the walker found; it never reasons about ladder semantics from scratch. This is by design: during the M0 spike, llama3.1:8b claimed XIC means "not in contact" (it actually means "examine if closed"). LLMs hallucinate domain knowledge; the walker doesn't.

Non-negotiable constraints

  • Read-only PLC access. Never writes to the PLC. Approval interrupts gate the operator's physical action ("go replace the wire"), not PLC writes.
  • On-prem only. Local LLM (Ollama), local RAG (FAISS), local everything. No cloud dependency.
  • Graceful degradation. Works without LLM (raw trace). Works without PLC (stale-cached values with timestamps). Works without Redis (single-turn, no resume).
  • Mock everything in CI. No real hardware or Ollama required for pytest.

Architecture

L5X file ──► Parser ──► Walker ──┐
                                  ├──► LangGraph ──► Explanation
Live PLC ──► Tag Resolver ───────┘                   + SOP refs
                                  ▲
                  RAG ────────────┘  (FAISS + MiniLM-L6-v2)
                  Anomaly Detector ─► Proactive alerts (arq worker)
Layer Tech Module
L5X parsing lxml + pydantic parser/
Rung walker pure Python walker/
Live tag I/O pycomm3 (mock-swappable) tags/
Multi-agent orchestration LangGraph ai/
RAG LlamaIndex + FAISS + sentence-transformers rag/
API FastAPI (SSE) api/
Observability Langfuse (fail-silent) api/deps.py
Async worker (anomaly) arq + Redis (M10) anomaly/
UI Streamlit + streamlit-agraph streamlit/

Quickstart

Prerequisites: Python 3.12+ (3.14 tested), uv, a CIP-capable PLC or Studio 5000 Logix Emulate (M4+).

git clone <this-repo> && cd rung-reader
uv sync --dev

# All tests, no real hardware required
uv run pytest -m "not integration"

# Lint + type check
uv run ruff check src/ tests/
uv run mypy -p rung_reader

End-to-end demo (Streamlit UI) lands at M11. Single-trace CLI landed at M4; LLM explainer landed at M5.

CLI quick reference

# Deterministic trace — no LLM
uv run python -m rung_reader trace \
  --tag Motor_01_Running \
  --l5x tests/fixtures/handcrafted/simple_rung.L5X \
  --plc mock \
  --scenario tests/fixtures/mock_plc_scenarios/simple_rung.yaml

# Trace + LLM narration via on-prem Ollama (requires `ollama pull qwen2.5:3b`)
LLM_PROVIDER=ollama uv run python -m rung_reader explain \
  --tag Motor_01_Running \
  --l5x tests/fixtures/handcrafted/simple_rung.L5X \
  --plc mock \
  --scenario tests/fixtures/mock_plc_scenarios/simple_rung.yaml

# Quality mode (llama3.1:8b — gaming-box only, ~20s on 1050 Ti)
uv run python -m rung_reader explain ... --quality

# JSON output for downstream consumers (M7 FastAPI will return this same shape)
uv run python -m rung_reader explain ... --json

# Mock LLM for CI / local smoke (no Ollama required)
LLM_PROVIDER=mock uv run python -m rung_reader explain ...

Environment variables (M5):

Var Default Purpose
LLM_PROVIDER ollama mock | ollama — on-prem only, cloud branches are not accepted
OLLAMA_MODEL qwen2.5:3b Overridden to llama3.1:8b by --quality
OLLAMA_BASE_URL http://localhost:11434 Override for LAN-hosted Ollama
RUNG_READER_OLLAMA_HOST unset Enables the opt-in integration test suite

Exit codes: 0 success, 2 argparse usage, 3 tag not found, 4 driver / config failure, 5 LLM error (empty response, unreachable Ollama, timeout).

Project layout

rung-reader/
├── docs/
│   ├── design.md              # Approved design spec (213 lines)
│   ├── ROADMAP.md             # Live milestone status
│   ├── SESSION_NOTES.md       # Cross-session handoff log
│   └── spikes/                # Spike notes (pycomm3, ollama, sibling port map)
├── src/rung_reader/
│   ├── parser/                # M1, M2 — L5X → AST + AOI/alias/metadata resolution
│   ├── walker/                # M3 — deterministic rung trace
│   ├── tags/                  # M4 — live PLC reads, mock driver
│   ├── ai/                    # M5, M9 — LangGraph nodes
│   ├── api/                   # M7, M9 — FastAPI gateway
│   ├── rag/                   # M8 — FAISS retriever + teach-mode
│   └── (anomaly/)             # M10 — arq watcher (planned)
├── tests/
│   ├── fixtures/
│   │   ├── public/            # MIT-licensed L5X samples + Rockwell V35 schema
│   │   └── handcrafted/       # Edge-case fixtures (malformed/circular/missing)
│   └── eval/                  # M6 + M12 — ground-truth eval cases
└── streamlit/                 # M11 — UI app

Roadmap

14 milestones (M0M13), versioned v0.N.0 per milestone. v0.13.0 is the final demo. Live status: docs/ROADMAP.md. Canonical plan: /mnt/TempNVME/projects/docs/superpowers/plans/2026-04-16-rung-reader-roadmap.md.

Fixtures + Attribution

  • tests/fixtures/public/logix-libraries/ — Studio 5000 AOIs/UDTs from JeremyMedders/LogixLibraries (MIT)
  • tests/fixtures/public/l5x2c/ — single ladder example from alairjunior/l5x2c (MIT)
  • tests/fixtures/handcrafted/ — minimal edge-case fixtures (this project, GPL-3.0)

Each upstream LICENSE is preserved alongside its files.

License

GPL-3.0-or-later. The deterministic core (parser/walker/tags) is intentionally GPL so any production fork must publish parser-rule fixes back to the community.

Sibling project

Architecture patterns (LangGraph state, graph builder, FastAPI graph singleton, RAG ingest+retriever, MockChatModel) are ported from /mnt/TempNVME/projects/supply-chain-agents/. See docs/spikes/sibling-port-map.md for the verified port table.