# AGENTS

Single source of truth for coding-agent guidance in this repo.

## Project Basics

- Python: >=3.10 (use modern type hint syntax: `list[str]`, `str | None`).
- Formatting and linting: Ruff (line length 99).
- Commit style: Conventional Commits (`type(scope): summary`), enforced by hooks.

## Repo Layout

- `src/albert/collections/` — API-facing collection classes that call endpoints.
- `src/albert/resources/` — Pydantic models representing API resources.
- `src/albert/core/` — Session, pagination, shared enums, and base classes.
- `src/albert/utils/` — Reusable helper utilities.
- `docs/` — mkdocs content (autogenerated from docstrings via mkdocstrings).
- `tests/` — pytest suites, fixtures, and seed helpers.

## Coding Standards

- **Keep it simple.** Minimum code that solves the problem. No speculative abstractions, no configurability that wasn't asked for.
- **Follow existing patterns.** Check similar code before writing new code. Match style and structure.
- **Touch only what's needed.** Don't refactor adjacent code, improve unrelated formatting, or remove pre-existing dead code unless asked. Remove only imports/symbols that *your* changes made unused.
- **Validate at boundaries only.** Trust internal code and type hints. Only validate user input and external API responses.
- Collections inherit from `BaseCollection` and accept an `AlbertSession`.
- Public collection methods use `@validate_call` for runtime validation.
- Resources use `BaseAlbertModel`/`BaseResource` with Pydantic `Field` and aliases.
- Keep API payloads in wire format (camelCase) via `Field(alias=...)` and `model_dump(by_alias=True, mode="json", exclude_none=True)`.
- All new public methods and classes must have Numpy-style docstrings:

```python
def get_by_id(self, *, id: str) -> Cas:
    """Retrieve a CAS by ID.

    Parameters
    ----------
    id : str
        The CAS ID.

    Returns
    -------
    Cas
        The matching CAS object.
    """
```

## Pagination

Many list/search methods use `AlbertPaginator` (`src/albert/core/pagination.py`). Two modes:

- **Offset** (`PaginationMode.OFFSET`) — uses `offset` param, defaults to `limit=1000`, stops when `Items` is empty.
- **Key** (`PaginationMode.KEY`) — uses `startKey`, expects `lastKey` in response. Do not pass `limit` from the SDK; the backend controls page size.

Expose a `max_items` parameter on public list/search methods where appropriate to allow early stopping.

## Testing

- Tests use pytest (see tests/).
- Integration-style tests require environment variables:
  - ALBERT_CLIENT_ID_SDK
  - ALBERT_CLIENT_SECRET_SDK
  - ALBERT_BASE_URL
- Only add integration-style tests. Do not add unit tests that use `FakeAlbertSession`.
- Seed helpers live in `tests/seeding.py` and are reused across fixtures.
- Test docstrings should be crisp, start with "Test ...", and avoid implementation details.
- Required env vars: `ALBERT_CLIENT_ID_SDK`, `ALBERT_CLIENT_SECRET_SDK`, `ALBERT_BASE_URL`.
- Verify changes work by running the related tests — don't assume.

## Documentation

- When adding a new collection, add a docs page under `docs/collections/` and link it in `mkdocs.yml` (alphabetical in nav).
- When adding a new resource, add a docs page under `docs/resources/` and link it in `mkdocs.yml` (alphabetical in nav).
- Keep docstrings Numpy-style for all public APIs.
- Docstrings must describe **what** a method does from the caller's perspective — never mention internal implementation details or backend API specifics (e.g. diffing, patching, HTTP methods, "returned by the API").
  - Wrong: `"""Update an attachment by diffing the current server state."""`
  - Right: `"""Update an attachment."""`
  - Wrong: `The updated attachment returned by the API.`
  - Right: `The updated Attachment.`
- Every collection class docstring must include a `Methods` section listing all public methods:

```python
class TagCollection(BaseCollection):
    """
    TagCollection manages Tag entities in the Albert platform.

    Parameters
    ----------
    session : AlbertSession
        The Albert session instance.

    Attributes
    ----------
    base_path : str
        The base URL for tag API requests.

    Methods
    -------
    get_all(...) -> Iterator[Tag]
        Lists all tag entities with optional filters.
    get_by_id(id) -> Tag
        Retrieves a tag by its ID.
    create(tag) -> Tag
        Creates a new tag entity.
    delete(id) -> None
        Deletes a tag by its ID.
    """
```

## After Every Code Edit

```bash
uv run ruff format .
uv run ruff check . --fix
uv run pytest tests/<relevant_test_file>.py -v
```

Run the full suite (`uv run pytest`) if the change is broad.

## Commits & Releases

- Prefer multiple focused commits over one large commit.
- Use Conventional Commits: `feat(scope): summary`, `fix(scope): summary`, `chore(scope): summary`.
- Version is defined in `src/albert/__init__.py`. Releases are created by tagging and drafting a GitHub release.

Example commit:

```
feat(cas): add search by name support
```
