ADR-180: Modular Product Installation Architecture
Status
Proposed -- 2026-02-12
Extends: ADR-057 (Initial Setup), ADR-114 (Protected Installation), ADR-118 (Database Architecture), ADR-179 (FM Distribution)
Context
The CODITECT install script (CODITECT-CORE-INITIAL-SETUP.py v2.10.0) currently installs only coditect-core in 16 steps to a protected location (~/Library/Application Support/CODITECT/core/). As the product portfolio grows (Financial Model, Runway Calculator, Development Studio, etc.), there is no mechanism for:
- Optional product installation -- Users cannot select which products to install alongside core
- Protected product deployment -- Products lack the same protection (read-only, checksums, .git removal) as core
- User-owned components -- No location exists for users to create their own agents, skills, commands, or hooks
- Component origin tracking --
platform.dbcannot distinguish between system, product, and user-created components
ADR-179 established the Financial Model as the first product submodule (submodules/products/coditect-financial-model/), but the install script has no awareness of products.
Decision
D1: Products install to APP_SUPPORT_DIR/products/{product-name}/
Products are installed alongside core in the protected Application Support directory:
~/Library/Application Support/CODITECT/
├── core/ # Existing (ADR-057)
└── products/ # NEW
├── coditect-financial-model/ # Product installations
│ ├── src/
│ ├── .venv/ # Per-product Python venv
│ └── requirements.txt
└── coditect-runway-calculator/
Symlinks from core provide discovery: CODITECT_DIR/products/{name} -> APP_SUPPORT_DIR/products/{name}
D2: Interactive product selection during install
The install script presents selectable products between license acceptance and repository clone:
[2/19] Select optional products to install
[x] 1. Financial Model Engine - SaaS financial projections
[ ] 2. Runway Calculator - Cash runway analysis
Enter numbers to toggle, or press Enter to continue:
- In
--non-interactivemode: install all products withdefault: True - New
--productsflag allows explicit CSV selection:--products coditect-financial-model,coditect-runway-calculator
D3: Each product has its own venv
Products with Python dependencies get isolated virtual environments at products/{name}/.venv/. This prevents dependency conflicts between products and core.
D4: Configurable user-components directory with install-time selection
Users choose where their custom components live during installation (Step 18). The chosen path is stored in a config file for runtime discovery.
Config file: ~/.coditect-data/user-components-config.json
{
"path": "/Users/alice/PROJECTS/.coditect-data/user-components",
"created": "2026-02-12T14:00:00+00:00",
"version": "3.0.0"
}
Path resolution priority:
--user-components-dirCLI flag (install script or env)- Existing
user-components-config.json(from previous install) - Interactive prompt during install (default or custom path)
- Default:
~/.coditect-data/user-components/
Default directory structure:
<user-components-dir>/
├── agents/ # User-created agent definitions
├── skills/ # User-created skills
├── commands/ # User-created commands
├── hooks/ # User-created hooks
└── README.md # Templates and instructions
D4a: Symlink-based component discovery
The install script creates _user symlinks from the protected core's component directories to the user's chosen location:
~/Library/Application Support/CODITECT/core/agents/_user → <user-components-dir>/agents/
~/Library/Application Support/CODITECT/core/skills/_user → <user-components-dir>/skills/
~/Library/Application Support/CODITECT/core/commands/_user → <user-components-dir>/commands/
~/Library/Application Support/CODITECT/core/hooks/_user → <user-components-dir>/hooks/
This enables Claude Code's glob-based discovery (agents/**/*.md) to find user components alongside system components without any framework changes. The _user prefix sorts them last and makes them visually distinct.
Protection considerations:
apply_protection()skips symlinks (avoids chmod'ing writable targets)- Checksum generation skips symlinks (user content changes freely)
- Symlinks are created in Step 18, before protection in Step 19
D4b: /component-create --user flag
The /component-create command gains a --user flag that:
- Reads the user-components path from
user-components-config.json - Creates the component in
<user-dir>/{type}/instead of<core>/{type}/ - Tags the component with
component_origin: userin frontmatter
D5: platform.db gains component_origin column
The components table in platform.db adds a component_origin column:
| Value | Source | Description |
|---|---|---|
system | core/agents/, core/commands/, etc. | Built-in framework components |
product | products/{name}/ | Product-provided components |
user | user-components/ | User-created components |
The component-indexer.py scans all three locations and tags each component with its origin.
D6: Products receive same protection as core
After cloning, products undergo the same protection steps as core:
.gitdirectory removed- Read-only permissions applied
- SHA256 checksums generated and added to the manifest
D7: Clean database seeding
All databases are created with schema only -- no pre-populated data. This is already the current behavior (confirmed in code review), formalized here as a decision.
Consequences
Positive
- Users can select which products to install, reducing disk usage
- Products are protected from accidental modification
- User components enable customization without modifying the framework
- Component origin tracking enables disambiguation in search results
- Per-product venvs prevent dependency conflicts
- Configurable user-components directory gives power users flexibility
- Config file (
user-components-config.json) enables runtime discovery by all tools - Symlink-based discovery requires zero changes to Claude Code's glob patterns
Negative
- Install time increases proportionally with selected products
- Total step count increases from 16 to 19
- Product updates require re-running the install script
- Symlinks may behave differently on Windows (mitigated: Windows uses junction points)
Neutral
- Existing installations are unaffected until re-run
- The
PRODUCT_REGISTRYdictionary serves as the single source of truth for available products - Users who never create custom components see no difference (directories exist but stay empty)
References
- ADR-057: CODITECT Core Initial Setup
- ADR-114: User Data Separation (Protected Installation)
- ADR-118: Database Architecture (Four-Tier)
- ADR-179: Hybrid Financial Model Distribution
- TRACK: N.6.15.2.3 (Install Script Update)