Agent skill
40-03-dependency-direction
Dependencies flow one direction. Shared state → domain logic → presentation. Never circular. Prevents import tangles and initialization order bugs.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/40-03-dependency-direction
SKILL.md
40.03 Dependency Direction
Dependencies flow downward. Lower layers never import from higher layers.
The Layers
┌─────────────────────────────┐
│ Presentation (UI, CLI, │ Reads state, dispatches actions
│ API surface) │
├─────────────────────────────┤
│ Domain actions / queries │ Reads shared state, calls into services
├─────────────────────────────┤
│ Domain logic (entity mgmt, │ Reads + writes shared state
│ event handlers, sync) │
├─────────────────────────────┤
│ Shared state (refs, tables,│ The data. Depends on nothing.
│ caches, stores) │
├─────────────────────────────┤
│ Infrastructure (connection,│ SDK, protocol, IO, types
│ bindings, types) │
└─────────────────────────────┘
Arrows point down only.
The Rules
-
Shared state imports nothing from the project. Only types and external libraries. It's the foundation — everything depends on it, it depends on nothing.
-
Domain logic imports shared state. Entity management reads from state. Never the reverse.
-
Actions/queries import shared state. Feature actions read refs and call reducers. They don't import domain logic internals.
-
Presentation imports actions and reads state. Components/views call actions and read from state/stores. They don't import shared state directly.
How Circular Dependencies Happen
Module A imports Module B. Module B imports Module A. At load time, one of them is partially initialized → undefined references, subtle bugs.
Common cause: shared state that imports a computation from a higher layer.
Fix: if shared state needs a computation, the computation is a pure function that lives at the same level or lower.
Runtime Callbacks (the one valid upward call)
Connection lifecycle needs to call into domain logic when events arrive (subscription fires → upsert entity). This goes "upward" at runtime.
This is safe because:
- All modules are fully loaded before any callback fires
- The callback is registered at runtime, not at import time
- No circular import — only the lower module imports the higher one
Keep callbacks thin — translate the event into a domain function call, nothing more.
The Test
Draw the import graph. Do any arrows point upward?
If yes — move the shared dependency down, or extract it to a lower layer.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?