agentex
Skill190 starsChanged 6 months agoMITView on GitHub
Use when building, wiring, or debugging an Agentex agent — choosing agent type, configuring acp.py and manifest.yaml, using adk.messages or adk.state, or resolving Windows-specific setup issues.
- Reads credentials
Files
Agentex Platform
Agentex is a platform for building and deploying intelligent agents. The repo has two main parts:
agentex/— FastAPI backend + Temporal workflows (runs in Docker)agentex-ui/— Next.js frontend (runs locally)
Agents are built with the agentex-sdk CLI and run as separate processes that register with the backend.
When to Activate
- Choosing between sync, async, or Temporal agent type for a new agent
- Wiring
acp.py,manifest.yaml, orrun_worker.pyfor a new agent - Using
adk.messages,adk.state, oradk.providersin an activity or workflow - Debugging ACP protocol issues or agent registration failures
- Understanding the backend DDD layer boundaries or exception mapping
- Windows-specific setup issues (
uv sync, port conflicts,.envloading)
Agent Types
Sync ACP
One message in, one response out. Stateless.
acp = FastACP.create(acp_type="sync")
@acp.on_message_send
async def handle(params: SendMessageParams) -> TaskMessageContent:
return TextContent(author="agent", content="reply")Use when: FAQ bots, translation, data lookups, single-turn interactions.
Async ACP (base)
Task lifecycle with persistent state across multiple turns.
acp = FastACP.create(acp_type="async", config=AsyncACPConfig(type="base"))
@acp.on_task_create # called once — initialize state
@acp.on_task_event_send # called per message — respond via adk.messages.create
@acp.on_task_cancel # called on cancel — cleanupKey difference from sync: responses are pushed via adk.messages.create, not returned.
State is persisted via adk.state.create / get_by_task_and_agent / update.
Use when: multi-turn conversations, stateful workflows, streaming LLM responses. Warning: race conditions if parallel events arrive — use Temporal for production.
Async ACP + Temporal
Same as Async but every step is a durable Temporal workflow. Survives crashes and restarts.
# manifest.yaml
agent:
acp_type: async
temporal:
enabled: trueUse when: production agents, long-running tasks, human-in-the-loop, complex multi-step tool chains.
ACP State Pattern (Async)
class MyState(BaseModel):
turn: int
messages: List[Message]
# Create on task init
await adk.state.create(task_id=..., agent_id=..., state=MyState(...))
# Read on each event
task_state = await adk.state.get_by_task_and_agent(task_id=..., agent_id=...)
state = MyState.model_validate(task_state.state)
# Write back after mutating
await adk.state.update(state_id=task_state.id, task_id=..., agent_id=..., state=state)Sending Messages (Async)
# Echo user message back (so it shows in UI)
await adk.messages.create(task_id=params.task.id, content=params.event.content)
# Send agent reply
await adk.messages.create(
task_id=params.task.id,
content=TextContent(author="agent", content="response text"),
)
# Streaming LLM (auto-sends chunks to UI)
await adk.providers.litellm.chat_completion_stream_auto_send(
task_id=params.task.id,
llm_config=LLMConfig(model="gpt-4o-mini", messages=state.messages, stream=True),
)manifest.yaml Structure
local_development:
agent:
port: 8000 # must be unique per agent (8000, 8001, 8002...)
host_address: host.docker.internal
paths:
acp: project/acp.py
agent:
name: my-agent # unique name, shown in UI
acp_type: sync # or async
temporal:
enabled: false
credentials: []
env: {}Backend Architecture
src/
├── api/routes/ # FastAPI endpoints
├── domain/entities/ # Pure Pydantic models
├── domain/use_cases/ # Business logic
├── adapters/crud_store/ # DB adapters (Postgres + MongoDB)
├── adapters/streams/ # Redis SSE streams
└── config/dependencies.py # Singleton GlobalDependenciesLayer rules:
- Domain layer has zero framework imports
- API layer → use cases → domain ← adapters
- ORM ↔ domain conversion via explicit converter functions — never skip layers
Exceptions:
ClientError→ 400,ServiceError→ 500,ItemDoesNotExist→ 404
Windows-Specific Gotchas
| Problem | Fix |
uv sync fails: platform not compatible | Add "sys_platform == 'win32'" to environments in root pyproject.toml, then uv lock |
load_dotenv(override=True) clobbers Docker env vars | Change to override=False in environment_variables.py |
| Local PostgreSQL on port 5432 blocks Docker | Change Docker postgres port to 5434:5432 in docker-compose.yml |
agentex init Unicode error | Set $env:PYTHONUTF8 = "1" before running |
agentex init path has \n in it | Type short relative name (my-agent), not a full path |
source .venv/bin/activate fails | Use .venv\Scripts\Activate.ps1 on Windows |
Temporal worker connects to localhost inside Docker | Caused by .env overriding Docker network hostnames — needs override=False |
Ports
| Port | Service |
| 3000 | Frontend UI |
| 5003 | FastAPI backend (Swagger at /swagger) |
| 5432 | Local PostgreSQL (if installed) |
| 5434 | Docker agentex-postgres (remapped to avoid conflict) |
| 5433 | Docker Temporal PostgreSQL |
| 6379 | Redis |
| 7233 | Temporal server |
| 8080 | Temporal UI |
| 8000+ | Agent ACP servers (one port per agent) |
| 27017 | MongoDB |
Key Environment Variables (agentex/.env)
ENVIRONMENT=development
DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:5434/agentex
TEMPORAL_ADDRESS=localhost:7233
REDIS_URL=redis://localhost:6379
MONGODB_URI=mongodb://localhost:27017
MONGODB_DATABASE_NAME=agentex
AGENTEX_SERVER_TASK_QUEUE=agentex-server
ALLOWED_ORIGINS=http://localhost:3000
ENABLE_HEALTH_CHECK_WORKFLOW=trueRunning Tests
cd agentex
# Unit tests (no Docker needed)
.\build.ps1 test-unit
# Integration tests (needs Docker infra running)
.\build.ps1 test-integration
# Specific file
.\build.ps1 test -File tests/unit/test_foo.pyRed Flags
- Sync ACP for multi-turn conversations — sync agents receive one message and return one reply; they have no state, no turn history, and no mechanism to stream responses; use async ACP (or async + Temporal) for any stateful interaction
- Handler decorators in
acp.pyfor a Temporal agent — Temporal agents route all ACP events through the workflow engine; registering@acp.on_task_createdecorators inacp.pybypasses Temporal and runs handlers outside the durable execution context - Returning a response from an async handler instead of using
adk.messages.create— async agent handlers are not expected to return a value; the return value is silently discarded and the user sees no reply; push responses explicitly viaadk.messages.create - Not following load → mutate → save with
adk.state— reading state, mutating it in-memory, and then returning without saving means the next signal handler loads stale state; always calladk.state.updateafter every mutation before returning - Omitting
get_all_activities()inrun_worker.py— ADK built-in activities (messages, state persistence, tracing) are registered viaget_all_activities(); omitting it means alladk.messages.createandadk.state.*calls fail at runtime with "activity not found" - Two agents sharing the same port in
manifest.yaml— each ACP server process binds a port; running two agents with the samelocal_development.agent.portcauses one to fail to start; increment the port for each agent (8000, 8001, 8002, …) load_dotenv(override=True)when running inside Docker — overriding with the local.envfile replaces Docker-injected environment variables such asDATABASE_URLandTEMPORAL_ADDRESSwith localhost values, breaking service discovery inside the container network
Checklist
acp_typechosen correctly inmanifest.yaml(sync / async / async + temporal)- Temporal agent
acp.pyhas onlyFastACP.create(acp_type="async", config=TemporalACPConfig(...))— no handler decorators adk.messages.createused to send responses (not returned from handlers)- State follows load → mutate → save pattern via
adk.state on_task_createends withawait workflow.wait_condition(lambda: self._done)for Temporal agentsget_all_activities()included in worker alongside custom activities- Agent port in
manifest.yamlis unique across all running agents (8000, 8001, …) - Windows:
load_dotenv(override=False)to avoid clobbering Docker env vars - Domain exceptions (
ClientError,ServiceError,ItemDoesNotExist) used — notHTTPExceptionin use cases
In this repository65 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- accessibilitySkill
- ai-engineerSkill
- angularSkill
- api-designSkill
- authSkill
- awsSkill
- azure-service-busSkill
- azureSkill
- cachingSkill
- ci-cdSkill
- claude-apiSkill
- claude-codeSkill
- coding-standardsSkill
- complex-doc-ragSkill
- containerizationSkill
- database-designSkill
- data-pipelinesSkill
- deployment-strategiesSkill
- development-workflowSkill
- dockerSkill
- error-handlingSkill
- event-drivenSkill
- fastapiSkill
- feature-flagsSkill
- frontendSkill
- general-temporalSkill
- github-issuesSkill
- goSkill
- graphqlSkill
- incident-responseSkill
- infrastructure-as-codeSkill
- integration-testingSkill
- langgraphSkill
- memory-mapSkill
- microservicesSkill
- mongodbSkill
- nextjsSkill
- observabilitySkill
- openai-agentsSkill
- performanceSkill
- performance-testingSkill
- postgresqlSkill
- promptbaseSkill
- pydanticSkill
- pythonSkill
- reactSkill
- redisSkill
- requirements-planningSkill
- securitySkill
- smoke-testingSkill
- solution-testingSkill
- spellbook-setupSkill
- sqlalchemySkill
- system-designSkill
- tailwindSkill
- technical-documentationSkill
- temporalSkill
- test-strategySkill
- typescriptSkill
- The first 60 shown.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

