Architecture
SpecFact CLI is a contract-first Python CLI with a production-ready module registry and bridge-based integration layer.
Current Architecture Status
- Module system is production-ready (introduced in
v0.27) and is the default command-loading path. - Architecture commands such as
specfact architecture derive|validate|traceare planned and tracked in OpenSpec changearchitecture-01-solution-layer. - Protocol FSM modeling exists in data models; a full runtime FSM engine is still planned.
Layer Model
SpecFact is organized as three core quality layers plus supporting implementation layers:
- Specification layer:
ProjectBundlemodels and protocol specs. - Contract layer: runtime contracts (
@icontract,@beartype) plus type checks. - Enforcement layer: CLI/workflow quality gates and validation orchestration.
- Adapter layer: external integration via
BridgeAdapterimplementations. - Analysis layer: analyzers and validators for repository and backlog intelligence.
- Module layer: command modules discovered and loaded through the registry.
Command Registry and Module System
The command runtime uses lazy loading through CommandRegistry in src/specfact_cli/registry/registry.py:
- Registration stores command metadata and loader callables.
get_typer()loads module Typer apps on first use and caches them.- Help/list operations use metadata without importing every module.
register_builtin_commands()wires module packages from discovery.
Module discovery and registration logic lives in src/specfact_cli/registry/module_packages.py and reads module manifests from module-package.yaml.
Module package structure
Canonical package structure used by current modules:
src/specfact_cli/modules/<module-name>/
module-package.yaml
src/
__init__.py
app.py
commands.py
For externalized module development (workspace-level modules), the same manifest and source conventions apply.
module-package.yaml fields
Common manifest fields:
- Required:
name,version,commands - Common optional:
command_help,pip_dependencies,module_dependencies,core_compatibility,tier,addon_id - Extension/security optional:
schema_extensions,service_bridges,publisher,integrity
See also:
Operational Modes
Mode detection currently exists via src/specfact_cli/modes/detector.py and CLI flags.
Detection order:
- Explicit
--mode - Environment/context-based detection
- Fallback to
cicd
Current implementation note:
- Mode detection is implemented.
- Some advanced mode-specific behavior remains roadmap/planned and is tracked in OpenSpec.
- See Implementation Status for implemented vs planned details.
Adapter Architecture
Bridge integration is defined by BridgeAdapter in src/specfact_cli/adapters/base.py.
Required adapter interface
All adapters implement:
detect(repo_path, bridge_config=None) -> boolget_capabilities(repo_path, bridge_config=None) -> ToolCapabilitiesimport_artifact(artifact_key, artifact_path, project_bundle, bridge_config=None) -> Noneexport_artifact(artifact_key, artifact_data, bridge_config=None) -> Path | dictgenerate_bridge_config(repo_path) -> BridgeConfigload_change_tracking(bundle_dir, bridge_config=None) -> ChangeTracking | Nonesave_change_tracking(bundle_dir, change_tracking, bridge_config=None) -> Noneload_change_proposal(bundle_dir, change_name, bridge_config=None) -> ChangeProposal | Nonesave_change_proposal(bundle_dir, proposal, bridge_config=None) -> None
Tool capabilities and adapter selection
ToolCapabilities is defined in src/specfact_cli/models/capabilities.py and includes:
tool,version,layout,specs_dirsupported_sync_modeshas_external_config,has_custom_hooks
BridgeProbe/sync flows use detection and capabilities to select adapters and choose sync behavior safely.
See also:
Change Tracking and Protocol Scope
- Change tracking models exist and are used by adapter flows.
- Support is adapter-dependent and not uniformly complete across all external systems.
- Protocol specs exist as models/spec artifacts; full FSM execution and guard engine behavior is not yet fully implemented.
Status and roadmap references:
- Implementation Status
- OpenSpec change
architecture-01-solution-layer
Error Handling Conventions
Architecture-level error handling conventions:
- Raise specific exceptions (
ValueError, adapter-specific runtime errors) with actionable context. - Validate public API inputs using
@icontractand@beartype. - Use bridge logger via
specfact_cli.common.get_bridge_loggerfor non-fatal lifecycle and adapter failures. - Keep module lifecycle resilient: malformed optional metadata is skipped with warnings instead of crashing the CLI.
- In command paths, prefer structured and user-oriented error output over raw trace text.
Component Overview
graph TD
CLI[CLI Entry] --> Registry[CommandRegistry]
Registry --> Discovery[Module Package Discovery]
Registry --> LazyLoad[Lazy Module Loading]
LazyLoad --> Modules[Module Commands]
Modules --> Adapters[Bridge Adapters]
Modules --> Analysis[Analyzers and Validators]
Modules --> Models[ProjectBundle and Change Models]
Terminology
ProjectBundle: canonical persisted bundle under.specfact/projects/<bundle>/.PlanBundle: legacy conceptual model references in older docs/code paths.
Use ProjectBundle for current architecture descriptions unless explicitly discussing legacy compatibility.
Architecture Decisions
- ADR index: Architecture ADRs
- Initial ADR: ADR-0001 Module-First Architecture