Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions agents/agent1/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Minimal container for agent1 installed from a wheel
FROM python:3.12-slim AS builder

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

WORKDIR /app

# Install build tooling (flit via build) and any system deps if needed
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir build

# Copy project files (include LICENSE for flit license-files) and build wheel
COPY pyproject.toml README.md LICENSE ./
COPY src ./src
RUN python -m build --wheel --outdir /tmp/wheels

FROM python:3.12-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

WORKDIR /app

RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# Install agent1 from the built wheel
COPY --from=builder /tmp/wheels /tmp/wheels
RUN pip install --no-cache-dir /tmp/wheels/*.whl

# Default command; override with args
CMD ["agent1", "World"]
44 changes: 31 additions & 13 deletions agents/agent1/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
# agent1

Example agent built from the python-agent-template. Use this as a starting point and replace the description/code with your own agent.
Example agent built from the python-agent-template. Use this as a starting point and replace the description/code with your own agent. For a fuller walkthrough template, see [docs/agent-guide-template.md](../../docs/agent-guide-template.md).

## Quickstart
- From the repo root, set up once: `uv run poe setup` (creates/refreshes `.venv`, installs deps, installs pre-commit hooks).
- Full validation (all agents): `uv run poe check`.
- Faster, agent-scoped runs (from repo root):
- `uv run poe -C agents/agent1 fmt`
- `uv run poe -C agents/agent1 lint`
- `uv run poe -C agents/agent1 pyright`
- `uv run poe -C agents/agent1 mypy`
- `uv run poe -C agents/agent1 bandit`
- `uv run poe -C agents/agent1 test`
- To run only on agents changed by your branch: `python scripts/run_tasks_in_changed_agents.py <task>`
## Quickstart (typical flow)
- Setup (repo root): `uv run poe setup` (creates/refreshes `.venv`, installs deps, hooks).
- Change into the agent: `cd agents/agent1`.
- Run the agent: `uv run agent1 Alice --greeting hello`.
- Run full checks for this agent: `uv run poe check` (from `agents/agent1`).
- Optional: switch back to root for repo-wide checks: `cd ../.. && uv run poe check`.

## Common dev tasks (agent-scoped)
- Format: `uv run poe fmt`
- Lint: `uv run poe lint`
- Type check: `uv run poe pyright` / `uv run poe mypy`
- Security scan: `uv run poe bandit`
- Tests: `uv run poe test`

## Run from repo root (alternative)
- Run the agent without `cd`: `uv run -C agents/agent1 agent1 Alice --greeting hello`.
- Agent checks from root: `uv run -C agents/agent1 poe check`.
- Repo-wide checks: `uv run poe check`.

## Build the image (wheel-based)
- Build the container (from `agents/agent1`): `docker build -t agent1:latest .`.
- Run the container: `docker run --rm agent1:latest agent1 Bob` (override args as needed).

## Publish the package to GitHub Packages
- Configure env vars for publishing:
- `export UV_PUBLISH_URL=https://pypi.pkg.github.com/<owner>`
- `export UV_PUBLISH_TOKEN=<ghp_or_fine_grained_token_with_package_write>`
- Publish from the agent dir (`agents/agent1`): `uv run poe publish` (uploads the built wheel/sdist). From repo root use `uv run -C agents/agent1 poe publish`.
- Package namespace: `python_agent_template.agents.agent1` uses a namespace root without `__init__.py` so multiple agents can coexist (PyPA guidance: https://packaging.python.org/en/latest/guides/packaging-namespace-packages/).

## Anatomy
- `src/agent1/agent.py` — agent implementation.
- `src/python_agent_template/agents/agent1/agent.py` — agent implementation.
- `tests/` — unit tests; extend with PyTest.
11 changes: 7 additions & 4 deletions agents/agent1/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ classifiers = [
]

[project.scripts]
agent1 = "agent1.__main__:main"
agent1 = "python_agent_template.agents.agent1.__main__:main"

[tool.uv]
package = true
Expand Down Expand Up @@ -70,7 +70,7 @@ no_implicit_optional = true
show_error_codes = true

[tool.bandit]
targets = ["src/agent1"]
targets = ["src/python_agent_template/agents/agent1"]
exclude_dirs = ["tests"]

[tool.poe]
Expand All @@ -79,10 +79,13 @@ include = "../../shared_tasks.toml"

[tool.poe.tasks]
# Project-specific overrides to scope checks/coverage to this agent; shared tasks remain available for cross-agent runs
bandit = "uv run bandit -c pyproject.toml -r src/agent1"
bandit = "uv run bandit -c pyproject.toml -r src/python_agent_template/agents/agent1"
mypy = "uv run mypy --config-file $POE_ROOT/pyproject.toml src"
test = "uv run pytest --cov=agent1 --cov-report=term-missing:skip-covered"
test = "uv run pytest --cov=python_agent_template.agents.agent1 --cov-report=term-missing:skip-covered"

[build-system]
requires = ["flit-core>=3.12.0,<4"]
build-backend = "flit_core.buildapi"

[tool.flit.module]
name = "python_agent_template.agents.agent1"
3 changes: 0 additions & 3 deletions agents/agent1/src/__init__.py

This file was deleted.

26 changes: 0 additions & 26 deletions agents/agent1/src/agent.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import argparse
import logging

from agent1.agent import AgentConfig, ExampleAgent
from python_agent_template.agents.agent1.agent import AgentConfig, ExampleAgent

logger = logging.getLogger(__name__)

Expand Down
4 changes: 2 additions & 2 deletions agents/agent1/tests/test_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import pytest

from agent1 import AgentConfig, ExampleAgent
from agent1.agent import MissingNameError
from python_agent_template.agents.agent1 import AgentConfig, ExampleAgent
from python_agent_template.agents.agent1.agent import MissingNameError


def test_run_greets_name() -> None:
Expand Down
86 changes: 86 additions & 0 deletions docs/agent-guide-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Agent Guide Template

Use this as a blueprint when creating or maintaining any agent in this monorepo. Replace `<agent>` with your agent’s name.

## Principles and conventions
- Isolated per-agent projects under `agents/<agent>` to avoid dependency/release coupling.
- `src/` layout to force imports from the installed package and catch packaging/import issues early.
- Namespace per project: `python_agent_template.agents.<agent>` with namespace packages (no `__init__.py` at the namespace roots) per PyPA guidance: https://packaging.python.org/en/latest/guides/packaging-namespace-packages/
- Wheel-first images: build a wheel and install it in the runtime image for reproducibility and smaller layers.
- Tasks via `uv run` + `poe` for consistent env management.

## Structure (replace `<agent>`)
```
agents/<agent>/
├─ Dockerfile # wheel-based image build
├─ LICENSE # agent-specific license (included in wheel/sdist)
├─ README.md # quickstart and usage
├─ pyproject.toml # agent metadata, tasks, tooling config, script entrypoint
├─ src/
│ └─ python_agent_template/
│ └─ agents/
│ └─ <agent>/
│ ├─ __init__.py # exports
│ ├─ __main__.py # CLI entrypoint
│ └─ agent.py # core logic
└─ tests/
└─ test_agent.py # unit tests for agent logic
```

## Creating a new agent (recipe)
1) Copy `agents/agent1` to `agents/<agent>`.
2) Rename package path under `src/python_agent_template/agents/<agent>`; update imports.
3) Update `pyproject.toml`: project name/description/URLs, script entrypoint, `tool.flit.module = "python_agent_template.agents.<agent>"`, bandit target, coverage target.
4) Adjust Dockerfile tags/paths if needed.
5) Update README for the new agent with run/build/publish instructions.
6) Run `uv run poe check` inside `agents/<agent>`; optionally run `uv run poe check` from root.

## Daily workflow
1) Setup once (root): `uv run poe setup`.
2) Work inside the agent: `cd agents/<agent>`.
3) Run the CLI: `uv run <agent> Alice --greeting hello` (or from root with `uv run -C agents/<agent> ...`).
4) Run agent checks: `uv run poe check`.
5) Before publishing or merging, optionally run repo-wide checks from root: `uv run poe check`.

## Tasks (agent-scoped)
- `poe fmt` — ruff format
- `poe lint` — ruff lint
- `poe pyright` — strict pyright
- `poe mypy` — strict mypy
- `poe bandit` — security scan on agent code
- `poe test` — pytest with coverage
- `poe check` — bundle of the above
Run with `uv run poe <task>` from `agents/<agent>`, or `uv run -C agents/<agent> poe <task>` from root.

## Running the agent
- From agent dir: `uv run <agent> Alice --greeting hello`
- From root: `uv run -C agents/<agent> <agent> Alice --greeting hello`

## Testing and coverage
- Unit tests: `uv run poe test`
- The CLI guard `if __name__ == "__main__":` is often marked `# pragma: no cover` because it only runs as a script; add a CLI test and drop the pragma if you want it counted.

## Lint, types, security
- Format then lint: `uv run poe fmt` and `uv run poe lint`
- Types: `uv run poe pyright` and `uv run poe mypy`
- Security: `uv run poe bandit`

## Build the container (wheel-based)
- Build: `docker build -t <agent>:latest .`
- Run: `docker run --rm <agent>:latest <agent> Bob`
- Rationale: builder stage creates a wheel; runtime installs the wheel for reproducibility and a smaller attack surface.

## Publish to GitHub Packages
- Set:
- `export UV_PUBLISH_URL=https://pypi.pkg.github.com/<owner>`
- `export UV_PUBLISH_TOKEN=<token_with_package_write>`
- From agent dir: `uv run poe publish` (uploads wheel/sdist for this agent), or from root: `uv run -C agents/<agent> poe publish`.

## What lives where
- Agent-level (agents/<agent>): code, tests, Dockerfile, agent-specific tasks/config, LICENSE, README, built artifacts.
- Project-level (root): shared tasks, root `pyproject.toml`, shared scripts (`scripts/`), CI, global lint/type/test settings.

## Troubleshooting
- uv missing: install via `curl -LsSf https://astral.sh/uv/install.sh | sh`.
- Publish auth errors: confirm `UV_PUBLISH_TOKEN` and `UV_PUBLISH_URL` point to your owner.
- Import errors: use `uv run ...` and correct cwd (`agents/<agent>` or `-C agents/<agent>`).
7 changes: 5 additions & 2 deletions shared_tasks.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ lint = "ruff check"
pyright = "pyright"
bandit = "sh -c 'ROOT=$(git -C \"$POE_ROOT\" rev-parse --show-toplevel); uv run bandit -c \"$ROOT/pyproject.toml\" -r \"$ROOT/agents\" \"$ROOT/scripts\"'"

# publish builds and uploads the package to the configured index (e.g., GitHub Packages)
publish = "uv publish"

# repo/agent check bundle; when run with -C agents/<name>, scopes to that agent
check = ["fmt", "lint", "pyright", "mypy", "bandit", "test"]

clean-dist = "rm -rf dist"
build-package = "uv build"
move-dist = "sh -c 'mkdir -p ../../dist && mv dist/* ../../dist/ 2>/dev/null || true'"
build = ["build-package", "move-dist"]
build = ["build-package"]
Loading