Skip to main content

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:

  1. Optional product installation -- Users cannot select which products to install alongside core
  2. Protected product deployment -- Products lack the same protection (read-only, checksums, .git removal) as core
  3. User-owned components -- No location exists for users to create their own agents, skills, commands, or hooks
  4. Component origin tracking -- platform.db cannot 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-interactive mode: install all products with default: True
  • New --products flag 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:

  1. --user-components-dir CLI flag (install script or env)
  2. Existing user-components-config.json (from previous install)
  3. Interactive prompt during install (default or custom path)
  4. 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

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:

  1. Reads the user-components path from user-components-config.json
  2. Creates the component in <user-dir>/{type}/ instead of <core>/{type}/
  3. Tags the component with component_origin: user in frontmatter

D5: platform.db gains component_origin column

The components table in platform.db adds a component_origin column:

ValueSourceDescription
systemcore/agents/, core/commands/, etc.Built-in framework components
productproducts/{name}/Product-provided components
useruser-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:

  • .git directory 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_REGISTRY dictionary 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)