Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]¶
Added¶
WorkflowContext.resolve_input_valuefor step-input resolution that preserves raw object types. The existingresolve()always returns astrviare.sub, which silently coerces complex outputs (dicts,WorkOrderinstances) to theirstrrepr. The new method returns the raw referenced value when the entire template is a single{key}placeholder, and falls back toresolve()for templates with surrounding text. This lets workflow steps pass complex objects between steps — e.g. theWorkOrderproduced bywork_order_factory.createnow flows intocmms.create_work_order(work_order=…)without coercion. Backward compatible: text-with-placeholder templates still produce strings.- Section-aware chunking + parent-document retrieval (
SectionAwareSplitter,ParentSection,MatchChunk). The splitter detects Markdown headings (fence-aware), numbered headings, and ALL-CAPS headings (the last two require blank-line context). Small match chunks feed embedding / BM25 / rerank; the LLM receives the full surrounding section so a multi-step procedure stays together. Oversized sections are windowed around the match using char offsets. - Layout-aware PDF/DOCX parsing via Docling (
LayoutAwareParser,ParsedDocument,Section,TableBlock) behind[docs-rag-parsing]extra. Tables are emitted as atomic chunks (DocumentChunk.is_table=True) that retrieval never splits mid-row. Per-file failures fall back toPyPDFLoader/Docx2txtLoader. Surfaces a[TABLE]tag informat_document_resultsso the LLM treats table results as structured rows. - Swappable embedder via
embedder=constructor param onDocumentStoreConnector(e.g."BAAI/bge-m3"for multilingual technical content). Falls back to Chroma's default on any failure. [docs-rag-pro]aggregator extra pullingdocs-rag + docs-rag-hybrid + docs-rag-rerank + docs-rag-parsing. Now referenced by[all].- Connector documentation at
docs/connectors/document-store.mdcovering metadata schema, sidecar / frontmatter, extras, embedder configuration, citation contract, and failure-mode table. examplesextra inpyproject.toml, pulling inpython-dotenv. The example preflight now loadsexamples/.envautomatically so users can keep API keys in a local file instead of exporting shell variables every session. The import is wrapped intry/exceptso users onmachina-ai[litellm]without the new extra are unaffected.- Shared CLI helper
examples/_mode.pyexposingadd_mode_flags()andresolve_sandbox(). Every example agent and theodl-generator-from-texttemplate now accept mutually exclusive--sandboxand--liveflags.--helpadvertises which mode is the default (LIVE forquickstart, SANDBOX everywhere else). - CLI consistency tests (
tests/unit/test_examples_mode_helper.py,tests/unit/test_template_mode_parity.py,tests/e2e/test_examples_cli_consistency.py). The e2e test auto-discovers everyagent.pyunderexamples/andtemplates/, so new examples are covered without manual registration.
Changed¶
DocumentStoreConnector.search()result semantics:DocumentChunk.contentnow carries the full parent section (after dedup-by-parent), not the small match passage. The match passage is still what was embedded and ranked; only the surface returned to the caller (and the LLM) changed. Callers that previously assumedcontentwas a short passage may need to adjust slicing logic. The chunk metadata still carries the deterministicchunk_idfor citation purposes. NewDocumentChunkfields:parent_id,start_offset,is_table(appended to preserve positional construction).predictive_pipelinedefault mode flipped from LIVE to SANDBOX for safety. Pass--liveto execute writes.quickstartkeeps LIVE as the default (Q&A is read-mostly), but the CLI now accepts--liveand--sandboxsymmetrically and the help text annotates which is the default.- Documentation:
examples/quickstart/README.mdnow shows the.envworkflow alongsideexport/$env:/setsyntax for bash, PowerShell, and CMD. Install command updated topip install "machina-ai[litellm,docs-rag,examples]".
Fixed¶
- Document source paths no longer leak into LLM responses.
DocumentChunk.sourceflowed verbatim into both the context-gathering payload and thesearch_documentstool result, so absolute paths likeC:\Users\foo\bar\manual.mdreached the LLM and surfaced in citations. The redaction inActionTracerprotected logs but not the LLM-visible payload. Sanitisation now happens at both runtime boundaries via a small_safe_sourcehelper that strips directory components from path-like strings while passing through opaque IDs and URLs.format_document_resultsalso calls it as defence in depth. A new Guideline 8 in the system prompt forbids disclosure of absolute paths, directory structures, database schemas, or system architecture as backstop. The rawchunk.sourceis preserved for non-LLM consumers (logs, traces). Agent.sandboxmutations now propagate to theWorkflowEngine. The engine was constructed insideAgent.__init__with a snapshot of the sandbox flag; mutatingagent.sandboxafterward (the pattern every example uses when--liveis passed) left the engine's copy stuck on the construction-time value. The CLI banner readMode: LIVEbut workflow logs showedsandbox=Trueand every write went throughsandbox_service/sandbox_connectorinterception.Agent.sandboxis now a@propertywith a setter that writes through toself._engine.sandbox— single mutation point, no behaviour change for the three existingif self.sandboxread sites.alarm_to_workorderbuilt-in workflow steps now consume upstream outputs.generate_work_orderandsubmit_work_orderhad noinputs={...}declaration, so the engine dispatched them with empty kwargs — sandbox logs showedinputs={}and live runs would have failed on missing arguments. The two steps now declare explicitinputsmappingasset_id,failure_mode(fromanalyze_alarmoutput via the new raw-passthrough behaviour described above),description(templated with alarm and asset IDs), andwork_order(the factory output flowing into the CMMS connector).- Unified
Agent.channelswith the connector registry (#31). Channels passed viaAgent(channels=[...])are now registered into theConnectorRegistry, so workflow steps dispatched viachannels.send_message(e.g.alarm_to_workorder.notify_technician) correctly route through them. Previously onlyconnectors=[...]was discoverable by capability-based dispatch, and channel-only agent configurations silently returned{"sent": False, "error": "No communication connector available"}. Channels passed to bothconnectors=andchannels=as the same instance are deduplicated by identity. - Sandbox now gates channel lifecycle (#31). With
sandbox=True,Agent.start()andAgent.stop()skipchannel.connect()/channel.disconnect(), soEmailConnectorno longer performs real SMTP logins and other channels (Slack, Telegram) no longer open outbound sockets in sandbox mode. - Example CLI conventions unified. Previously three examples accepted only
--sandbox(default LIVE), two accepted only--live(default SANDBOX), and--liveon the quickstart raised an argparse error. Every example agent and the template now accept both flags consistently. Preflight error messages route to stderr.
[0.3.0] - 2026-04-20¶
Added¶
- MCP Server — expose Machina connectors via Model Context Protocol. Supports
stdio(IDE integration) andstreamable-http(multi-client deployment) transports. Tools are auto-registered from connector capabilities. Includes resources (asset details, work orders, failure taxonomy) and pre-built prompts (diagnosis, preventive planning, history summary). - MCP Authentication — static bearer token auth with per-token client identity tracking (
MACHINA_MCP_TOKENS_JSON). PluggableTokenVerifierprotocol for Vault/AKV integration. - Typed Capability enum —
Capabilityenum replaceslist[str]for connector capabilities. Dual-accept registry preserves backward compatibility through v0.3.x. - Excel/CSV Connector (
ExcelCsvConnector) — read/write maintenance data from.xlsxand.csvfiles with YAML schema mapping and file watcher support. - SQL Connector (
GenericSqlConnector) — read from PostgreSQL, SQL Server, SQLite, DB2 with YAML table-to-entity mapping. - GenericCmms YAML Mapper — zero-Python entity mapping for any REST CMMS. Declarative field specs with coercers (
enum_map,regex_extract,datetime), reverse mapping for writes, and pluggable coercer registry. - ActionTracer v2 —
conversation_idfield groups traces by conversation. LLM cost tracking (prompt_tokens,completion_tokens,usd_cost,model). JSONL export with automatic secret redaction and summary truncation. - Docker deployment — multi-stage Dockerfile, docker-compose with Machina + ChromaDB + mock CMMS,
.env.examplewith all configuration variables documented. - systemd deployment — production-ready
machina.serviceunit with security hardening (ProtectSystem=strict,NoNewPrivileges, dedicated user/group). - Starter-kit template (
templates/odl-generator-from-text/) — clone-configure-deploy package: Italian free-text message → asset resolution → Work Order creation. Dual substrate (Excel / REST CMMS). Email + Telegram channels. 20 PMI-Italia sample assets. Italian entity-resolver prompt with typo/abbreviation/synonym tolerance. - Deployment documentation — on-premise guide, Docker guide, uptime/resilience doc (16-combination behavior matrix), security doc (threat model for stdio/HTTP/DocumentStore/traces), scaling doc (why CPU autoscaling is wrong for LLM workloads), secrets management decision matrix.
- MCP documentation — setup, tools reference, resources, prompts, auth configuration.
- Observability documentation — action traces format, JSONL export, cost tracking and analysis.
- Connector documentation — Excel/CSV, SQL, GenericCmms YAML mapper guides.
- Migration guide — v0.2 → v0.3 checklist (5-minute upgrade path for custom connector authors).
Changed¶
- Connector
capabilitiesproperty type:list[str]→frozenset[Capability]. The old format is still accepted (dual-accept registry) but will be removed in v0.4. machina.mcp.MCPServerstub replaced by a real MCP server implementation (FastMCP-based).mkdocs.ymlnavigation expanded with MCP, Templates, Deployment, and Observability sections.- Top-level README updated with Starter Kit section.
Deprecated¶
list[str]capability format on connectors — migrate tofrozenset[Capability]before v0.4.MACHINA_MCP_TOKENS(comma-separated) — useMACHINA_MCP_TOKENS_JSONfor per-token client identity.
Removed¶
MCPServerNotImplementedErrorstub — replaced by real implementation.
Deferred to v0.3.1¶
- Kubernetes manifests, Helm charts, HPA configuration
- Conversation replay API (
ActionTracer.for_conversation()) - Alerting hooks (
ActionTracer.on_alert) - Templates: technician-chatbot, predictive-workflow
- MCP resource URI scheme promotion from pre-stable to stable
- OAuth 2.1 authorization server for MCP
- WhatsApp connector (pending Meta approval)
- MaintainX dedicated connector (GenericCmms YAML covers the use case)
[0.2.1] - 2026-04-15¶
A focused consolidation release between v0.2.0 and v0.3. No new features; the goal was an honest, stable base ahead of the MCP server layer work in v0.3. No public API removed.
Added¶
docs/roadmap.md— what ships in v0.2.1 and what's planned for v0.3 (MCP server,#31channels/registry unification, MaintainX/Limble/Fiix,AgentTeam, anomaly detection, plugin system, WhatsApp/Teams).docs/troubleshooting.md— short entries for the issues adopters hit most: LLM provider model strings, sandbox vs live mode, connector capability discovery, config-loader errors.- Loud stub for
machina.mcp.MCPServer— instantiation raisesNotImplementedErrorwith a pointer to the roadmap.import machina.mcpcontinues to work, reserving the import path across the v0.2 → v0.3 jump. EmailConnector— available as a communication connector for workflow notification. Seedocs/connectors/email.mdfor setup.- LiteLLM contract tests (
tests/unit/test_llm_provider.py::TestLiteLLMModelStringContract) — exercise the reallitellm.get_llm_providerparser, pinning theprovider:model → provider/modelnormalization introduced inb48f649and anchoring that the colon form keeps being rejected by LiteLLM. tests/validate_examples.pyconstruct check — now imports every runnableexamples/*/agent.pyso module-levelAgent(...)construction actually runs. Catches the "imports fine but blows up at first call" class of regression that produced the post-v0.2.0 reactive-fix cadence.- Per-module coverage floors in CI (agent 88%, config 95%, llm 95%, observability 85%, workflows 90%). Floors sit ~5% below the measured baseline; any silent regression in a core module now trips CI.
Changed¶
docs/mcp-server.mdwarning admonition — describes the new import-OK / instantiate-raises behaviour and links the newdocs/roadmap.md.- Test layout — contract tests live alongside fake-based tests in
tests/unit/test_llm_provider.py(one test file per source file, perCLAUDE.mdconvention).
Fixed¶
- No code fixes beyond the honesty cleanup above; v0.2.0 shipped stably and this release is scaffolding.
Deprecated¶
- None.
Removed¶
- None.
machina.mcpimport path is preserved; it was empty before and is a loud stub now, but still importable.
Notes¶
- A framework gap surfaced during consolidation: workflow notification steps resolve channels via the connector registry while
Agent(channels=[...])lives on a separate list, andsandbox=Truedoes not gatechannel.connect(). Tracked in #31 for v0.3.
[0.2.0] - 2026-04-11¶
Added¶
- Workflow Engine with trigger-step-action model, sequential execution,
template variable resolution (
{trigger.field},{step_name.field}), per-step error policies (RETRY, SKIP, STOP, NOTIFY), guard conditions, configurable timeouts, and action tracing - Sandbox mode for safe experimentation: write actions (create, update, delete, send) are logged but not executed; read-only actions still run normally. Sandbox enforced in both WorkflowEngine and Agent tool dispatch
alarm_to_workorderbuilt-in workflow — 7-step template from sensor alarm through diagnosis, spare part check, work order creation, technician notification, confirmation, and CMMS submissionSlackConnector— Slack integration via the Bolt SDK in Socket Mode (WebSocket-based, no public endpoint required). Supports channel whitelisting, bot-message filtering, and bidirectional messagingEmailConnector— Email integration with two backends:- Standard SMTP/IMAP (zero external dependencies, TLS/SSL support)
- Gmail API backend via OAuth2 (
pip install machina-ai[gmail]) - Polling-based inbox monitoring with persistent IMAP connections
CalendarConnectorwith three pluggable backends:- Google Calendar API v3 (OAuth2 + service account auth)
- Microsoft 365 / Outlook (MSAL client-credentials + Graph API)
- iCal
.icsfiles and URLs (read-only, with RRULE expansion) - Facade pattern with dynamic capabilities (read-only for iCal, full CRUD for Google/Outlook)
- Convenience methods:
get_production_schedule(),get_planned_downtime(),get_technician_availability() CalendarEvent,PlannedDowntime,ShiftPatterndomain entities withEventTypeenumOpcUaConnector— OPC-UA client for real-time sensor data with subscription-based monitoring, value-to-alarm conversion, and security policy support (None, Sign, SignAndEncrypt)MqttConnector— MQTT pub-sub with JSON, Sparkplug B, and raw payload support. Topic wildcards, TLS, and fan-out architecture for concurrent subscriptionsStep.is_writefield for explicit write-action marking, overriding the keyword-based heuristic in sandbox mode- Workflow
depends_onvalidation — the engine validates all step dependency references at execution start, raisingWorkflowErrorfor invalid references IncomingMessageandMessageHandlerextracted tomachina.connectors.comms.typesfor clean cross-connector imports- Phase 2 CMMS connectors:
SapPmConnector(SAP PM OData),MaximoConnector(IBM Maximo OSLC/JSON),UpKeepConnector(UpKeep REST v2) OAuth2ClientCredentialsauth strategy for SAP S/4HANA and other enterprise systems requiring OAuth2 machine-to-machine authSparePart.metadatafield to preserve connector-specific fields verbatim, consistent withAsset.metadataandWorkOrder.metadata- Shared HTTP retry helper (
machina.connectors.cmms.retry.request_with_retry) with exponential backoff on 429 / 503 responses (honouring numericRetry-Afterheaders) and transient network errors (httpx.TimeoutException,httpx.ConnectError,httpx.ReadError). All HTTP calls inSapPmConnector,MaximoConnector, andUpKeepConnectornow route through it. SapPmConnector.__init__acceptsbom_service,bom_entity_set,bom_material_field,bom_equipment_fieldto configure the BOM OData endpoint per SAP version. Defaults targetAPI_BILL_OF_MATERIAL_SRV/BillOfMaterialItem(standard S/4HANA Cloud).MaximoConnector.__init__acceptsasset_type_map: dict[str, AssetType]that maps Maximoclassstructureid(orassettype) values to MachinaAssetType. Without the map the connector falls back to the historical default ofROTATING_EQUIPMENT.get_work_order(id)single-record fetch for all three CMMS connectors (follows the existingget_asset()pattern).update_work_order(id, *, status, assigned_to, description)via PATCH for all three CMMS connectors, with keyword-only args for partial updates.close_work_order(id)andcancel_work_order(id)convenience wrappers on all three connectors — delegate toupdate_work_orderwith the appropriateWorkOrderStatustransition.read_work_orders(status=WorkOrderStatus)now accepts a MachinaWorkOrderStatusenum (automatically reverse-mapped to native CMMS code) in addition to raw status strings, for all three connectors.- Failure-mode mapping:
SapPmConnectornow extractsMaintenanceActivityType→WorkOrder.failure_modeandMaintenanceCause→WorkOrder.failure_cause;MaximoConnectorextractsfailurecode→failure_modeandfailureremark→failure_cause.
Security¶
- Secret redaction in structured logs — fields matching
token,password,secret,api_key,client_secret,authorizationare automatically replaced with***REDACTED*** - Input length limit —
Agent.handle_message()truncates messages exceeding 10,000 characters with a warning log - Prompt hardening — system prompt now includes guideline rejecting instruction override attempts and role changes
- Sandbox enforcement —
Agent._tool_create_work_order()now respects sandbox mode (previously bypassed) - Insecure connection warnings — OPC-UA and MQTT connectors log warnings when security/TLS is disabled
- Dependabot configured for weekly pip and GitHub Actions vulnerability scanning
.gitignoreexpanded to block*.pem,*.key,credentials.json, and client secret files- Auth docstring examples updated to use
os.environ[]instead of hardcoded secrets
Fixed¶
- OPC-UA task reference leak —
_DataChangeHandlernow tracks background tasks in asetwithadd_done_callbackto prevent garbage collection of in-flight tasks under rapid data changes - MQTT shared iterator bug — replaced per-subscription
_message_loopwith a single_reader_loopfan-out architecture, preventing competing consumers on theaiomqtt.Client.messagesasync generator - Guard condition exceptions now logged with
exc_info=Trueinstead of being silently swallowed - Outlook Calendar token refresh — MSAL app instance is now stored
and tokens are refreshed via
acquire_token_silent()before each API call, preventing failures after the initial 1-hour token expiry - IMAP connection reuse —
EmailConnectornow maintains a persistent IMAP connection across poll cycles with automatic reconnection on failure, reducing TCP/TLS handshake overhead SapPmConnectorCSRF token flow:_fetch_csrf_tokenreplaced by_write_with_csrfwhich performs the CSRF fetch and the write (POST/PATCH) within a singlehttpx.AsyncClientcontext, sharing session cookies. The previous implementation used separate HTTP sessions, which caused SAP to reject the CSRF token with 403 on most configurations.MaximoConnector._parse_spare_partandUpKeepConnector._parse_spare_partnow preserve unknown fields inSparePart.metadata(previously dropped)UpKeepConnector._parse_spare_partnow preferspartNumber/barcodeas the SKU, falling back to the UpKeep recordidonly when neither is available — the previous implementation conflated internal record IDs with physical part identifiersUpKeepConnectorpriority mapping corrected to match the UpKeep REST API v2 0-indexed scale (0 = lowest, 3 = highest). Previously used an off-by-one 1-4 scale which mislabelled every work order's priority.SapPmConnector.read_spare_partspreviously pointed at the non-existentAPI_EQUIPMENT/EquipmentBOMentity set. The default now targetsAPI_BILL_OF_MATERIAL_SRV/BillOfMaterialItem; users on legacy SAP versions can override via constructor parameters.
Changed¶
- BREAKING:
MaximoConnector.read_spare_partsandUpKeepConnector.read_spare_partsno longer accept theasset_idparameter. The previous implementation filtered onSparePart.compatible_assets, which was never populated by either parser — the feature was silently returning empty lists.SapPmConnector.read_spare_partsretainsasset_idbut the filter is now routed through the configurablebom_equipment_fieldand is silently dropped (with a warning log) when no equivalent field exists on the configured BOM entity set. - BREAKING:
UpKeepConnector_reverse_priority/_UPKEEP_PRIORITY_MAPswitched from a 1-4 scale to the correct 0-3 scale. Callers that were constructing raw UpKeep payloads assuming the old scale must update their code; callers going throughPriorityenums are unaffected.
[0.1.1] - 2026-04-07¶
Added¶
.zenodo.jsonmetadata for automatic Zenodo DOI generationCITATION.cfffor academic citation
[0.1.0] - 2026-04-07¶
Added¶
- Project scaffolding: pyproject.toml, CI, linting, testing setup
- Core domain model:
Asset,WorkOrder,FailureMode,SparePart,Alarm,MaintenancePlan,Plant BaseConnectorprotocol andConnectorRegistry- Exception hierarchy (
MachinaErrorand subclasses) - Configuration system with YAML and environment variable support
- LLM abstraction layer (LiteLLM wrapper) with function-calling tool definitions
- Structured logging with structlog and action tracing (
ActionTrace) GenericCmmsConnectorfor JSON/CSV-based CMMS integrationTelegramConnectorfor maintenance notifications and commandsDocumentStoreconnector with RAG (ChromaDB + LangChain document loaders)Agentruntime with domain-aware prompting, tool dispatch, and conversation loopEntityResolverfor natural language → Asset/WorkOrder resolutionFailureAnalyzer,WorkOrderFactory,MaintenanceSchedulerdomain servicesknowledge_agentquickstart example- 306 unit tests, 98% coverage