Integration Guides
M99 integrates with any Python agent in three lines. This page covers vanilla Python, FastAPI, LangChain, and LlamaIndex.
Quick Start — Under Five Minutes
1
Install
git clone https://github.com/RichardBarron27/m99-community.git cd m99-community pip install -e .
2
Start the Server
m99 serve # Running on http://localhost:8099 # Dashboard at http://localhost:8099/
3
Register Your Agent
from doomsday.sdk import M99Client, M99KillSwitchTriggered
client = M99Client("http://localhost:8099")
client.register("my-agent", "autonomous")
4
Fire the Kill Switch
m99 arm --by admin@example.com --reason "Testing" m99 execute --auth <id_from_arm> --force # Your agent raises M99KillSwitchTriggered
Vanilla Python
Any Python agent or script. Call check_status() before each action.
from doomsday.sdk import M99Client, M99KillSwitchTriggered
client = M99Client("http://localhost:8099")
client.register(
name="my-agent",
agent_type="autonomous",
endpoint="http://localhost:9000", # Optional — your agent's endpoint
)
try:
while True:
# Always check before taking an action
client.check_status()
do_work()
except M99KillSwitchTriggered as e:
print(f"Kill switch triggered: {e.level}")
save_state_if_needed()
finally:
client.disconnect() # Clean unregister + stop heartbeat
The context manager handles disconnect() automatically:
with M99Client("http://localhost:8099") as client:
client.register("my-agent", "autonomous")
while True:
client.check_status()
do_work()
FastAPI
Integrate M99 into a FastAPI application. Use the lifespan context manager to register on startup and disconnect on shutdown. Add an M99 middleware to check kill switch state before every request.
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request, HTTPException
from doomsday.sdk import M99Client, M99KillSwitchTriggered
m99 = M99Client("http://localhost:8099")
@asynccontextmanager
async def lifespan(app: FastAPI):
m99.register("my-fastapi-agent", "api-server")
yield
m99.disconnect()
app = FastAPI(lifespan=lifespan)
@app.middleware("http")
async def m99_guard(request: Request, call_next):
try:
m99.check_status()
except M99KillSwitchTriggered:
raise HTTPException(status_code=503, detail="Agent suspended by kill switch")
return await call_next(request)
@app.get("/do-work")
async def do_work():
# Kill switch already checked by middleware
return {"result": perform_action()}
The middleware adds ~1ms overhead per request. For high-throughput APIs, consider checking only on write operations or moving the check to specific route dependencies.
LangChain
Wrap a LangChain agent with M99 using a callback handler. The handler fires before each agent step and raises if the kill switch is active.
from langchain.callbacks.base import BaseCallbackHandler
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_openai import ChatOpenAI
from doomsday.sdk import M99Client, M99KillSwitchTriggered
class M99GuardCallback(BaseCallbackHandler):
def __init__(self, client: M99Client):
self.client = client
def on_agent_action(self, action, **kwargs):
try:
self.client.check_status()
except M99KillSwitchTriggered as e:
raise RuntimeError(f"M99 kill switch: {e.level}") from e
# Setup
m99_client = M99Client("http://localhost:8099")
m99_client.register("langchain-agent", "autonomous")
guard = M99GuardCallback(m99_client)
llm = ChatOpenAI(model="gpt-4o")
agent = create_openai_tools_agent(llm, tools, prompt)
executor = AgentExecutor(
agent=agent,
tools=tools,
callbacks=[guard],
verbose=True,
)
try:
result = executor.invoke({"input": "Do some work"})
except RuntimeError as e:
if "M99 kill switch" in str(e):
print("Agent stopped by kill switch")
finally:
m99_client.disconnect()
LlamaIndex
Use a LlamaIndex step callback to intercept each reasoning step. M99 raises before the step executes if the kill switch is armed.
from llama_index.core.agent import ReActAgent
from llama_index.core.callbacks import CallbackManager, BaseCallbackHandler
from llama_index.core.callbacks.schema import CBEventType
from doomsday.sdk import M99Client, M99KillSwitchTriggered
class M99StepGuard(BaseCallbackHandler):
def __init__(self, client: M99Client):
super().__init__(event_starts_to_ignore=[], event_ends_to_ignore=[])
self.client = client
def on_event_start(self, event_type, payload=None, **kwargs):
if event_type in (CBEventType.AGENT_STEP, CBEventType.FUNCTION_CALL):
try:
self.client.check_status()
except M99KillSwitchTriggered as e:
raise RuntimeError(f"M99 kill switch active: {e.level}") from e
def on_event_end(self, event_type, payload=None, **kwargs):
pass
# Setup
m99_client = M99Client("http://localhost:8099")
m99_client.register("llamaindex-agent", "autonomous")
callback_manager = CallbackManager([M99StepGuard(m99_client)])
agent = ReActAgent.from_tools(
tools,
llm=llm,
callback_manager=callback_manager,
verbose=True,
)
try:
response = agent.chat("Do some work")
except RuntimeError as e:
if "M99 kill switch" in str(e):
print("Agent stopped by kill switch")
finally:
m99_client.disconnect()
Both LangChain and LlamaIndex callbacks execute synchronously within the agent step. The M99 check adds a single HTTP round-trip — typically under 5ms on a local server.