Creating an Agent with Python¶
This guide walks the operator through creating a production-ready SI agent using
agent-utilities. The repository-local reference agent
provides a runnable companion implementation.
Prerequisites¶
- Python 3.11+
agent-utilities[agent-runtime]installed (includespydantic-ai,fastmcp,universal-skills,skill-graphs)- An LLM endpoint (local LM Studio, OpenAI, Anthropic, etc.)
Project Structure¶
Every agent in the ecosystem follows the same layout:
my-agent/
├── my_agent/
│ ├── __init__.py
│ ├── __main__.py # Entry point: from .agent_server import agent_server; agent_server()
│ ├── agent_server.py # Agent server bootstrap (see below)
│ ├── main_agent.json # Agent identity (name, description, system prompt)
│ └── mcp_config.json # MCP server configuration
├── pyproject.toml
└── README.md
Step 1: Create main_agent.json¶
This JSON file defines the operator's agent's identity. It is loaded by load_identity():
{
"name": "My Agent",
"type": "prompt",
"description": "My custom AI agent for X operations.",
"capabilities": ["task-automation", "data-analysis"],
"tags": ["custom"],
"content": "You are My Agent. You specialize in X operations and can help users with Y and Z."
}
Step 2: Create agent_server.py¶
This is the heart of the operator's agent. Here is the reference pattern used by all ecosystem agents:
#!/usr/bin/python
import logging
import os
import sys
from agent_utilities import (
build_system_prompt_from_workspace,
create_agent_parser,
create_agent_server,
initialize_workspace,
load_identity,
)
__version__ = "1.0.0"
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler()],
)
logger = logging.getLogger(__name__)
# Initialize workspace and load identity
initialize_workspace()
meta = load_identity()
DEFAULT_AGENT_NAME = os.getenv("DEFAULT_AGENT_NAME", meta.get("name", "My Agent"))
DEFAULT_AGENT_DESCRIPTION = os.getenv(
"AGENT_DESCRIPTION",
meta.get("description", "My custom AI agent."),
)
DEFAULT_AGENT_SYSTEM_PROMPT = os.getenv(
"AGENT_SYSTEM_PROMPT",
meta.get("content") or build_system_prompt_from_workspace(),
)
def agent_server():
print(f"{DEFAULT_AGENT_NAME} v{__version__}", file=sys.stderr)
logger.info("Application startup complete")
parser = create_agent_parser()
args = parser.parse_args()
if args.debug:
logging.getLogger().setLevel(logging.DEBUG)
logger.debug("Debug mode enabled")
create_agent_server(
mcp_url=args.mcp_url,
mcp_config=args.mcp_config or "mcp_config.json",
host=args.host,
port=args.port,
provider=args.provider,
model_id=args.model_id,
router_model=args.model_id,
agent_model=args.model_id,
base_url=args.base_url,
api_key=args.api_key,
custom_skills_directory=args.custom_skills_directory,
enable_web_ui=args.web,
enable_otel=args.otel,
otel_endpoint=args.otel_endpoint,
otel_headers=args.otel_headers,
otel_public_key=args.otel_public_key,
otel_secret_key=args.otel_secret_key,
otel_protocol=args.otel_protocol,
debug=args.debug,
)
if __name__ == "__main__":
agent_server()
Key Functions Explained¶
| Function | Purpose |
|---|---|
initialize_workspace() |
Discovers and sets the workspace root directory |
load_identity() |
Loads main_agent.json from the package directory |
build_system_prompt_from_workspace() |
Builds a system prompt from AGENTS.md, README, etc. |
create_agent_parser() |
Creates a standardized CLI argument parser with provider, model, host, port, MCP config, etc. |
create_agent_server() |
Bootstraps the full graph agent server with ACP, A2A, AG-UI endpoints, knowledge graph, and MCP tool loading |
Step 3: Configure mcp_config.json¶
Register the already-installed GraphOS command. Configure its JWT validation
policy and exactly one of KG_AUTH_TOKEN_REF or KG_IDENTITY_OAUTH2 in the XDG
AgentConfig before start; no credential, endpoint, or machine path belongs in
this tracked client file:
Run agent-utilities-doctor --only graph_identity auth secrets before starting
the agent. Use the installed console command above in every deployment.
Step 4: Set Up pyproject.toml¶
[project]
name = "my-agent"
version = "1.0.0"
requires-python = ">=3.11,<3.14"
dependencies = [
"agent-utilities[agent-runtime]>=2.5.0,<3.0.0",
]
[project.scripts]
my-agent = "my_agent.agent_server:agent_server"
my-agent-mcp = "my_agent.mcp_server:mcp_server"
Step 5: Run The operator's Agent¶
# Development (uses the default entry in the configured model registry)
uv run my-agent --debug
# With web UI
uv run my-agent --web --port 8080
# Override with any registered adapter/model identity
export LLM_API_KEY_REF=vault://platform/llm#api_key
uv run my-agent --provider provider-z --model-id operator/model-v1 \
--base-url https://models.example.test/v1 --api-key-ref "$LLM_API_KEY_REF"
CLI Flags Reference¶
All agents inherit these flags from create_agent_parser():
| Flag | Description | Default |
|---|---|---|
--provider |
Registered model adapter identity | Default registry entry |
--model-id |
Model identifier | Default registry entry |
--base-url |
Model endpoint override | Default registry entry |
--api-key-ref |
Runtime reference for the model API key (env://, vault://, or secret://) |
Default registry entry or none |
--host |
Server bind address | 0.0.0.0 |
--port |
Server port | 8000 |
--mcp-config |
MCP config file path | mcp_config.json |
--mcp-url |
Direct MCP server URL | None |
--web |
Enable embedded web UI | False |
--debug |
Enable debug logging | False |
--otel |
Enable OpenTelemetry | False |
--otel-headers-ref |
Runtime reference for OTLP headers | None |
--otel-secret-key-ref |
Runtime reference for the OTLP secret key | None |
--custom-skills-directory |
Custom skills directory | None |
Credential values are deliberately not command-line options because process arguments are inspectable. Configure credentials through the model registry or pass one of the reference-only options above; the parser resolves the value in memory before the existing agent factory is called.
Next Steps¶
- Add MCP tools to the operator's agent: see Building MCP Servers
- Add custom skills: place
.mdfiles in a directory and pass--custom-skills-directory - Deploy with Docker: see the operator's agent's
Dockerfileandcompose.yaml - Learn about the graph orchestration pipeline: see Architecture
Creating an Agent¶
All agents in the ecosystem follow the same pattern powered by agent-utilities. Here's the reference template used by genius-agent:
#!/usr/bin/python
import logging, os, sys
from agent_utilities import (
build_system_prompt_from_workspace,
create_agent_parser,
create_agent_server,
initialize_workspace,
load_identity,
)
__version__ = "1.0.0"
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
initialize_workspace()
# Note: load_identity() now transparently retrieves the agent's identity from the Knowledge Graph
meta = load_identity()
DEFAULT_AGENT_NAME = os.getenv("DEFAULT_AGENT_NAME", meta.get("name", "My Agent"))
DEFAULT_AGENT_SYSTEM_PROMPT = os.getenv(
"AGENT_SYSTEM_PROMPT", meta.get("content") or build_system_prompt_from_workspace()
)
def agent_server():
print(f"{DEFAULT_AGENT_NAME} v{__version__}", file=sys.stderr)
parser = create_agent_parser()
args = parser.parse_args()
create_agent_server(
mcp_url=args.mcp_url, mcp_config=args.mcp_config or "mcp_config.json",
host=args.host, port=args.port, provider=args.provider,
model_id=args.model_id, base_url=args.base_url, api_key=args.api_key,
enable_web_ui=args.web, debug=args.debug,
)
if __name__ == "__main__":
agent_server()
This page is the complete walkthrough for the project structure,
main_agent.json, mcp_config.json, pyproject.toml, and CLI flags.