This guide explains how to build and extend agents within the Agentic Development Platform. It assumes familiarity with the core BaseAgent and the Think–Act–Observe (T‑A‑O) pattern.
- Basic Python knowledge (async/await, typing, dependency injection).
- Understanding of
core.agents.base.BaseAgentandcore.mcp.protocol(tool calls and results). - Access to
tests/unit/test_base_agent.pyandtests/unit/test_orchestrators.pyas reference tests.
- Single responsibility: each agent type owns a narrow domain (code, tests, docs, voice, etc.).
- Composability: agents can be chained via an
OrchestratorAgentor via scratchpad‑based coordination. - Dependency‑inversion: agents depend only on tool contracts (
IToolExecutor) and the scratchpad, not on concrete MCP implementations.
Follow the pattern in core.agents.code_agent.CodeAgent:
-
Create
core/agents/your_agent.py. -
Subclass
BaseAgentand add any agent‑specific config. -
Implement
think,act, andobservesuch that:thinkconverts a task description and context into a plan dictionary.actuses that plan to produce aToolCall.observeconsumes theToolResultand updates the context.
Example skeleton:
from core.agents.base import BaseAgent, AgentConfig
from core.mcp.protocol import ToolCall, ToolResult
from typing import Dict, Any
@dataclass(frozen=True)
class YourAgentConfig(AgentConfig):
custom_param: str = "default"
class YourAgent(BaseAgent):
def __init__(..., config: YourAgentConfig):
super().__init__(..., config=config)
self._config = config # Narrowed type
def think(self, task_description: str, context: Dict[str, Any]) -> Dict[str, Any]:
# ...
return plan
def act(self, plan: Dict[str, Any], context: Dict[str, Any]) -> ToolCall:
# ...
return tool_call
async def observe(self, tool_result: ToolResult, context: Dict[str, Any]) -> Dict[str, Any]:
# ...
return contextIf config.scratchpad_enabled is True, record:
- Plans in a
"Plan"section. - Observations and errors in
"Observations"or"Errors".
Example:
if self.config.scratchpad_enabled:
await self.scratchpad.append_section(
project_id=self.project_id,
agent_id=self.agent_id,
task_id=context["task_id"],
section="Plan",
content=plan,
)Do not call MCP server internals directly. Instead:
- Accept an
IToolExecutorin__init__. - Produce
ToolCallobjects inact. - Interpret
ToolResultmetadata and content inobserve.
This allows the same agent to run against different MCP backends (local, remote, mocked).
- Unit tests:
tests/unit/test_your_agent.py. - Verify that
thinkreturns a well‑shaped plan,actproduces validToolCalls, andobservecorrectly updates context. - Use
StubToolExecutorandUnstableToolExecutorfromtests/unit/test_base_agent.pyas test doubles. - Assert scratchpad interactions when
scratchpad_enabledis enabled.
If your agent participates in multi‑step workflows:
- Add it to an agent registry (or configuration) that the
OrchestratorAgentcan route to. - Ensure its
thinkreturns plans that include"agent_id"hints. - The orchestrator’s
actcan then conditionally route subtasks to your agent based on that field.
- Immutable configuration: use
@dataclass(frozen=True)for agent config. - Idempotent tools: prefer tools that describe what to do (e.g., patches) rather than imperative mutations.
- Auditable history: log all plans and results to the scratchpad so that failures can be replayed.
- Coupling to a specific LLM backend or MCP transport.
- Directly writing to project files without going through approved tools.
- Storing large artifacts inside the agent; instead store references or IDs in the scratchpad.
With this guide, you can extend the platform with new agents such as:
- Test‑generation agents.
- Documentation‑generation agents.
- Dependency‑management or security‑linting agents.