Security-first template for building and shipping multiple Python agents from one monorepo, derived from the Microsoft Agent Framework. It aims to give newcomers a ready-to-run, batteries-included starting point with guardrails (typing, linting, security, CI, releases) that you can adapt to your org’s standards.
Disclaimer: This template is based on the Microsoft Agent Framework and provided for learning/acceleration. Evaluate and adapt to your organization’s security, compliance, and coding standards before production use.
- uv + poe: fast installs and repeatable task runner (fmt/lint/types/tests/bandit).
- Ruff, Pyright, MyPy, Bandit, PyTest, markdown code fence lint: code quality and security guardrails.
- Task fan-out scripts: run tasks across all agents or only changed agents to keep CI fast.
- Security automation: CodeQL scanning and Dependabot for updates; good hygiene baseline.
- Docs generation: experimental py2docfx workflow (disabled by default) to emit docfx YAML.
- Licensing: each agent can ship its own LICENSE for package publication.
- Python 3.10–3.13 installed locally (3.13 default for
poe setup). - curl available to install uv, or install uv via your package manager:
curl -LsSf https://astral.sh/uv/install.sh | sh. - Git for cloning and hooks.
- Install uv:
curl -LsSf https://astral.sh/uv/install.sh | sh - Install dev deps (workspace-wide):
uv run poe setup - Run full quality gate:
uv run poe check
poe setup creates/refreshes .venv, installs all dev dependencies with uv, and installs pre-commit hooks so staged changes get checked automatically.
Local setup quickstart: clone the repo, ensure Python 3.10–3.13 is installed, run uv run poe setup to create/refresh .venv and install hooks, then uv run poe check to validate the workspace. For speed, python scripts/run_tasks_in_changed_agents.py <task> narrows lint/type/test to modified agents.
poe check(full suite, repo-wide):- Ruff format (
fmt), Ruff lint (lint), Pyright, MyPy, Bandit, PyTest, Markdown code fence lint. - Runs across all agents. Use for CI and pre-merge confidence; catches issues outside your current diff.
- Ruff format (
- Pre-commit hooks (fast, staged-only):
- Ruff format+lint, scoped MyPy, Bandit (via hook), trailing whitespace/EOF fixers, markdown fence checks on staged files.
- Purpose: keep diffs clean and reduce CI churn. Because it only sees staged files, it is fast but not a substitute for
poe check.
Why staged-only for pre-commit: speed and focus on what you are changing. Why still run full checks in CI: to catch regressions in untouched files, ensure type/safety coverage repo-wide, and validate tests end-to-end.
- Install once per clone:
uv run poe pre-commit-install(adds hooks to.git/hooks). - Run manually on all files:
uv run pre-commit run --all-files(useful before large refactors or in CI if desired). - Hook set (from
.pre-commit-config.yaml): Ruff format + Ruff lint, MyPy (scoped), Bandit, trailing-whitespace/EOF fixers, markdown fenced-code checker, config validators, uv lock refresher. - If you must skip briefly, prefer
SKIP=hookname pre-commit runinstead of disabling globally.
Check (repo-wide poe check):
flowchart LR
A[poe check] --> B[Ruff format]
B --> C[Ruff lint]
C --> D[Pyright]
D --> E[MyPy]
E --> F[Bandit]
F --> G[PyTest + coverage]
G --> H[Markdown code fence lint]
Pre-commit check task (poe pre-commit-check, staged-aware):
flowchart LR
P[poe pre-commit-check] --> P1[Ruff format]
P1 --> P2[Ruff lint]
P2 --> P3[Pyright staged]
P3 --> P4[Markdown code fence lint]
Pre-commit hook pipeline (on git commit):
flowchart LR
C[git commit] --> H1[pre-commit framework]
H1 --> H2[Whitespace/EOF/line endings]
H2 --> H3[Config checks YAML/TOML/JSON]
H3 --> H4[pyupgrade]
H4 --> H5[Ruff format + Ruff lint]
H5 --> H6[MyPy scoped]
H6 --> H7[Bandit]
H7 --> H8[Markdown fence check]
H8 --> H9[nbQA notebook parse]
H9 --> H10[uv-lock update if manifests change]
agents/— each agent as a package (e.g.,agent1/).scripts/— task fan-out and helper scripts (e.g., run tasks across agents, check markdown code blocks)..github/workflows/— CI (checks, release, CodeQL) and automation..pre-commit-config.yaml— local hook definitions.pyproject.toml— shared config for uv, ruff, mypy, pyright, bandit, poe tasks.docs/— output/placeholder; doc generation is experimental.
Scripts explained (scripts/)
run_tasks_in_agents_if_exists.py: runs a given task (fmt/lint/pyright/mypy/bandit/test) in every agent that defines it, sopoe checkcan fan out safely even if some agents lack tasks.run_tasks_in_changed_agents.py: detects which agents changed relative to the target branch and runs the requested task only there; use for fast local/PR lint/type passes.check_md_code_blocks.py: validates fenced code blocks in README files; helps keep docs runnable.
Task catalog (root poe tasks)
poe setup: create/refresh.venv, install deps, install pre-commit hooks (usespoe venv,install,pre-commit-install).poe venv:uv venv --clear --python <version>; default 3.13, override with-p/--python.poe install:uv sync --all-extras --dev(docs group excluded by default).poe pre-commit-install: install and refresh hooks.poe fmt: Ruff format.poe lint: Ruff lint.poe pyright: strict Pyright.poe mypy: strict MyPy.poe bandit: Bandit security scan (fans out to agents + scripts).poe bandit-agents: Bandit against all agents (fan-out viarun_tasks_in_agents_if_exists).poe bandit-scripts: Bandit against thescripts/tree.poe test: PyTest + coverage.poe markdown-code-lint: fenced-code checks in READMEs.poe check: bundle that runs fmt, lint, pyright, mypy, bandit, test, markdown-code-lint.
Bundled task contents (what runs where)
poe setup: (1) create/refresh.venv, (2)uv sync --all-extras --dev, (3) install pre-commit hooks. Use once per clone or after Python version changes.poe check: Ruff format → Ruff lint → Pyright → MyPy → Bandit → PyTest + coverage → markdown code fence lint. Use before merge/CI to cover the full workspace.- Pre-commit hook run (staged files only): Ruff format + Ruff lint, scoped MyPy, trailing-whitespace/EOF fixes, markdown fence checks; install with
uv run poe pre-commit-install. Fast hygiene, not a replacement forpoe check.
- Ruff
- Format: Black-like formatter, import sorting; keeps 120-col width and normalizes strings/spacing.
- Lint (selected families): pycodestyle E/W, pyflakes F (unused imports/vars, undefined names), bugbear B (risky patterns), pyupgrade UP (modern syntax), pylint PLC/PLE/PLR/PLW (naming, refactors, errors, warnings), Bandit S (security), pytest PT, return rules RET, async ASYNC, datetime TZ, string concat ISC, simplify SIM, quotes Q, exceptions TRY, todo TD/FIX, naming N, docstyle D (Google convention), import conventions ICN/I, pydantic guards PGH, debugger T100.
- Per-file relaxations: tests allow assert-raises constant (
S101) and magic numbers (PLR2004); notebooks skip copyright and long-line checks.
- Pyright (strict)
- Coverage:
agentsandscripts, strict mode, unused imports reported; tests and venv paths excluded. - Catches: incorrect call signatures, bad attribute access, incompatible unions/Optionals, missing/invalid imports, unreachable code, mismatched overloads, missing type annotations, and unsafe narrowing; includes
scriptsviaextraPathsso helper scripts must stay typed.
- Coverage:
- MyPy (strict)
- Coverage:
agentsandscripts, strict + pydantic plugin; disallow untyped defs/decorators, no implicit Optional, warn on return Any, show error codes. - Catches: type mismatches, Optional misuse, protocol/interface violations, missing annotations, decorator typing gaps; pydantic plugin enforces typed fields and forbid-extra in init.
- Coverage:
Tip: Run poe lint/poe pyright/poe mypy individually during development; poe check runs them all before tests and docs lint.
- Copy
agents/agent1toagents/<your-agent>. - Update metadata in
agents/<your-agent>/pyproject.toml(name, description, URLs, deps). - Implement your code under
src/<your_agent>/and extendtests/. - If you will publish the agent, place a
LICENSEfile in the agent directory and uselicense-files = ["LICENSE"]so wheels/sdists include it. - Run
uv run poe check.
- Create fresh env and install:
uv run poe setup(runspoe venv→uv sync→ pre-commit install). Default python is 3.13; override with-p/--python. - Manual fallback if needed:
uv venv --python 3.13 && uv sync --all-extras --dev. - Clean everything: remove
.venvand caches withrm -rf .venv .pytest_cache .ruff_cache .mypy_cache __pycache__ agents/**/{.pytest_cache,.ruff_cache,.mypy_cache,__pycache__}.
- Scripts use py2docfx to emit docfx YAML into
docs/. The docs tasks are commented out by default; install docs deps withuv sync --group docsif you want to experiment. Expect rough edges.
Local + CI (from pyproject.toml and .pre-commit-config.yaml)
| Tool / service | Where it runs | What it does | Why it matters | Docs |
|---|---|---|---|---|
| uv | Local + CI | Fast Python installer/resolver and executor for reproducible envs and tasks. | Keeps dependency installs deterministic and quick, so developers actually run checks. | uv docs |
| Poe the Poet | Local + CI | Task runner that fans commands to all agents and provides poe check/poe pre-commit-check. |
One entry point for fmt/lint/types/tests/security, reducing configuration drift. | Poe docs |
| Ruff (format + lint) | Local, pre-commit, CI | Auto-formats and lints Python/imports/docstrings; flags dead code, unsafe patterns, and some security issues. | Removes style noise from reviews and catches correctness issues early. | Ruff docs |
| Pyright (strict) | Local + CI | Fast static type checker with precise inference. | Prevents type regressions and interface drift; great developer ergonomics. | Pyright docs |
| MyPy (strict) | Local + CI (scoped in pre-commit) | Second static type checker with a different inference engine and plugin support (pydantic). | Adds coverage where Pyright differs; reduces blind spots by double-checking types. | MyPy docs |
| Bandit | Local, pre-commit, CI | Security static analysis for Python. | Flags risky calls (eval, weak crypto, subprocess misuse) before merge. | Bandit docs |
| PyTest + pytest-cov | Local + CI | Runs tests with coverage reporting. | Proves behavior still works; coverage highlights untested risk. | PyTest, pytest-cov |
| Markdown code fence lint | Local + CI | Checks fenced code blocks in project READMEs. | Prevents broken snippets and docs drift. | scripts/check_md_code_blocks.py |
| pre-commit framework | Local | Runs the hook set on staged files. | Automates hygiene (format, lint, security) before commits land. | pre-commit docs |
| pre-commit-hooks bundle | Local | Trims whitespace, fixes EOF, normalizes newlines, validates YAML/TOML/JSON, AST checks, forbids debug statements. | Removes common footguns and keeps config files valid. | pre-commit-hooks |
| pyupgrade hook | Local | Rewrites Python syntax to modern 3.10+. | Eliminates legacy syntax and aligns with supported versions. | pyupgrade |
| nbQA hook | Local | Validates notebook cells parse as Python. | Stops broken notebooks from entering the repo. | nbQA docs |
| uv-lock hook | Local | Refreshes uv.lock when pyproject.toml changes. |
Ensures lockfile matches manifests, preventing supply-chain drift. | uv-pre-commit |
| Poe pre-commit-check hook | Local | Runs diff-aware fmt/lint/pyright/markdown checks via Poe. | Fast, staged-only guardrail that mirrors CI styling and type rules. | pyproject.toml |
Why both Pyright and MyPy: they use different inference engines and plugin ecosystems, so running both raises signal and lowers the chance of missing type errors.
GitHub-hosted automation (security and updates)
| Service | What it does | Why it matters | Docs |
|---|---|---|---|
| CodeQL Analysis | Code scanning for Python and GitHub Actions code. | Finds dataflow and security issues beyond linters/typing. | CodeQL docs |
| Dependabot | Weekly updates for pip/uv dependencies and GitHub Actions. | Shrinks vulnerability exposure windows and keeps CI runners current. | Dependabot docs |
- Dependabot: keeps pip/uv and GitHub Actions up to date. Alternatives: Renovate, Snyk, Mend. Important to run some updater to shrink vulnerability exposure windows.
- CodeQL: SAST/code scanning for Python and GitHub Actions. Alternatives: semgrep, commercial SAST. Important to have at least one scanner in place.
- Branch protection/rulesets and auto-fix: enforce required checks, signed commits, and allow trusted bots (e.g., Dependabot) to auto-merge with autofix where policy allows.
- Ruff copyright enforcement is available but disabled. If your org requires it, enable the
flake8-copyrightblock inpyproject.tomland add headers. Leave it off to avoid breaking contributions until ready.