Ctrl K
ComunidadGuías…

docs/adding_features.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Adding a feature

Four shapes of change, and each one has a worked example somewhere else. This page
is the map: what a change of that shape has to touch, and where the long version
lives.

## Adding a new API endpoint

!!! abstract "One walkthrough, in the Guides"

    [Add an API endpoint](howto/add-api-endpoint.md) is the worked
    example — schema, model, repository, service, dependency, route, router,
    migration, tests. There is deliberately no second copy of it here: two
    copies written for the same reader are two copies that disagree.

The shape it teaches, in one paragraph: a **schema** per operation
(`*Create`/`*Update`/`*Read`/`*List`), a **model** on `Base, TimestampMixin`
with a `__repr__`, a **repository** of stateless functions using
`flush()`/`refresh()` and never `commit()`, a **service** holding only the
session and raising domain exceptions, an `Annotated` **dependency** in
`api/deps.py`, and a **route** returning `-> Any` with `response_model` doing the
serialization.

## Adding a custom CLI command

Commands are auto-discovered from `app/commands/`.

```python
# app/commands/my_command.py
import click

from app.commands import command, success


@command("my-command", help="What this does")
@click.option("--name", "-n", required=True, help="Whose name")
def my_command(name: str) -> None:
    """One line, because `--help` prints it."""
    success(f"Done: {name}")
```

`success`, `error`, `warning` and `info` are the output helpers — a command says
what happened through those rather than through `print`, so every command in the
CLI reads the same way. Run it with:

```bash
uv run agenticos cmd my-command --name test
```

!!! note "A new command owes `docs/commands.md` a row"

    That page is the reference an operator reads; a command absent from it is a
    command nobody finds.

## Adding a tool the agent can call

There is no single agent module to hang a `@agent.tool` on. Agents here are data,
assembled per run from the capabilities their spec names, so a new tool arrives as
part of a **capability**:

- A new one → [Add a capability](howto/add-capability.md).
- One more tool on a capability that already exists →
  [Adding a tool to an existing capability](howto/add-capability.md#adding-a-tool-to-an-existing-capability).
- A third-party API that already publishes an MCP server → no code at all, see
  [MCP](mcp.md).

!!! danger "A tool the registry does not declare cannot be gated or renamed"

    The list in `@register(tools=...)` is what per-tool approval and per-agent
    renaming key on. An undeclared tool still runs — it just runs ungated, which
    is the failure worth avoiding.

What ships today is in the [capability catalog](reference/capabilities.md).

## Adding a database migration

!!! warning "`make db-check` skips itself when no database is listening"

    `alembic check` needs one, so the target prints a warning and **exits 0**
    without a database on `CHECK_DB_PORT` — a model change with no migration then
    passes local `make check`. CI's **`test`** job has a Postgres beside it and so
    does not skip, which is where that mistake is actually caught. Run
    `make docker-db` first if you want the local answer.

!!! tip "Autogenerate is a draft, not an answer"

    Read the revision before committing it, and give it a downgrade that actually
    reverses it — `make test-migrations` cycles the whole chain both ways.

```bash
# Create migration
uv run alembic revision --autogenerate -m "Add notifications table"

# Apply migration
uv run alembic upgrade head

# Or use CLI
uv run agenticos db migrate -m "Add notifications table"
uv run agenticos db upgrade
```