AgentDeck is a declarative runtime harness for multi-agent systems and workflows (OpenAI Agents SDK, plus AgentDeck-native @tool/@workflow).
Core standards: docs/engineering/: the linked suite of binding engineering law:
docs/engineering/principles.md: Product philosophy & North Star.docs/engineering/coding-standards.md: Binding front door for every code change.docs/engineering/coding-agents.md: Mandatory rules for coding agents.- Specialized standards:
architecture.md,runtime-contracts.md,testing.md,dependencies.md,repository-policy.md,import-boundaries.md. docs/patterns/: the project's taste as real good/bad pairs. Read the file for your concern before writing; match the good side.
Make powerful agentic systems feel obvious to build, compose, run, and operate. Great software does the hard work so its users do not have to. Simple on the outside, elegant on the inside.
- User owns intent, AgentDeck owns machinery: Users define agents, tools, workflows, skills, and context. AgentDeck manages run identity, execution lifecycle, persistence, event streams, cancellation, and concurrency.
- Abstractions must delete complexity: An abstraction is successful only when the caller needs to know less. Never leak internal plumbing (stores, resolvers, internal contexts, log keys) into public user APIs.
- One obvious path first: One clean, standard path for common tasks (
await deck.run(...)). Advanced knobs remain escape hatches, never obstacles. - Conciseness is mandatory: No fluff, no sprawling prose. If one sentence suffices, write one sentence. Code, comments, docs, PR descriptions, and issue specs must be terse, precise, and dense with signal.
- No em dashes: Never use the
-character in any documentation, code, comments, or agent output. Use a regular hyphen-, colon:, or separate into distinct sentences.
Deck is the single composition root: Deck(...) or Deck.from_project() (discovering ./.agentdeck/).
agentdeck/core/: Pure domain model, event schema, content blocks, ports, error taxonomy. Imports stdlib + pydantic only (enforced byimport-linter).agentdeck/runtime/: Execution orchestration, lifecycle state machine, event dispatch. Importscore/only.agentdeck/adapters/: Pluggable integrations (executors:openai_agents,native; stores:sqlite,postgres,redis;mcp;telemetry). Each adapter importscore/plus exactly one external technology. Adapters never import other adapters.agentdeck/authoring/: Declarations (Agent,@tool,@workflow,Skill) compiled to specs.agentdeck/surfaces/: Ingress surfaces (HTTP/SSE insurfaces/serve/, CLI).
- Correctness before convenience: Strict internal invariants, forgiving external APIs. Make invalid states impossible to express.
- Errors are part of the API: Every error must state what happened, why it happened, and the exact code/action to resolve it.
- Good (real,
runtime/registry.py): "No {self.label} named {name!r}. Available: {sorted(plugins)}." - a lookup failure names the alternatives. - Bad: "invalid workflow state".
- Good (real,
- Typing: Python ≥3.12. Strict annotations everywhere. Pydantic v2 models at system boundaries;
@dataclass(frozen=True, slots=True)for internal immutable value objects. No unprincipledAny. - Zero unnecessary abstractions: YAGNI. Delete dead code aggressively. Do not add configuration for things that never change.
- Good (real,
deck.py): cancellation isRun.cancel(), a method on the existing handle. - Bad: a new
CancellationManagerclass for that same responsibility. Runuv run scripts/repomap.pybefore adding any public abstraction.
- Good (real,
- Comments: Extremely rare, max 1–2 lines explaining non-obvious why, never restating what the code does.
- Good (real,
core/control.py):# Before the raise, because the raise is what records the effect: an intent left pending behind an honored one would be honored a second time on the next resume. - Bad:
# Increment the retry countaboveretry_count += 1. APostToolUsehook (scripts/slopcheck.py) flags this per edit.
- Good (real,
- Gate:
make check(runs ruff, ty typecheck, import-linter, and pytest). Must be 100% green. - Settings & Env: Layered pydantic-settings; all environment variables use the
AGENTDECK_*prefix exclusively (except third-party SDK vars likeOPENAI_*). - Goldens & Snapshots:
tests/golden/andtests/core/snapshots/update only via intentionalmake goldenwith PR justification. - CHANGELOG: Add concise, user-facing entries under
## [Unreleased]for any user-visible change.
- Communication conciseness: Keep text between tool calls to ≤25 words. Keep final responses to ≤100 words unless more detail is required.
- Branches:
devis default; PRs targetdev.mainis release-only. - No attribution trailers: Never include an AI
Co-Authored-By,🤖 Generated with, or AI vendor signatures in commits, PRs, or issues. A trailer naming a person is collaboration, not attribution: GitHub writes one itself when a contributor accepts a maintainer's suggestion. - Draft PR workflow: Open a draft PR on your first commit (
gh pr create --draft) and push continuously as you work. Mark ready withgh pr readyonly whenmake checkis clean.