Contributing to AGENT-33
Thanks for taking the time to consider a contribution. AGENT-33 is an open multi-agent orchestration framework, and the project is at its best when it is shaped by the people who actually deploy and depend on it. This guide explains how to file an issue, propose a feature, and submit a change — whether that change is a one-line documentation fix or a new subsystem.
If anything below is unclear, open a discussion or a draft pull request and ask. We would rather help you land your first contribution than have you guess at our preferences and bounce off.
Project at a glance
AGENT-33 is a Python 3.11+ runtime engine (engine/) plus a Markdown-native
specification layer (core/) and a React/TypeScript control plane
(frontend/). The engine is FastAPI-based and depends on PostgreSQL with
pgvector, Redis, NATS, and an optional local LLM via Ollama. The project is
released under the Apache License 2.0.
The official repository is
github.com/mattmre/AGENT33-PUBLIC.
Container images are published to
ghcr.io/mattmre/agent33.
You can contribute in several ways:
- Bug reports and reproductions. Even a careful description of an unreproducible issue is helpful — it often surfaces a missing log line or an unclear error path.
- Documentation. Typos, broken links, clearer explanations, new tutorials, and worked examples are all in scope and very welcome.
- Agent definitions, workflow templates, skills, and packs. These are
declarative artifacts under
core/andengine/agent-definitions/— you do not need to touch the runtime to ship a useful one. - Engine features and fixes. Bug fixes, new tools, new providers, new observability hooks, and improvements to the workflow engine.
- Frontend features and fixes. The control plane is a Vite + React app
under
frontend/.
Filing an issue
Use GitHub Issues for bug reports and feature requests. Before opening a new one, please search both open and closed issues — a quick check often finds the answer or an active thread.
A useful bug report contains:
- A short title that names the surface and the symptom
(e.g. "
agent33 bench runexits 0 even when no tasks discovered"). - What you ran, including the command, environment, and Python version.
If the bug is in the engine, the output of
agent33 statusis often enough to reproduce. - What you expected to happen.
- What actually happened, with the relevant log lines or stack trace. Wrap multi-line output in fenced code blocks so it stays readable.
- A minimal reproduction, if you have one. A single failing command or a five-line snippet beats a long narrative.
A useful feature request contains:
- The problem you are trying to solve. Even a one-sentence "I want to do X but cannot because Y" is enough.
- Why the existing surface does not solve it. This helps us avoid suggesting a workaround you have already tried.
- A sketch of the API or UX you would like. This does not need to be precise — it is a conversation starter, not a spec.
Please do not file public issues for security-sensitive reports. See
SECURITY.md for the disclosure process.
Proposing a change
For small fixes (typos, obvious bugs, one-line clarifications), you can skip straight to a pull request. For larger changes — anything that adds a new API surface, changes existing behavior, or touches multiple subsystems — please open an issue first to discuss the direction. A short design conversation up front saves everyone time.
If your change is substantial, opening the PR early as a draft is a great way to get feedback while you are still iterating. Mark it ready for review when you are happy with it.
Setting up locally
You will need:
- Python 3.11 or newer. The engine targets
>=3.11and uses syntax from newer versions. - Node 20 or newer if you plan to touch the frontend.
- Git, of course.
- Docker is optional but useful for the full development stack (Postgres, Redis, NATS, Ollama).
Clone the repository and create a worktree-local virtual environment for the engine:
git clone https://github.com/mattmre/AGENT33-PUBLIC.git
cd AGENT33-PUBLIC/engine
python -m venv .venv
# Linux/macOS:
source .venv/bin/activate
# Windows PowerShell:
.\.venv\Scripts\Activate.ps1
python -m pip install -e ".[dev]"
We strongly recommend the worktree-local virtualenv. Sibling Git worktrees sharing one global editable install will silently run code from the wrong checkout, which is the kind of bug that costs an afternoon.
For frontend work:
cd ../frontend
npm install
A fresh worktree never inherits node_modules from its parent — always run
npm install once per worktree before any npm run command.
To spin up the full local stack (engine + database + Redis + NATS):
make up # docker compose up -d --build
make logs # follow the API logs
make down # stop the stack
See docs/testing.md for the test layout and
docs/CONVENTIONS.md for the contribution standard
reviewers apply.
Branch and pull-request workflow
We use a lightweight, PR-based workflow:
- Branch off
main. Use a short, descriptive branch name. Prefix it withfix/,feat/,docs/, or similar if you like — we do not enforce a convention, but readable branch names help. - Keep PRs focused. One coherent change per PR. If you find yourself adding "and also" to the description, that probably wants to be a second PR.
- Write a useful PR description. Explain why, not just what — the problem you are solving, what you considered, and any tradeoffs. Code answers "what"; the PR body should answer "why".
- Push and open the PR. A
.github/PULL_REQUEST_TEMPLATE.mdis provided. You do not need to fill out every field of the contributor-internal template — focus on the summary, test plan, and any caveats. - Respond to review. A reviewer may ask for changes, ask questions, or suggest a different approach. None of this is personal; it is how the project stays consistent.
- Squash-merge is the default. Once approved and CI is green, your PR
will be squash-merged into
main. Delete your branch after the merge — long-lived branches drift.
We do not require contributors to sign a CLA. By submitting a contribution you agree it can be distributed under the Apache 2.0 license — that is the extent of the legal mechanics.
Commit message conventions
Commit messages are encouraged to follow a simple Conventional Commits-style prefix when practical:
feat(workflows): add resume endpoint for paused executions
fix(memory): correct off-by-one in token chunker
docs(plugins): clarify lifecycle ordering for on_enable
refactor(api): consolidate auth scope helpers
test(execution): cover Windows subprocess quoting
chore(deps): bump pydantic to 2.10
We do not enforce this with a hook. The point is to make git log skimmable,
not to gate merges on commit message format. For PRs with multiple small
commits, the squash-merge title is what ends up on main, so make that title
informative.
Code quality standards
Every PR must pass these checks locally before being marked ready for review. CI runs the same set; you should not be guessing whether a check will fail.
From engine/:
python -m ruff check src/ tests/ # zero errors
python -m ruff format --check src/ tests/ # zero diffs
python -m mypy src --config-file pyproject.toml # strict, zero errors
python -m pytest tests/ -q # full suite green
From frontend/:
npm run lint # TypeScript no-emit type check
npm run test # Vitest
npm run build # full production build
ruff check and ruff format --check are independent — the linter can pass
while the formatter still wants to reflow whitespace. Always run both.
Type checking is configured in strict mode. New code should be fully annotated.
Tests should test behavior
The single most common reason a PR is sent back is shallow tests. A test that asserts only on a route's existence, or that the module can be imported, or that an endpoint returns 401 without auth, has near-zero regression value — it would not catch any real bug in the handler.
When you add code, the test should exercise the same code path that production traffic exercises and assert on response shapes, validation errors, business rules, or state changes. If the boundary you need to mock does not exist, build the mock — do not write a placeholder test instead and call it done.
This is explained in more depth in
docs/CONVENTIONS.md, which is the contribution
standard reviewers apply. Reading it before your first substantial PR is worth
fifteen minutes.
Documentation contributions
Documentation lives in:
- The root files:
README.md,QUICKSTART.md,INSTALL.md,CHANGELOG.md,RELEASE_NOTES.md. - The
docs/tree: concepts, glossary, conventions, testing, releasing, examples, plus theoperators/andrunbooks/subdirectories. - Inline docstrings and code comments.
Documentation PRs follow the same workflow as code PRs — branch, PR, review, merge. Two things to keep in mind:
- Examples should be runnable. If you include a command, a YAML snippet, or a curl call, copy it out of your terminal — do not type it from memory. Broken examples are worse than no examples.
- Keep cross-links accurate. If you rename a file, search the repo for inbound links and update them. Broken doc links are a project-wide tax.
If you are adding a new agent definition, workflow template, plugin, or pack,
the documentation for it lives next to the artifact. New plugins should include
a top-level README.md; new workflows should include an inline description
and a useful metadata.tags field.
Anti-patterns we ask you to avoid
These are the most common ways well-intentioned PRs get bounced. None of them will get you flamed — they will get the PR sent back with a request to fix them, and avoiding them up front is faster.
- Half-wired client/server features. If a change specifies that the client calls a server endpoint, both sides must exist and actually be connected. Calling the database directly from the client to "ship faster" defeats the layering and tends to break later in subtle ways.
- Placeholder values shipped unresolved. If a UI field needs to be resolved from data (a title, a name, a URL), the code that resolves it must exist in the same PR. Raw IDs as display text with a comment promising "later" is a bug, not a feature.
- Silent scope reduction. If a blocker prevents you from delivering what was discussed, say so explicitly in the PR description with a concrete proposal to close the gap. Quietly substituting an easier deliverable is the worst-case outcome for everyone.
- Tests that cannot fail. An assertion like
assert status == 401 or status == 503tests nothing — it means the test author did not know what the code would do. Each assertion should check one specific outcome. - Test count as a quality metric. Twenty tests that all check "the module imports" are worth less than three tests that catch real regressions. Write fewer, sharper tests.
If your PR drifts toward one of these because of a real blocker, the right move is to call it out in the PR body and propose a follow-up. The wrong move is to hope the reviewer does not notice.
Platform-specific gotchas
A few things have bitten enough contributors to be worth flagging up front:
- Fresh frontend worktrees need
npm install. A new Git worktree never inheritsfrontend/node_modulesfrom the parent. - Windows console encoding can mask the real error. On a Windows shell
with a non-UTF-8 code page, stack traces from
structlogcan cascade into aUnicodeEncodeErrorthat hides the underlying failure. SetPYTHONIOENCODING=utf-8before running tests if you see encoding errors. - Editable installs across worktrees. If
pytestseems to be running code from a different checkout than the one you are editing, you almost certainly have a stalepip install -epointing at a sibling worktree. Fix it with a worktree-local venv as described above.
Releases
The project follows Semantic Versioning and uses a
release lifecycle described in docs/releasing.md. You
do not need to think about releases as a contributor — they are cut from main
on a rolling cadence — but a couple of things help:
- Update
CHANGELOG.mdfor any change that a user might notice. Add an entry under## [Unreleased]in the appropriate Added / Changed / Deprecated / Removed / Fixed / Security section. - For breaking changes, call them out in the PR title (
feat!:orBREAKING CHANGE:in the body) and in the changelog entry.
License
AGENT-33 is licensed under the Apache License, Version 2.0. By submitting a contribution to this repository, you agree that your contribution may be distributed under the same license. There is no separate contributor agreement to sign.
Code of Conduct
This project is governed by the Contributor Covenant Code of Conduct. By participating, you agree to uphold it. Reports of unacceptable behavior may be sent to the maintainer contact listed in that document.
A note on tone
Reviews on this project aim to be direct, specific, and focused on the work. "This needs to handle the empty-list case" is fine. "This is bad" is not. We try to extend the same standard to contributor responses. If a review comment lands wrong, please tell us so we can recalibrate — we would much rather adjust than lose a contributor over a phrasing mistake.
Thanks again for considering a contribution. Clear, well-tested, end-to-end changes from the community are what keep the project useful in the long run.
See also:
docs/CONVENTIONS.md— contribution standarddocs/concepts.md— the mental modeldocs/testing.md— how to write tests that matterdocs/examples.md— end-to-end worked examplesSECURITY.md— security disclosure process