Skip to content
Optophi / EcosystemPYACTUATOR · OPEN-SOURCE FOUNDATION

Give agents tools.
Define their boundaries.

Make useful operations available to your agent. Select its tools, apply configured rules at the action boundary, and inspect the result.

CAPABILITY WITH CONTROL

A useful tool.
An explicit boundary.

An agent requests an operation. Configured validation and policy decide whether the selected adapter can run. The result identifies what happened.

  • Choose which tools the agent can discover.
  • Apply policy at configured action boundaries.
  • Identify mock and real adapter results.
  • Retain records with a configured audit writer.
ONE REQUEST. CLEAR BOUNDARIES.OP / 001
YOUR AGENT

Send the report to operations.

Your manifestversioned configuration
CapabilitySend a report
BoundaryOperations channel only
RecordRequest and outcome
Within the boundary. Ready to act.The selected operation can proceed through its configured controls.

Illustrative walkthrough · no message is sent

CLAUDE CODE

Claude Code in 2 minutes.

Install PyActuator 0.0.17, the current PyPI release, connect Claude Code over MCP, and refuse one order before the adapter runs. The refusal is written to a local audit file. PyActuator is its own package. This path does not start another Optophi package.

01 / INSTALL

Install the current release.

These commands match PyPI pyactuator 0.0.17, the current release.

python -m pip install 'pyactuator[mcp]==0.0.17'
02 / CONNECT

Register the MCP server with Claude Code.

This is the command in the 0.0.17 guide docs/guides/mcp-server.md. The profile communications is a built-in profile. pyactuator mcp serve --help accepts --profile, and pyactuator tools profiles lists communications.

claude mcp add pyactuator -- pyactuator mcp serve --profile communications

The command adds the PyActuator MCP server and offers the built-in communications profile.

03 / REFUSE

A risky order stops before the adapter runs.

Save the program below as refuse.py, or download the same file, then run it. A limit of 10000 refuses a DEMO order of 100 at 250. The policy gate returns POLICY_DENIED and does not call the broker adapter.

Download refuse.py

python refuse.py
# PyActuator 0.0.17. python -m pip install 'pyactuator[mcp]==0.0.17'
import json
from decimal import Decimal

from pyactuator.core.audit import AuditQueryFilters
from pyactuator.core.policy import LimitNotional
from pyactuator.store.sqlite_audit import SqliteAuditWriter
from pyactuator.sync import invoke, run

audit = SqliteAuditWriter("audit.sqlite")
result = invoke(
    "pyactuator.trading.place_order",
    {
        "symbol": "DEMO",
        "side": "buy",
        "quantity": "100",
        "order_type": "limit",
        "limit_price": "250",
        "client_order_id": "demo-order-001",
    },
    policy_enforcer=LimitNotional(Decimal("10000")),
    audit_writer=audit,
)
record = run(audit.query(AuditQueryFilters(tag="policy_denied", limit=1))).records[0]
print(
    json.dumps(
        {
            "success": result["success"],
            "code": result["error"]["code"],
            "message": result["error"]["message"],
            "adapter_class": result["adapter"]["class"],
            "adapter_real": result["adapter"]["real"],
            "audit_operation": record.operation,
            "audit_success": record.success,
            "audit_tags": list(record.tags),
        },
        indent=2,
    )
)
RECORDED STDOUT / PYACTUATOR 0.0.17
{
  "success": false,
  "code": "POLICY_DENIED",
  "message": "notional 25000 exceeds limit 10000 (qty=100, price=250)",
  "adapter_class": "MockExecutionClient",
  "adapter_real": false,
  "audit_operation": "pyactuator.trading.place_order",
  "audit_success": false,
  "audit_tags": [
    "policy",
    "policy_denied"
  ]
}

adapter_real is false. The envelope names MockExecutionClient so a mock configuration stays visible. The same run prints two lines on stderr: the analytics extra is not installed, and the policy denial. The order call does not use the analytics extra.

04 / AUDIT

The refusal is a row in the audit file.

refuse.py writes audit.sqlite through SqliteAuditWriter and reads the row tagged policy_denied. That row is the end of this flow. Durable audit is optional: with no writer configured, the default is to drop the record.

Coming next. An activity view of this call is coming next. This flow ends on the audit row above.
Coming next. A loopback approval page is coming next. In this release a caller outside the allow-list is denied or dry-run.
START WITH ONE OPERATION

A small tool surface.
A clear place to begin.

This profile exposes the Slack messaging operation over local MCP. Save the file, install the MCP extra, and start the server.

pip install "pyactuator[mcp]"
pyactuator mcp serve --profile communications-demo --profiles-file profiles.json

A profile limits discovery. Policy and credentials remain host configuration. Follow the selected runtime's guide for its supported operations, adapters and execution behavior.

Read the PyActuator package guide
profiles.json
{
  "profiles": {
    "communications-demo": {
      "include": ["pyactuator.comms.slack_send"]
    }
  }
}
Expose one selected operation to an agent.

This native PyActuator profile controls tool discovery. Policy, credentials, and durable audit are configured by the host runtime.

KEEP BUILDING WITH OPTOPHI

Make the next action explicit.

Feedback