From hexagonal-agents
Builds hexagonal architecture web apps where AI agents dynamically generate HTML UI using Claude Agent SDK, FastAPI, HTMX, and Tailwind. Ideal for agent-driven UIs instead of static frontend designs.
How this skill is triggered — by the user, by Claude, or both
Slash command
/hexagonal-agents:hexagonal-agentsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Build web applications where an AI agent serves as the UI layer, dynamically generating HTML in response to user messages. The agent sits at the center of a hexagonal architecture — tools handle data (ports), FastAPI/HTMX handle transport (adapters), and a skill file teaches the agent its entire UI vocabulary.
references/architecture.mdreferences/component_library.mdreferences/debugging.mdreferences/enhanced_ux.mdreferences/eval_patterns.mdreferences/multi_agent_patterns.mdreferences/saved_views.mdreferences/sdk_reference.mdreferences/sqlite_persistence.mdscripts/init_hexagonal_app.pytemplates/agent.py.templatetemplates/main.py.templatetemplates/skill_ui.md.templatetemplates/tools.py.templateBuild web applications where an AI agent serves as the UI layer, dynamically generating HTML in response to user messages. The agent sits at the center of a hexagonal architecture — tools handle data (ports), FastAPI/HTMX handle transport (adapters), and a skill file teaches the agent its entire UI vocabulary.
uv init, uv add, uv run uvicornclaude_agent_sdk package. Provides ClaudeSDKClient, ClaudeAgentOptions, TextBlock, @tool, create_sdk_mcp_server.ANTHROPIC_API_KEY environment variable.Browser (static shell + HTMX)
│ POST /agent {message: "..."}
▼
FastAPI (HTTP Adapter)
│ agent.process(message)
▼
Agent (ClaudeSDKClient)
│ System prompt = skill file
│ Calls tools for data, generates HTML
▼
Tools (MCP Server)
│ Pure data operations → JSON
Tools are the agent's interface to data. Each tool:
@tool("list_items", "Get all items. Returns array of items with id, name, status.", {})
async def list_items(args: dict[str, Any]) -> dict[str, Any]:
items = load_items()
return {"content": [{"type": "text", "text": json.dumps({"items": items, "count": len(items)})}]}
Return format: {"content": [{"type": "text", "text": json.dumps(data)}]}. Errors: add "is_error": True.
Tool names in allowed_tools must follow: mcp__{server_key}__{tool_name}
The skill file (app/skills/ui.md) teaches the agent how to generate UI. Critical requirements:
hx-post, hx-target, hx-vals.Every button: <button hx-post="/agent" hx-target="#content" hx-vals='{"message":"action"}'>
Every form: <form hx-post="/agent" hx-target="#content"> with hidden message input.
For the complete design system (colors, typography, spacing) and full component library (cards, lists, forms, alerts, empty states, etc.):
→ references/component_library.md
For detailed hexagonal architecture explanation and SDK API details:
→ references/architecture.md
→ references/sdk_reference.md
Load any stored feedback preferences before starting:
python ${PLUGIN_ROOT}/scripts/feedback_manager.py hexagonal-agents show-feedback
If feedback entries exist, apply them throughout app scaffolding:
Locate the init script within this skill's directory and run it:
uv run {skill_root}/scripts/init_hexagonal_app.py my-app-name --domain items
Where {skill_root} is the installed path of this skill (e.g., the directory containing this SKILL.md). Alternatively, create the project structure manually following the layout below.
Creates:
my-app-name/
├── pyproject.toml
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI application
│ ├── agent.py # Agent wrapper
│ ├── tools.py # MCP tool definitions
│ └── skills/
│ └── ui.md # UI skill file
└── data/ # Created at runtime
Edit app/tools.py. Create an MCP server with CRUD operations:
def create_tools_server():
return create_sdk_mcp_server(
name="app_tools", version="1.0.0",
tools=[list_items, get_item, create_item, update_item, delete_item]
)
Edit app/skills/ui.md to teach the agent its UI vocabulary. Structure:
# Application UI Skill
## Critical Output Rules (raw HTML only, never markdown)
## Design System (colors, typography)
## Component Patterns (with full HTML examples)
## Available Tools (when to call each)
## Response Patterns (user intent → tool → UI)
Use components from references/component_library.md.
The agent wrapper (app/agent.py) connects everything:
class Agent:
def __init__(self):
self.tools_server = create_tools_server()
self._allowed_tools = ["mcp__app_tools__list_items", ...]
async def _ensure_connected(self):
skill_content = SKILL_PATH.read_text()
options = ClaudeAgentOptions(
system_prompt=skill_content,
mcp_servers={"app_tools": self.tools_server},
allowed_tools=self._allowed_tools,
permission_mode="acceptEdits",
)
self.client = ClaudeSDKClient(options=options)
await self.client.connect()
async def process(self, message: str) -> str:
await self._ensure_connected()
await self.client.query(message)
html_parts = []
async for msg in self.client.receive_response():
for block in msg.content:
if isinstance(block, TextBlock):
html_parts.append(block.text)
return self._clean_html("\n".join(html_parts))
The FastAPI app (app/main.py) serves the base template and handles agent messages:
@app.post("/agent", response_class=HTMLResponse)
async def handle_message(request: Request):
form_data = await request.form()
message = str(form_data.get("message", "")).strip()
# Append extra form fields to message
extra_fields = [f"{k}={v}" for k, v in form_data.items() if k != "message" and v]
if extra_fields:
message = f"{message} [{', '.join(extra_fields)}]"
html = await agent.process(message)
return html
Before considering the app ready, verify:
To adapt for a new domain:
_allowed_tools listA running hexagonal agent web application:
cd my-app-name
export ANTHROPIC_API_KEY=your_key_here
uv run uvicorn app.main:app --reload
# Open http://localhost:8000
As the app matures:
→ references/multi_agent_patterns.md — Specialized agents communicating via semantic messages
→ references/saved_views.md — Progressive UI caching to reduce latency and API costs
→ references/sqlite_persistence.md — Migrate from JSON to SQLite for ACID compliance
→ references/enhanced_ux.md — Animated loading states and visual feedback
→ references/eval_patterns.md — Systematic testing with pydantic-evals
For common issues (agent outputs markdown instead of HTML, tools not being called, HTMX not working, blank responses):
→ references/debugging.md
npx claudepluginhub joshuaoliphant/claude-plugins --plugin hexagonal-agentsGenerates interactive, semantic HTML prototypes for human+AI agent use with Tailwind+DaisyUI (Tier A) or React+shadcn/ui+Vite (Tier B). Includes Playwright previews for iteration.
Deploys websites, apps, AI agents to Agentuity production. Creates new projects, migrates Express/Next.js/Vite apps, restructures code, and manages full deploy workflows.
Scaffolds new Tambo generative UI React apps from scratch via tambo create-app CLI. Gathers app type, Next.js or Vite framework, and name; sets up TamboProvider and starter components.