Metadata-Version: 2.4
Name: mirrorneuron-python-sdk
Version: 1.2.27
Summary: MirrorNeuron Python SDK
License-Expression: MIT
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: grpcio>=1.50.0
Requires-Dist: protobuf>=4.21.0
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: ruff>=0.8; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Dynamic: license-file

# MirrorNeuron Python SDK

`mn-python-sdk` provides the Python gRPC client and workflow-bundle helpers used
by the CLI, API, and Python-defined workflows.

## Declarative Step Handlers

`mn.workflow.source/v2` manifests declare direct DAG dependencies with `needs`
and select Python behavior modules with `run.handler`:

```json
{
  "id": "research",
  "needs": ["intake"],
  "run": {
    "handler": "my_blueprint.steps.research",
    "with": {"operation": "company_identity"}
  }
}
```

The module defines `run()`; the manifest does not need a `:run` suffix. During
expansion, the standard `blueprint` profile configures each handler-backed
worker to run `python3 -m mn_sdk.step_runtime`. The SDK entrypoint invokes only
the scheduler-selected handler and passes a `StepContext` containing the step
id, run id, attempt metadata, incoming message, and embedded config.

A logical step can instead reference a Python `StepSpec`. Registry entries own
immutable agent handlers and parameters, while the step module owns its input
contract, output contract, and internal collaboration graph:

```json
{
  "agents": {
    "registry": {
      "extractor": {"handler": "my_blueprint.agents.extractor"},
      "normalizer": {"handler": "my_blueprint.agents.normalizer"}
    }
  },
  "workflow": {
    "steps": [{
      "id": "prepare",
      "needs": [],
      "run": {"definition": "steps.prepare"}
    }]
  }
}
```

```python
from mn_sdk.step_graph import (
    InputSpec,
    OutputSpec,
    StepSpec,
    agent,
    flow_output,
    run_input,
    sequence,
)

STEP = StepSpec(
    input=InputSpec(fields={"document_folder": run_input("document_folder")}),
    flow=sequence(
        agent("extractor", as_="extract"),
        agent("normalizer", as_="normalize"),
    ),
    output=OutputSpec(fields={"company_evidence": flow_output()}),
)
```

The compiler expands each logical step into a start boundary, its internal
agent graph, and an end boundary. It supports `sequence`, all-required
`parallel`, `choice` with a
default, `fallback`, and `bounded_loop`. Workflow edges connect only a previous
step's end boundary to the next step's start boundary. Agent handlers use
`receive_input(context)` and `send_output(...)`; Redis routing, retries,
fan-out, and fan-in remain outside agent code.

## Quick Start

Install locally and run tests:

```bash
python3.11 -m venv .venv
. .venv/bin/activate
.venv/bin/python -m pip install -e ".[dev]"
.venv/bin/python -m pytest -q
.venv/bin/python -m ruff check .
```

Minimal client example:

```python
from mn_sdk import Client

client = Client(target="localhost:55051")
print(client.list_jobs(limit=5))
```

## Details

- [MirrorNeuron Component Guide](../mn-docs/component-guide.md#python-sdk)
- [Python SDK](../mn-docs/SDK.md)
- [Job Bundle Format](../mn-docs/bundle.md)
- [Environment Variables](../mn-docs/env_variables.md)

## Source Manifests

Blueprints may use `apiVersion: mn.workflow.source/v1` for a compact,
CSS-like `manifest.json` that declares intent and overrides while SDK profiles
provide common defaults. Generate the executable runtime manifest with:

```bash
mn-manifest-converter expand manifest.json --output build/manifest.executable.json
mn-manifest-converter check manifest.json --against build/manifest.executable.json
```

The CLI/API expand source manifests automatically before validation and
submission. Existing `mn.workflow/v1` executable manifests continue to work.

For source/v2 blueprints, `config.manifest_defaults` can expose authoritative
manifest descriptors through resolved runtime configuration without copying
them into `config/default.json`. A dotted string keeps the same path; a mapping
projects it to another config path:

```json
{
  "config": {
    "manifest_defaults": [
      "llm",
      {"from": "requirements", "to": "resources"}
    ]
  }
}
```

Manifest values are merged first, followed by the default config file and the
invocation overlay. Both manifest compilation and `load_runtime_config()` use
this order.

### DAG dependencies and trigger rules

`workflow.requires` and `workflow.provides` compile into runtime DAG edges.
Declare an explicit `workflow.edges` list when an edge needs a custom event or
otherwise cannot be inferred from a provided capability. A step can declare a
runtime trigger at `trigger_rule` (or `control.trigger_rule`): `all_success`,
`all_done`, `one_success`, `one_done`, `one_failed`,
`none_failed_min_one_success`, or `quorum_success` with a positive `quorum`.
The generated manifest places these under `flow.steps` and `flow.graph.edges`,
which are consumed by the Core workflow ledger.

## Configuration

Configuration is loaded by `mn_sdk.config` in this order:

```text
real environment variables
> .env.${MN_ENV}
> .env
> built-in safe defaults
```

`MN_ENV` defaults to `dev` when unset. `MN_ENV=development` loads `.env.dev`;
`MN_ENV=test` loads `.env.test`; `MN_ENV=prod` or `MN_ENV=production` loads
`.env.prod` when present. Production does not require any `.env` file.

Development example:

```bash
export MN_ENV=dev
cp .env.example .env.dev
mn-cli ...
```

Test example:

```bash
export MN_ENV=test
mn-cli ...
```

Production example:

```bash
export MN_ENV=production
export MN_HOME=/var/lib/mirrorneuron
export MN_LOG_LEVEL=info
export MN_API_HOST=0.0.0.0
export MN_API_PORT=8080
mn-api ...
```

### Model catalog overrides

The SDK uses the packaged `mn_sdk/model_catalog.json` as its baseline catalog.
If present, `$MN_HOME/models/catalog.json` is loaded next; `$MN_HOME` defaults
to `~/.mn`. Entries are deep-merged by model ID, so an external entry can
override selected fields while unmentioned built-in models remain available.

Set `MN_MODEL_CATALOG_PATH` to load a final, highest-priority catalog file.
The file may be a model list, an object with a `models` list, or an object keyed
by model ID. Paths support `~`, `$MN_HOME`, and normal environment-variable
expansion.

For example, this changes the bundled Gemma model endpoint and adds a new
catalog entry without copying the entire packaged catalog:

```bash
mkdir -p "$MN_HOME/models"
cat > "$MN_HOME/models/catalog.json" <<'JSON'
{
  "models": [
    {
      "id": "gemma4:e2b",
      "model": "local/gemma4:E2B",
      "requirements": {"min_vram_gb": 4}
    },
    {
      "id": "my-local-model",
      "model": "local/my-model",
      "aliases": ["my-model"]
    }
  ]
}
JSON
```

Catalog precedence is:

1. Packaged `mn_sdk/model_catalog.json`.
2. `$MN_HOME/models/catalog.json`, when present.
3. `MN_MODEL_CATALOG_PATH`, when configured.

Matching entries are merged by `id`. Nested objects are merged recursively;
scalar values and lists from the higher-priority catalog replace lower-priority
values. A malformed existing catalog raises a validation error rather than
being silently ignored.

Do not commit real `.env` files. Use `.env.example` for placeholders only, and
put secrets in real environment variables or token files.

## Notes

- A running MirrorNeuron core is required for live client calls.
- Constructor arguments take precedence over environment variables.
- Generated protocol modules are included with the package.
