Building tmates
Tmates are just Python packages with a manifest, a prompt brain, and a small amount of glue code. This guide walks through the entire lifecycle so your tmate behaves consistently across Tmates Cloud and self-hosted deployments.
1. Plan the role
Before touching code, write down:
- Mission statement – one sentence describing what the tmate solves (e.g., “Turns raw meeting notes into structured action plans”).
- Success signals – what a good response looks like (attachments, tone, metadata, etc.).
- Required tools – APIs, files, or SDK integrations it needs.
This planning step becomes the foundation for the manifest and prompt instructions.
2. Scaffold the agent folder
Every tmate lives under app/agents/<key> with this structure:
app/agents/<key>/
├── manifest.yaml
├── agent.py
├── brain.py
├── interface/
│ └── api.py
├── tests/
└── prompts/
manifest.yamldescribes branding, capabilities, environment variables, and tools.agent.pyexposesAGENT_CLASSinheriting fromAgentBase.brain.py(or another module) houses the core logic/prompt.interface/api.pyadapts CLI/API requests into the brain.tests/holds pytest suites for regression coverage.
Use an existing tmate (e.g., app/agents/adam) as a reference, but don’t copy prompts verbatim.
3. Write the manifest
Key sections:
name,slug,description,category– used in the catalog and clients.branding– emoji/color/avatar so the UI can render a consistent face.playbook.optional_params– documented knobs users can tweak.tools– describe each callable capability (inputs, outputs, keywords for routing).env.required/env.optional– document every secret or feature flag the tmate needs.
Keep the manifest honest: if a variable is required, mark it as such so self-hosted installs don’t miss it.
4. Implement the brain
In brain.py (or a similar module):
- Import
run_agent_api_requestfromapp.sdk.agents.tmates_agents_sdkto handle sessions and attachments. - Implement
run_promptor equivalent function that calls OpenAI/Azure models, other services, or your custom tools. - Sanitize outputs (strip URLs you’re going to send as attachments, format Markdown, etc.).
Example skeleton:
from app.sdk.agents.tmates_agents_sdk import run_agent_api_request
async def run_prompt(message, user_id, session_id, context=None):
# Call LLMs, tools, or custom logic
return "Thanks for the update!"
def process_api_request(request, user_context=None):
return run_agent_api_request(
agent_key="planner",
author_name="Planner",
request=request,
user_context=user_context,
run_prompt=run_prompt,
)
5. Add tests
Use pytest to lock in behavior:
- Mock the LLM/tool layer so tests run quickly.
- Cover manifest changes (e.g., schema validation) if you add new sections.
- Simulate CLI invocations with
python run.py agent <key> --message "..."inside the test suite or a smoke-test script.
6. Run locally
WORKER_KEY=<key> python run.py agent <key> --message "first draft" --user-id <supabase_user_id>
This exercises the same code path that Celery workers use. Fix any issues before moving on.
7. Checklist before publishing
- Manifest is complete (branding, tools, env vars, version).
- Unit/integration tests pass.
- CLI smoke test succeeds.
- Generated files are registered via
generated_media_registryif applicable. - Logging goes through
app.logger.logor structured logging (no strayprint).
Once you’re confident, head to Publishing tmates to package and distribute your creation.