← ClaudeAtlas

claudeloop-architecturelisted

Explains claudeloop's onion architecture — the four layers (domain, application, infrastructure, cli), the import-linter contract enforcing them, and exactly where new code belongs. Use this whenever adding a new file, class, or function to src/claudeloop/, whenever unsure which layer something belongs in, whenever import-linter or lint-imports fails, or when the user mentions "onion architecture", "layers", "ports and adapters", "bootstrap.py", "composition root", or asks "where should this go". Make sure to consult this before writing any new module under src/claudeloop/ — placing code in the wrong layer is the most common mistake in this codebase and import-linter will reject it in CI regardless.
the-vibey-project/vibey · ★ 2 · AI & Automation · score 68
Install: claude install-skill the-vibey-project/vibey
# claudeloop architecture > **Codex skill mirror** of `.claude/skills/claudeloop-architecture/SKILL.md`. When this guidance changes, update Claude skill, Cursor rule, and `.agents/skills/` in the same PR. `claudeloop` is a strict onion / ports-and-adapters design. Dependencies point inward only. This is enforced in CI and pre-commit by `import-linter`, not by convention — a violation fails with a named contract error, not a review comment. ## The four layers, innermost first ``` src/claudeloop/ ├── domain/ # PURE. stdlib only. No I/O, no async, no third-party imports. ├── application/ # Protocol-based ports + use cases. Imports domain + stdlib only. ├── infrastructure/ # Adapters. The ONLY layer allowed to import anthropic / │ # claude_agent_sdk / structlog / httpx / any third-party SDK. ├── cli/ # Typer commands. Calls application use cases via bootstrap. └── bootstrap.py # Composition root — the ONE module allowed to see every layer. ``` ## The decision test — where does new code go? Ask in this order: 1. **Does it touch the filesystem, network, clock, or an SDK?** → `infrastructure/`, behind a `Protocol` port defined in `application/ports.py`. Never call `anthropic.*` or `claude_agent_sdk.*` from anywhere else. 2. **Is it a decision — a branch determining what happens next — with zero I/O of its own?** → `domain/`. Test: can you write its test as `assert some_function(SomeDataclass