| title | Contributing to TinyAgent | ||
|---|---|---|---|
| when_to_read |
|
||
| summary | Contributor guidance for working within TinyAgent's architecture, docs, and quality gates. | ||
| last_updated | 2026-04-04 |
TinyAgent is a small, typed, streaming-first agent framework for Python. This
repo also owns the in-repo Rust binding that backs the optional
tinyagent._alchemy runtime path.
Contributions here should keep the public Python contract coherent, preserve the enforced module boundaries, and stay aligned with the repo's blocking quality gates.
Read these before making non-trivial changes:
README.mdfor package overview, installation, and examplesdocs/ARCHITECTURE.mdfor module responsibilities, event flow, and debt policydocs/api/README.mdfor the API reference indexHARNESS.mdfor enforced hooks and release gatesdocs/releasing-alchemy-binding.mdfor wheel and binding release workflowtests/architecture/test_import_boundaries.pyfor the layer contract
Use the repo's existing uv workflow:
uv sync --group dev
uv run pre-commit installPython 3.10+ is required.
tinyagent/: published Python packagerust/: in-repo crate that builds the optionaltinyagent._alchemybindingtests/: unit, contract, release, and architecture testsdocs/: architecture, API reference, release notes, and harness docsdocs/harness/: live typed tool-call harness and harness-specific rulesscripts/: custom enforcement, release, and smoke-check toolingrules/: ast-grep rules used for harness enforcement
Key package modules:
tinyagent/agent.py: high-levelAgentAPI and state handlingtinyagent/agent_loop.py: orchestration looptinyagent/agent_tool_execution.py: concurrent tool executiontinyagent/agent_types.py: shared runtime models and event typestinyagent/alchemy_provider.py: adapter for the optional_alchemybindingtinyagent/rust_binding_provider.py: Rust binding provider integrationtinyagent/proxy.pyandtinyagent/proxy_event_handlers.py: proxy streaming pathtinyagent/caching.py: prompt caching helpers
The import graph is enforced in tests/architecture/test_import_boundaries.py.
Higher layers may depend on lower layers. The reverse is not allowed.
- Layer 3:
agent - Layer 2:
agent_loop,proxy - Layer 1:
agent_tool_execution,alchemy_provider,rust_binding_provider,proxy_event_handlers,caching - Layer 0:
agent_types
agent_types.py must remain the leaf module among governed TinyAgent modules.
If you add or rename a governed package module, update the layer test in the same change.
tinyagent/__init__.py is the package surface. Keep exports aligned with the
architecture linter and avoid expanding the root namespace casually.
Optional provider modules should be imported directly by callers when that is
the intended API. Do not bypass scripts/lint_architecture.py.
The repo is built around a few stable ideas:
- streaming-first LLM interactions
- event-driven execution and state updates
- typed runtime models at boundaries
- clear separation between internal agent messages and LLM-boundary messages
Prefer changes that reinforce those constraints rather than weakening them with special cases or implicit behavior.
The architecture linter blocks these patterns in library code:
- no
.envloading ordotenvimports insidetinyagent/ - no mutation of
os.environinside provider modules
Library code consumes configuration; it does not own process environment setup.
Free-form TODO, FIXME, HACK, XXX, and DEBT markers are not allowed.
If you need a debt marker in Python code, tie it to a real ticket in .tickets/
using the documented format from docs/ARCHITECTURE.md.
If a lesson keeps repeating, encode it in structure:
- tests
- scripts
- pre-commit hooks
- ast-grep rules
- import-boundary checks
HARNESS.md is critical repo infrastructure, not optional process commentary.
This repo is intentionally bringing the binding back in-tree. That changes where the code lives, not the Python-facing contract contributors should preserve.
When you touch binding-related code:
- keep the
tinyagent._alchemycontract stable unless a change is explicitly intended - prefer isolating Rust and wheel-packaging work from the core Python layer graph
- update
docs/releasing-alchemy-binding.md,HARNESS.md, and release checks if the binding build or packaging workflow changes
Update code, tests, and docs together when behavior changes.
- Public API changes: update
README.mdand the relevant files underdocs/api/ - Architecture or policy changes: update
docs/ARCHITECTURE.md - Release or wheel changes: update
docs/releasing-alchemy-binding.md - Harness changes: update
docs/harness/and rerun the harness-specific rules - Package surface changes: verify
tinyagent/__init__.pystill matches the intended public API and linter constraints
Do not leave docs trailing behind code changes in this repo.
Run the checks that match your change. The core blockers are:
uv run pytest
uv run mypy --ignore-missing-imports --exclude "lint_file_length\\.py$" .
python3 scripts/lint_architecture.py
.venv/bin/python -m pytest tests/architecture/test_import_boundaries.py -x -q
uv run vulture --min-confidence 80 tinyagent
uv run pylint --disable=all --enable=duplicate-code tinyagent
python3 scripts/lint_debt.pyUseful local workflow:
uv run pre-commit run --all-filesExtra checks for specific change types:
If you touch release or wheel logic:
python3 scripts/check_release_binding.py
python3 scripts/check_release_binding.py --require-present
python3 scripts/check_release_wheels.py distIf you touch docs/harness/:
uv run python docs/harness/tool_call_types_harness.py
sg scan -r rules/harness_no_duck_typing.yml docs/harness/
sg scan -r rules/harness_no_thin_protocols.yml docs/harness/If you build or publish wheels that are expected to ship the binding, the
release gate in HARNESS.md applies: stage the built _alchemy artifact into
tinyagent/ first, then run
python3 scripts/check_release_binding.py --require-present.
- Keep diffs focused and coherent
- Prefer deleting obsolete paths over adding compatibility layers
- Keep modules small enough to satisfy the file-length ceiling enforced under
tinyagent/ - Do not commit cache directories or empty package directories under
tinyagent/ - Add or update regression tests when fixing bugs or changing behavior
A good PR for this repo:
- explains the behavior change clearly
- names the checks you ran
- updates docs when the public contract changed
- avoids mixing unrelated cleanup with functional changes
If a rule matters enough to block future mistakes, do not stop at prose. Add or update the corresponding test, script, hook, or rule file in the same change.