ADR-0011: AI Agents as a Separate Package Above optimization¶
| Status | Accepted |
| Date | 2026-07-05 |
| Deciders | Chief Software Architect, MineProductivity |
| Governs | mineproductivity.agents |
| Related documents | docs/architecture/11_AI_Agents_Design_Specification.md; docs/design/11_AI_Agents_Implementation_Checklist.md; docs/architecture/10_Optimization_Design_Specification.md §37; ADR-0010-Optimization.md; docs/architecture/09_Simulation_Design_Specification.md §37; docs/architecture/08_Digital_Twin_Design_Specification.md §34; docs/architecture/07_Decision_Intelligence_Design_Specification.md §36; docs/architecture/06_Analytics_Engine_Design_Specification.md §33 (not yet merged to main - see feature/analytics-engine) |
Context¶
MineProductivity's Foundation Layer and its five consumer packages, analytics, decision, digital_twin, simulation, and optimization, are complete, tested, and locked as of optimization v1.2.0. Four of those packages' own documents already named what comes next. Decision Intelligence's own Future Roadmap named agents the anticipated consumer of Explanation "as the structured, evidence-linked justification an agent needs to act autonomously or to explain its own action to a human," and a plausible eventual implementer of RootCauseAnalyzer (spec 07 §36). Digital Twin's own Future Roadmap named it the anticipated consumer of TwinState/TwinSnapshot "for autonomous monitoring" (spec 08 §34). Simulation's own Future Roadmap named it the anticipated consumer of SimulationResult/SimulationState, observing it "may drive ExperimentRunner directly to explore many hypotheses without a human in the loop" (spec 09 §37). Optimization's own Future Roadmap went furthest of the four: it named agents the anticipated consumer of OptimizationResult/ParetoResult, observing it "may drive OptimizationExecutor directly to explore many candidate problems without a human in the loop" (spec 10 §37). This ADR formalizes and designs agents, the package all four already-locked documents assumed would exist, and resolves the autonomous-orchestration layer none of them declined to build for itself.
The immediate question this ADR answers: given already-measured KPIs, already-characterized trends, already-explained recommendations, a represented current twin state, projected hypothetical futures, and solved optimal plans, who decides what to actually do next, moment to moment, across ten distinct operational domains - coordinating many specialized reasoners, invoking tools, delegating between peers, and pausing for human approval where required - without becoming a seventh computation engine, a second stateful-representation layer, a second projection layer, a second search-and-solve layer, or a large-language-model wrapper coupled to one vendor's API? This ADR decides where that orchestration layer lives, why it is shaped as a model-independent contract over pluggable reasoning backends rather than a shipped LLM integration, and why agents.Agent - mirroring decision.DecisionModel rather than simulation.SimulationModel/optimization.OptimizationModel - is the sixth package-defining "as-object" abstraction in this series to ship zero concrete subclasses, but the first whose shared abstract method spans categories that differ in domain rather than computational shape.
Decision¶
Create mineproductivity.agents as a new, independent package sitting directly above optimization and directly below the not-yet-designed visualization package:
core → ontology → events → kpis → analytics → decision → digital_twin → simulation → optimization → agents
agents is permitted to import core, ontology, events, registry, plugins, connectors, kpis, analytics, decision, digital_twin, simulation, and optimization; it introduces its own public API (Agent and AgentContext; AgentMetadata/AgentCategory as a closed, ten-member registration schema; Permission/AgentCapabilitySet as an authorization model with no counterpart in any lower package; AgentPolicy/PolicyStatus/PolicyEngine as a governed guardrail mechanism deliberately distinct from decision.Policy; Task - a core.BaseEntity[str] subclass - and TaskStatus/TaskState; TaskExecutor; WorkflowEngine/Goal for multi-task decomposition; two interface-only ABCs for pluggable extension, AgentMemory and Tool; ConversationTurn/ConversationContext; ApprovalRequest/ApprovalStatus; AgentMessage/DelegationRequest composing events.EventBus; AgentResult reusing decision.Explanation directly; AgentAuditTrail/AgentAuditEntry; TaskRepository as a direct type alias over core.BaseRepository[Task, str]) without requiring any change to any Foundation Layer file, or to analytics/decision/digital_twin/simulation/optimization, or to any of their public APIs or dependency rules. This package holds two independent Registry instances - agents.REGISTRY for Agent types and agents.TOOLS for Tool types - each a direct specialization of registry.Registry, exactly as optimization.REGISTRY, simulation.REGISTRY, digital_twin.REGISTRY, decision.REGISTRY, analytics.REGISTRY, and kpis.REGISTRY already are, applied here twice because an Agent type and a Tool type are orthogonal registrable concepts. Full design detail is in the governing specification linked above; this ADR records why the package exists and why it is shaped the way it is.
Why a Separate Package (Not Folded Into optimization or decision)¶
- Distinct responsibility, distinct question being answered.
decisionanswers "what should happen, given already-known facts."optimizationanswers "what is the single best combination of decisions achievable under constraints."agentsanswers a fourth, different question none of the nine packages below it was ever chartered to answer: "given everything already measured, characterized, recommended, represented, projected, and solved, who decides what to actually do next, moment to moment, and who coordinates the many specialized reasoners that decision spans across?" An agent's action is a governed, audited, potentially delegated and human-gated event in its own right, not merely a recommendation or a solved plan waiting to be read. - All four lower specs already drew this boundary, from four directions. Decision spec 07 §36, Digital Twin spec 08 §34, Simulation spec 09 §37, and Optimization spec 10 §37 each independently named
agentsas the anticipated consumer of their own already-stable output types (Explanation,TwinSnapshot/TwinState,SimulationResult/SimulationState,OptimizationResult/ParetoResult) rather than proposing to build an autonomous decision-and-action loop into any of themselves. Folding orchestration logic intodecisionoroptimizationwould mean shipping the exact autonomy commitment each package's own specification already declined to make. - A materially different position on the stateless/stateful spectrum than a simple continuation of
optimization's.agents.Agentis as stateless askpis.BaseKPI/analytics.AnalyticsModel/decision.DecisionModel/simulation.SimulationModel/optimization.OptimizationModel(spec 05 §24, spec 06 §8, spec 07 §8, spec 09 §8, spec 10 §8) - but, unlikesimulation's andoptimization's category ABCs, which deliberately share no abstract method because their categories differ in computational shape,Agentshares one abstract_actmethod across all ten categories, mirroringdecision.DecisionModel's identical shared-_decideposture, since every agent category answers the same underlying question and differs only in domain.agents.Taskis stateful for the same reasondigital_twin.Twin,simulation.SimulationRun, andoptimization.OptimizationRunare: an executing or completed unit of agent work is itself a piece of history the instant it starts. This package is the fourth, not the first, to reach forcore.BaseEntity's "produce a new instance viawith_state()" idiom. - Consistent with every other layer boundary already drawn in this platform, including the five
analytics,decision,digital_twin,simulation, andoptimizationjust established at the five layers below. A platform that has consistently drawn a package boundary at every "distinct responsibility, distinct rate of change, distinct statefulness/governance profile" seam would be inconsistent to stop doing so at the one seam (optimization→agents) four of its own most recent specifications already named from four different directions.
Dependency Rationale¶
agents is permitted to import the entire Foundation Layer plus analytics, decision, digital_twin, simulation, and optimization, not merely optimization directly, for the same structural reason ADR-0007 through ADR-0010 already established at their own layers: an AgentContext (governing spec §8) legitimately needs kpis.KPIResult/analytics.AnalyticsResult (as measurement/characterization evidence), decision.DecisionResult and its Explanation (directly, as the structured justification an autonomous action needs, per Decision spec 07 §36's own anticipation, reused verbatim on AgentResult rather than redefined), digital_twin.TwinSnapshot/TwinState (as current-condition evidence, per Digital Twin spec 08 §34's own anticipation), simulation.SimulationResult/ExperimentRunner (as projected-outcome evidence and, for the latter, direct composition for hypothesis exploration, per Simulation spec 09 §37's own anticipation), and optimization.OptimizationResult/OptimizationExecutor (as solved-plan evidence and, for the latter, direct composition for candidate-plan search, per Optimization spec 10 §37's own anticipation). Restricting agents to only optimization would have forced pass-through re-exports of types it does not otherwise need to expose, exactly the worse alternative ADR-0006 through ADR-0010 already rejected at their own layers.
connectors is included in the permitted-import list for platform-wide layering consistency, and is exercised narrowly here, unlike in every package below it: connectors.RetryPolicy/BackoffStrategy (spec 04 §10) are reused directly as configuration value objects governing TaskExecutor's own retry loop (governing spec §12) - this package's own retry loop executes them, never a connector's, so agents still never touches a vendor-specific wire format directly. ontology is available for the vocabulary a task's scope is expressed in, mirroring digital_twin.Twin.scope's original use (spec 08 §9), but introduces no new concept.
Architectural Trade-offs¶
- Trade-off accepted:
Agentshares one abstract method (_act) across all ten categories, unlikesimulation's/optimization's category ABCs, which deliberately share none. This departs from the two most immediately preceding packages' own precedent, but mirrorsdecision.DecisionModel's shared-_decideposture instead - accepted because every named agent category (Production, Dispatch, Fleet, Maintenance, Drill & Blast, Shift Supervisor, ESG, Safety, Executive Advisor, Planning) answers the identical underlying question ("given a task and context, decide what should happen next"), differing in domain and permission scope rather than in computational shape, exactly the condition under whichdecision's shape, notsimulation's/optimization's, is the correct precedent to follow. - Trade-off accepted: this package introduces two independent
Registryinstances (REGISTRY,TOOLS) rather than one, the first package in this series to do so. Accepted because anAgenttype and aTooltype are orthogonal registrable concepts - one decides, the other acts on or queries the world at an agent's direction - and conflating "what can decide" with "what can be invoked" would blur a boundary (§9, §17) this design otherwise keeps deliberately sharp. This is treated as an explicit, justified exception to "one extension mechanism, platform-wide" (governing spec §3.7), not a violation of it, since both registries still specialize the identicalregistry.Registrymechanism. - Trade-off accepted:
Tasksubclassescore.BaseEntity[str]and is immutable, with state changes producing a new instance (with_state()), rather than being a plain mutable Python object, exactly mirroring the trade-off ADR-0010 already accepted forOptimizationRun, which itself mirrored ADR-0009's forSimulationRunand ADR-0008's forTwin. The governing spec's own Performance Considerations (§36) judges the allocation cost negligible next to the policy-evaluation call and repository round-trip already on the hot path of every task dispatch. - Trade-off accepted:
AgentPolicyis a dedicated new abstraction, deliberately not a reuse ofdecision.Policy, despite both being versioned, governed rule artifacts. Accepted becausedecision.Policyexpresses a business threshold that triggers aRecommendation, whileAgentPolicyexpresses an authorization guardrail on an already-decided task - another occurrence in this series of "shape looks similar, coupling doesn't fit" (afterdecision.ActionPlannerdecliningkpis.DependencyGraph, spec 07 §21, and two further occurrences one and two layers down, spec 08 §22, spec 09 §26) - the first of these to occur between two packages that are otherwise both new to this specification. - Trade-off accepted: this package introduces no dedicated cache, unlike
kpis.ResultCache,digital_twin.TwinStateCache, andsimulation.SimulationStateCache, and consistent withoptimization's own identical non-need one layer down (spec 10 §26). This is a deliberate absence, not an oversight:AgentContextis assembled once, by the caller, from evidence each lower package has already computed and, where applicable, already cached on its own side.AgentMemory(governing spec §14) is explicitly documented as not a substitute for this absence, since it is semantically consulted by an agent's own reasoning rather than a transparent, silently-evictable performance optimization - the governing specification records this distinction explicitly (§14, §27) rather than conflating the two. - Trade-off accepted:
Agent,Tool, andAgentMemoryship as three interface-only ABCs with zero concrete implementations, the sixth occurrence of this discipline in the series (afteranalytics' forecasting/anomaly/outlier interfaces,decision's root-cause/what-if interfaces,digital_twin's simulation interface,simulation's four methodology interfaces, andoptimization's six paradigm interfaces). This means the package cannot, on its own, actually reason, remember, or act until a plugin implements at least one of the three - a materially weaker out-of-the-box capability than shipping even a single reference rule-based agent would provide. Accepted for the same reasons ADR-0006 through ADR-0010 already accepted the equivalent trade-off at their own layers (see "Alternatives Rejected"), now extended from numerical solving/projection paradigms to reasoning backends themselves.
Alternatives Considered¶
- Fold autonomous-orchestration logic directly into
decision(e.g. an executable action loop embedded inActionPlanner). Rejected - directly contradictsdecision's own already-locked scope and its own Future Roadmap's framing ofagentsas the separate, downstream consumer of itsExplanationoutput (spec 07 §36). - Fold autonomous-orchestration logic directly into
optimization(e.g. an execution loop wrapped aroundOptimizationExecutor). Rejected -optimization's own charter explicitly excludes autonomous, self-directed action, and its own Future Roadmap already framesagentsas the separate package positioned to composeOptimizationExecutor, not absorb it (spec 10 §37). - Defer
agentsentirely until a specific LLM-integration need arises, treating orchestration as that integration's own internal detail. Rejected - for the same reason ADR-0006 through ADR-0010 each rejected deferring their own packages:visualization(governing spec §37) is independently expected to consumeAgentResult/AgentAuditTrail; deferring this package would mean any eventual integration reimplements its own, likely mutually inconsistent, notion of "what does an agent, a task, and an audited action look like." - A single, larger "optimization + agents" package, reasoning that deciding what to do with a solved plan is just an extension of solving for it. Rejected -
visualization(governing spec §37) is expected to consume agent-orchestration output without needingoptimization's full problem-definition surface exposed alongside it, and vice versa; bundling the two would also obscure the subtly different reason each package's central "as-object" abstraction shares (or does not share) an abstract method (see "Why a Separate Package," item 3). - Couple
Agent/the package's design to one specific LLM provider (e.g. a native Anthropic or OpenAI integration) as the reference implementation, on the reasoning that a package with no working reasoning backend is of limited immediate use. Rejected - see "Alternatives Rejected" below; this was the most seriously debated alternative, mirroring the equivalent "ship at least one concrete implementation" debate ADR-0006 through ADR-0010 each recorded for their own interface-only capabilities. - Bundle prompt-engineering, chat-interface, or model-inference code directly into this package, reasoning that an "AI agents" package should include at least a minimal working chat loop. Rejected - see "Alternatives Rejected" below; explicitly out of scope per this package's own brief.
Alternatives Rejected¶
Shipping at least one concrete implementation of Agent, Tool, or AgentMemory is rejected for the same three compounding reasons ADR-0006 through ADR-0010 already established for their own interface-only capabilities, restated at this layer:
- Scope creep into reasoning-backend/model-integration territory. Choosing a specific LLM provider, local-model runtime, or rule-engine implementation is exactly the kind of implementation decision this package's charter (governing spec §3.1, §3.5, §4) excludes. Shipping one "just as a starting point" would establish a precedent that quietly widens
agents' scope every time a plausible-looking model integration seems worth adding. - Premature commitment to an interface's shape via its first implementation. Defining
Agent,Tool, andAgentMemorynow and deferring their first concrete implementations to independently-versioned future plugins keeps each contract general, rather than shaped by whichever reasoning backend happened to ship first. - The package's charter is explicitly to remain model-independent, per its own brief: architecture must support OpenAI, Anthropic, Gemini, Llama, local models, and rule-based agents without coupling to any specific provider. Shipping a concrete implementation backed by any one of them would be the first, precedent-setting violation of that explicit non-negotiable.
Bundling prompt-engineering, chat-interface, or model-inference code was the second most seriously considered alternative, and is rejected for a related but distinct reason:
- It would make
agentsthe first package in this series whose Foundation Layer position is coupled to a third-party model provider's own API surface, rate limits, and versioning cadence - a materially different kind of dependency than the platform's existing, deliberately dependency-light optional extras, each of which is an interchangeable backend behind an already-stable interface, never a mandatory single choice baked into the architecture itself. - This package's own brief names prompt engineering, chat interfaces, model APIs, inference code, tool implementations, and concrete LLM integrations as explicitly out of scope; bundling any of them would be a direct violation of the brief, not a judgment call within it.
- The
Agent/Tool/AgentMemoryinterfaces (governing spec §8, §14, §17) already give every reasoning backend, memory store, and tool integration - and any future one - an equally first-class path into the platform via the identical plugin mechanism every other extension point already uses (governing spec §31); no capability is lost by declining to bundle one now.
Long-Term Evolution¶
This package is expected to grow along the same axes ADR-0006 through ADR-0010 already established for analytics, decision, digital_twin, simulation, and optimization, without requiring a new ADR:
- New concrete
Agent/Toolimplementations within existing categories, or newAgentPolicy/AgentCapabilitySetartifacts - ordinary, checklist-governed extension (governing spec §31), not an architectural change. - The first concrete implementations of
Agent,Tool, andAgentMemory, whenever they arrive - expected to land as plugins (an OpenAI-, Anthropic-, Gemini-, Llama-, local-model-, or rule-based-backed adapter being the most plausible first instances, per this package's own brief) against the already-stable interfaces this design defines. - A production-grade
TaskRepositorybackend (SQL, document store) implementingcore.BaseRepository[Task, str]directly - no code change to this package required (governing spec §25). - The
visualizationpackage's consumption ofAgentResult/AgentAuditTrail, the last remaining promise named by any already-locked specification (governing spec §37), closing the final "future package" reference this series has carried since Decision Intelligence.
A new ADR would be warranted if a future need arose to: change agents' position in the dependency chain; permit agents to be imported by a Foundation Layer package or by analytics/decision/digital_twin/simulation/optimization (which would indicate a design error, not a legitimate evolution); introduce a third registry alongside REGISTRY/TOOLS, or merge the two, reversing the deliberate two-registry trade-off recorded above; couple this package's architecture to a specific LLM provider, reversing the model-independence guarantee recorded above; or introduce a dedicated cache, reversing the deliberate non-need recorded above, in light of a measured performance problem this ADR did not anticipate.
Future Compatibility¶
Every public type this package introduces (governing spec §20, AgentResult, and §21, AgentAuditEntry) is a plain, frozen core.BaseValueObject (or, for Task itself, a frozen core.BaseEntity), serializable via the platform's existing core.serialization mechanism, with no agents-internal state leaking into any type a future package would need to consume - the identical compatibility guarantee ADR-0006 through ADR-0010 each already established for analytics.AnalyticsResult, decision.DecisionResult, digital_twin.TwinResult, simulation.SimulationResult, and optimization.OptimizationResult, extended one layer up. This is a deliberate guarantee for the package named in the governing specification's Future Roadmap (§37) - visualization - which is not designed by this ADR or by the governing specification, but is expected to consume agents' output types without requiring a breaking change to them. The two interface-only ABCs this package defines for pluggable extension (governing spec §14, §17), together with the model-independent Agent contract itself (governing spec §8), exist specifically so that whichever future reasoning backend, memory store, or tool integration arrives first can implement against a contract that already exists, and so that this package can close, at last, every "future package promise" four already-locked specifications made on its behalf before it existed.
This ADR governs the existence and shape of mineproductivity.agents as a package. See 11_AI_Agents_Design_Specification.md for the full object model and 11_AI_Agents_Implementation_Checklist.md for the locked implementation contract.