A2A agent that audits another deployed agent's source pre-deploy. Reads the target Gitea repo via a short-lived read-only token minted through ctx.mint_gitea_token(), runs an inner DeepAgents graph backed by GiteaBackend, and emits a typed ReviewReport. Skill bundles: - security-anti-patterns (credentials, eval, sandbox bypass, egress) - a2apack-best-practices (class shape, decorators, types, timeouts) - grant-scope-evaluation (declared vs actual workspace scope) Tools: - sandbox_a2a_card : round-trips the project through microsandbox - sandbox_ruff_check: objective static checks - submit_review_report: typed final report 7 smoke tests pass; agent card loads cleanly via `a2a card`.
76 lines
3.3 KiB
Markdown
76 lines
3.3 KiB
Markdown
---
|
|
name: a2apack-best-practices
|
|
description: Shape of a well-formed A2A Pack agent. Use when reviewing agent.py for class structure, @skill decorators, type hints, error handling, idempotency, and timeouts.
|
|
---
|
|
# A2A Pack Best Practices
|
|
|
|
Use this skill when reviewing the *shape* of an agent — not its security
|
|
posture (that's `security-anti-patterns`) and not its grants (that's
|
|
`grant-scope-evaluation`).
|
|
|
|
## Class contract
|
|
|
|
* The class must inherit from `A2AAgent[ConfigT, AuthT]` with concrete
|
|
generic parameters. Missing parameters → `warning`.
|
|
* Class variables `name`, `description`, `version` must be set. Missing →
|
|
`warning`. `description` shorter than ~30 chars → `info`.
|
|
* `config_model` and `auth_model` must reference declared Pydantic
|
|
models (or `NoAuth`). A mismatched generic and class var → `warning`.
|
|
|
|
## @skill decorators
|
|
|
|
* Every public skill should declare `description`. Missing → `warning`.
|
|
* `timeout_seconds` should be set explicitly. Default is short; long-running
|
|
skills that omit it will time out in production. Missing on a skill that
|
|
does file work, LLM calls, or sandbox exec → `warning`.
|
|
* `stream=True` is required if the skill calls `ctx.emit_progress`,
|
|
`ctx.ask`, `ctx.collect`, or `ctx.request_scope`. Missing while the body
|
|
does emit → `critical`.
|
|
* `idempotent=True` matters for skills that can be safely retried. Skills
|
|
that write files, mutate state, or charge money → `info` if not set
|
|
explicitly (either direction is fine, just be intentional).
|
|
|
|
## Type hints
|
|
|
|
* Every skill parameter must have a concrete type hint (no `Any`, no missing
|
|
annotation). The Card's `input_schema` is built from these. Missing → `warning`.
|
|
* Return type should be `dict[str, Any]`, a concrete Pydantic model, or `str`.
|
|
Returning untyped values surprises callers → `info`.
|
|
|
|
## Error handling
|
|
|
|
* Skills should return structured error dicts (e.g. `{"error": "..."}`), not
|
|
raise unhandled exceptions for *expected* failure modes (bad input, missing
|
|
workspace, timeouts). Bare `raise` for invalid input → `info`.
|
|
* `try/except Exception` that swallows the error without logging or returning
|
|
→ `warning`.
|
|
|
|
## ctx.workspace / ctx.sandbox usage
|
|
|
|
* If the skill calls `ctx.workspace_backend()`, the class must declare
|
|
`workspace_access = WorkspaceAccess.dynamic(...)`. Mismatch → `critical`.
|
|
* Subprocesses that produce user-visible files must run through
|
|
`ctx.workspace_shell` or `ctx.workspace_python`, not raw
|
|
`asyncio.create_subprocess_exec`. Already covered in
|
|
`security-anti-patterns` but worth a second look here.
|
|
|
|
## Recursion limits
|
|
|
|
* If the skill invokes a DeepAgents graph via `ainvoke` or `astream_events`,
|
|
it must pass `config={"recursion_limit": 500}` to match agent-builder.
|
|
Missing → `warning`.
|
|
|
|
## Manifest (a2a.yaml)
|
|
|
|
* `name` must match the agent's `name` class var. Mismatch → `critical`.
|
|
* `entrypoint` must point at a real `module:Class`. Stub or broken → `critical`.
|
|
* `version` should be semantic (major.minor.patch). Bad shape → `info`.
|
|
|
|
## Severity rubric (specific to this skill)
|
|
|
|
* `critical` — breaks the runtime contract (stream/emit mismatch, manifest
|
|
doesn't import, name disagreement).
|
|
* `warning` — works today but degrades the developer or caller experience
|
|
(no timeout, no type hint, bare raise).
|
|
* `info` — style nudges.
|