Purpose:
- Provide a centralized workspace that acts as a single source of truth for development tools by establishing shared infrastructure for testing and builds.
- Accelerate development by providing a refined and repeatable platform for building new tools and workflows.
User Value Statement: Eliminates the manual and repetitive effort of porting workflow improvements across different projects, significantly reducing time spent on "meta-work".
Note: This document is intended to be a living document. Update the document immediately when code changes affect architecture.
Primary Users:
- Technical Product Manager (Wesley) - Eliminating fragmented workflow development and establishing a refined, repeatable framework for building AI-assisted development tools
- AI Coding Assistants - Leveraging centralized semantic tools, testing frameworks, and standardized configurations to deliver consistent, reliable automation across development workflows
Secondary Users:
- Future Team Members: Learning established patterns and contributing to the centralized toolkit
- AI-Assisted Developers: Understanding architecture that scales beyond simple projects and supports complex semantic tooling
- Community Members: Adapt patterns for their own workflows
The system's design is guided by core principles that prioritize simplicity, maintainability, and extensibility through a modular, CLI-first architecture.
Read ARCHITECTURE-PRINCIPLES %% force-extract %%
TypeScript as Architecture Enabler:
-
Data-First Design: TypeScript enforces explicit type contracts for all data structures, making data schemas first-class citizens that serve as living documentation and compile-time validation.
-
Fail Fast: TypeScript surfaces type errors at compile-time rather than runtime, catching contract violations before code executes and reducing debugging cycles.
-
Self-Contained Naming: Type annotations provide immediate inline documentation, reducing cognitive load and making interfaces self-documenting without external lookup.
-
Modular Design: TypeScript's type system enforces explicit API boundaries between modules, preventing accidental coupling and ensuring each component's contract is clearly defined.
Implementation: TypeScript compilation (tsc) is integrated into the build pipeline, with strict type checking enabled to maximize these benefits. Type definitions (.d.ts) are generated alongside compiled output, enabling type-safe consumption by other tools and projects.
-
Architecture Pattern: Monorepo (multi-package workspace) — a single repo acting as a centralized, single source of truth for multiple, distinct development utilities. The first tool is the
citation-manager. -
System Design: tooling monorepo hosting a multi-command CLI with shared packages for test/build. This is a toolkit of independent tools that consume common services like testing (FR2)and builds (FR3)—not a single linear pipeline.
Monorepoimplemented vianpm workspaces(NPM Workspaces vs Alternatives)cli multi-commandimplemented viacommander(initial). Clear upgrade path tooclifif/when plugin-based extensibility is required.TypeScriptas primary development language with strict type checkingVitefor shared development infrastructure (HMR, dev server, bundling)
- Modular Component Design: - each tool (e.g., citation-manager) is isolated for independent evolution and migration, while shared utilities live in shared packages.
- Primary Language: TypeScript with strict type checking, compiled to JavaScript for execution
- Interaction Style: CLI-based, with commands executed via root-level NPM scripts
- Runtime Model: Local, on-demand execution of compiled Node.js tool scripts from
dist/directories - Development Model: Vite provides HMR and dev server for rapid iteration during development
- Build Pipeline: TypeScript compilation (
tsc) for type checking and JavaScript generation, with.d.tstype definitions - Deployment Model: Fully self-contained within a version-controlled repository; no external deployment required
- Scaling Approach: Scales by adding new, isolated tool packages to the workspace, with a clear migration path to more advanced tooling if the package count grows significantly. Start with
npm workspaces; if growth demands, adoptNx/Turborepofor caching & task orchestration.
- Simplicity First: Native Node.js + npm integration minimizes tooling overhead.
- Right-Sized Performance: Optimized for ~5–10 tools/packages—fast installs/builds without premature complexity.
- Less Meta-Work: Shared dependencies and scripts reduce coordination cost while keeping each tool|package independently maintainable.
- ADR-001: NPM Workspaces for Monorepo Management
This document captures the baseline architecture of the CC Workflows Workspace to enable centralized development, testing, and deployment of semantic and deterministic tooling. When implementing improvements or new capabilities, this baseline serves as the reference point for identifying which containers, components, and code files require modification.
The C4 model decomposes complex architecture by drilling down through four levels: Context (system boundaries), Containers (deployable units), Components (grouped functionality), and Code (implementation details). This structured approach enables understanding of the system at appropriate levels of detail, from high-level system interactions down to specific file and class implementations.
This diagram shows the CC Workflows Workspace as a central system used by developers to create and manage a toolkit of reusable components. These components are then consumed by external Developer Projects and automated AI Coding Assistants. The workspace itself relies on Git for version control and NPM for managing its internal dependencies.
graph TD
Developer("<b style='font-size: 1.15em;'>Technical PM / Developer</b><br/>[Person]<br/><br/>Builds and maintains the reusable development toolkit")@{ shape: notch-rect }
AiAssistants("<b style='font-size: 1.15em;'>AI/LLM</b><br/>[Software System]<br/><br/>Automated coding agents that consume tools and configurations to perform development tasks")@{ shape: notch-rect }
Workspace("<b style='font-size: 1.15em;'>CC Workflows Workspace</b><br/>[Software System]<br/><br/>Centralized environment for creating, testing, and managing reusable development tools and AI configurations")
DevProjects("<b style='font-size: 1.15em;'>Developer Projects</b><br/>[Software System]<br/><br/>External projects that consume the tools and workflows provided by the workspace")
Developer -.->|"<div>Builds, tests, and manages tools USING</div>"| Workspace
AiAssistants -.->|"<div>Leverage semantic tools and configurations FROM</div>"| Workspace
Workspace -.->|"<div>Provisions tools and configurations FOR</div>"| DevProjects
%% Color coding for C4 diagram clarity
classDef person stroke:#052e56, stroke-width:2px, color:#ffffff, fill:#08427b
classDef softwareSystemFocus stroke:#444444, stroke-width:2px, color:#444444, fill:transparent
classDef softwareSystemExternal fill:#999999,stroke:#6b6b6b,color:#ffffff, stroke-width:2px
class Developer person
class Workspace softwareSystemFocus
class AiAssistants,DevProjects softwareSystemExternal
linkStyle default color:#555555
graph LR
subgraph systemBoundary ["CC Workflows Workspace"]
direction LR
style systemBoundary fill:#fafafa, stroke:#555555
subgraph infrastructure ["Infrastructure"]
direction TB
style infrastructure fill:transparent, stroke:#555555
workspace["<div style='font-weight: bold'>Workspace</div><div style='font-size: 85%; margin-top: 0px'>[Node.js, NPM Workspaces, Vitest, Biome]</div><div style='font-size: 85%; margin-top:10px'>Infrastructure platform managing dependencies, orchestrating execution, and enforcing quality</div>"]
style workspace fill:#438dd5,stroke:#2e6295,color:#ffffff
end
subgraph tools ["Tools"]
direction TB
style tools fill:transparent, stroke:#555555
toolPackages["<div style='font-weight: bold'>Tool Packages</div><div style='font-size: 85%; margin-top: 0px'>[Node.js, Commander]</div><div style='font-size: 85%; margin-top:10px'>CLI tools for workflow automation (citation-manager, etc.)</div>"]
style toolPackages fill:#438dd5,stroke:#2e6295,color:#ffffff
end
end
developer["<div style='font-weight: bold'>Developer</div><div style='font-size: 85%; margin-top: 0px'>[Person]</div><div style='font-size: 85%; margin-top:10px'>Builds and maintains the reusable development toolkit</div>"]@{ shape: circle }
style developer fill:#08427b,stroke:#052e56,color:#ffffff
aiAssistants["<div style='font-weight: bold'>AI Coding Assistants</div><div style='font-size: 85%; margin-top: 0px'>[Software System]</div><div style='font-size: 85%; margin-top:10px'>Automated agents that consume tools and configurations</div>"]@{ shape: notch-rect }
style aiAssistants fill:#999999,stroke:#6b6b6b,color:#ffffff
devProjects["<div style='font-weight: bold'>Developer Projects</div><div style='font-size: 85%; margin-top: 0px'>[Software System]</div><div style='font-size: 85%; margin-top:10px'>External projects that consume the tools and workflows</div>"]
style devProjects fill:#999999,stroke:#6b6b6b,color:#ffffff
developer-. "<div>Builds, tests, and manages tools USING</div><div style='font-size: 85%'>[CLI commands]</div>" .->workspace
aiAssistants-. "<div>Builds, tests, and manages tools USING</div><div style='font-size: 85%'>[CLI commands]</div>" .->workspace
workspace-. "<div>Manages (orchestration, testing, quality, build)</div><div style='font-size: 85%'>[npm]</div>" .->toolPackages
tools<-. "<div>IS USED BY</div><div style='font-size: 85%'>[CLI commands]</div>" .->devProjects
linkStyle default color:#555555
classDef softwareSystemFocus stroke-width:2px, fill:transparent
class workspace,toolPackages softwareSystemFocus
- Name: CC Workflows Workspace
- Technology:
Node.js,TypeScript,NPM Workspaces,Vite,Vitest,Biome - Technology Status: Production
- Description: Development infrastructure platform that:
- Manages dependencies and workspace configuration via NPM Workspaces
- Provides TypeScript compilation and type checking via shared
tsconfig.base.json - Provides Vite development infrastructure for HMR and dev server capabilities
- Orchestrates tool execution through centralized npm scripts
- Runs automated tests for all tools via shared Vitest framework
- Enforces code quality standards via Biome linting and formatting (JavaScript + TypeScript)
- Provides monorepo directory structure (
tools/,packages/) for tool isolation
- User Value: Centralized workspace with shared infrastructure vs. scattered tools across projects, eliminating duplicated effort and reducing "meta-work" tax
- Interactions:
- is used by Developer (synchronous)
- manages Tool Packages (orchestration, testing, quality, build) (synchronous)
- provides tools and configurations for Developer Projects and AI Assistants
- Name: Tool Packages
- Technology:
Node.js,TypeScript,Commander(varies by tool) - Technology Status: Production
- Description: Individual CLI tools for development workflow automation:
- Written in TypeScript with strict type checking
- Compiled to JavaScript in tool-specific
dist/directories - Type definitions (
.d.ts) generated for type-safe consumption - Markdown validation and processing
- Content transformation and extraction
- Code analysis and formatting
- Citation Manager is the first production tool in this container
- User Value: Reusable, type-safe, tested tools vs. scattered, inconsistent scripts across projects
- Interactions:
- is used by Developer and AI Assistants
Component-level architecture (C4 Level 3) is defined within each tool's own architecture documentation, not at the workspace level. This approach enforces our Modular Design Principles by treating each tool as a self-contained container, keeping the workspace architecture focused on system-level boundaries.
See the content-aggregation-architecture for a reference implementation.
Component interfaces and data contracts are internal details of each tool container. To maintain a clean separation of concerns and treat each tool as a "black box," these specifications are defined within the respective tool's architecture document and are intentionally excluded from the parent workspace architecture.
This level details the initial organization of the workspace, its file structure, and the naming conventions that will ensure consistency as the project grows.
The workspace is organized as a monorepo using NPM Workspaces. The structure separates documentation, shared packages, and individual tools into distinct top-level directories.
cc-workflows/
├── design-docs/ # Project documentation (architecture, PRDs, etc.)
├── packages/ # Shared, reusable libraries (e.g., common utilities)
│ └── shared-utils/ # (Future) For code shared between multiple tools
├── tools/ # Houses the individual, isolated CLI tools
│ └── citation-manager/ # The first tool being migrated into the workspace
│ ├── src/ # Source code for the tool
│ ├── test/ # Tests specific to the tool
│ └── package.json # Tool-specific dependencies and scripts
├── biome.json # Root configuration for code formatting and linting
├── package.json # Workspace root: shared dependencies and top-level scripts
└── vitest.config.js # Root configuration for the shared test framework
Cross-cutting features affect the entire workspace (e.g., Claude Code skills, workspace-level tooling, shared conventions) rather than a single tool. These features live at the workspace root and follow the same Feature Organization Patterns documented below.
Workspace root location:
design-docs/ # Workspace-level (cross-cutting)
└── features/
└── {{YYYYMMDD}}-{{feature-name}}/
└── user-stories/ # Same epic/user-story patterns
├── epic{{X}}-{{epic-name}}/ # Fast/simple features
└── us{{X.Y}}-{{story-name}}/ # Slow/complex features
Tool-specific location (for comparison):
tools/citation-manager/
└── design-docs/ # Tool-specific features
└── features/
└── {{YYYYMMDD}}-{{feature-name}}/
└── user-stories/ # Same epic/user-story patterns
The key difference is location (workspace root vs tool directory), not structure. See Tool/Package Documentation Organization below for complete pattern details.
Each tool or package maintains its own design-docs/ folder structure following the same pattern as the project root, enabling self-contained documentation and feature management.
The workspace supports two documentation patterns based on feature complexity:
Fast/Simple Pattern (Epic-Level): For straightforward features with limited scope, low risk, and quick delivery timelines:
- Roll all user stories into a single epic-level design and implementation plan
- Used when: Feature is well-understood, has minimal dependencies, or requires rapid iteration
- Example:
epic1-router-implementation/in the fast-slow-skill-variants feature
Slow/Complex Pattern (User-Story-Level): For complex features with multiple dependencies, high risk, or requiring thorough validation:
- Break down into individual user stories, each with its own design and implementation plans
- Used when: Feature requires staged delivery, has unclear requirements, or needs isolated validation
- Example: Individual user stories in content-aggregation feature
Decision Criteria:
- Use Epic-Level (Fast) when: Straightforward implementation, limited scope (<5 days), low risk, team has domain expertise
- Use User-Story-Level (Slow) when: Complex implementation, multiple dependencies, high risk, requires staged validation
tools/citation-manager/
├── design-docs/ # Tool-level design documentation
│ ├── Overview.md # Tool baseline overview
│ ├── Principles.md # Tool-specific principles
│ ├── Architecture.md # Tool baseline architecture
│ └── features/ # Tool-specific features
│ └── {{YYYYMMDD}}-{{feature-name}}/
│ ├── {{feature-name}}-prd.md # Feature PRD
│ ├── {{feature-name}}-design-plan.md # Feature architecture and design plan
│ ├── {{feature-name}}-implement-plan.md # (Optional) For smaller features that don't need epics and user stories
│ ├── research/ # Feature research
│ └── user-stories/ # Epic or user story implementations
│ ├── epic{{X}}-{{epic-name}}/ # FAST/SIMPLE: Epic-level organization
│ │ ├── epic{{X}}-{{epic-name}}-design.md
│ │ ├── epic{{X}}-{{epic-name}}-plan.md
│ │ └── tasks/ # Task implementation details (optional)
│ │ └── task-{{task-number}}-dev-results.md
│ └── us{{X.Y}}-{{story-name}}/ # SLOW/COMPLEX: User-story-level organization
│ ├── us{{X.Y}}-{{story-name}}.md
│ ├── us{{X.Y}}-{{story-name}}-design-plan.md
│ └── us{{X.Y}}-{{story-name}}-implement-plan.md
├── src/ # Source code
├── test/ # Tests
├── README.md # Quick start and tool summary
└── package.json # Package configuration
Rationale: This flexible structure enables appropriate documentation rigor based on feature complexity while maintaining consistent organizational patterns. Fast features benefit from reduced documentation overhead, while complex features get the detailed planning they require.
Action-Based Organization: Following our Action-Based File Organization principle, files should be named by their primary transformation or operation on data.
- Tool Scripts: Executable entry points for tools must use
kebab-case.ts(e.g.,citation-manager.ts) - Source Modules: Implementation files should use
camelCase.tsfollowing transformation naming (e.g.,parseMarkdown.ts,validateCitations.ts,generateReport.ts) - Data Contracts: Type definition files use
camelCase.tswithTypessuffix (e.g.,citationTypes.ts,validationTypes.ts) - Test Files: Test files mirror the module name with
.test.tssuffix (e.g.,parseMarkdown.test.ts) - Configuration Files: TypeScript configs use
.tsextension (vitest.config.ts,vite.config.ts), standard configs remain unchanged (package.json,biome.json,tsconfig.json) - Compiled Output: JavaScript files in
dist/directory mirror source structure with.jsextension and accompanying.d.tstype definitions
-
Transformation Naming: Name files by their primary operation using verb-noun or noun-verb patterns:
parseMarkdown.ts- parses markdown to ASTvalidateCitations.ts- validates citation referencesextractContent.ts- extracts content from documentscalculateMetrics.ts- calculates metrics from data
-
Primary Export Pattern: Each file exports one main function matching (or closely related to) the file name:
parseMarkdown.ts→export function parseMarkdown()validateCitations.ts→export function validateCitations()
-
Helper Co-location: Supporting functions stay in the same file as their primary operation:
parseMarkdown.tscontains helper functions likenormalizeWhitespace(),tokenizeLine()
-
Type Separation: Extract shared types to dedicated
*Types.tsfiles to prevent circular dependencies:citationTypes.ts- interfaces and types used across citation validation, parsing, and reportingvalidationTypes.ts- interfaces and types used across multiple validation modules- TypeScript interfaces and type aliases provide compile-time contracts without runtime overhead
-
Component Folders: Group related operations by level 3 component:
src/core/MarkdownParser/- all parsing operationssrc/core/CitationValidator/- all validation operationssrc/service/Logger/- all logging operations. INservice/since it is cross-cutting
-
Strategy Subfolders: Extract variants when using strategy patterns:
src/parsing/strategies/- markdown, html, json parserssrc/validation/rules/- different validation rule implementations
To ensure a consistent, traceable, and agent-friendly development process, all feature work will adhere to the following workflow and organizational structure. This process creates a single source of truth for each user story, from its definition to its implementation details.
The implementation of a user story follows four distinct phases:
- Elicitation: The process begins with the high-level Architecture Document and the Product Requirements Document (PRD), which together define the strategic context and goals.
- Decomposition: A specific User Story is created as a markdown file. This file acts as the central orchestration document for all work related to the story.
- Tasking: Within the User Story file, the work is broken down into a checklist of discrete Tasks, each representing a verifiable step toward completing the story's acceptance criteria.
- Specification: Each task in the story file links to a self-contained Implementation Details markdown file, which provides the specific, detailed instructions for a development agent to execute that task.
TypeScript introduces additional validation steps in the development workflow:
- Type Checking: Run
tsc --noEmitbefore committing to catch type errors - Build Verification: Run
npm run buildto ensure TypeScript compiles successfully - Test Execution: Tests run against TypeScript source with integrated type checking
- Development Mode: Use
npm run devfor HMR during active development - Pre-Commit Validation: Biome checks + TypeScript type checking must pass
All artifacts for a given user story must be organized within the design-docs/features/ directory using the following hierarchical structure, which prioritizes discoverability and temporal context.
- Pattern:
design-docs/features/{{YYYYMMDD}}-{{feature-short-name}}/user-stories/us{{story-number}}-{{story-full-name}}/
- Example:
design-docs/features/20250926-version-based-analysis/user-stories/us1.1-version-detection-and-directory-scaffolding/
Complete feature documentation follows this hierarchical organization:
design-docs/features/{{YYYYMMDD}}-{{feature-short-name}}/
├── {{feature-short-name}}-prd.md # Product Requirements Document
├── {{feature-short-name}}-architecture.md # Architecture (impact to baseline)
├── research/ # Feature research and analysis
│ └── {{research-topic}}.md
└── user-stories/ # User story implementations
└── us{{story-number}}-{{story-full-name}}/
├── us{{story-number}}-{{story-full-name}}.md
└── tasks/ # Task implementation details (optional)
└── us{{story-number}}-t{{task-number}}-{{task-name}}.md
Example:
design-docs/features/20250928-cc-workflows-workspace-scaffolding/
├── cc-workflows-workspace-prd.md
├── cc-workflows-workspace-architecture.md
├── research/
│ └── content-aggregation-research.md
└── user-stories/
└── us1.1-establish-workspace-directory-structure-and-basic-config/
└── us1.1-establish-workspace-directory-structure-and-basic-config.md
-
Feature PRD: Product requirements document for the feature
- Pattern:
{{feature-short-name}}-prd.md - Example:
cc-workflows-workspace-prd.md
- Pattern:
-
Feature Architecture: Architecture document showing impact to baseline
- Pattern:
{{feature-short-name}}-architecture.md - Example:
cc-workflows-workspace-architecture.md
- Pattern:
-
Research Documents: Analysis and research supporting feature decisions
- Pattern:
{{research-topic}}.md - Example:
content-aggregation-research.md
- Pattern:
Use for straightforward features with limited scope (<5 days), low risk, and minimal dependencies.
-
Epic Design Document: Design and architecture for the entire epic
- Pattern:
epic{{X}}-{{epic-name}}-design.md - Example:
epic1-router-implementation-design.md
- Pattern:
-
Epic Implementation Plan: Implementation plan and pseudocode for the entire epic
- Pattern:
epic{{X}}-{{epic-name}}-plan.md - Example:
epic1-router-implementation-plan.md
- Pattern:
Use for complex features requiring staged delivery, unclear requirements, or isolated validation.
-
User Story File: The central orchestration document for the story
- Pattern:
us{{X.Y}}-{{story-full-name}}.md - Example:
us1.1-establish-workspace-directory-structure-and-basic-config.md
- Pattern:
-
User Story Design Plan: Design plan bridging requirements to technical details
- Pattern:
us{{X.Y}}-{{story-full-name}}-design-plan.md - Example:
us1.1-establish-workspace-directory-structure-and-basic-config-design-plan.md
- Pattern:
-
User Story Implementation Plan: Implementation plan with pseudocode
- Pattern:
us{{X.Y}}-{{story-full-name}}-implement-plan.md - Example:
us1.1-establish-workspace-directory-structure-and-basic-config-implement-plan.md
- Pattern:
-
Task Implementation Details File: Self-contained specification for a single task (optional)
- Pattern:
tasks/us{{X.Y}}-t{{task-number}}-{{full-task-name}}.md - Example:
tasks/us1.1-t2.1.1-directory-manager-interface-test.md
- Pattern:
This project follows JavaScript/TypeScript naming conventions with one strategic exception for test methods, aligned with our Self-Contained Naming Principles.
This project follows TypeScript naming conventions aligned with our Action-Based File Organization principle.
-
Files: File naming depends on purpose:
- Tool Scripts (executable entry points): Use kebab-case.ts (e.g.,
citation-manager.ts,ask-enhanced.ts) - Implementation Modules (transformation operations): Use camelCase.ts named by their primary transformation (e.g.,
parseMarkdown.ts,validateCitations.ts,extractContent.ts) - Rationale: File names describe operations that transform data, following Transformation Naming
- Tool Scripts (executable entry points): Use kebab-case.ts (e.g.,
-
Functions & Variables: Use camelCase for all functions and variables (e.g.,
parseMarkdown,extractContent,validationResult)- Primary Exports: Each file's main export should match or closely relate to the file name (Primary Export Pattern)
- Type Annotations: Include explicit type annotations for function parameters and return types
-
Constants: Use UPPER_SNAKE_CASE for constants (e.g.,
MAX_DEPTH,DEFAULT_ENCODING) -
Classes: Use TitleCase for class names (e.g.,
CitationValidator,MarkdownParser) -
Interfaces: Use TitleCase with
Iprefix optional (e.g.,CitationorICitation,ValidationResultorIValidationResult)- Rationale: Modern TypeScript convention omits
Iprefix; use team preference consistently
- Rationale: Modern TypeScript convention omits
-
Type Aliases: Use TitleCase for type aliases (e.g.,
ValidationError,CitationTarget) -
Type Files: Use camelCase.ts with
Typessuffix for shared type definitions (e.g.,citationTypes.ts,validationTypes.ts)- Rationale: Separates data contracts (WHAT) from operations (HOW) per Data Contracts Separate
-
Enums: Use TitleCase for enum names and UPPER_SNAKE_CASE for enum values (e.g.,
enum LogLevel { DEBUG = "DEBUG", INFO = "INFO" }) -
Test Descriptions: Use natural language with spaces for test descriptions in
it()methods (e.g.,it('should validate citations with valid references', () => {...}))- Rationale: Test descriptions serve as executable specifications requiring maximum clarity per our "Names as Contracts" philosophy
Components define their own dependency interfaces inline. This enforces the Interface Segregation principle: each component declares only the methods it needs.
Decision Tree:
- 1 component needs it: Define interface inline in that component
- 2 components need it: Copy the interface definition to each component (keep them independent)
- 3+ components need the exact same contract: Promote to
src/types/interfaces.tsas a shared type
Example: CitationValidator needs only resolveParsedFile() from the cache. It defines ParsedFileCacheInterface inline with that single method. If ContentExtractor later needs cache access, it defines its own interface—even if identical—to remain decoupled from CitationValidator.
Anti-Pattern: Never import a dependency interface from another component (e.g., ContentExtractor importing from CitationValidator). This creates nonsensical coupling where one component breaks when another changes its requirements.
NEVER use any type - Using any defeats the entire purpose of TypeScript by disabling type checking. Instead:
- Use proper type definitions - Define explicit interfaces or types for your data structures
- Use type guards - Create runtime type guards with
ispredicates for unknown types - Use
unknownwith type narrowing - For truly unknown values, useunknownand narrow with type guards - Use generic types - Parameterize types to maintain type safety across transformations
Type Guards Over Type Assertions:
- Prefer runtime type guards (
ispredicates) over type assertions (ascasts) - Type assertions bypass type checking and can hide bugs
- Type guards provide runtime validation that aligns with compile-time types
Explicit Types for Public APIs:
- All exported functions must have explicit parameter and return type annotations
- All exported classes must have explicit property type annotations
- Internal/private code may use type inference when the type is obvious
Strict TypeScript Configuration:
- All projects use
strict: trueintsconfig.json noExplicitAnyrule is enforced inbiome.json- These settings catch maximum number of type errors at compile time
- Indentation: Use tabs for indentation (configured via Biome)
- Rationale: Tabs allow developers to configure visual width to their preference while maintaining smaller file sizes. The existing codebase uses tabs consistently, and Biome is configured to enforce this standard.
- Modular Structure: Each module should have a single, clear responsibility (Single Responsibility)
- Interface Boundaries: Define clear APIs between components (Black Box Interfaces)
- Error Handling: Implement fail-fast principles with clear error messages (Fail Fast)
- Self-Documenting Code: Names should provide immediate understanding without lookup (Immediate Understanding)
- Inline Comments: Include contextual comments for complex logic (Contextual Comments)
- Function Documentation: Use docstrings to document public APIs and their contracts
- MVP-Focused Testing: We will maintain a lean target test-to-code ratio of 0.3:1 to 0.5:1. The primary goal is to prove that functionality works as specified in the user story's acceptance criteria, not to achieve 100% test coverage.
- Integration-Driven Development: We start by writing a failing integration test that validates a user story, then build the minimum code required to make it pass.
- Real Systems, Fake Fixtures:
- Real Systems:
- Tests will run against the real file system, execute real shell commands, and inject real Components
- Fake Fixtures:
- Test fixture files (not production documents). You can copy a production document into the fixture folders
- We have a zero-tolerance policy for mocking.
- Static, Not Dynamic: Fixtures created once and checked into repo
- Real Systems:
The workspace provides a shared Vitest configuration and common testing principles, but each tool maintains its own independent test suite. Fulfills the requirement for a shared, centralized testing framework FR2
Test Files:
- Test files use
.test.tsextension (TypeScript) - TypeScript type checking integrated into test execution
- Tests run against TypeScript source without requiring pre-compilation
Type Safety in Tests:
- All test code uses TypeScript with strict type checking
- Type errors caught at compile-time before test execution
- IDE provides autocomplete and inline documentation during test development
Browser Testing:
- For browser-based testing needs, use the
superpowers-chromeMCP tool - Playwright is NOT used in this workspace (CLI-first tooling focus)
- Browser testing via
superpowers-chromewhen validating web-based workflows
Current State:
- No shared test utilities or helpers
- Each tool creates its own fixtures and test infrastructure
- Tools are completely self-contained
Future State:
- Shared test utilities will be promoted to workspace-level when patterns emerge across multiple tools
- Will follow cross-cutting testing investment level (comprehensive coverage of shared infrastructure)
Our strategy distinguishes between cross-cutting workspace functionality and tool-specific functionality, allowing us to invest testing effort appropriately.
- Scope: Shared workspace functionality that multiple tools depend on, such as configuration management, dependency resolution, or future shared utilities.
- Goal: To prove shared infrastructure is rock-solid and trustworthy. The focus is on testing the component's public API, success paths, and expected failure modes.
- Investment Level: Test every public method or function against its defined behavior—primary success path, known failure modes, and critical edge cases.
- Current Status: As of MVP, the workspace has minimal cross-cutting functionality (Vitest config, Biome config, NPM workspace setup). Cross-cutting test patterns will be documented as shared workspace infrastructure emerges.
- Scope: Validation of tool-specific functionality and user story acceptance criteria.
- Goal: To prove the tool's functionality works as specified. Treat the tool as a system and verify it produces expected results.
- Investment: Minimal and focused, adhering to the lean 0.3:1 to 0.5:1 test-to-code ratio.
- Reference Implementation: See citation-manager test suite as the established pattern for tool-level testing.
Test method names follow our Self-Contained Naming Principles with a specific exception to optimize for readability and clarity:
- Convention: Use natural language with spaces for test descriptions in
it()method strings - Examples:
it('should authenticate user with valid credentials', () => {...})it('should reject payment processing with insufficient funds', () => {...})it('should run migrated test suite from root test command', () => {...})
Rationale:
- Maximum Readability: Natural language with spaces reads exactly like documentation
- Self-Documenting: Test descriptions serve as executable specifications that anyone can understand immediately
- Immediate Understanding: Test descriptions benefit from natural sentence structure per our "Names as Contracts" philosophy
- String Literal Context: Since test descriptions are string literals in
it()methods, they can use spaces without language constraints
Implementation Examples:
// Preferred: Natural language with spaces for clear test intent
describe('PaymentProcessor', () => {
it('should succeed when processing payment with valid card', () => {
// Given: Valid payment data and authenticated user
// When: Payment is processed through gateway
// Then: Transaction succeeds and receipt is generated
});
it('should retry when timeout occurs during gateway communication', () => {
// Given: Network timeout simulation
// When: Payment gateway times out
// Then: System retries with exponential backoff
});
});This naming convention aligns with our "Names as Contracts" philosophy (Descriptive Labels, Immediate Understanding) by prioritizing communication clarity and natural readability.
All tests must be structured with comments that follow the Behavior-Driven Development (BDD) style of Given-When-Then. This practice makes the intent of each test unambiguous and serves as clear documentation.
- Given: This block describes the initial context or preconditions. It sets up the state of the system before the action under test occurs.
- When: This block describes the specific action, event, or operation being tested. It should ideally be a single, focused action.
- Then: This block contains the assertions that verify the expected outcome, result, or state change.
Code Example: This is how the convention should be applied within a Vitest test file
describe('MyUtility', () => {
it('should return true when conditions are met', () => {
// Given: A specific setup or initial state.
const utility = new MyUtility({ config: 'enabled' });
const input = 'valid_input';
// When: The method under test is called.
const result = utility.checkConditions(input);
// Then: The outcome is asserted.
expect(result).toBe(true);
});
});The workspace uses two complementary testing approaches based on what's being validated:
When testing CLI entry points, use execSync() to test the entire system from the outside. No dependency injection needed - the CLI creates its own components.
import { strict as assert } from 'node:assert';
import { execSync } from 'node:child_process';
import { join } from 'node:path';
import { describe, test } from 'node:test';
describe('Citation Manager Integration Tests', () => {
test('should validate citations in valid-citations.md successfully', async () => {
// Given: A markdown file with valid citations exists in test fixtures
const testFile = join(__dirname, 'fixtures', 'valid-citations.md');
// When: The validate command executes against the test file
// Note: No DI needed - CLI creates its own components internally
const output = execSync(
`node "${citationManagerPath}" validate "${testFile}"`,
{ encoding: 'utf8' }
);
// Then: The validation report confirms all citations are valid
assert(output.includes('✅ ALL CITATIONS VALID'), 'Should report all citations as valid');
assert(output.includes('Total citations:'), 'Should show citation count');
assert(output.includes('Validation time:'), 'Should show validation time');
});
});When to use: Testing user-facing behavior and acceptance criteria.
Issue: The current CLI integration testing pattern using execSync() to spawn subprocesses creates a 64KB stdio pipe buffer limit on macOS. When CLI output exceeds this limit (e.g., large JSON validation results with 100+ citations producing 92KB+ output), the data gets truncated, resulting in malformed JSON and test failures.
Root Cause: Node.js child_process stdio pipes have OS-level buffer limits (~64KB on macOS). Tests that spawn the CLI as a subprocess are subject to these limits, while production CLI usage (writing directly to terminal stdout) is not affected.
Current Workaround: Shell redirection to temporary files bypasses pipe buffers but adds complexity to test infrastructure.
Recommended Mitigation: Refactor tests to import CLI functions directly instead of spawning subprocesses:
- Import
validateFile(),formatAsJSON()from CLI Orchestrator component - Reserve subprocess testing for true E2E scenarios (argument parsing, exit codes)
- Aligns test architecture with production architecture (both use same code path)
Reference: Bug 3: Buffer Limit Resolution
Architectural Decision: CLI tools must maintain strict separation between data output (stdout) and diagnostic messages (stderr). This separation ensures:
- JSON output remains parseable (no warnings/errors mixed in)
- Real-world CLI usage patterns work correctly (piping, redirection)
- Tests accurately reflect production behavior
Implementation Pattern:
CLI tools should route output based on type:
- stdout: Structured data (JSON), primary command output
- stderr: Warnings, diagnostics, validation errors, progress messages
Test Helper Pattern:
The cli-runner.ts helper supports both capture modes:
// For JSON output - capture only stdout (default: captureStderr=true)
const output = runCLI(
`node dist/citation-manager.js validate file.md --format json`,
{ captureStderr: false } // Don't mix stderr into stdout
);
const result = JSON.parse(output); // Clean JSON parsing
// For text output - capture both streams
const output = runCLI(
`node citation-manager.js validate file.md`,
{ captureStderr: true } // Merge stderr for full output
);
expect(output).toContain('Validation errors found'); // Check errorsExample - Citation Manager:
// Production code correctly separates streams
if (options.format === 'json') {
console.log(JSON.stringify(result, null, 2)); // stdout
} else {
console.log(formatTextReport(result)); // stdout
}
console.error('Validation errors found:'); // stderrTest Pattern:
it('should validate with JSON format', () => {
// Given: Test file with citations
const testFile = join(FIXTURES_DIR, 'test.md');
// When: Execute with JSON format (stderr not captured)
const output = runCLI(
`node citation-manager.js validate "${testFile}" --format json`,
{ captureStderr: false }
);
// Then: Clean JSON can be parsed without warnings
const result = JSON.parse(output);
expect(result.summary.total).toBeGreaterThan(0);
});Rationale: This pattern matches real-world usage where users pipe JSON to other tools (citation-manager validate file.md --format json | jq .summary) or redirect output (citation-manager validate file.md > report.txt 2> errors.log). Tests must verify this separation works correctly.
When testing component collaboration, use constructor dependency injection to pass in real dependencies (not mocks).
Note: This example represents the target architecture after refactoring citation-manager to implement DI (technical debt) and factory pattern (mitigation strategy).
Production Code - USES Factory:
// File: tools/citation-manager/src/citation-manager.js (CLI entry point)
import { createCitationValidator } from './factories/componentFactory.js';
const validator = createCitationValidator(scopeDirectory);
const results = await validator.validateFile(filePath);Test Code - DEFAULT USES Factory: Use factory as the default. This aligns with our integraiton testing strategy
// File: tools/citation-manager/test/validation.test.js
import { join } from 'node:path';
import { describe, it, expect } from 'vitest';
import { createCitationValidator } from '../src/factories/componentFactory.js';
describe('CitationValidator Integration Tests', () => {
it('should validate citations using factory-created dependencies', () => {
// Given: Factory creates validator with standard production dependencies
const validator = createCitationValidator(join(__dirname, 'fixtures'));
const testFile = join(__dirname, 'fixtures', 'valid-citations.md');
// When: Validator processes file using factory-created components
const result = validator.validateFile(testFile);
// Then: Integration of real components produces expected result
expect(result.isValid).toBe(true);
expect(result.citations).toHaveLength(5);
expect(result.errors).toHaveLength(0);
});
});Test Code - Option 2: BYPASSES Factory: Use only when you need to mock a dependency for more comprehensive unit testing (i.e. a cross cutting concern). Otherwise, we favor integration testing to deliver quickly.
// File: tools/citation-manager/test/validation.test.js
import { join } from 'node:path';
import { describe, it, expect, beforeEach } from 'vitest';
import { CitationValidator } from '../src/CitationValidator.js';
import { MarkdownParser } from '../src/MarkdownParser.js';
import { FileCache } from '../src/FileCache.js';
describe('CitationValidator Integration Tests', () => {
let validator;
beforeEach(() => {
// Given: Real component dependencies created explicitly (bypass factory)
const parser = new MarkdownParser(); // Real parser, not mock
const cache = new FileCache(join(__dirname, 'fixtures')); // Real cache, not mock
// Direct constructor injection for explicit dependency control
validator = new CitationValidator(parser, cache);
});
it('should validate citations using explicitly injected dependencies', () => {
// Given: Test fixture with known citation structure
const testFile = join(__dirname, 'fixtures', 'valid-citations.md');
// When: Validator processes file using explicitly injected dependencies
const result = validator.validateFile(testFile);
// Then: Integration of real components produces expected result
expect(result.isValid).toBe(true);
expect(result.citations).toHaveLength(5);
expect(result.errors).toHaveLength(0);
});
});The ONLY difference: How the validator is created. The factory just wires dependencies - assertions are identical.
Factory Location: Tool-level (tools/citation-manager/src/factories/). Only promotes to workspace-level when multiple tools share component instantiation patterns.
Key Distinction: CLI tests use execSync() to test from outside (no DI needed). Component tests use constructor injection to validate collaboration with real dependencies (DI required).
The citation-manager tool provides the established pattern for tool-level testing within the workspace. See Citation Manager Testing Strategy for complete test structure and principles.
| Technology/Library | Category | Version | Module | Purpose in the System | Used By (Container.Component) |
|---|---|---|---|---|---|
| Node.js | Runtime | >=18.0.0 | node |
Provides the JavaScript execution environment for all tools and scripts. | All Containers |
| TypeScript | Primary Language | >=5.3.0 | typescript |
Primary development language with strict type checking, compiles to JavaScript for execution. Generates .d.ts type definitions for type-safe consumption. |
All Tool Packages |
| NPM Workspaces | Build & Dependency Management | npm 7+ | npm (CLI) |
The core mechanism for managing the monorepo, handling dependency hoisting, and enabling script execution across packages. | Workspace Infrastructure |
| Vite | Development Infrastructure | >=5.0.0 | vite |
Provides shared development infrastructure including HMR, dev server, and bundling capabilities for rapid iteration. | Workspace Infrastructure |
| Vitest | Testing Framework | >=4.0.0 | vitest |
Provides the shared testing framework for running TypeScript unit and integration tests across all packages in the workspace. | All Tool Packages |
| Biome | Code Quality | >=1.9.0 | @biomejs/biome |
Enforces consistent code formatting and linting standards for both JavaScript and TypeScript across the entire monorepo from a single, root configuration. | All Containers |
These are system-wide responsibilities that affect multiple components and tools within the workspace.
Workspace behavior is configured through root-level configuration files that provide shared infrastructure for all tools. This centralized approach ensures consistency and avoids configuration duplication.
- Workspace Structure: The root
package.jsonfile defines the monorepo structure using theworkspacesarray, which specifies glob patterns (tools/*,packages/*) for package discovery. NPM automatically hoists shared dependencies to the rootnode_modules/directory. - TypeScript Configuration: The
tsconfig.base.jsonfile provides shared TypeScript compiler settings that all tools extend, ensuring consistent type checking and compilation behavior across the workspace. - Vite Configuration: The
vite.config.tsfile provides shared development infrastructure (HMR, dev server, bundling) for all tools. - Testing Framework: The
vitest.config.tsfile defines test discovery patterns, the execution environment, and coverage settings for the entire workspace with TypeScript support. - Code Quality: The
biome.jsonfile centralizes all linting and formatting rules for both JavaScript and TypeScript, ensuring that any tool in the workspace inherits these standards automatically.
Key settings within tsconfig.base.json:
| Key | Type | Description |
|---|---|---|
compilerOptions.target |
string |
ECMAScript target version (ES2022). Modern JavaScript features for Node.js >=18. |
compilerOptions.module |
string |
Module system (ES2022). Native ESM support. |
compilerOptions.strict |
boolean |
Enables all strict type checking options for maximum type safety. |
compilerOptions.declaration |
boolean |
Generates .d.ts type definition files alongside compiled JavaScript. |
compilerOptions.sourceMap |
boolean |
Generates source maps for debugging compiled code. |
Key settings within vite.config.ts:
| Key | Type | Description |
|---|---|---|
build.lib.formats |
array(string) |
Output formats (es, cjs). Supports both ESM and CommonJS consumers. |
build.target |
string |
Build target (node18). Optimized for Node.js runtime. |
resolve.conditions |
array(string) |
Module resolution conditions (node). Ensures Node.js-compatible resolution. |
Key settings within biome.json:
| Key | Type | Description |
|---|---|---|
formatter.indentStyle |
string |
Indentation standard (tabs). Allows developer preference configuration while maintaining smaller file sizes. |
javascript.formatter.quoteStyle |
string |
String quote convention (double quotes). Ensures consistency across all JavaScript and TypeScript files. |
linter.rules.recommended |
boolean |
Enables Biome's recommended ruleset for code quality enforcement (JavaScript + TypeScript). |
organizeImports.enabled |
boolean |
Automatic import sorting and organization on format operations. |
files.include |
array(string) |
Glob patterns defining which files Biome processes (includes .ts files). |
files.ignore |
array(string) |
Directories excluded from linting (node_modules, dist, build artifacts). |
Key settings within vitest.config.ts:
| Key | Type | Description |
|---|---|---|
test.environment |
string |
Execution environment (node). Optimized for file system and CLI testing. |
test.include |
array(string) |
Test discovery patterns supporting .test.ts files in workspace packages. |
test.pool |
string |
Process isolation strategy (forks). Ensures proper module isolation. |
test.globals |
boolean |
Disables global test functions (false). Requires explicit imports for clarity. |
coverage.provider |
string |
Coverage collection tool (c8). Native Node.js coverage without instrumentation overhead. |
All code quality enforcement is centralized through Biome, which provides both linting and formatting from a single tool. Quality checks are run from the repository root and apply to all workspace packages.
- Formatting Standards: The workspace enforces tab indentation and double-quote strings to reduce file size and allow for developer-specific display preferences.
- Linting Enforcement: Biome's recommended ruleset is enabled to detect common errors and enforce consistent coding patterns in both JavaScript and TypeScript.
- Type Checking: TypeScript compiler (
tsc) provides additional validation beyond linting, catching type errors at compile-time. - Validation Pattern: Quality checks are run via
npx biome check .for linting/formatting andtsc --noEmitfor type checking from the repository root.
The workspace provides a TypeScript-first build pipeline that compiles source code to JavaScript with type definitions for distribution.
- TypeScript Compilation: The
tsccompiler transforms TypeScript source (.ts) to JavaScript (.js) with accompanying type definitions (.d.ts) in tool-specificdist/directories. - Type Checking: Strict type checking runs during compilation, catching type errors before code execution.
- Source Maps: Generated source maps enable debugging of compiled code with TypeScript source line numbers.
- Build Commands:
npm run build- Builds all workspace packagesnpm run type-check- Type checks without emitting files- Tool-specific builds via
npm run build:citationfor individual tools
- Vite Integration: Vite provides additional bundling capabilities and HMR during development, complementing TypeScript compilation.
The workspace provides Vite-based development infrastructure for rapid iteration during tool development.
- Dev Server: Vite dev server (
npm run dev) provides HMR for instant feedback during development. - Hot Module Reloading (HMR): Code changes reflect immediately without full restart, accelerating development cycles.
- Build Watch Mode: Continuous compilation during development via
npm run devin tool directories. - TypeScript Integration: Vite natively supports TypeScript, providing seamless development experience with type checking and HMR.
The workspace provides a shared Vitest testing framework that discovers and executes TypeScript tests across all packages from a single root command, fulfilling the requirement for a centralized testing framework.
- Test Discovery: Vitest is configured with glob patterns to discover
.test.tsfiles in workspace packages (tools/**/test/**/*.test.ts,packages/**/test/**/*.test.ts). - TypeScript Support: Tests run against TypeScript source without pre-compilation, with type checking integrated into test execution.
- Testing Principles: All tests must adhere to the "Real Systems, Fake Fixtures" principle, which mandates a zero-tolerance policy for mocking application components and favors testing against real file system operations. Tests must also follow the BDD Given-When-Then comment structure.
NPM Workspaces manages all dependencies through a centralized installation process that hoists shared packages to the root level while supporting package-specific requirements.
- Hoisting Strategy: Shared development dependencies like
vitestand@biomejs/biomeare installed once at the rootnode_modules/directory to ensure version consistency and reduce installation overhead. - Installation Process: A single
npm installcommand from the repository root installs dependencies for all workspace packages. The rootpackage-lock.jsonfile ensures deterministic dependency resolution across the entire workspace.
The workspace establishes a consistent pattern for executing tool CLIs through root-level npm scripts, providing centralized command discovery and parameter passing.
- Root Script Orchestration: The root
package.jsondefines npm scripts that execute workspace package CLIs from compiled output vianodecommands (e.g.,"citation:validate": "node tools/citation-manager/dist/citation-manager.js validate"). This makes all tool commands discoverable vianpm run. - Compilation Requirement: Tools must be compiled (
npm run build) before execution, as CLIs run fromdist/directories containing compiled JavaScript. - Parameter Passing: CLI arguments are passed to the target script using the standard
--separator convention (e.g.,npm run citation:validate -- file.md).
TypeScript tools configure their bin field to point directly to the compiled output with a shebang:
Pattern:
- Compiled Output (
dist/src/tool-name.js): TypeScript compilation target with shebang (#!/usr/bin/env node) - Bin Configuration: Points directly to compiled output
Implementation:
// src/citation-manager.ts (source)
#!/usr/bin/env node
// CLI implementationPackage.json Configuration:
{
"main": "dist/src/citation-manager.js",
"bin": {
"citation-manager": "./dist/src/citation-manager.js"
},
"scripts": {
"postbuild": "chmod +x dist/src/citation-manager.js"
}
}Rationale:
- Direct bin-to-dist linking is the 2025 best practice (2ality.com)
- No wrapper needed - TypeScript preserves shebangs in compiled output
- Simpler pattern with fewer files to maintain
- Postbuild script ensures executable permissions
Test Pattern:
Tests reference the dist file directly (e.g., node tools/citation-manager/dist/src/citation-manager.js --help)
The current workspace establishes foundational error handling at the infrastructure level, with individual tools remaining responsible for their own specific error management. A more comprehensive, centralized logging strategy is planned for the future.
- Configuration Validation: Schema validation for configuration files occurs at tool startup. For instance, schema issues in
biome.jsonwere discovered and corrected during the Story 1.1 implementation. - Test Execution Errors: Vitest provides detailed reporting for test failures, including stack traces and assertion messages.
- CLI Error Reporting: Individual tools are expected to handle their own errors and report them to
stderrwith appropriate non-zero exit codes, a pattern that enables reliable script composition.
Use Dependency Injection (DI) as a foundational pattern to achieve a modular architecture. DI is the practice of providing a component with its dependencies from an external source, rather than having the component create them internally. This approach is the primary mechanism for supporting our core principles of Modularity, Replaceable Parts, and Dependency Abstraction. By decoupling components, we make them easier to test, reuse, and replace without causing ripple effects across the system.
While DI makes it possible to inject mock dependencies for isolated unit testing, our testing philosophy explicitly prioritizes integration tests that verify real component interactions. Therefore, the workspace adheres to the "Real Systems, Fake Fixtures" principle, which includes a "zero-tolerance policy for mocking" application components. Our strategy is to use DI to inject real dependencies during testing to gain the highest confidence that our components work together correctly.
For example, the CitationValidator should receive its MarkdownParser dependency via its constructor. During testing, we will pass in the real MarkdownParser to ensure the validation logic works with the actual parsing output. This gives us confidence that the integrated system functions as expected. The existing citation-manager code, which does not fully use DI, has been identified as technical debt to be refactored to align with this principle.
The workspace supports sharing tools with external projects through npm link, enabling local development workflows where external projects can consume workspace tools without publishing them to a registry. This pattern is particularly valuable for iterating on tools while testing them in real-world usage contexts.
Use Cases:
- Local development iteration across multiple projects
- Testing tool changes in external projects before release
- Sharing tools with projects outside the workspace (e.g., cc-workflows-site, ResumeCoach)
Implementation:
The npm link pattern creates symlinks in two steps:
-
Create Global Link (from tool directory):
cd /path/to/cc-workflows/tools/citation-manager npm linkCreates symlink:
/opt/homebrew/lib/node_modules/@cc-workflows/citation-manager→ tool directory -
Link to External Project (from consuming project):
cd /path/to/external-project npm link "@cc-workflows/citation-manager"
Creates symlink:
node_modules/@cc-workflows/citation-manager→ global package
Result: Changes to the tool in cc-workflows workspace are immediately available in the external project without rebuilding or republishing.
Technical Implementation: Workspace tools must properly detect when executed via symlink (npm link or node_modules/.bin). The CLI entry point uses realpathSync() to resolve symlinks before comparing execution paths:
// citation-manager.js
import { realpathSync } from "node:fs";
import { pathToFileURL } from "node:url";
const realPath = realpathSync(process.argv[1]);
const realPathAsUrl = pathToFileURL(realPath).href;
if (import.meta.url === realPathAsUrl) {
program.parse();
}Rationale: The naive comparison import.meta.url === \file://${process.argv[1]}`fails with symlinks becauseprocess.argv[1]contains the symlink path whileimport.meta.urlresolves to the real path. UsingrealpathSync()` ensures proper detection regardless of how the tool is invoked.
Test Coverage: The cli-execution-detection.test.ts test suite validates symlink execution for all command types (help, validate, extract) to prevent regression.
Reference: See Linking CC-Workflows Tools to External Projects for complete setup guide, troubleshooting, and alternative patterns.
- Status: Accepted
- Date: 2025-09-25
- Context: The project requires a monorepo structure to centralize multiple development tools and eliminate code duplication, starting with the
citation-manager. The solution needed to have low initial overhead and strong performance for a small number of packages (5-10) while integrating natively with the Node.js ecosystem. - Decision: We will use NPM Workspaces as the foundational technology for managing the
cc-workflowsmonorepo. It will be the primary mechanism for handling shared dependencies, running scripts across packages, and linking local packages together. - Consequences:
- Positive: The approach has low overhead, as it requires no third-party dependencies and aligns with our Simplicity First principle.
- Positive: The performance is well-suited for our scale, with research confirming excellent installation and build times for repositories with 5-10 packages.
- Positive: It provides a streamlined developer experience with a unified installation process (
npm install) and simple script execution (npm run <script> --workspaces). - Negative: The solution has known scaling limitations, with research indicating potential performance degradation if the workspace grows beyond 70+ packages. ^cc-workflows-workspace-adr-001
- Negative: It lacks advanced features like built-in task dependency graphing and computation caching, which may require supplemental tooling (e.g., Nx, Turborepo) if future complexity increases.
- Status: Accepted
- Date: 2024-11-12
- Context: The workspace reached a stable foundation with established testing patterns and operational tooling. As complexity grows and more tools are added, the risk of runtime type errors increases. JavaScript's dynamic typing provides flexibility but defers error detection to runtime or test execution, increasing debugging cycles. The citation-manager tool has ~58 files (10 source, 48 tests) with complex data flows between components, making it an ideal candidate for type safety validation before expanding the workspace further.
- Decision: Adopt TypeScript as the primary development language for all workspace tools, with strict type checking enabled. All new tools must be written in TypeScript, and existing tools will be migrated following the Infrastructure-First pattern validated with citation-manager as the pilot.
- Alternatives Considered:
- JSDoc + Type Checking: Provides gradual typing without compilation step, but offers weaker type guarantees and inferior IDE support
- Flow: Facebook's type system with similar capabilities, but smaller ecosystem and uncertain long-term support
- Continue with JavaScript: Lowest friction, but accumulating technical debt as codebase complexity increases
- Consequences:
- Positive: Compile-time error detection catches type violations before code executes, reducing debugging cycles
- Positive: IDE autocomplete and inline documentation via type information improves developer experience
- Positive: Explicit type contracts serve as living documentation without manual maintenance
- Positive: Refactoring confidence through compiler-verified type safety during large-scale changes
- Positive: Architecture principle alignment - strengthens Data-First Design, Fail Fast, and Self-Contained Naming principles
- Negative: Build step required - adds compilation before execution, though mitigated by HMR during development
- Negative: Learning curve for team members unfamiliar with TypeScript (minimal for experienced JavaScript developers)
- Negative: Migration effort - 58 files in citation-manager require conversion, though Infrastructure-First approach minimizes risk
- Status: Accepted
- Date: 2024-11-12
- Context: The workspace lacked unified development infrastructure for rapid iteration. Developers manually restarted processes after code changes, slowing development cycles. TypeScript compilation added a build step, making instant feedback even more critical. The workspace needed a development server with Hot Module Reloading (HMR) to maintain fast iteration while supporting TypeScript. The cc-workflows-site project successfully demonstrated Vite with TypeScript + Vitest integration, providing a validated reference pattern.
- Decision: Adopt Vite as the shared development infrastructure for HMR, dev server capabilities, and bundling. Vite complements TypeScript compilation by providing instant feedback during development while supporting production builds when needed.
- Alternatives Considered:
- Webpack: Mature bundler with extensive ecosystem, but complex configuration and slower HMR
- esbuild: Extremely fast builds, but limited plugin ecosystem and less mature dev server
- No dev server: Simplest option, but forces manual restarts and slow iteration cycles
- ts-node-dev: TypeScript-specific watch mode, but limited to Node.js and no bundling capabilities
- Consequences:
- Positive: Hot Module Reloading provides instant feedback during development without full restarts
- Positive: Native TypeScript support eliminates separate transpilation configuration
- Positive: Fast cold starts due to native ESM and esbuild-powered transforms
- Positive: Unified tooling - Vite integrates with Vitest (already in use) for consistent dev experience
- Positive: Flexible output - supports both ESM and CommonJS for diverse consumers
- Positive: Validated pattern - cc-workflows-site project demonstrates successful integration
- Negative: Build complexity - adds another tool to the stack, though benefits outweigh overhead
- Negative: Not required for CLI tools - dev server less critical for CLI-focused workspace, but HMR valuable during development
- Negative: Learning curve - team must understand Vite configuration, though simpler than alternatives
Semantic Tools: AI agent definitions and configurations that require evaluation frameworks rather than traditional unit testing
Deterministic Tools: Standard code-based utilities that can be tested with conventional testing frameworks
Meta-Work Tax: The 2-4 day overhead of planning, impact analysis, and manual file management required before any actual feature development can begin
Centralized Workspace: Single repository containing all reusable development tools, shared testing infrastructure, and common build processes
Related Architecture Documents:
- TypeScript + Vite Migration PRD: Requirements document for TypeScript and Vite adoption
- CC Workflows PRD: Product requirements and epic breakdown for MVP implementation
- Content Aggregation Research: Industry patterns and technical recommendations for workspace management
- [C4 Model Framework Overview](/Users/wesleyfrederick/Documents/ObsidianVaultNew/Technical KnowledgeBase/AI Coding Assistants/Concepts/C4 Framework Overview.md): Architectural documentation methodology used in this document
- Psuedocode Style Guide: Pseudocode syntax reference used in this document
- citation-guidelines: Citation and reference formatting standards used in this document
- WORKSPACE-SETUP: Validated workspace patterns for workspace configuration and development
External References:
- TypeScript Documentation: Official TypeScript language and compiler documentation
- TypeScript Handbook: Comprehensive TypeScript guide and best practices
- Vite Documentation: Official Vite build tool and dev server documentation
- Vitest Documentation: Official Vitest testing framework documentation (Vite-native)
- NPM Workspaces Documentation: Foundation pattern for package management
- C4 Model Documentation: Architectural documentation methodology used in this document
| Date | Version | Level | Change Description | Author |
|---|---|---|---|---|
| 2025-09-23 | 1.0 | System Context | Initial baseline architecture through Level 1 context diagram | Wesley |
| 2025-10-04 | 2.0 | Baseline | Copied from workspace feature to Baseline arch doc | Wesley |
| 2024-11-12 | 3.0 | Baseline | TypeScript + Vite adoption - comprehensive architecture update reflecting TypeScript as primary language, Vite for dev infrastructure, updated all sections (principles, containers, code org, testing, tech stack, cross-cutting concerns, ADRs) | Application Tech Lead |
| 2025-01-13 | 3.1 | Code Organization | Added dual documentation patterns (epic-level vs user-story-level) to Tool/Package Documentation Organization and File Naming Conventions sections. Epic-level pattern for fast/simple features (<5 days, low risk), user-story-level pattern for slow/complex features (staged delivery, high risk). Includes decision criteria and examples from fast-slow-skill-variants feature. | Application Tech Lead |