- All modules live under the
A2A.*namespace - No
Implsuffix — use behaviour modules and concrete implementations directly - Example:
A2A.TaskStore(behaviour),A2A.TaskStore.ETS(implementation)
- 100-character line limit
@moduledoc,@doc, and@specrequired on all public functions- Use
@moduledoc falsefor internal modules (never omit the attribute) - Pipe chains: prefer pipes for 2+ transformations
- Guard optional deps with
Code.ensure_loaded?/1checks - Example:
if Code.ensure_loaded?(Plug) do ... end - Never call optional dep modules unconditionally
- Use
{:ok, value}/{:error, reason}tuples for all business logic - No
raisefor expected/recoverable errors raiseonly for programmer errors (e.g., invalid arguments that indicate a bug)
- Test file structure mirrors
lib/structure - All test modules use
async: trueunless they need shared state - Use
doctestwhere practical mix test— run unit tests (must pass before committing)mix quality— run format, credo, dialyzer (must pass before committing)bin/tck mandatory— run A2A TCK compliance suite (requiresuvorpip)- TCK server:
test/tck/server.exs— standalone agent for TCK testing - TCK agent:
test/support/agents/tck_agent.ex— agent used in unit tests - Both must stay in sync when changing agent behavior
- TCK server:
- Conventional Commits format:
feat:,fix:,docs:,chore:,refactor:,test: - Keep commits small and focused
- Create a
config/directory — this is a library, not an application - Use
Application.get_env/3— accept config via function arguments or struct fields - Add a supervision tree or
mod:toapplication/0 - Create empty placeholder module files — only create modules when implementing them
- Add
@impl trueon callbacks without a corresponding@behaviour