The open-source Python framework for building AI agents specialized in industrial maintenance.
Project description
Machina
Build AI agents for industrial maintenance in a few lines of Python.
Quick Start • Examples • Why Machina • Docs • Contributing
Quick Start
pip install machina-ai[litellm,docs-rag]
git clone https://github.com/LGDiMaggio/machina.git
cd machina/examples/quickstart
python agent.py
LLM provider required. Choose one:
Provider Setup Ollama (local, free) Install from ollama.com, then ollama pull llama3OpenAI export OPENAI_API_KEY=sk-...Anthropic export ANTHROPIC_API_KEY=sk-ant-...Override the default with
python agent.py --llm openai:gpt-4oor--llm anthropic:claude-sonnet-4-20250514.
The agent is built in 13 lines:
from pathlib import Path
from machina import Agent, Plant
from machina.connectors.cmms import GenericCmmsConnector
from machina.connectors.docs import DocumentStoreConnector
from machina.connectors.comms.telegram import CliChannel
SAMPLE_DIR = Path(__file__).resolve().parent.parent / "sample_data"
agent = Agent(
name="Maintenance Assistant",
plant=Plant(name="Demo Plant"),
connectors=[
GenericCmmsConnector(data_dir=SAMPLE_DIR / "cmms"),
DocumentStoreConnector(paths=[SAMPLE_DIR / "manuals"]),
],
channels=[CliChannel()],
llm="ollama:llama3", # or "openai:gpt-4o", "anthropic:claude-sonnet"
)
agent.run()
Sample data included: 6 assets, 5 work orders, 6 spare parts, 10 failure modes, 2 equipment manuals. Your technicians can now talk to their plant data:
You: What is the bearing replacement procedure for pump P-201?
Agent: Based on the Grundfos CR 32-2 maintenance manual for P-201:
1. Lock out/tag out and isolate power supply
2. Drain the pump casing, disconnect piping
3. Extract drive-end bearing (SKF 6310-2RS) using a bearing puller
4. Press-fit new bearing using induction heater (110 C)
5. Reassemble, torque cover bolts to 45 Nm
6. Verify vibration per ISO 10816-3 after commissioning
Recommended spare: SKF 6310-2RS (in stock: 4 units)
You: Are there open work orders on that pump?
Agent: Yes, one corrective work order for P-201:
WO-2026-0087 | Priority: HIGH | Bearing replacement
Status: Scheduled | Assigned to: Maintenance Team A
You: Create a predictive work order for bearing replacement, priority HIGH
Agent: Work order created:
WO-2026-0412 | Type: PREDICTIVE | Priority: HIGH
Asset: P-201 (Cooling Water Pump)
Description: Replace drive-end bearing based on elevated vibration.
Spare parts: SKF 6310-2RS reserved (1 of 4 in stock)
The agent resolves "pump P-201" to the actual asset, retrieves context from your CMMS, searches manuals via RAG, and takes action -- grounded in real data, not hallucinated.
Try it now: cd examples/quickstart && python agent.py -- full quickstart guide
Now Make It Automate
Add one line to register a workflow. The agent handles alarms end-to-end:
from machina.workflows.builtins import alarm_to_workorder
agent = Agent(
connectors=[cmms, docs],
workflows=[alarm_to_workorder], # alarm → diagnosis → WO → notify
sandbox=True,
)
Alarm: P-201 | vibration_velocity = 7.8 mm/s (threshold: 6.0)
[+] analyze_alarm — Bearing wear (BEAR-WEAR-01), confidence: HIGH
[+] check_spare_parts — SKF 6310-2RS in stock (4 units)
[+] create_work_order — [LLM] Priority HIGH, est. 4 hours
[+] notify_technician — [SANDBOX] Message logged
Result: SUCCESS (2.34s)
6 steps, only 2 use the LLM. The rest are deterministic -- fast, predictable, testable. Try it: cd examples/alarm_to_workorder && python agent.py -- full guide
Or configure via YAML
For knowledge-base agents (Q&A over CMMS data, manuals, spare parts), you can skip Python entirely and configure via YAML:
name: "Maintenance Assistant"
plant:
name: "North Plant"
connectors:
cmms:
type: generic_cmms
settings:
data_dir: "./sample_data/cmms"
docs:
type: document_store
settings:
paths: ["./sample_data/manuals"]
channels:
- type: cli
llm:
provider: "ollama:llama3"
from machina import Agent
agent = Agent.from_config("machina.yaml")
agent.run()
YAML config is ideal for knowledge-base agents — technician Q&A, document search, asset lookup. For agents with automated workflows (alarm response, predictive pipelines), use Python — workflows need logic (guards, error policies, LLM reasoning steps) that YAML can't express. See the YAML config guide for details.
What You Can Build
Two examples take you from zero to automation. Then deploy with the starter kit.
| Step | Example | What happens |
|---|---|---|
| 1. Understand | quickstart/ | Agent answers questions about equipment, procedures, spare parts, maintenance history |
| 2. Automate | alarm_to_workorder/ | Alarm fires -- agent diagnoses failure, checks parts, creates work order, notifies team |
| 3. Deploy | odl-generator-from-text/ | Italian free-text messages become Work Orders. Docker, sandbox-first, production-ready |
All examples run with ollama:llama3 -- local, free, no API key needed. Override: --llm openai:gpt-4o
More patterns in examples/reference/: predictive pipelines, CMMS portability, custom workflows, YAML config, autonomous agents.
Starter Kit
Ready to deploy? The odl-generator-from-text template is a complete, clone-configure-deploy package:
cp -r templates/odl-generator-from-text my-agent
cd my-agent
cp .env.example .env # fill in your LLM key
docker compose up # sandbox mode by default
A technician sends an email or Telegram message in their language:
Italian:
"pompa P-201 perde acqua, caldaia C-3 rumore anomalo, prego creare OdL"English:"pump P-201 leaking water, boiler C-3 abnormal noise, please create WO"
The agent parses the text, resolves assets, creates Work Orders, and replies with confirmation. Supports Excel and REST CMMS substrates. Full template guide →
From Demo to Production
The quickstart uses sample data. When you're ready, swap connectors to your real systems -- the agent logic doesn't change:
# Demo (quickstart) # Production
GenericCmmsConnector(data_dir="./sample/") --> SapPM(url="https://sap.company.com/odata/v4", auth=...)
Maximo(url="https://maximo.company.com/oslc", auth=...)
DocumentStoreConnector(paths=["./manuals/"])--> DocumentStoreConnector(paths=["/shared/manuals/"])
CliChannel() --> Telegram(bot_token="...")
"ollama:llama3" --> "openai:gpt-4o"
Add sensors when you need predictive maintenance:
from machina.connectors import OpcUA, MQTT
agent = Agent(
connectors=[cmms, docs, OpcUA(endpoint="opc.tcp://plc:4840", ...)],
workflows=[alarm_to_workorder],
llm="openai:gpt-4o",
)
Same agent, same workflows. Just more data flowing in.
Why Machina?
Building an AI maintenance agent today means writing custom connectors for SAP PM, handling OPC-UA subscriptions, defining domain concepts from scratch, and engineering prompts that understand maintenance -- before writing a single line of business logic. That takes months.
Machina provides the missing vertical layer between general-purpose frameworks (LangChain, CrewAI) and the industrial maintenance world:
- Pre-built connectors for CMMS, IoT sensors, communication platforms, and document stores
- Canonical maintenance domain model -- Asset, WorkOrder, FailureMode, SparePart, Alarm with hierarchies and validation
- Domain-aware AI -- agents that resolve equipment references, inject maintenance context, and ground answers in real data
- Rule-based + LLM intelligence -- deterministic services (
FailureAnalyzer,WorkOrderFactory,MaintenanceScheduler) work alongside the LLM, not instead of it - Workflow engine -- composable multi-step workflows with error policies, guard conditions, and sandbox mode
- LLM-agnostic -- OpenAI, Anthropic, Mistral, Llama, Ollama, and any LiteLLM-compatible provider
- Sandbox mode -- test everything safely with a log-only runtime before connecting real systems
How It Works Under the Hood
When a user asks "What's wrong with pump P-201?", the agent:
- Resolves entities -- "the pump" or "P-201" maps to the actual Asset with its domain metadata, failure history, and criticality
- Gathers context -- parallel async queries to all connectors: work orders from CMMS, readings from sensors, procedures from manuals (RAG)
- Grounds the LLM -- the retrieved context (real asset data, real inventory, real history) is injected into the prompt, so the LLM reasons with facts, not hallucinations
- Takes action -- workflows mix deterministic steps (rule-based diagnosis, spare part checks) with LLM reasoning (root cause synthesis, work order drafting)
Connector Matrix
CMMS
| Connector | System | |
|---|---|---|
GenericCmms |
Any REST-based CMMS (configurable via schema mapping) | Available |
SapPM |
SAP Plant Maintenance (OData v2/v4, OAuth2 + Basic Auth) | Available |
Maximo |
IBM Maximo (OSLC/JSON, API key + Basic + Bearer) | Available |
UpKeep |
UpKeep CMMS (REST API v2, Session-Token) | Available |
MaintainX |
MaintainX | Planned |
Limble |
Limble CMMS | Planned |
Fiix |
Fiix (Rockwell) | Planned |
IoT & Industrial Protocols
| Connector | Protocol | |
|---|---|---|
OpcUA |
OPC-UA | Available |
MQTT |
MQTT / Sparkplug B | Available |
Modbus |
Modbus TCP/RTU | Planned |
Communication & Scheduling
| Connector | Platform | |
|---|---|---|
Telegram |
Telegram Bot API | Available |
Slack |
Slack Bolt SDK (Socket Mode) | Available |
Email |
SMTP / IMAP (+ Gmail API) | Available |
Calendar |
Google Calendar / Outlook / iCal | Available |
WhatsApp |
WhatsApp Business Cloud API | Planned |
Teams |
Microsoft Graph API | Planned |
Documents & Knowledge
| Connector | Source | |
|---|---|---|
DocumentStore |
PDF / DOCX with RAG (LangChain + ChromaDB) | Available |
Architecture
+---------------------------+
| Claude / Cursor / MCP |
+-------------+-------------+
| MCP Protocol
+------------------------------------------------------+
| YOUR APPLICATION |
| +---------------------+ +------------------------+ |
| | AGENT LAYER | | MCP SERVER LAYER | |
| | Runtime + Workflows | | (auto-generated from | |
| | Domain Prompting | | connector caps) | |
| +----------+-----------+ +-----------+------------+ |
+-----------+----------------------------+--------------+
| DOMAIN LAYER |
| Asset . WorkOrder . FailureMode . SparePart . Alarm |
+-------------------------------------------------------+
| CONNECTOR LAYER |
| CMMS . IoT . ERP . Communication . Documents |
+-------------------------------------------------------+
| CORE LAYER |
| LLM Abstraction . Config . Observability |
+-------------------------------------------------------+
Domain Model
The domain model is the backbone of Machina. Every connector normalizes external data into domain entities, the agent reasons in domain terms, and LLM prompts are grounded in domain context.
Why this matters:
- Portability -- Switch CMMS backends, your agent logic doesn't change
- Deterministic logic where it counts -- FailureAnalyzer, WorkOrderFactory, MaintenanceScheduler encode expertise as code, not LLM guesses
- LLM grounding -- the LLM works with real, validated data (failure codes, maintenance history, inventory levels), not hallucinated IDs
- Industry-aligned taxonomy -- failure modes and equipment classes follow established industrial standards
from machina.domain import Asset, AssetType, FailureMode
pump = Asset(
id="P-201",
name="Cooling Water Pump",
type=AssetType.ROTATING_EQUIPMENT,
criticality="A",
equipment_class_code="PU", # ISO 14224 Table A.4
)
bearing_wear = FailureMode(
code="BEAR-WEAR-01",
iso_14224_code="VIB", # ISO 14224 Annex B Table B.15
name="Bearing Wear",
mechanism="fatigue",
typical_indicators=["vibration_velocity_mm_s", "bearing_temperature_c"],
recommended_actions=["replace_bearing", "check_alignment"],
)
The full domain includes: Asset (hierarchical trees), WorkOrder (lifecycle management), FailureMode (ISO 14224 taxonomy), SparePart (inventory tracking), Alarm (severity-based), MaintenancePlan (scheduling), plus three domain services that provide rule-based intelligence alongside the LLM.
Workflow Engine
Build multi-step maintenance workflows that mix deterministic steps with LLM reasoning:
from machina.workflows import Workflow, Step, Trigger, TriggerType, ErrorPolicy
alarm_to_workorder = Workflow(
name="Alarm to Work Order",
trigger=Trigger(type=TriggerType.ALARM, filter={"severity": ["critical"]}),
steps=[
Step("diagnose", action="failure_analyzer.diagnose",
on_error=ErrorPolicy.STOP),
Step("check_history", action="cmms.read_maintenance_history",
inputs={"asset_id": "{trigger.asset_id}"},
on_error=ErrorPolicy.SKIP),
Step("create_wo", action="work_order_factory.create",
on_error=ErrorPolicy.STOP),
Step("notify", action="channels.send_message",
template="WO created for {trigger.asset_id}: {diagnose}",
on_error=ErrorPolicy.NOTIFY),
],
)
agent = Agent(workflows=[alarm_to_workorder], sandbox=True)
result = await agent.trigger_workflow("Alarm to Work Order", {"asset_id": "P-201"})
Or use the built-in template: from machina.workflows.builtins import alarm_to_workorder
Features: trigger types (alarm, schedule, manual, condition), error policies (retry/skip/stop/notify), guard conditions, template variables ({trigger.*}, {step_name}), sandbox mode, and full observability via ActionTracer.
MCP Server (v0.3)
Expose connectors as MCP servers -- let Claude Desktop, Cursor, or any MCP client query your CMMS and sensors directly:
machina mcp serve --config machina.yaml
Ask Claude: "What's the maintenance history for pump P-201?" -- and it queries your SAP PM through Machina's MCP server. No agent code required.
Roadmap
v0.1 -- Core domain model, CMMS connectors (SAP PM, Maximo, UpKeep), DocumentStore with RAG, Telegram, Agent runtime, CI/CD
v0.2 -- Workflow engine, IoT connectors (OPC-UA, MQTT), Slack, Email, Calendar, sandbox mode, security hardening
v0.3 (in progress) -- MCP Server layer, MaintainX/Limble/Fiix connectors, plugin system, anomaly detection, multi-agent orchestration, RUL estimation, WhatsApp, Teams
Contributing
We welcome contributions! See CONTRIBUTING.md for the full guide.
git clone https://github.com/LGDiMaggio/machina.git
cd machina
pip install -e ".[dev,all]"
make ci # lint + typecheck + test
Community & Support
- GitHub Discussions -- Ask questions, share ideas, show what you've built
- Issues -- Report bugs and request features
License
Apache License 2.0. See LICENSE.
Acknowledgments
LiteLLM | LangChain | asyncua | ChromaDB | structlog | MCP SDK
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
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 machina_ai-0.3.0.tar.gz.
File metadata
- Download URL: machina_ai-0.3.0.tar.gz
- Upload date:
- Size: 381.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8173cb4109b979d8ae4cbefea7bf491f66b2f2a77216a191c1f6efcd74bc57d4
|
|
| MD5 |
3bfafc731f2a084d5373887639804de9
|
|
| BLAKE2b-256 |
e96f63e2733b986e7e2bd7fbe4b2721277a0acb5b5938dd5c5472b38676ea0ca
|
File details
Details for the file machina_ai-0.3.0-py3-none-any.whl.
File metadata
- Download URL: machina_ai-0.3.0-py3-none-any.whl
- Upload date:
- Size: 193.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
876533dfea74913c7ede20dc1811599870a49aeb71cdd22ee1283b6a0cd73b95
|
|
| MD5 |
4b2b7ca17dd46803d6ca06bce449c7a3
|
|
| BLAKE2b-256 |
5edbd6438cbe57a19e397a5357372af7c5cc3007bf1cb446d84070183546afb9
|