Extend an Agent
Coding-agent workflow — a
/slash-commandyour coding agent (Claude Code, Codex, …) runs while developing this repo. Not a runtime skill the deployed @context agent runs; those live inskills/.
You are recursively extending a target agent with the user in the driver's seat. Each iteration: the user names a change, you implement it with an Agno-aware eye (using the agno-docs MCP for any toolkit / API research), the change is verified against the live agent, then you ask if there's more to do. Stop when the user says they're done.
This is the user-driven half of the iteration loop. The autonomous half lives in the improve-agent skill — Claude derives probes from the agent's INSTRUCTIONS and hardens behavior with no user input. Use this skill to change the agent (add tools, add capabilities, refine the prompt, fix a known bug). Run improve-agent afterward to confirm nothing else regressed.
The platform is on http://localhost:8000 with hot-reload enabled (RUNTIME_ENV=dev), so edits to agents/<slug>.py are picked up by uvicorn within ~1s. Edits to app/main.py (e.g. registering a new sub-agent) require a container restart — Step 5 covers this.
0. Preconditions
Live container reachable:
curl -sSf http://localhost:8000/healthreturns 200. If not, ask the user todocker compose up -d --buildfirst. (docker compose psis unreliable from worktrees or alternate clones — trust the health probe.)Live container is bound to this checkout — otherwise hot-reload won't see your edits:
docker inspect context-api --format '{{range .Mounts}}{{.Source}}{{"\n"}}{{end}}' | grep -F "$(pwd)"Empty result = the container's
/appis bound to a different repo path. Eithercdto that repo or restart the container from this directory (docker compose down && docker compose up -d --build).Ask the user for the target agent slug (usually
context— the one registered agent).Recommend the user create a feature branch (
git checkout -b extend/<slug>-$(date +%Y%m%d)) so any wrong turns are easy to revert.
1. Read the agent first
Open agents/<slug>.py. Capture:
- Stated purpose — the file's docstring + the
INSTRUCTIONSstring. - Tools — what's wired and what each one does.
- Pattern — deterministic function tools registered straight on the agent (like the queue tools in
agents/inbox.py) or a context provider — a sub-agent behindquery_<id>/update_<id>tools, built by a_create_<id>_provider()factory inagents/sources.py. - Existing levers —
learning=(theLearningMachineand its store modes),num_history_runs,knowledge=, model id.
Restate the agent's purpose to the user in 1-2 sentences before asking what to change. This catches "I thought it did X but actually it does Y" upfront.
2. Ask what to improve
Use the AskUserQuestion tool with these branches (multi-select allowed if the user wants multiple changes in one pass — handle them sequentially in Steps 3-6, then loop):
- Add a tool — new MCP server, agno toolkit, or function tool.
- Add a capability — knowledge base (RAG), memory tweak, sub-agent / context provider, scheduled task.
- Refine instructions — clarify a rule, narrow scope, change tone, change format.
- Fix a bug — user has a specific failing prompt or wrong behavior in mind.
- Something else — free-form; let the user describe.
If the user picked "Fix a bug" or "Something else," ask a follow-up free-form question for the specifics (the failing prompt, the observed behavior, what they want instead).
3. Ground the change in agno docs
For any change touching agno surface area — toolkit imports, knowledge config, memory flags, scheduler, sub-agent patterns — search the agno-docs MCP (configured in .mcp.json) before writing code. Fall back to fetching https://docs.agno.com/llms.txt only if the MCP is unavailable.
What to capture per branch (stacking multiple changes in one session? run the agno-docs lookups in parallel):
- Add a tool — import path (e.g.
from agno.tools.exa import ExaTools), constructor args that matter for this agent, required env vars, pip dependencies. The toolkit'sPrerequisitessection lists deps and auth. - Add a capability:
- Knowledge base — build an agno
Knowledgewith aPgVectorvector db (db_urlfromdb.url), pass viaknowledge=on the Agent. Document load step (.add_content_async()) goes wherever ingestion lives. - Memory / learning — the
learning=LearningMachine(...)on the Agent constructor (per-store configs andLearningModes — note the shared-scope storesentity_memory/learned_knowledge/decision_loginject context for every caller, so they must not be enabled on this agent; seedocs/SECURITY.md), plusadd_history_to_context,num_history_runs. Read agno's learning docs to pick the right store and mode. - Source / context provider — mirror a
_create_<id>_provider()factory inagents/sources.pyand add it tocreate_context_providers()(env-gated providers go through thetry/exceptloop). The main agent seesquery_<id>(andupdate_<id>if writable); the sub-agent does the work. - Scheduled task — see agno scheduler docs and the
scheduler=Trueline inapp/main.py.
- Knowledge base — build an agno
- Refine instructions — no docs needed. Read the current
INSTRUCTIONS, propose a minimal diff. Prefer narrowing ("on recent-events questions, follow up with aweb_fetch") over forbidding. - Fix a bug — first reproduce the failure on the live agent (see Step 6). Then identify the layer:
INSTRUCTIONS(most common), tool (wrong tool wired or missing), model (under-capable), env (rate limit, missing key, MCP unreachable).
Don't guess any of these. If the agno-docs MCP returns nothing for a name the user gave (e.g. an MCP server they want to wire), tell them; offer to use generic MCPTools(url=..., transport=...) and ask for the URL.
4. Propose, then edit
Before editing, tell the user in 2-3 lines what you're about to change and why. Get a quick "yes" — most missteps come from misunderstanding the ask, not bad code.
Then edit. Files in scope:
agents/<slug>.py— tools, model, memory flags, knowledge. (Forcontext, prompt text lives inagents/instructions.pyand providers inagents/sources.py.)app/main.py— only if registering a new sub-agent or changing interface wiring.app/config.yaml— add or update the agent'squick_promptsto exercise the new capability.pyproject.toml— only if a toolkit needs new pip deps.
Keep edits surgical. One change per iteration of this loop — if the user asked for three things, do them one at a time so each can be smoke-tested independently.
5. Reload
Edited only
agents/<slug>.py,app/config.yaml, or other files insideagents//app/— uvicorn picks it up in ~1s. No restart.Edited
app/main.py(registered a sub-agent, changed interfaces) — restart:docker compose restart context-apiAdded pip deps in
pyproject.toml— regenerate the lockfile and rebuild:./scripts/generate_requirements.sh docker compose up -d --build
After a restart or rebuild, poll /health until the API is back:
until curl -sSf http://localhost:8000/health > /dev/null; do sleep 0.5; done
For hot-reload, confirm the edit reached the container before smoke-testing:
docker exec context-api grep -c "<unique substring from your edit>" /app/agents/<slug>.py
0 means the file in the container hasn't changed — almost always a bind-mount mismatch. Step 0 catches this earlier.
6. Smoke test the change
Pick a prompt that exercises the change you just made. For "Add a tool," the prompt should force the new tool to fire. For "Fix a bug," reuse the failing prompt the user described. For "Refine instructions," pick a prompt the rule was meant to handle.
curl -sS -X POST http://localhost:8000/agents/<slug>/runs \
-F "message=<the targeted prompt>" \
-F "user_id=claude-extend-agent" \
-F "stream=false" \
-o /tmp/improve-out.json \
-w "HTTP %{http_code} in %{time_total}s\n"
jq -r '.content // .' < /tmp/improve-out.json
Read tool calls from the container logs to confirm the right tool fired:
docker logs context-api --since 30s 2>&1 | grep -E "Running: \w+\(" | head -40
(Running: <tool>( is the line shape agno emits per tool call when AGNO_DEBUG=True, which compose sets for dev.)
Show the user the response and the tool calls. Did the change land?
- Yes — go to Step 7.
- Almost — one more edit pass. Iterate at most 2-3 times before stopping and asking the user how they want to proceed (revert, try a different approach, accept and move on).
- No / made it worse — surface what happened. Offer to revert (
git checkout agents/<slug>.py) before trying again.
7. Loop or wrap up
Ask the user (free-form): "Anything else to improve, or are we done?"
- More to do — go back to Step 2.
- Done — Step 8.
The recursion is the point: each iteration is one small, verified change. Drift shows up faster when changes are small and tested in isolation.
8. Report
Summarize for the user:
- One line per accepted change (which lever, what changed).
git diff --statplus a shortgit diffblock for the agent file.- Suggested commit message —
feat(<slug>): <one-line>for new tools/capabilities,fix(<slug>): <one-line>for bug fixes,chore(<slug>): refine instructionsfor prompt-only edits. Combine if multiple types in one session. - Recommended next step — run the
improve-agentskill to autonomously verify the agent still does what itsINSTRUCTIONSsay it does. The change you just made widened the agent's surface area; the autonomous loop catches anything that regressed.
A simple change (one tool, one prompt refinement) takes 5-10 minutes. A capability addition (knowledge base, sub-agent) usually 15-30. The loop scales linearly with how many changes the user wants to stack into one session — keep them small and verifiable.
Worked example
Target: context. The user wants @context to also read their Google Drive.
Step 2 — user picks "Add a capability" (a new source / context provider).
Step 3 — search the agno-docs MCP for the gdrive context provider. Capture the import path, constructor args, required env vars / auth, and any pip deps.
Step 4 — propose: "Add an env-gated gdrive source: a _create_gdrive_provider() factory in agents/sources.py, wired through the try/except loop in create_context_providers() so a bad credential can't take the registry down. Document the env vars in example.env. Add a quick prompt that exercises it." User says yes.
Edit agents/sources.py (factory + registry — the provider exposes query_gdrive to the agent automatically; no change to context.py). Add the env vars to example.env. Add a quick prompt to app/config.yaml:
context:
- "What's in my Q3 planning doc?"
Step 5 — pip deps changed? ./scripts/generate_requirements.sh && docker compose up -d --build; otherwise hot-reload picks up agents/ edits in ~1s. Poll /health.
Step 6 — cURL the context agent with the quick prompt. Logs show Running: query_gdrive(. Response is grounded in the doc.
Step 7 — user says "no, that's it."
Step 8 — diff summary, commit feat(context): add gdrive source, recommend improve-agent to harden the broader behavior.
That's the loop. Most sessions are smaller — one tool, one rule, one bug.