# Capabilities Architecture ## Overview MarkiTect uses a **capabilities-based architecture** where functionality is organized into independent, reusable packages called **capabilities**. Each capability is a self-contained git submodule with its own repository, enabling independent development, versioning, and reuse across projects. ## Core Principles ### 1. **Separation of Concerns** **Critical Rule:** The main repository (`markitect-main`) **MUST NOT** directly modify capability code. - ✅ **DO**: Use capabilities as dependencies - ✅ **DO**: Configure capabilities through documented interfaces - ✅ **DO**: Report issues and feature requests to capability repos - ❌ **DON'T**: Edit capability code from the main repo - ❌ **DON'T**: Make commits directly in capability subdirectories - ❌ **DON'T**: Bypass the submodule boundary **Why?** Capabilities are independent repositories. Direct modifications create: - Merge conflicts when syncing with upstream - Broken dependency management - Loss of independent versioning - Confusion about source of truth ### 2. **Git Submodule Architecture** Capabilities are integrated as **git submodules**, not regular directories: ``` markitect-main/ ├── .gitmodules # Submodule configuration ├── capabilities/ │ ├── testdrive-jsui/ # Git submodule → separate repo │ ├── issue-facade/ # Git submodule → separate repo │ ├── kaizen-agentic/ # Git submodule → separate repo │ ├── markitect-content/ # Local capability (legacy) │ └── release-management/ # Local capability (legacy) ``` **Submodule vs Local Capabilities:** - **Submodules**: Independent git repositories, separate development lifecycle - **Local**: Part of main repo, shared lifecycle (being phased out) **Target State:** All capabilities should eventually be submodules. ### 3. **Independent Development Lifecycle** Each capability has its own: - ✅ Git repository on gitea - ✅ Version numbering (semantic versioning) - ✅ Issue tracking and roadmap - ✅ Testing and CI/CD pipeline - ✅ Documentation and README - ✅ Contributors and maintainers ### 4. **Interface-Based Integration** Capabilities expose **stable interfaces** to the main project: ```python # markitect uses capability through documented interface from testdrive_jsui import TestDriveJSUIEngine engine = TestDriveJSUIEngine() engine.render_document(content, mode='edit', config=config) ``` **Integration Points:** 1. **Python Package Interface**: Clean import and API 2. **Configuration**: Via `pyproject.toml` dependencies 3. **Plugin System**: Via plugin registration and metadata 4. **Makefile Targets**: Via capability discovery system ## Development Workflow ### Working on Capabilities **Rule:** Each capability is developed in **its own Claude Code session**. #### Main Repository Session ```bash # In markitect-main/ cd /home/worsch/markitect-main # Main repo tasks: # - Integrate capabilities # - Update dependencies # - Configure capability usage # - Test integration points ``` #### Capability Session ```bash # In capability repository cd /home/worsch/markitect-main/capabilities/testdrive-jsui # OR clone separately git clone http://gitea/coulomb/testdrive-jsui.git cd testdrive-jsui # Capability tasks: # - Implement features # - Fix bugs # - Write tests # - Update documentation # - Make releases ``` ### Recommended Session Pattern **Scenario: Need to add feature to testdrive-jsui** 1. **Open separate Claude instance** for testdrive-jsui ```bash # In new terminal/session cd /path/to/testdrive-jsui # Work on feature git commit -m "feat: new feature" git push origin main ``` 2. **Update main project** (different Claude instance) ```bash cd /home/worsch/markitect-main git submodule update --remote capabilities/testdrive-jsui git commit -m "chore: update testdrive-jsui submodule" ``` **Why separate instances?** - Clear context boundaries - Prevents accidental cross-contamination - Respects repository independence - Better commit hygiene ### Updating Submodules When a capability releases a new version: ```bash # In main repo cd /home/worsch/markitect-main # Update specific capability cd capabilities/testdrive-jsui git pull origin main cd ../.. git add capabilities/testdrive-jsui git commit -m "chore: update testdrive-jsui to v1.2.0" # Or update all capabilities git submodule update --remote git commit -am "chore: update all capabilities" ``` ### Adding New Capabilities ```bash # 1. Create capability repository on gitea # http://gitea/coulomb/new-capability # 2. Add as submodule to main repo cd /home/worsch/markitect-main git submodule add http://gitea/coulomb/new-capability.git capabilities/new-capability # 3. Add dependency to pyproject.toml # dependencies = [ # "new-capability @ file:./capabilities/new-capability" # ] # 4. Commit submodule addition git commit -m "feat: add new-capability as submodule" ``` ## Dependency Management Capabilities are declared in `pyproject.toml`: ```toml [project] dependencies = [ # Core dependencies "markdown-it-py", "click>=8.0.0", # Capabilities (file-based dependencies) "release-management @ file:./capabilities/release-management", "testdrive-jsui @ file:./capabilities/testdrive-jsui", "issue-facade @ file:./capabilities/issue-facade", ] ``` **Pattern for Capabilities:** ```toml "capability-name @ file:./capabilities/capability-name" ``` This enables: - ✅ pip install with editable dependencies - ✅ Proper package resolution - ✅ Clean imports in code - ✅ Development mode support ## Capability Structure Each capability should follow this structure: ``` capability-name/ ├── README.md # Comprehensive documentation ├── pyproject.toml # Package configuration ├── Makefile # Build and test automation ├── .gitignore # Git ignore rules ├── src/capability_name/ # Python package source │ ├── __init__.py │ ├── core/ # Core functionality │ ├── utils/ # Utilities │ └── testing/ # Testing infrastructure ├── js/ # JavaScript (if applicable) │ ├── components/ │ ├── controls/ │ └── tests/ ├── static/ # Static assets (if applicable) │ ├── css/ │ ├── images/ │ └── templates/ ├── tests/ # Python tests │ └── test_*.py └── docs/ # Additional documentation ├── API.md └── USAGE.md ``` ### Required Files 1. **README.md** - Must include: - Purpose and description - Installation instructions - Usage examples - API documentation - Integration guide 2. **pyproject.toml** - Must define: - Package metadata - Dependencies - Build system - Entry points 3. **Makefile** - Should include: - help target - test targets - install/setup targets - capability-info target (for discovery) ## Plugin System Integration For capabilities that provide plugins (like testdrive-jsui): ### Plugin Self-Declaration ```python class TestDriveJSUIEngine(RenderingEnginePlugin): """Plugin declares its own location - no hardcoded paths.""" def get_plugin_source_dir(self) -> Path: """Plugin knows where it lives.""" return Path(__file__).parent.parent.parent / "capabilities" / "testdrive-jsui" def get_asset_paths(self) -> Dict[str, Path]: """Plugin declares its asset structure.""" base = self.get_plugin_source_dir() return { 'js': base / 'js', 'css': base / 'static' / 'css', 'templates': base / 'static' / 'templates', } ``` ### Plugin Discovery The main repo uses **generic discovery** - no hardcoded capability names: ```python # ✅ Good: Generic discovery if hasattr(engine, 'get_plugin_source_dir'): source_dir = engine.get_plugin_source_dir() # ❌ Bad: Hardcoded capability names if engine_name == 'testdrive-jsui': source_dir = Path('capabilities/testdrive-jsui') ``` ## Testing Strategy ### Capability Tests Each capability tests **in isolation**: ```bash cd capabilities/testdrive-jsui pytest tests/ npm test ``` ### Integration Tests Main repo tests **integration points**: ```python # tests/integration/test_capabilities.py def test_testdrive_jsui_integration(): """Test that testdrive-jsui integrates correctly.""" engine = TestDriveJSUIEngine() result = engine.render_document(sample_content, 'edit', config) assert result is not None ``` ### Test Boundaries - **Capability tests**: Internal functionality, unit tests, component tests - **Main repo tests**: Integration, configuration, plugin discovery ## Migration Path ### Converting Local Capability to Submodule 1. **Create separate git repo** ```bash cd /tmp cp -r markitect-main/capabilities/capability-name capability-name cd capability-name git init git add . git commit -m "Initial commit" git remote add origin http://gitea/coulomb/capability-name.git git push -u origin main ``` 2. **Remove from main repo** ```bash cd markitect-main git rm -rf capabilities/capability-name git commit -m "chore: remove capability-name for submodule conversion" ``` 3. **Add as submodule** ```bash git submodule add http://gitea/coulomb/capability-name.git capabilities/capability-name git commit -m "feat: add capability-name as submodule" ``` ## Best Practices ### DO ✅ 1. **Develop capabilities independently** - Use separate Claude instances - Maintain clear context boundaries - Follow semantic versioning 2. **Use documented interfaces** - Import via Python packages - Use plugin APIs - Follow configuration patterns 3. **Test integration points** - Verify capability imports - Test plugin discovery - Validate configurations 4. **Update submodules explicitly** - Pull capability changes deliberately - Review updates before committing - Update main repo pointer 5. **Document integration** - How to use the capability - Configuration options - Example usage ### DON'T ❌ 1. **Edit capability code from main repo** - Opens separate repo/instance instead - Respects submodule boundary - Maintains clean separation 2. **Hardcode capability paths** - Use self-declaration instead - Generic discovery patterns - Interface-based access 3. **Create circular dependencies** - Main depends on capabilities - Capabilities should NOT depend on main - Keep dependency graph acyclic 4. **Bypass submodule system** - Don't manually copy files - Use git submodule commands - Respect version control ## Troubleshooting ### Submodule not updated ```bash # Pull latest from capability repo cd capabilities/testdrive-jsui git pull origin main # Update main repo pointer cd ../.. git add capabilities/testdrive-jsui git commit -m "chore: update testdrive-jsui" ``` ### Import errors ```bash # Reinstall capabilities pip install -e . # Or specific capability pip install -e ./capabilities/testdrive-jsui ``` ### Merge conflicts in submodules ```bash # Don't merge in submodule from main repo! # Instead, go to capability repo directly cd /path/to/separate/testdrive-jsui # or cd capabilities/testdrive-jsui # Resolve conflicts there git pull origin main # fix conflicts git push origin main # Then update main repo cd ../../ git submodule update --remote ``` ## See Also - [Agent: Capability Manager](../../agents/agent-capability-manager.md) - Automated capability management - [Plugin System](../PLUGIN_SYSTEM.md) - Plugin architecture documentation - [Git Submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) - Official git submodules guide --- **Remember:** Capabilities are **independent projects**. Treat them with the same respect you'd give any external dependency - use their interfaces, don't modify their internals.