Ir al contenido

Extending Chimera

Esta página todavía no está traducida, así que estás leyendo el original en inglés.

Chimera is built to be extended. This guide shows the four ways to teach it something new — a tool, a skill, a recipe, or an external integration — each with a complete, copy-pasteable example. No deep knowledge of the codebase required.

New to the project first? Read the Usage Guide and the Architecture overview. Ready to send a change? See CONTRIBUTING.md.

I want to… Add a… Where
Give the agent a new action (call an API, run a computation, touch a device) Tool chimera/tools/
Package a reusable procedure/prompt the agent can reuse and improve Skill chimera/skills/builtin/
Automate a multi-step routine described in a file Recipe (workflow YAML) examples/
Plug in an existing external tool/server without forking MCP server mcp.md

1. Add a tool

A tool is a single action the agent can take. Subclass Tool, set three attributes, and implement run — which always returns a string (never raises; report problems as "error: …"). That's the whole contract.

# chimera/tools/weather.py
from __future__ import annotations

from typing import Any

from chimera.tools.base import Tool


class WeatherTool(Tool):
    name = "weather"
    description = "Get the current temperature for a city (demo tool)."
    parameters = {
        "type": "object",
        "properties": {
            "city": {"type": "string", "description": "City name, e.g. 'Lisbon'."},
        },
        "required": ["city"],
    }

    def run(self, **kwargs: Any) -> str:
        import httpx  # lazy import: keep tool construction cheap

        city = str(kwargs["city"]).strip()
        if not city:
            return "error: 'city' is required"
        try:
            geo = httpx.get(
                "https://geocoding-api.open-meteo.com/v1/search",
                params={"name": city, "count": 1}, timeout=15,
            ).json()
            if not geo.get("results"):
                return f"error: city not found: {city}"
            lat, lon = geo["results"][0]["latitude"], geo["results"][0]["longitude"]
            wx = httpx.get(
                "https://api.open-meteo.com/v1/forecast",
                params={"latitude": lat, "longitude": lon, "current": "temperature_2m"},
                timeout=15,
            ).json()
            return f"{city}: {wx['current']['temperature_2m']}°C"
        except (httpx.HTTPError, KeyError, ValueError) as exc:
            return f"error: weather lookup failed: {exc}"

Register it so the agent can use it — add one line in default_registry (chimera/tools/builtin.py):

from chimera.tools.weather import WeatherTool
registry.register(WeatherTool())

Test it (no network — Chimera tests are hermetic; mock the boundary):

# tests/test_weather_tool.py
from chimera.tools.weather import WeatherTool

def test_weather_requires_city():
    assert WeatherTool().run(city="  ").startswith("error:")

Conventions that keep a tool mergeable:

  • run returns a string and never raises — wrap I/O in try/except and return "error: …".
  • Lazy-import heavy dependencies inside run, not at module top.
  • Keep secrets out of code — read them from the environment (see chimera/config.py).
  • If the tool reads untrusted content (web pages, files), it's automatically data-fenced and taint-tracked when run under --taint; don't reinvent that (see security.md).

2. Add a skill

A skill is a reusable, model-backed procedure — the "augmented tool" tier the agent surfaces by relevance and the evolution engine later refines. Subclass LLMSkill, set name / description / version, and return a SkillResult.

# chimera/skills/builtin/naming_skills.py
from __future__ import annotations

from typing import Any

from chimera.skills.base import SkillResult
from chimera.skills.llm_skill import LLMSkill


class NameThingSkill(LLMSkill):
    """Suggest short, memorable names for a project or product."""

    name = "name_thing"
    description = "Suggest 5 short, brandable names for a described project."
    version = "0.1.0"

    def run(self, **kwargs: Any) -> SkillResult:
        about = kwargs.get("about")
        if not isinstance(about, str) or not about.strip():
            return SkillResult(ok=False, error="missing required string 'about'")
        system = "You name things. Reply with exactly 5 short names, one per line, no numbering."
        text = self.ask(system=system, user=about)   # LLMSkill helper: one model call
        return SkillResult(ok=True, output=text)

Register it in chimera/skills/builtin/__init__.py (follow the existing pattern there). Skills carry usage metrics and a lifecycle (provisional → active → retired) driven by measured success — see chimera/evolution/ — so a skill that stops helping is demoted automatically, never by guesswork.

Tool vs skill? A tool does something deterministic (an API call, a file edit). A skill is a prompted procedure that uses the model. Pick a tool for actions with side effects; a skill for reusable reasoning/generation.


3. Add a recipe (workflow)

A recipe automates a multi-step routine without any code — a YAML file the agent runs with chimera workflow. Great for scheduled jobs. See real ones in examples/ (email triage, morning brief, repo watchdog).

Each step uses a capability of the agent stack (run, solve, crew, …); when: prev_succeeded gates a step on the previous one, and repeat + until: success retry a step.

# my_flow.yaml — build a small module, then write a changelog only if it built
name: build-and-report
steps:
  - name: build
    uses: solve
    with:
      task: "Create greeting.py with greet(name) returning 'Hello, ' + name."
      verify: "python -c \"import greeting; assert greeting.greet('x') == 'Hello, x'\""
    repeat: 2
    until: success
  - name: report
    uses: run
    when: prev_succeeded
    with:
      prompt: "Write a one-line changelog entry for adding greeting.greet()."
chimera workflow my_flow.yaml
# schedule it to run every morning at 8:
chimera cron add digest "0 8 * * *" "chimera workflow my_flow.yaml"

4. Connect an external tool (MCP)

To use a tool that already exists — a database server, a SaaS integration, someone else's toolkit — you don't fork Chimera. Point it at any MCP server and its tools appear alongside the native ones. Full guide + a runnable example: mcp.md. Chimera can also be an MCP server (chimera serve --mcp), so other agents can use its tools.


Before you open a PR

Run the same gate CI runs — it must be green:

uv run --no-sync ruff check .          # style + lint
uv run --no-sync mypy chimera          # types (strict)
uv run --no-sync pytest -q             # tests (hermetic: no network)

Add a test for anything you add, keep run returning strings (tools) or SkillResult (skills), and describe what / why / how to test in the PR. Honest, measured changes are the bar — if a change claims an improvement, show the number. Thank you for making Chimera better. 🧬

Editar esta página en GitHub