Common Module (common)
Overview
Section titled “Overview”common is a standalone crate providing logging, standardized errors, CLI parsing, and the ports and adapters for configuration and permissions. It has no domain logic and no hardware dependencies; it is the cross-cutting utility layer that keeps the hexagon pure.
Key principle: common is pure Rust: no unsafe code, no FFI, no platform-specific dependencies. It can be compiled and tested on any platform.
Ports & Adapters
Section titled “Ports & Adapters”common has no feature flags. It contains only portable, cross-platform code. Unlike other domain crates, its adapters are always compiled (not feature-gated) since they provide essential cross-cutting functionality.
| Adapter | Implements Port | Purpose |
|---|---|---|
FileConfigAdapter | ConfigProvider | Parses static configuration files (TOML, JSON, YAML) |
SQLitePermissionAdapter | PermissionManager | SQLite storage for user-granted permissions |
Architecture Context / Relationships
Section titled “Architecture Context / Relationships”At the foundation of the dependency graph, common acts as a shared utility layer. The composition root (pai-engine) and core depend on it directly. Together with Core, it forms the hardware-agnostic “hexagon”. All other domain crates safely rely on common (often transitively through Core) for shared logging and error traits.
Crate Structure
Section titled “Crate Structure”Like other domain crates, common follows the Hexagonal Architecture pattern. For an overview of this structure, see Engine Domains.
Key difference from other crates: The adapters in common are always compiled (not feature-gated), since they provide essential cross-cutting functionality needed by all domain crates.
Internal Domain Components
Section titled “Internal Domain Components”| Component | Responsibility |
|---|---|
Logger | Centralized, thread-safe tracing and logging facility used by all crates |
ErrorTypes | Global, standardized error definitions for consistent error handling across domain boundaries |
ArgParse | Command-line argument parsing for the engine executable |
Ports and Adapters
Section titled “Ports and Adapters”ConfigProvider Port & FileConfigAdapter
Section titled “ConfigProvider Port & FileConfigAdapter”- Contract: Defines how system and hardware configuration is retrieved.
- Adapter:
FileConfigAdapter: Parses static configuration files from the local filesystem (e.g.,hardware.toml). - Supported formats: TOML, YAML, or JSON. The adapter must detect the format automatically (via file extension or content sniffing) or be configured explicitly at initialization.
- Domain crates depend only on the
ConfigProvidertrait; they never depend on file formats or filesystem details.
PermissionManager Port & SQLitePermissionAdapter
Section titled “PermissionManager Port & SQLitePermissionAdapter”- Contract: The critical contract for the HITL security concept. Resolves whether an action is “Allowed”, “Denied”, or “Ask”.
- Adapter:
SQLitePermissionAdapter: Connects to a local SQLite database to persistently store and retrieve user-granted permissions and preferences. - Domain crates call the trait only; they do not depend on SQLite or any specific storage implementation.
- Not feature-gated. The PermissionManager port and its adapter are always compiled. Making the permission system optional would weaken the HITL security guarantee: every build must enforce permission checks. For testing, a
MockPermissionAdapter(always returns “Allowed”) can be injected via the composition root; the port itself is never conditionally compiled.
Related Documentation
Section titled “Related Documentation”- ADR-004: Engine Architecture: Workspace layout and shared foundation role
- Core Module: Orchestrator that depends on common
- Workspace and Build: Where common sits in the crate tree
- Security Architecture: How PermissionManager and HITL integrate