Skip to main content

Python SDK for building MIRASTACK agents — agentic workflow automation for platform engineering

Project description

mirastack-agents-sdk

Python SDK for building MIRASTACK agents — the external gRPC plugins that perform READ, MODIFY, and ADMIN actions on platform engineering systems. Agents are pure compute: they receive params via gRPC and use the EngineContext proxy to interact with the engine.

License: GNU AGPL v3 — see LICENSE.

Installation

pip install mirastack-agents-sdk

Quick Start

from mirastack_sdk import (
    Plugin, PluginInfo, PluginSchema, Action, IntentPattern,
    Permission, DevOpsStage, ExecuteRequest, ExecuteResponse,
    respond_map, serve,
)

class MyAgent(Plugin):
    def info(self) -> PluginInfo:
        return PluginInfo(
            name="my-agent",
            version="0.1.0",
            description="Example observability agent",
            actions=[
                Action(
                    id="query",
                    description="Query metrics for a service",
                    permission=Permission.READ,
                    stages=[DevOpsStage.OBSERVE],
                    input_params=[{"name": "service", "type": "string", "required": True}],
                ),
            ],
            intents=[
                IntentPattern(pattern=r"query.*metrics|show.*metrics", description="Query metrics", priority=1),
            ],
        )

    def schema(self) -> PluginSchema:
        return PluginSchema(actions=self.info().actions)

    async def execute(self, req: ExecuteRequest) -> ExecuteResponse:
        service = req.params.get("service", "")
        return respond_map({"service": service, "status": "ok"})

    async def health_check(self) -> None: pass

    async def config_updated(self, config: dict) -> None: pass

if __name__ == "__main__":
    serve(MyAgent())

Plugin Interface

class Plugin(ABC):
    def info(self) -> PluginInfo: ...
    def schema(self) -> PluginSchema: ...
    async def execute(self, req: ExecuteRequest) -> ExecuteResponse: ...
    async def health_check(self) -> None: ...
    async def config_updated(self, config: dict[str, str]) -> None: ...

Response Helpers

from mirastack_sdk import respond_map, respond_json, respond_error, respond_raw

return respond_map({"metric": 42.0, "service": "api"})   # typed dict response
return respond_json(my_dataclass)                         # any serialisable type
return respond_error("backend unavailable")               # error response
return respond_raw(b'{"raw": "json"}')                    # raw JSON passthrough

Agent-Specific Features

Actions — Tool Catalog Registration

Action(
    id="restart_service",
    description="Restart a Kubernetes deployment",
    permission=Permission.MODIFY,   # READ | MODIFY | ADMIN
    stages=[DevOpsStage.OPERATE],
    input_params=[
        {"name": "namespace",  "type": "string", "required": True},
        {"name": "deployment", "type": "string", "required": True},
    ],
    output_params=[{"name": "status", "type": "string"}],
)

Intent Patterns — Natural Language Routing

IntentPattern(
    pattern=r"restart.*deployment|rollout.*restart",
    description="Restart a Kubernetes deployment",
    priority=10,
)

Prompt Templates

from mirastack_sdk import PromptTemplate

PromptTemplate(
    name="my_agent_analysis",
    description="Analysis prompt contributed to the engine PromptTemplate Store",
    content="Analyse the following data: {{ data }}",
)

Engine Context

from mirastack_sdk import EngineContext

class MyAgent(Plugin):
    def set_engine_context(self, ctx: EngineContext) -> None:
        self._ctx = ctx

    async def execute(self, req: ExecuteRequest) -> ExecuteResponse:
        url   = await self._ctx.get_config("backend.url")
        await   self._ctx.cache_set("key", "value", ttl=300)
        val   = await self._ctx.cache_get("key")
        await   self._ctx.publish_result({"data": val})
        ok    = await self._ctx.request_approval("Proceed?", Permission.MODIFY)
        await   self._ctx.log_event("action_completed", {"action": "query"})

DateTime Utilities

Convert req.time_range to backend-specific formats — never parse time in a plugin:

from mirastack_sdk import datetimeutils

start = datetimeutils.format_epoch_seconds(req.time_range.start_epoch_ms)  # VictoriaMetrics
start = datetimeutils.format_epoch_micros(req.time_range.start_epoch_ms)   # VictoriaTraces
start = datetimeutils.format_rfc3339(req.time_range.start_epoch_ms)        # VictoriaLogs

SDK Components

Module Purpose
plugin.py Plugin ABC, PluginInfo, Action, IntentPattern, PromptTemplate
context.py EngineContext proxy — config, cache, publish, approval, audit log
respond.py respond_map, respond_json, respond_error, respond_raw helpers
serve.py gRPC server bootstrap — call serve(agent) from __main__
datetimeutils.py Time format converters for all MIRASTACK backends
gen/ Hand-written gRPC proto stubs (will be replaced by buf generate)

Environment Variables

Variable Default Description
MIRASTACK_ENGINE_ADDR localhost:50051 Engine gRPC address
MIRASTACK_PLUGIN_PORT 50052 Port this agent listens on

Tenant Isolation

Every plugin process serves exactly one tenant. The engine launches separate processes per tenant — plugin processes are never shared.

Required Environment Variable

Variable Description
MIRASTACK_PLUGIN_TENANT_ID UUID5 of the tenant this plugin serves (primary). Derived via IDFromSlug(slug) from the engine engine tenant namespace.
MIRASTACK_PLUGIN_TENANT_SLUG Human-readable slug (e.g. acme). Used as fallback when MIRASTACK_PLUGIN_TENANT_ID is not set — the SDK derives the UUID5 automatically.

At least one of the two must be set. If both are missing the process exits immediately with a fatal log. This is non-negotiable: a plugin without a tenant identity is unsafe to run.

How Tenant ID Is Derived

The UUID5 is deterministically derived from the slug:

namespace = UUID("f9f3a4d4-2c64-5b9e-9e25-8a8b6f6f6f6f")
tenant_id = UUID5(namespace, "tenant:" + strings.ToLower(strings.TrimSpace(slug)))

This matches the formula used by mirastack-engine/internal/tenants/id.go so plugin processes and the engine always agree on the tenant identity.

Helper Function

// IDFromSlug derives the tenant UUID5 from a human-readable slug.
// Useful in tests and operator tooling — not needed in normal plugin code.
tenantID := mirastack.IDFromSlug("acme")

Auto-Stamping

The SDK automatically stamps tenant_id on every outbound gRPC call to the engine (config, cache, publish, approval, log, call_plugin, register). Plugin authors must never set tenant_id manually or read it from params.

No Cross-Tenant Calls

When an agent calls another agent via CallPlugin / call_plugin_with_time_range, the SDK stamps the caller's own tenant_id. The engine will reject any cross-tenant call. Federation is out of scope.

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

mirastack_agents_sdk-1.5.1.tar.gz (39.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mirastack_agents_sdk-1.5.1-py3-none-any.whl (40.5 kB view details)

Uploaded Python 3

File details

Details for the file mirastack_agents_sdk-1.5.1.tar.gz.

File metadata

  • Download URL: mirastack_agents_sdk-1.5.1.tar.gz
  • Upload date:
  • Size: 39.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mirastack_agents_sdk-1.5.1.tar.gz
Algorithm Hash digest
SHA256 4b382790a7d09850c5f5876bf3a5790a25b08196200caca1a819054c18d513ee
MD5 008a034afb5b92bc91eae888f3b6f2b0
BLAKE2b-256 6797fc3c66d6037f6bed9bcb7f79904ac9629172c29217ef42ac763e490a2c5b

See more details on using hashes here.

Provenance

The following attestation bundles were made for mirastack_agents_sdk-1.5.1.tar.gz:

Publisher: release.yaml on mirastacklabs-ai/mirastack-agents-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mirastack_agents_sdk-1.5.1-py3-none-any.whl.

File metadata

File hashes

Hashes for mirastack_agents_sdk-1.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ebec1d1dcc4f01eab7301e21dffe15e48a39aae539fab1cc8acbaddc6a3e154c
MD5 03afc216a71d7294ca17d3768ac73943
BLAKE2b-256 137e4d287d32f957ef9e3dafa8aa1730ca7cba98686003b0a24393ce7f2e4ed0

See more details on using hashes here.

Provenance

The following attestation bundles were made for mirastack_agents_sdk-1.5.1-py3-none-any.whl:

Publisher: release.yaml on mirastacklabs-ai/mirastack-agents-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page