Quick Start¶
Govern your first agent in about five minutes. By the end you'll have a LangChain agent whose tool calls pass through the Agent Assembly policy gate — and it runs offline, against a mock LLM, so you need no API keys and no network access to the outside world.
1. Install¶
The package is published on PyPI as
agent-assembly.
agent-assembly is the pure-Python client. agent-assembly[runtime] additionally pulls a
platform wheel (manylinux, macosx) that bundles the aasm gateway/runtime binary, so a
local gateway is available without a separate install.
2. Point the SDK at a gateway¶
init_assembly() needs to reach a gateway — the policy brain that returns allow/deny
decisions. You have three options:
- Let the SDK auto-start one. Call
init_assembly()with nogateway_url; the SDK probeshttp://localhost:7391and, if nothing answers, runsaasm start --mode local --foregroundfor you. This needs theaasmbinary on yourPATH(theagent-assembly[runtime]extra provides it). - Run one yourself with
aasm start --mode local --foregroundin a separate terminal. For a full gateway walkthrough, see the core Run the gateway guide. - Pass an explicit URL, as the example below does.
See Configuration for the full URL/key resolution chain (7391 is the
local default port).
3. Govern your first agent¶
This example imports LangChain alongside the SDK, so install both:
Then run:
from langchain.agents import AgentExecutor, create_react_agent
from langchain.tools import Tool
from langchain_community.llms import FakeListLLM
from langchain_core.prompts import PromptTemplate
from agent_assembly import init_assembly
with init_assembly(
gateway_url="http://localhost:7391",
api_key="dev-key",
agent_id="quickstart-agent",
mode="sdk-only",
):
llm = FakeListLLM(responses=[
"Thought: I should look up the user.\nAction: whoami\nAction Input: alice\n",
"Thought: I have the answer.\nFinal Answer: alice is in engineering\n",
])
tools = [Tool(name="whoami", func=lambda name: f"{name} is in engineering", description="who")]
prompt = PromptTemplate.from_template(
"Use the tools.\n{tools}\nTool names: {tool_names}\nQ: {input}\n{agent_scratchpad}"
)
executor = AgentExecutor(agent=create_react_agent(llm, tools, prompt), tools=tools, max_iterations=2)
print(executor.invoke({"input": "Which team is alice on?"})["output"])
What just happened¶
init_assembly()wired in governance. It registered the agent (quickstart-agent) with the gateway and auto-loaded the LangChain adapter — every tool call from this point on is routed through the policy gate.- The
FakeListLLMreplays canned responses, so the agent runs entirely offline with no real LLM. - The
whoamitool call was governed. The adapter interceptedBaseTool._runand asked the gateway for a verdict before the tool actually ran. - The
withblock tore everything down on exit — adapter hooks were unwound and the gateway connection closed, leaving the process exactly as it was before.
Expected output¶
If instead you see a ToolExecutionBlockedError, that is not a bug — the gateway's policy
denied the whoami call. That's the product working. See
Handling allow/deny decisions for how to catch and respond to
those, and Troubleshooting if init_assembly() itself raised.
mode="sdk-only" — why this example uses it¶
mode="sdk-only" is the in-process-only interception layer: the framework adapter enforces on
tool calls, with no network sidecar to start. It's the most portable mode and the best choice
for deterministic, offline examples and tests. The other modes (auto, proxy, ebpf) add
network/kernel interception — see Core Concepts → Modes.
Next steps¶
- Core Concepts — the adapter pattern, the
init_assembly()lifecycle, and the modes/enforcement model. - Examples — wire the SDK into the framework you actually use.
- Configuration — drop the hard-coded URL and key; let the resolver chain find them.