@abarcenas/ai-workflow-template 1.21.0 → 1.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,46 +1,22 @@
1
- ---
2
- applyTo: "**"
3
- description: "Persistent project knowledge accumulated across sessions. This file grows over time as agents discover patterns, conventions, gotchas, and preferences during work. It enables self-improvement — each session learns from the last."
4
- ---
1
+ # Learned Knowledge
5
2
 
6
- # Learned Project Knowledge
3
+ > Accumulated patterns, conventions, gotchas, and agent tuning notes from TDD and other pipeline sessions.
7
4
 
8
- This file is the project's cumulative memory. It is read at the start of every session and updated at the end of every orchestrated pipeline.
5
+ ## Session: 2026-06-13
9
6
 
10
- ## How to Use
7
+ **Pipeline:** TDD Infrastructure Bootstrap
8
+ **Coverage:** N/A (infrastructure setup)
9
+ **TDD Iterations:** 0
11
10
 
12
- - **Read this file** at the beginning of every task to apply previously discovered patterns and conventions.
13
- - **Append new entries** when you discover something that would help future sessions (patterns, gotchas, preferences).
14
- - **Never overwrite** — only append. This is a living log.
11
+ **New knowledge:**
12
+ - Project is a template distribution package (npm), not a deployable application
13
+ - Source code is in `scripts/` (ES modules), not a traditional `src/` directory
14
+ - E2E tests use Playwright with `tests/` directory, `.spec.ts` extension
15
+ - Unit tests use Vitest with `scripts/` directory, `.test.{js,ts}` extension
16
+ - Playwright config uses `chromium` as default, `fullyParallel: true`
17
+ - Coverage threshold is 90% across all metrics (statements, branches, functions, lines)
15
18
 
16
- ---
17
-
18
- ## Project Overview
19
-
20
- <!-- High-level project description filled in over time -->
21
-
22
- ## Conventions & Patterns
23
-
24
- <!-- Coding conventions, architectural patterns, naming conventions discovered in this project -->
25
-
26
- ## Gotchas & Deviations
27
-
28
- <!-- Unexpected behaviors, tricky configs, known pitfalls -->
29
-
30
- ## Preferences
31
-
32
- <!-- User preferences about tooling, style, approach, etc. -->
33
-
34
- ## Architecture Decisions
35
-
36
- <!-- Key technical decisions and their rationale -->
37
-
38
- ## Agent Tuning Notes
39
-
40
- <!-- Per-agent prompt improvements discovered during sessions -->
41
-
42
- ---
43
-
44
- ## Session Log
45
-
46
- <!-- New entries are appended here by the orchestrator after each pipeline -->
19
+ **Agent tuning notes:**
20
+ - unit-tester: Must be told to look in `scripts/` for source and test files, not `src/`
21
+ - coder: Must be told the project uses ES module syntax (import/export, not require/module.exports)
22
+ - implementer: Plans should target `scripts/` for production code and tests
@@ -70,6 +70,20 @@ flowchart TD
70
70
  - Includes task index file (`_index.md`) listing all tasks with their statuses
71
71
  - Preserves complete thought process and history for each task
72
72
 
73
+ ### Graph-Enhanced Context (graphify)
74
+
75
+ When `graphify-out/graph.json` exists, it serves as a complementary machine-readable index of all file relationships, dependencies, and architectural patterns. The memory bank's markdown files capture human-written project context; graphify captures automatically extracted code-level connections.
76
+
77
+ **Bootstrap:** If `graphify-out/graph.json` does not exist, run `graphify .` to generate the knowledge graph before reading any memory bank files. This ensures code-level relationship data is available alongside the markdown context.
78
+
79
+ **When to query the graph instead of reading files:**
80
+ - Architecture and dependency questions → `graphify query` (subgraph results, ~200-800 tokens)
81
+ - Component interaction tracing → `graphify path "<A>" "<B>"`
82
+ - Focused concept deep-dives → `graphify explain "<concept>"`
83
+ - Community/pattern overview → `graphify-out/GRAPH_REPORT.md`
84
+
85
+ **Keeping the graph current:** After any code modification, run `graphify update .` (AST-only, zero API cost) to sync the graph.
86
+
73
87
  ### Additional Context
74
88
 
75
89
  Create additional files/folders within memory-bank/ when they help organize:
@@ -86,8 +100,12 @@ Create additional files/folders within memory-bank/ when they help organize:
86
100
 
87
101
  ```mermaid
88
102
  flowchart TD
89
- Start[Start] --> ReadFiles[Read Memory Bank]
90
- ReadFiles --> CheckFiles{Files Complete?}
103
+ Start[Start] --> CheckGraph{graphify-out/graph.json exists?}
104
+ CheckGraph -->|No| Bootstrap[Run graphify .]
105
+ Bootstrap --> ReadFiles[Read Memory Bank]
106
+ CheckGraph -->|Yes| ReadFiles
107
+ ReadFiles --> QueryGraph[Query graphify for architecture context]
108
+ QueryGraph --> CheckFiles{Files Complete?}
91
109
 
92
110
  CheckFiles -->|No| Plan[Create Plan]
93
111
  Plan --> Document[Document in Chat]
@@ -139,6 +157,41 @@ For every task:
139
157
 
140
158
  The Markdown record is the source of truth for auditing, traceability, and recovery after session resets.
141
159
 
160
+ ## Graphify-Enhanced Context Retrieval
161
+
162
+ When `graphify-out/graph.json` exists, prefer graphify over grep/glob for codebase questions:
163
+
164
+ | Question Type | Graphify Command | Replaces |
165
+ |---|---|---|
166
+ | How does X work? | `graphify explain "X"` | Grep for definitions, reading multiple files |
167
+ | What calls Y? | `graphify query "calls Y depends-on Y invokes Y"` | Recursive grep for callers across files |
168
+ | How does A connect to B? | `graphify path "A" "B"` | Manual dependency tracing across files |
169
+ | Architecture overview | `graphify query "architecture layers patterns dependencies"` | GRAPH_REPORT.md / file-by-file analysis |
170
+ | Community structure | `graphify-out/GRAPH_REPORT.md` `## Communities` | Manual folder hierarchy analysis |
171
+ | Key abstractions | `graphify query "interface abstract class base pattern"` | Grep for interface/abstract class definitions |
172
+
173
+ **Token efficiency:** graphify queries return focused subgraphs (~200-800 tokens) vs. raw grep results (often 3000+ tokens for large codebases). Always query the graph first; fall back to grep only when graphify lacks sufficient data or `graphify-out/graph.json` is missing.
174
+
175
+ **Expanding queries:** When a graphify query returns 0 hits, expand the question against the graph's vocabulary before falling back to grep. Run:
176
+ ```
177
+ $(cat graphify-out/.graphify_python) -c "
178
+ import json, re
179
+ from pathlib import Path
180
+ data = json.loads(Path('graphify-out/graph.json').read_text())
181
+ vocab = set()
182
+ for n in data['nodes']:
183
+ for c in re.findall(r'[^\W\d_]+', n.get('label','') or '', re.UNICODE):
184
+ parts = re.findall(r'[A-Z]+(?=[A-Z][a-z])|[A-Z]?[a-z]+|[A-Z]+', c) or [c]
185
+ for p in parts:
186
+ t = p.lower()
187
+ if 3 <= len(t) <= 30:
188
+ vocab.add(t)
189
+ Path('graphify-out/.vocab.txt').write_text('\n'.join(sorted(vocab)))
190
+ print(f'vocab: {len(vocab)} tokens')
191
+ "
192
+ ```
193
+ Then select up to 12 tokens from the vocabulary list that semantically match the query intent, and re-run with the expanded query.
194
+
142
195
  ## Documentation Updates
143
196
 
144
197
  Memory Bank updates occur when:
@@ -147,6 +200,7 @@ Memory Bank updates occur when:
147
200
  2. After implementing significant changes
148
201
  3. When user requests with **update memory bank** (MUST review ALL files)
149
202
  4. When context needs clarification
203
+ 5. After code changes that introduce new relationships — run `graphify update .` to sync the graph
150
204
 
151
205
  ```mermaid
152
206
  flowchart TD
@@ -22,12 +22,16 @@ All planning, implementation, and execution work must be recorded in Markdown fi
22
22
 
23
23
  **MUST complete before starting implementation:**
24
24
 
25
+ 0. **Verify graphify graph:** Check `graphify-out/graph.json` exists. If not, run `graphify .` to generate it. The graph provides code-level relationship data (dependencies, callers, patterns) that the memory bank's markdown docs alone cannot capture. Skip this step only if the task exclusively modifies markdown/docs files.
25
26
  1. Read `memory-bank/activeContext.md` to understand current focus and recent changes
26
27
  2. Read `memory-bank/progress.md` to understand project-wide status
27
28
  3. Read `memory-bank/tasks/_index.md` to find the task assigned to you
28
29
  4. Read the full task file in `memory-bank/tasks/` — understand the request, thought process, implementation plan, and all subtasks
29
- 5. Identify referenced files mentioned in the task and examine them for context
30
- 6. Understand current project structure and conventions
30
+ 5. **Graphify context for referenced files:** For each referenced file mentioned in the task:
31
+ - Run `graphify explain "<file-or-component>"` to get all connected nodes and their relationships
32
+ - Run `graphify path "<task-relevant-component>" "<referenced-file>"` to trace dependency chains
33
+ - Fall back to the Read tool only when graphify lacks detail or the file is not in the graph
34
+ 6. Understand current project structure and conventions via the graph's community structure (`graphify-out/GRAPH_REPORT.md` `## Communities`) and the memory bank's `systemPatterns.md`
31
35
 
32
36
  ## 2. Systematic Implementation Process
33
37
 
@@ -36,7 +40,7 @@ All planning, implementation, and execution work must be recorded in Markdown fi
36
40
  1. **Process subtasks in order** — Follow the task file's subtask sequence exactly, one step at a time
37
41
  2. **Before implementing any subtask:**
38
42
  - Fully understand all implementation requirements from the task file
39
- - Gather any additional required context
43
+ - Gather any additional required context — prefer `graphify query "<subtask topic>"` over grep/glob for discovering related files, callers, and patterns
40
44
  3. **Implement the subtask completely with working code:**
41
45
  - Follow existing code patterns and conventions
42
46
  - Create working functionality that meets all requirements
@@ -74,6 +78,7 @@ All planning, implementation, and execution work must be recorded in Markdown fi
74
78
  2. Update `memory-bank/activeContext.md` — summarize what was implemented and set next steps
75
79
  3. Update `memory-bank/tasks/_index.md` — mark the task file as Completed
76
80
  4. Mark the task's overall status to Completed in its own file
81
+ 5. Run `graphify update .` to sync the knowledge graph with newly implemented code (AST-only, zero API cost)
77
82
 
78
83
  ## 5. Problem Resolution
79
84
 
@@ -88,16 +93,18 @@ All planning, implementation, and execution work must be recorded in Markdown fi
88
93
  ## Implementation Workflow
89
94
 
90
95
  ```
96
+ 0. Verify graphify-out/graph.json exists (run `graphify .` if not)
91
97
  1. Read activeContext.md, progress.md, tasks/_index.md, and the assigned task file
92
98
  2. For each unchecked subtask:
93
- a. Fully understand requirements
99
+ a. Fully understand requirements — query graphify for context
94
100
  b. Implement with working code following workspace patterns
95
101
  c. Validate implementation meets requirements
96
102
  d. Mark subtask complete in task file
97
103
  e. Add progress log entry to task file with date and details
98
104
  f. Update activeContext.md and _index.md
99
105
  3. Repeat until all subtasks complete
100
- 4. Update progress.md, activeContext.md, _index.md with final status
106
+ 4. Run `graphify update .` to sync graph
107
+ 5. Update progress.md, activeContext.md, _index.md with final status
101
108
  ```
102
109
 
103
110
  ## Success Criteria
@@ -5,6 +5,9 @@ description: 'Comprehensive project architecture blueprint generator that analyz
5
5
 
6
6
  # Comprehensive Project Architecture Blueprint Generator
7
7
 
8
+ > **Pre-discovery:** Load the `context-map` skill first to build a scoped file-level map via graphify. The context map feeds into the full blueprint below.
9
+ > **Graphify:** All codebase discovery uses `graphify query`, `graphify path`, and `graphify explain` against `graphify-out/graph.json`. Grep/glob/read are fallbacks only when graphify returns no results.
10
+
8
11
  ## Configuration Variables
9
12
  ${PROJECT_TYPE="Auto-detect|.NET|Java|React|Angular|Python|Node.js|Flutter|Other"} <!-- Primary technology -->
10
13
  ${ARCHITECTURE_PATTERN="Auto-detect|Clean Architecture|Microservices|Layered|MVVM|MVC|Hexagonal|Event-Driven|Serverless|Monolithic|Other"} <!-- Primary architectural pattern -->
@@ -19,18 +22,45 @@ ${FOCUS_ON_EXTENSIBILITY=true|false} <!-- Emphasize extension points and pattern
19
22
 
20
23
  "Create a comprehensive 'Project_Architecture_Blueprint.md' document that thoroughly analyzes the architectural patterns in the codebase to serve as a definitive reference for maintaining architectural consistency. Use the following approach:
21
24
 
25
+ ### 0. Graphify-First Discovery
26
+
27
+ Before any grep, glob, or manual file reads, leverage the project's knowledge graph for token-efficient discovery:
28
+
29
+ **0a. Bootstrap the graph if needed:**
30
+ If `graphify-out/graph.json` does not exist, generate it first:
31
+ ```
32
+ graphify .
33
+ ```
34
+ This builds the knowledge graph with AST-extracted relationships and community structure. All subsequent discovery steps query the graph.
35
+
36
+ **0b. Architecture detection via graph queries (primary):**
37
+ - `graphify query "architecture pattern layers dependencies"` — discover architectural structure
38
+ - `graphify query "technology stack frameworks packages imports"` — detect tech stack
39
+ - `graphify query "key interfaces abstractions design patterns"` — identify core abstractions
40
+ - `graphify query "cross-cutting concerns authentication logging configuration"` — find cross-cutting concern implementations
41
+
42
+ **0c. Relationship mapping via graph (primary):**
43
+ - `graphify path "<ComponentA>" "<ComponentB>"` — trace dependency chains between subsystems
44
+ - `graphify explain "<component>"` — deep-dive on a single node's connections and patterns
45
+ - `graphify query "circular dependency"` — detect layer violations and dependency cycles
46
+
47
+ **0d. Broad architecture scan:**
48
+ Read `graphify-out/GRAPH_REPORT.md` `## Communities` and `## God Nodes` sections for community structure and hub nodes. Use `graphify-out/wiki/index.md` for agent-navigable wiki if it exists.
49
+
50
+ **0e. Fallback to grep/glob/read:**
51
+ Only when graphify queries return no relevant results (rare for well-structured codebases), fall back to grep/glob/file-reads. Graphify subgraph results are typically 200-800 tokens vs. 3000+ tokens for raw grep output.
52
+
22
53
  ### 1. Architecture Detection and Analysis
23
- - ${PROJECT_TYPE == "Auto-detect" ? "Analyze the project structure to identify all technology stacks and frameworks in use by examining:
24
- - Project and configuration files
25
- - Package dependencies and import statements
26
- - Framework-specific patterns and conventions
27
- - Build and deployment configurations" : "Focus on ${PROJECT_TYPE} specific patterns and practices"}
28
-
29
- - ${ARCHITECTURE_PATTERN == "Auto-detect" ? "Determine the architectural pattern(s) by analyzing:
30
- - Folder organization and namespacing
31
- - Dependency flow and component boundaries
32
- - Interface segregation and abstraction patterns
33
- - Communication mechanisms between components" : "Document how the ${ARCHITECTURE_PATTERN} architecture is implemented"}
54
+ - ${PROJECT_TYPE == "Auto-detect" ? "Use graphify queries to identify all technology stacks and frameworks in use:
55
+ - `graphify query \"technology stack frameworks dependencies imports\"` for tech stack
56
+ - `graphify query \"build configuration deployment infrastructure\"` for build/deploy config
57
+ - Read `graphify-out/GRAPH_REPORT.md` `## Communities` for community-level technology groupings" : "Focus on ${PROJECT_TYPE} specific patterns and practices"}
58
+
59
+ - ${ARCHITECTURE_PATTERN == "Auto-detect" ? "Determine the architectural pattern(s) by querying the graph structure:
60
+ - `graphify query \"layer dependency direction boundaries\"` reveals dependency flow
61
+ - `graphify query \"interfaces abstractions contract segregation\"` reveals interface patterns
62
+ - `graphify path` between key subsystems reveals communication mechanisms
63
+ - `graphify explain \"<layer-name>\"` deep-dives into each architectural layer" : "Document how the ${ARCHITECTURE_PATTERN} architecture is implemented"}
34
64
 
35
65
  ### 2. Architectural Overview
36
66
  - Provide a clear, concise explanation of the overall architectural approach
@@ -39,17 +69,29 @@ ${FOCUS_ON_EXTENSIBILITY=true|false} <!-- Emphasize extension points and pattern
39
69
  - Note any hybrid architectural patterns or adaptations of standard patterns
40
70
 
41
71
  ### 3. Architecture Visualization
72
+
73
+ Extract component relationships from the graph before building diagrams:
74
+ - `graphify query "component subsystem module relationships dependencies"` — discover subsystems
75
+ - `graphify path "<SubsystemA>" "<SubsystemB>"` — verify dependency directions between specific subsystems
76
+ - `graphify explain "<subsystem>"` — deep-dive into a subsystem's internal structure and connections
77
+ - Use `graphify-out/GRAPH_REPORT.md` `## Surprising Connections` for non-obvious cross-boundary links
78
+
42
79
  ${DIAGRAM_TYPE != "None" ? `Create ${DIAGRAM_TYPE} diagrams at multiple levels of abstraction:
43
- - High-level architectural overview showing major subsystems
44
- - Component interaction diagrams showing relationships and dependencies
45
- - Data flow diagrams showing how information moves through the system
80
+ - High-level architectural overview showing major subsystems (from graph community structure)
81
+ - Component interaction diagrams showing relationships and dependencies (from graph edges)
82
+ - Data flow diagrams showing how information moves through the system (from `graphify path` traces)
46
83
  - Ensure diagrams accurately reflect the actual implementation, not theoretical patterns` : "Describe the component relationships based on actual code dependencies, providing clear textual explanations of:
47
- - Subsystem organization and boundaries
48
- - Dependency directions and component interactions
49
- - Data flow and process sequences"}
84
+ - Subsystem organization and boundaries (from graph communities)
85
+ - Dependency directions and component interactions (from graph edges)
86
+ - Data flow and process sequences (from `graphify path` traces)"}
50
87
 
51
88
  ### 4. Core Architectural Components
52
- For each architectural component discovered in the codebase:
89
+ Discover components via the graph first, then deep-dive:
90
+ - Identify major components from `graphify-out/GRAPH_REPORT.md` `## God Nodes` (hub nodes with highest degree)
91
+ - Use `graphify explain "<component>"` to get all connected nodes and relationships for each god node
92
+ - Use `graphify path "<component>" "<other>"` to trace specific interaction patterns between components
93
+
94
+ For each architectural component discovered:
53
95
 
54
96
  - **Purpose and Responsibility**:
55
97
  - Primary function within the architecture
@@ -321,6 +363,9 @@ Create a clear architectural guide for implementing new features:
321
363
 
322
364
  Include information about when this blueprint was generated and recommendations for keeping it updated as the architecture evolves.
323
365
 
366
+ ### Post-Generation: Keep Graph Current
367
+ After the blueprint is generated, run `graphify update .` to incrementally re-extract any changed files. This keeps the graph aligned with newly documented architecture understanding, so future queries (`graphify query`, `graphify path`, `graphify explain`) return up-to-date results without rebuilding the entire graph.
368
+
324
369
  ### ${INCLUDES_DECISION_RECORDS ? "18" : INCLUDES_CODE_EXAMPLES ? "17" : "16"}. Populate Agent Knowledge Base
325
370
 
326
371
  Write the discovered architecture details into the persistent knowledge system so all orchestrator agents (researcher, architect, implementer, coder, tracker) inherit this context without rediscovery:
@@ -5,6 +5,9 @@ description: "Generate a map of all files relevant to a task before making chang
5
5
 
6
6
  # Context Map
7
7
 
8
+ > **Wired into:** `architecture-blueprint-generator` loads this skill as its pre-discovery step to build a scoped file-level map before generating the full blueprint.
9
+ > **Graphify:** All discovery uses `graphify query`, `graphify path`, and `graphify explain` against `graphify-out/graph.json`. Grep/glob are fallbacks only.
10
+
8
11
  Before implementing any changes, analyze the codebase and create a context map.
9
12
 
10
13
  ## Task
@@ -13,10 +16,30 @@ Before implementing any changes, analyze the codebase and create a context map.
13
16
 
14
17
  ## Instructions
15
18
 
16
- 1. Search the codebase for files related to this task
17
- 2. Identify direct dependencies (imports/exports)
18
- 3. Find related tests
19
- 4. Look for similar patterns in existing code
19
+ ### Graphify-First Discovery
20
+
21
+ 1. **Bootstrap graph if needed:** Check `graphify-out/graph.json`. If missing, run `graphify .` first. The graph provides relationship data that grep alone cannot discover.
22
+
23
+ 2. **Discover related files:** Use `graphify query "{{task_description}}"` to find files and nodes relevant to the task. For multi-concept tasks, run separate queries per concept and merge results.
24
+
25
+ 3. **Identify direct dependencies:** Use `graphify path "<source>" "<target>"` between key components to trace dependency chains. This reveals import/export relationships without scanning every file.
26
+
27
+ 4. **Find related tests:** Use `graphify query "test spec <task_keywords>"` to surface test files connected to the relevant components.
28
+
29
+ 5. **Discover similar patterns:** Use `graphify explain "<pattern_or_component>"` to find existing implementations and connected nodes that follow the same pattern.
30
+
31
+ ### Fallback (graphify unavailable or no results)
32
+
33
+ If `graphify-out/graph.json` is missing and cannot be generated, or queries return no results:
34
+
35
+ 1. Search the codebase for files related to this task (grep/glob)
36
+ 2. Identify direct dependencies (imports/exports via grep)
37
+ 3. Find related tests (glob `**/*.test.*` / `**/*.spec.*`)
38
+ 4. Look for similar patterns in existing code (grep for class/function patterns)
39
+
40
+ ### Post-Generation
41
+
42
+ After the context map is created, run `graphify update .` to sync the graph with any newly identified relationships. This keeps future context-map invocations efficient.
20
43
 
21
44
  ## Output Format
22
45
 
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: graphify-framework-aware
3
+ description: Prepares framework-aware exclusions before graphify knowledge graph generation. Invoke alongside /graphify. Automatically detects Angular, Hugo, Next.js, Svelte, Jekyll, Flutter, WordPress, and Docusaurus projects and excludes their boilerplate files so the graph focuses on your custom code. Triggers on: /graphify, graphify, knowledge graph, codebase graph.
4
+ license: MIT
5
+ allowed-tools: Bash
6
+ ---
7
+
8
+ # graphify-framework-aware
9
+
10
+ Automatically detects your project's framework and configures `.graphifyignore` to exclude framework boilerplate so graphify's knowledge graph focuses on your custom code.
11
+
12
+ ## When to Use
13
+
14
+ Invoke this skill BEFORE running the standard `/graphify` pipeline. The skill is idempotent — running it multiple times is safe, and it will not duplicate patterns.
15
+
16
+ Use when:
17
+ - Running `/graphify` on a project for the first time
18
+ - Running `/graphify --update` to rebuild an existing graph
19
+ - After adding a new framework to a project
20
+ - After changing build tooling or project structure
21
+
22
+ Skip when:
23
+ - The project has no supported framework markers
24
+ - The `.graphifyignore` was already generated and the project structure hasn't changed
25
+ - Graph is already built and framework exclusions were already applied
26
+
27
+ ## Workflow
28
+
29
+ ### Step 1: Apply framework exclusions
30
+
31
+ Run the detection and apply script:
32
+
33
+ ```bash
34
+ python3 <skill-base>/scripts/fw-exclude.py apply <project-path>
35
+ ```
36
+
37
+ This script:
38
+ 1. Scans the project root for framework marker files (e.g., `angular.json`, `hugo.toml`)
39
+ 2. Generates appropriate `.graphifyignore` patterns for each detected framework
40
+ 3. Idempotently writes/updates `.graphifyignore` between marker comments
41
+
42
+ The script outputs a one-line summary:
43
+ ```
44
+ graphify-framework-aware: detected angular, nextjs — wrote 8 exclusion patterns to .graphifyignore
45
+ ```
46
+
47
+ If no frameworks are detected, the script exits with code 2 and prints:
48
+ ```
49
+ No supported frameworks detected.
50
+ ```
51
+
52
+ ### Step 2: Inspect the result (optional)
53
+
54
+ To preview what will be excluded without modifying files:
55
+
56
+ ```bash
57
+ python3 <skill-base>/scripts/fw-exclude.py show <project-path>
58
+ ```
59
+
60
+ To see detected frameworks as JSON:
61
+
62
+ ```bash
63
+ python3 <skill-base>/scripts/fw-exclude.py detect <project-path>
64
+ ```
65
+
66
+ ### Step 3: Proceed with graphify
67
+
68
+ After exclusions are applied, invoke the standard graphify pipeline:
69
+
70
+ ```
71
+ invoke skill: "graphify"
72
+ ```
73
+
74
+ The `.graphifyignore` file will be read by graphify's detection step, and framework boilerplate files will be excluded from the knowledge graph.
75
+
76
+ ### Step 4: Verify (optional)
77
+
78
+ Check the generated `.graphifyignore` at the project root. The framework patterns are in a clearly delimited section:
79
+
80
+ ```
81
+ # ===== graphify-framework-aware (auto-generated) =====
82
+ # auto-detected framework: angular
83
+ **/*.spec.ts
84
+ **/*.harness.ts
85
+ e2e/
86
+ ...
87
+ # ===== end graphify-framework-aware =====
88
+ ```
89
+
90
+ User-added patterns outside this block are never modified. To re-include a framework-excluded path, add a `!` negation pattern anywhere *after* the marker block (graphify reads `.graphifyignore` with last-match-wins semantics).
91
+
92
+ ## Supported Frameworks
93
+
94
+ | Framework | Marker |
95
+ |-----------|--------|
96
+ | Angular | `angular.json` |
97
+ | Next.js | `next.config.{js,ts,mjs}` |
98
+ | Svelte | `svelte.config.js` |
99
+ | Hugo | `hugo.{toml,yaml,json}` |
100
+ | Jekyll | `_config.yml` |
101
+ | Docusaurus | `docusaurus.config.{js,ts}` |
102
+ | Flutter | `pubspec.yaml` (content-verified) |
103
+ | WordPress | `wp-config.php` |
104
+
105
+ See [Framework Registry](./references/framework-registry.md) for the full list of exclusion patterns per framework and instructions for adding new frameworks.
106
+
107
+ ## Script Reference
108
+
109
+ [`scripts/fw-exclude.py`](./scripts/fw-exclude.py) — Python 3.10+, no dependencies beyond stdlib.
110
+
111
+ ```
112
+ usage: fw-exclude.py <detect|show|apply> <project-path>
113
+
114
+ detect Print JSON of detected frameworks and their markers.
115
+ show Print FW exclusion patterns (dry-run, no files written).
116
+ apply Idempotently write/update .graphifyignore with FW patterns.
117
+ ```
118
+
119
+ ## Interaction with graphify
120
+
121
+ - graphify reads `.graphifyignore` (and falls back to `.gitignore`) during its `detect()` step
122
+ - Framework patterns are appended with last-match-wins semantics — user `!` patterns override them
123
+ - Directories already skipped by graphify's built-in `_SKIP_DIRS` (`node_modules/`, `.next/`, `.angular/`, `dist/`, `build/`, etc.) are NOT duplicated in the generated patterns
124
+ - This skill must run **before** invoking the graphify skill so the `.graphifyignore` is in place when graphify scans files
125
+
126
+ ## Troubleshooting
127
+
128
+ | Issue | Solution |
129
+ |-------|----------|
130
+ | "No supported frameworks detected" | Project may use an unsupported framework. Add markers to `fw-exclude.py` or create `.graphifyignore` manually. |
131
+ | Too many files excluded | Check `.graphifyignore` marker block. Add `!` negation patterns after the block to re-include. |
132
+ | `pubspec.yaml` falsely detected as Flutter | Script checks for `flutter` keyword in the file content. Add `!` patterns if needed. |
133
+ | Hugo `config.toml` not detected | Script verifies content for Hugo-specific keys (`baseURL`, `title`). Rename to `hugo.toml` or add patterns manually. |
@@ -0,0 +1,95 @@
1
+ # Framework Exclusion Registry
2
+
3
+ This document defines the framework detection markers and exclusion patterns used by `graphify-framework-aware`. Each framework entry includes its detection markers, default exclusions, and any special heuristics applied.
4
+
5
+ ## Adding a New Framework
6
+
7
+ 1. Add detection marker(s) to `FRAMEWORK_MARKERS` in `scripts/fw-exclude.py`.
8
+ 2. Add exclusion patterns to `FRAMEWORK_EXCLUDES`.
9
+ 3. If complex detection logic is needed (e.g., Hugo theme detection), add it to the `_post_process_excludes()` function.
10
+ 4. Update this document with the new framework's entry.
11
+
12
+ ## Supported Frameworks
13
+
14
+ ### Angular
15
+
16
+ | Attribute | Value |
17
+ |-----------|-------|
18
+ | **Marker file** | `angular.json` |
19
+ | **Excluded** | `**/*.spec.ts`, `**/*.harness.ts`, `e2e/`, `src/environments/`, `karma.conf.js`, `src/test.ts` |
20
+ | **Kept** | `src/app/` (user components, services, modules), `src/assets/` |
21
+ | **Already handled by graphify** | `.angular/`, `node_modules/`, `dist/` |
22
+
23
+ ### Next.js
24
+
25
+ | Attribute | Value |
26
+ |-----------|-------|
27
+ | **Marker file** | `next.config.js`, `next.config.ts`, `next.config.mjs` |
28
+ | **Excluded** | `next-env.d.ts`, `out/` |
29
+ | **Kept** | `src/app/`, `src/pages/`, `src/components/` |
30
+ | **Already handled by graphify** | `.next/`, `node_modules/` |
31
+
32
+ ### Svelte / SvelteKit
33
+
34
+ | Attribute | Value |
35
+ |-----------|-------|
36
+ | **Marker file** | `svelte.config.js` |
37
+ | **Excluded** | `build/`, `**/*.test.ts` |
38
+ | **Kept** | `src/` (all user code) |
39
+ | **Already handled by graphify** | `.svelte-kit/`, `node_modules/` |
40
+
41
+ ### Hugo
42
+
43
+ | Attribute | Value |
44
+ |-----------|-------|
45
+ | **Marker file** | `hugo.toml`, `hugo.yaml`, `hugo.json` |
46
+ | **Excluded (always)** | `public/`, `resources/` |
47
+ | **Excluded (conditional)** | `archetypes/` (unless modified by user), `layouts/` (unless user has custom layouts at root), theme-internal dirs (when theme is vendored via git submodule) |
48
+ | **Kept** | `content/`, `data/`, `static/`, `assets/`, user `layouts/` with custom templates |
49
+ | **Heuristics** | Detects git submodules in `themes/` to exclude theme boilerplate. Detects `layouts/` structure at project root to determine if user has custom templates. |
50
+
51
+ ### Jekyll
52
+
53
+ | Attribute | Value |
54
+ |-----------|-------|
55
+ | **Marker file** | `_config.yml` |
56
+ | **Excluded** | `_site/`, `.jekyll-cache/`, `.jekyll-metadata` |
57
+ | **Kept** | `_posts/`, `_pages/`, `_data/`, `_includes/`, `_layouts/`, `_sass/`, `assets/` |
58
+ | **Already handled by graphify** | `node_modules/` |
59
+
60
+ ### Docusaurus
61
+
62
+ | Attribute | Value |
63
+ |-----------|-------|
64
+ | **Marker file** | `docusaurus.config.js`, `docusaurus.config.ts` |
65
+ | **Excluded** | `.docusaurus/`, `build/` |
66
+ | **Kept** | `docs/`, `src/`, `blog/`, `static/`, `sidebars.js` |
67
+ | **Already handled by graphify** | `node_modules/` |
68
+
69
+ ### Flutter
70
+
71
+ | Attribute | Value |
72
+ |-----------|-------|
73
+ | **Marker file** | `pubspec.yaml` (content-verified for `flutter` keyword) |
74
+ | **Excluded** | `.dart_tool/`, `build/`, `.flutter-plugins`, `.flutter-plugins-dependencies` |
75
+ | **Kept** | `lib/` (user code), `test/` (user tests) |
76
+ | **Already handled by graphify** | — |
77
+
78
+ ### WordPress
79
+
80
+ | Attribute | Value |
81
+ |-----------|-------|
82
+ | **Marker file** | `wp-config.php` |
83
+ | **Excluded** | `wp-admin/`, `wp-includes/`, `wp-content/languages/`, `wp-content/upgrade/` |
84
+ | **Kept** | `wp-content/themes/` (custom themes), `wp-content/plugins/` (custom plugins) |
85
+ | **Already handled by graphify** | `node_modules/` |
86
+
87
+ ## Noise Directories Handled by graphify (not duplicated)
88
+
89
+ The following directories are already excluded by graphify's built-in `_SKIP_DIRS` list. The framework-aware skill does NOT duplicate these patterns:
90
+
91
+ `.angular/`, `.cache/`, `.dart_tool/`, `.graphify/`, `.idea/`, `.next/`, `.nuxt/`, `.parcel-cache/`, `.pytest_cache/`, `.ruff_cache/`, `.serverless/`, `.svelte-kit/`, `.terraform/`, `.tox/`, `.turbo/`, `.venv/`, `__.pycache__/`, `build/`, `coverage/`, `dist/`, `dist-protected/`, `env/`, `graphify-out/`, `lib64/`, `node_modules/`, `out/`, `site-packages/`, `snapshots/`, `storybook-static/`, `target/`, `venv/`, `visual-tests/`
92
+
93
+ ## Noise Files Handled by graphify (not duplicated)
94
+
95
+ `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`, `Cargo.lock`, `poetry.lock`, `Gemfile.lock`, `composer.lock`, `go.sum`, `go.work.sum`
@@ -0,0 +1,425 @@
1
+ #!/usr/bin/env python3
2
+ """graphify-framework-aware: detect project frameworks and generate .graphifyignore patterns.
3
+
4
+ Commands:
5
+ detect <path> Print JSON of detected frameworks and their markers.
6
+ apply <path> Idempotently write/update .graphifyignore with FW patterns.
7
+ show <path> Print FW patterns only (dry-run, no files written).
8
+
9
+ Exit codes: 0 = success, 1 = error (bad path, invalid args), 2 = nothing to apply.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import os
16
+ import re
17
+ import subprocess
18
+ import sys
19
+ from pathlib import Path
20
+
21
+ # ── Framework Registry ────────────────────────────────────────────────────────
22
+ # Adding a new framework:
23
+ # 1. Add detection marker(s) to FRAMEWORK_MARKERS.
24
+ # 2. Add exclude patterns to FRAMEWORK_EXCLUDES.
25
+ # Complex detection (Hugo theme) goes in _post_process_excludes().
26
+
27
+ FRAMEWORK_MARKERS: dict[str, list[str]] = {
28
+ "angular": ["angular.json"],
29
+ "nextjs": ["next.config.js", "next.config.ts", "next.config.mjs"],
30
+ "svelte": ["svelte.config.js"],
31
+ "hugo": ["hugo.toml", "hugo.yaml", "hugo.json"],
32
+ "jekyll": ["_config.yml"],
33
+ "docusaurus": ["docusaurus.config.js", "docusaurus.config.ts"],
34
+ "flutter": ["pubspec.yaml"],
35
+ "wordpress": ["wp-config.php"],
36
+ }
37
+
38
+ FRAMEWORK_EXCLUDES: dict[str, list[str]] = {
39
+ "angular": [
40
+ "**/*.spec.ts",
41
+ "**/*.harness.ts",
42
+ "e2e/",
43
+ "src/environments/",
44
+ "karma.conf.js",
45
+ "src/test.ts",
46
+ ],
47
+ "nextjs": [
48
+ "next-env.d.ts",
49
+ "out/",
50
+ ],
51
+ "svelte": [
52
+ "build/",
53
+ "**/*.test.ts",
54
+ ],
55
+ "hugo": [],
56
+ "jekyll": [
57
+ "_site/",
58
+ ".jekyll-cache/",
59
+ ".jekyll-metadata",
60
+ ],
61
+ "docusaurus": [
62
+ ".docusaurus/",
63
+ "build/",
64
+ ],
65
+ "flutter": [
66
+ ".dart_tool/",
67
+ "build/",
68
+ ".flutter-plugins",
69
+ ".flutter-plugins-dependencies",
70
+ ],
71
+ "wordpress": [
72
+ "wp-admin/",
73
+ "wp-includes/",
74
+ "wp-content/languages/",
75
+ "wp-content/upgrade/",
76
+ ],
77
+ }
78
+
79
+ # Marker section boundaries in .graphifyignore
80
+ _MARKER_START = "# ===== graphify-framework-aware (auto-generated) ====="
81
+ _MARKER_END = "# ===== end graphify-framework-aware ====="
82
+
83
+ # Directories graphify already skips natively — don't duplicate them.
84
+ _GRAPHIFY_BUILTIN_SKIP = frozenset({
85
+ "node_modules", "__pycache__", ".git", "dist", "build", "target", "out",
86
+ "site-packages", "lib64", ".pytest_cache", ".mypy_cache", ".ruff_cache",
87
+ ".tox", ".eggs", "*.egg-info", "graphify-out",
88
+ "coverage", "lcov-report", "visual-tests", "visual-test",
89
+ "__snapshots__", "snapshots", "storybook-static", "dist-protected",
90
+ ".next", ".nuxt", ".turbo", ".angular",
91
+ ".idea", ".cache", ".parcel-cache", ".svelte-kit", ".terraform",
92
+ ".serverless", ".graphify", ".worktrees",
93
+ "venv", ".venv", "env", ".env",
94
+ })
95
+
96
+ # Lock files graphify already skips.
97
+ _GRAPHIFY_BUILTIN_SKIP_FILES = frozenset({
98
+ "package-lock.json", "yarn.lock", "pnpm-lock.yaml",
99
+ "Cargo.lock", "poetry.lock", "Gemfile.lock",
100
+ "composer.lock", "go.sum", "go.work.sum",
101
+ })
102
+
103
+
104
+ # ── Detection ─────────────────────────────────────────────────────────────────
105
+
106
+ def _glob_marker(root: Path, pattern: str) -> bool:
107
+ """Check if a glob pattern matches any file in root (non-recursive by default)."""
108
+ matches = list(root.glob(pattern))
109
+ if matches:
110
+ return any(m.is_file() for m in matches)
111
+ return False
112
+
113
+
114
+ def detect_frameworks(root: Path) -> dict:
115
+ """Scan project root for framework marker files.
116
+
117
+ Returns:
118
+ {"frameworks": ["angular", "nextjs"], "markers": {"angular": ["angular.json"], ...}}
119
+ """
120
+ root = root.resolve()
121
+ if not root.is_dir():
122
+ print(f"error: not a directory: {root}", file=sys.stderr)
123
+ sys.exit(1)
124
+
125
+ found: dict[str, list[str]] = {}
126
+ for fw_name, markers in FRAMEWORK_MARKERS.items():
127
+ matched = [m for m in markers if _glob_marker(root, m)]
128
+ if matched:
129
+ found[fw_name] = matched
130
+
131
+ # Flutter: pubspec.yaml is generic — verify it's a Flutter project
132
+ if "flutter" in found:
133
+ pubspec = root / "pubspec.yaml"
134
+ try:
135
+ content = pubspec.read_text(encoding="utf-8")
136
+ if "flutter" not in content.lower():
137
+ del found["flutter"]
138
+ except OSError:
139
+ del found["flutter"]
140
+
141
+ # Hugo: config.toml needs content check if not hugo.toml
142
+ # (config.toml is too generic — many non-Hugo projects use it)
143
+ if "hugo" in found:
144
+ hugo_specific = any("hugo" in m.lower() for m in found["hugo"])
145
+ if not hugo_specific:
146
+ # Only matched generic config.toml — verify it's actually Hugo
147
+ config_file = next((root / m for m in found["hugo"] if (root / m).exists()), None)
148
+ if config_file:
149
+ try:
150
+ content = config_file.read_text(encoding="utf-8")
151
+ if "baseURL" not in content and "title" not in content:
152
+ del found["hugo"]
153
+ except OSError:
154
+ del found["hugo"]
155
+ else:
156
+ del found["hugo"]
157
+
158
+ return {
159
+ "frameworks": sorted(found.keys()),
160
+ "markers": found,
161
+ }
162
+
163
+
164
+ # ── Exclude pattern generation ────────────────────────────────────────────────
165
+
166
+ def _hugo_theme_is_vendored(root: Path) -> bool:
167
+ """Check if Hugo themes/ directory contains git submodules or cloned themes."""
168
+ themes_dir = root / "themes"
169
+ if not themes_dir.is_dir():
170
+ return False
171
+
172
+ # Check for .gitmodules referencing themes
173
+ gitmodules = root / ".gitmodules"
174
+ if gitmodules.exists():
175
+ try:
176
+ content = gitmodules.read_text(encoding="utf-8")
177
+ if "themes/" in content:
178
+ return True
179
+ except OSError:
180
+ pass
181
+
182
+ # Check if individual themes are git repos (submodules)
183
+ for theme in themes_dir.iterdir():
184
+ if theme.is_dir() and (theme / ".git").exists():
185
+ return True
186
+
187
+ return False
188
+
189
+
190
+ def _hugo_user_has_custom_layouts(root: Path) -> bool:
191
+ """Check if the user has custom layouts at project root (outside themes/)."""
192
+ layouts = root / "layouts"
193
+ if not layouts.is_dir():
194
+ return False
195
+ # Has custom layouts if more than just _default/ and partials/ exist
196
+ entries = list(layouts.iterdir())
197
+ custom_entries = [e for e in entries
198
+ if e.name not in ("_default", "partials", "shortcodes")]
199
+ return len(custom_entries) > 0
200
+
201
+
202
+ def _post_process_excludes(frameworks: dict, root: Path) -> dict[str, list[str]]:
203
+ """Apply framework-specific heuristics to refine exclude patterns.
204
+
205
+ Args:
206
+ frameworks: Raw detection result {"frameworks": [...], "markers": {...}}.
207
+ root: Project root path.
208
+
209
+ Returns:
210
+ Per-framework final exclude lists (may add/remove patterns).
211
+ """
212
+ excludes: dict[str, list[str]] = {}
213
+ for fw in frameworks["frameworks"]:
214
+ patterns = list(FRAMEWORK_EXCLUDES.get(fw, []))
215
+ excludes[fw] = patterns
216
+
217
+ # Hugo: refine based on theme/layout detection
218
+ if "hugo" in excludes:
219
+ patterns = excludes["hugo"]
220
+ patterns.append("public/")
221
+ patterns.append("resources/")
222
+
223
+ if _hugo_theme_is_vendored(root):
224
+ patterns.append("archetypes/")
225
+ patterns.append("themes/**/archetypes/")
226
+ patterns.append("themes/**/layouts/")
227
+ else:
228
+ patterns.append("archetypes/")
229
+
230
+ # If user has custom layouts, only exclude defaults
231
+ if not _hugo_user_has_custom_layouts(root):
232
+ patterns.append("layouts/")
233
+ else:
234
+ patterns.append("layouts/_default/")
235
+ patterns.append("layouts/partials/")
236
+ patterns.append("layouts/shortcodes/")
237
+
238
+ return excludes
239
+
240
+
241
+ # ── .graphifyignore management ────────────────────────────────────────────────
242
+
243
+ def _read_graphifyignore(root: Path) -> tuple[str, list[str]]:
244
+ """Read .graphifyignore and split into preamble / our-section / postscript.
245
+
246
+ Returns: (full_raw_content, lines_matching_our_section)
247
+ """
248
+ gf = root / ".graphifyignore"
249
+ if not gf.exists():
250
+ return ("", [])
251
+ try:
252
+ content = gf.read_text(encoding="utf-8")
253
+ except OSError:
254
+ return ("", [])
255
+ return (content, _extract_marker_lines(content))
256
+
257
+
258
+ def _extract_marker_lines(content: str) -> list[str]:
259
+ """Extract lines between our start/end markers (exclusive)."""
260
+ lines = content.splitlines()
261
+ in_block = False
262
+ block_lines: list[str] = []
263
+ for line in lines:
264
+ if line.strip() == _MARKER_START:
265
+ in_block = True
266
+ continue
267
+ if line.strip() == _MARKER_END:
268
+ in_block = False
269
+ continue
270
+ if in_block:
271
+ block_lines.append(line)
272
+ return block_lines
273
+
274
+
275
+ def _normalize_ignore_line(line: str) -> str:
276
+ """Strip comments and whitespace from a single .graphifyignore line."""
277
+ stripped = line.strip()
278
+ if not stripped or stripped.startswith("#"):
279
+ return ""
280
+ return stripped
281
+
282
+
283
+ def _build_marker_block(excludes: dict[str, list[str]]) -> list[str]:
284
+ """Build the marker-delimited block of FW patterns."""
285
+ lines: list[str] = [_MARKER_START]
286
+ seen: set[str] = set()
287
+
288
+ for fw_name, patterns in excludes.items():
289
+ lines.append(f"# auto-detected framework: {fw_name}")
290
+ for pat in patterns:
291
+ normalized = _normalize_ignore_line(pat)
292
+ if not normalized or normalized in seen:
293
+ continue
294
+ # Skip patterns graphify already skips natively
295
+ if normalized.rstrip("/") in _GRAPHIFY_BUILTIN_SKIP:
296
+ continue
297
+ if normalized in _GRAPHIFY_BUILTIN_SKIP_FILES:
298
+ continue
299
+ seen.add(normalized)
300
+ lines.append(pat)
301
+
302
+ lines.append(_MARKER_END)
303
+ return lines
304
+
305
+
306
+ def _write_graphifyignore(root: Path, excludes: dict[str, list[str]]) -> str:
307
+ """Write or update .graphifyignore, replacing our marker section.
308
+
309
+ Returns the summary string describing what was written.
310
+ """
311
+ gf = root / ".graphifyignore"
312
+ existing_content, existing_block = _read_graphifyignore(root)
313
+
314
+ new_block = _build_marker_block(excludes)
315
+ new_block_text = "\n".join(new_block)
316
+
317
+ # Compare ignoring comments (our own section header comments are stable)
318
+ old_effective = [_normalize_ignore_line(l) for l in existing_block if _normalize_ignore_line(l)]
319
+ new_effective = []
320
+ for l in new_block:
321
+ n = _normalize_ignore_line(l)
322
+ if n and not n.startswith("#"):
323
+ new_effective.append(n)
324
+
325
+ if sorted(old_effective) == sorted(new_effective) and _MARKER_START in existing_content:
326
+ return "unchanged"
327
+
328
+ # Rebuild the file: remove old marker block, insert new one
329
+ if _MARKER_START in existing_content:
330
+ lines = existing_content.splitlines()
331
+ out_lines: list[str] = []
332
+ in_block = False
333
+ for line in lines:
334
+ if line.strip() == _MARKER_START:
335
+ in_block = True
336
+ continue
337
+ if line.strip() == _MARKER_END:
338
+ in_block = False
339
+ continue
340
+ if not in_block:
341
+ out_lines.append(line)
342
+ # Remove trailing blank lines before appending
343
+ while out_lines and out_lines[-1].strip() == "":
344
+ out_lines.pop()
345
+ out_lines.append("")
346
+ out_lines.append(new_block_text)
347
+ result = "\n".join(out_lines)
348
+ if not result.endswith("\n"):
349
+ result += "\n"
350
+ else:
351
+ # No existing block — append
352
+ if existing_content.strip():
353
+ result = existing_content.rstrip() + "\n\n" + new_block_text + "\n"
354
+ else:
355
+ result = new_block_text + "\n"
356
+
357
+ gf.write_text(result, encoding="utf-8")
358
+
359
+ # Build summary
360
+ fw_names = list(excludes.keys())
361
+ pattern_count = len(new_effective)
362
+ if pattern_count == 0:
363
+ return f"frameworks detected ({', '.join(fw_names)}) but no additional patterns needed"
364
+ return (
365
+ f"detected {', '.join(fw_names)} — wrote {pattern_count} "
366
+ f"exclusion pattern{'s' if pattern_count != 1 else ''} to .graphifyignore"
367
+ )
368
+
369
+
370
+ # ── CLI ───────────────────────────────────────────────────────────────────────
371
+
372
+ def _cmd_detect(root: Path) -> None:
373
+ result = detect_frameworks(root)
374
+ print(json.dumps(result, indent=2))
375
+
376
+
377
+ def _cmd_show(root: Path) -> None:
378
+ result = detect_frameworks(root)
379
+ if not result["frameworks"]:
380
+ print("No supported frameworks detected.", file=sys.stderr)
381
+ sys.exit(2)
382
+ excludes = _post_process_excludes(result, root)
383
+ for fw, patterns in excludes.items():
384
+ print(f"# {fw}")
385
+ for pat in patterns:
386
+ n = _normalize_ignore_line(pat)
387
+ if n and n not in _GRAPHIFY_BUILTIN_SKIP and n not in _GRAPHIFY_BUILTIN_SKIP_FILES:
388
+ print(pat)
389
+ print()
390
+
391
+
392
+ def _cmd_apply(root: Path) -> None:
393
+ result = detect_frameworks(root)
394
+ if not result["frameworks"]:
395
+ print("No supported frameworks detected.", file=sys.stderr)
396
+ sys.exit(2)
397
+ excludes = _post_process_excludes(result, root)
398
+ summary = _write_graphifyignore(root, excludes)
399
+ print(f"graphify-framework-aware: {summary}")
400
+
401
+
402
+ _CMD_TABLE: dict[str, callable] = {
403
+ "detect": _cmd_detect,
404
+ "show": _cmd_show,
405
+ "apply": _cmd_apply,
406
+ }
407
+
408
+
409
+ def main() -> None:
410
+ if len(sys.argv) < 3:
411
+ print(f"usage: {sys.argv[0]} <detect|show|apply> <project-path>", file=sys.stderr)
412
+ sys.exit(1)
413
+
414
+ cmd = sys.argv[1]
415
+ path = Path(sys.argv[2])
416
+
417
+ if cmd not in _CMD_TABLE:
418
+ print(f"error: unknown command '{cmd}' (expected: detect, show, apply)", file=sys.stderr)
419
+ sys.exit(1)
420
+
421
+ _CMD_TABLE[cmd](path)
422
+
423
+
424
+ if __name__ == "__main__":
425
+ main()
package/AGENTS.md CHANGED
@@ -141,9 +141,63 @@ The agent file is at `.opencode/agents/orchestrator/feature-pipeline.agent.md`.
141
141
 
142
142
  **When to use:** You want a predictable, four-step feature pipeline without dynamic agent selection. The orchestrator agent is more flexible; this is more opinionated.
143
143
 
144
+ ### TDD Orchestrator — Test-Driven Development Pipeline
145
+
146
+ Use this when you want strict Test-Driven Development: **tests first, code second**. The pipeline enforces the RED → GREEN → REFACTOR/VERIFY cycle:
147
+
148
+ ```
149
+ implementer (PLAN) → unit-tester∥ (RED) → coder∥ (GREEN) → unit-tester (VERIFY ≥90%) → reviewer → tracker
150
+ ```
151
+
152
+ | Step | Phase | Agent | Role |
153
+ |------|-------|-------|------|
154
+ | 1 | PLAN | implementer | Creates plan with parallel test/code batch tables |
155
+ | 2 | RED | unit-tester∥ | Writes failing tests before any implementation exists |
156
+ | 3 | GREEN | coder∥ | Writes minimal code to pass tests — no extra features |
157
+ | 4 | VERIFY | unit-tester | Runs all tests, checks coverage ≥ 90% |
158
+ | 5 | REVIEW | reviewer | Audits tests + code for quality, security, patterns |
159
+ | 6 | DOCUMENT | tracker | Records results to `docs/tracker-log.md` |
160
+
161
+ The agent file is at `.opencode/agents/orchestrator/tdd-orchestrator.agent.md`.
162
+
163
+ **When to use:** Any feature, bug fix, or refactor where tests should be written first. The orchestrator automatically selects this pipeline when testable code changes are requested.
164
+
165
+ **Coverage gate:** If coverage < 90%, the pipeline loops back to RED phase (up to 3 iterations).
166
+
167
+ ### Memory Bank
168
+
169
+ The memory bank at `memory-bank/` preserves project context across AI sessions. Core files:
170
+
171
+ | File | Purpose |
172
+ |------|---------|
173
+ | `projectbrief.md` | Core requirements, goals, scope |
174
+ | `productContext.md` | Problem solved, UX goals |
175
+ | `systemPatterns.md` | Architecture, design patterns |
176
+ | `techContext.md` | Technologies, setup, constraints |
177
+ | `activeContext.md` | Current focus, recent changes, next steps |
178
+ | `progress.md` | What works, what's left, known issues |
179
+ | `tasks/` | Per-task tracking with `_index.md` |
180
+
181
+ **Always read `activeContext.md` and `progress.md` at the start of every task.** Update them after completing work. See `.agents/instructions/memory-bank.instructions.md` for full details.
182
+
144
183
  ## Additional Resources
145
184
 
146
185
  ### Playwright MCP Configuration
147
186
 
148
187
  For details on how Playwright MCP integrates with the headed mode debugging configuration, see:
149
188
  - **Docs**: `docs/playwright-mcp-configuration.md`
189
+
190
+ ## graphify
191
+
192
+ This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships.
193
+
194
+ When the user types `/graphify`, invoke these skills in order before doing anything else:
195
+ 1. `skill: "graphify-framework-aware"` — detects project frameworks and configures `.graphifyignore` to exclude boilerplate
196
+ 2. `skill: "graphify"` — runs the knowledge graph pipeline
197
+
198
+ Rules:
199
+ - For codebase questions, first run `graphify query "<question>"` when graphify-out/graph.json exists. Use `graphify path "<A>" "<B>"` for relationships and `graphify explain "<concept>"` for focused concepts. These return a scoped subgraph, usually much smaller than GRAPH_REPORT.md or raw grep output.
200
+ - Dirty graphify-out/ files are expected after hooks or incremental updates; dirty graph files are not a reason to skip graphify. Only skip graphify if the task is about stale or incorrect graph output, or the user explicitly says not to use it.
201
+ - If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing.
202
+ - Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context.
203
+ - After modifying code, run `graphify update .` to keep the graph current (AST-only, no API cost).
package/README.md CHANGED
@@ -12,12 +12,17 @@ This isn't a one-off template to clone—it's a **live npm package** that distri
12
12
 
13
13
  - ⚙️ **27+ Specialized AI Skills** - Reusable, task-based workflows (`.agents/skills/`)
14
14
  - 🧠 **Smart Agent Frameworks** - Plan Mode, Implementation Plans, Research Spikes (`.agents/agents/`)
15
+ - 🔄 **Multi-Agent Orchestrator** — Dynamic pipeline builder with 10+ specialized sub-agents
16
+ - 🧪 **TDD Orchestrator** — Strict RED→GREEN→REFACTOR/VERIFY test-driven pipeline (90% coverage gate)
15
17
  - 📝 **Framework Instructions** - Technology-specific guidance (`.agents/instructions/`)
16
18
  - 💬 **Prompt Templates** - Ready-to-use prompt blueprints (`.agents/prompts/`)
19
+ - 🧠 **Memory Bank** — Persistent project context across AI sessions
17
20
  - 🏃‍♂️ **Caveman Mode** - Ultra-compressed communication for token efficiency
18
- - 🧪 **Playwright Testing** - Automated testing with MCP integration
21
+ - 🎭 **Playwright Testing** - Automated E2E testing with MCP integration
22
+ - ⚡ **Vitest Unit Testing** — Fast unit tests with v8 coverage (≥90% threshold)
19
23
  - 📦 **Version Auto-Bumping** - Husky-managed semantic versioning
20
24
  - 🚀 **Auto-Publishing** - npm publish on merge to `main`
25
+ - 🗺️ **graphify Knowledge Graph** — Queryable code-level relationship mapping
21
26
 
22
27
  ---
23
28
 
@@ -158,6 +163,7 @@ Some agents require MCP servers configured in `opencode.mcp.json` (copy from `op
158
163
  - 📋 `create-implementation-plan` - Structured task planning
159
164
  - ✍️ `create-readme` - Automated README generation
160
165
  - 🎯 `context-map` - File relevance mapping
166
+ - 🧠 `graphify` - Codebase knowledge graph generation
161
167
 
162
168
  ### Development Tools
163
169
  - 🎭 `playwright-explore-website` / `playwright-generate-test` - Browser automation
@@ -179,6 +185,84 @@ Some agents require MCP servers configured in `opencode.mcp.json` (copy from `op
179
185
 
180
186
  ---
181
187
 
188
+ ### 🧠 Knowledge Graph (graphify)
189
+
190
+ Turns any folder of code, docs, papers, images, or videos into a **queryable knowledge graph** with community detection, interactive HTML visualization, and GraphRAG-ready JSON.
191
+
192
+ ```bash
193
+ # Build a knowledge graph for the current directory
194
+ /graphify
195
+
196
+ # Build for a specific path
197
+ /graphify <path>
198
+
199
+ # Query an existing graph
200
+ /graphify query "How does authentication work?"
201
+ ```
202
+
203
+ #### Prerequisites
204
+
205
+ - **Python 3.10+** — required runtime
206
+ - **`graphifyy` Python package** — `pip install graphifyy` or `uv tool install graphifyy`
207
+ - **Optional: Gemini API key** (`GEMINI_API_KEY` or `GOOGLE_API_KEY`) — enables faster semantic extraction; without it, graphify falls back to Claude subagents
208
+
209
+ > 📖 [GitHub: safishamsi/graphify](https://github.com/safishamsi/graphify) — full docs, examples, and source
210
+
211
+ ---
212
+
213
+ ### 🧪 TDD Orchestrator — Test-Driven Development Pipeline
214
+
215
+ The project enforces a strict **Test-Driven Development** methodology through a specialized orchestrator that runs the **RED → GREEN → REFACTOR/VERIFY** cycle:
216
+
217
+ ```
218
+ implementer (PLAN) → unit-tester∥ (RED) → coder∥ (GREEN) → unit-tester (VERIFY) → reviewer → tracker
219
+ ```
220
+
221
+ | Step | Agent | Phase | Description |
222
+ |------|-------|-------|-------------|
223
+ | 1 | Implementer | PLAN | Creates implementation plan with parallel test/code batch tables |
224
+ | 2 | Unit Tester | RED | Writes FAILING tests first — defines expected behavior before any code exists |
225
+ | 3 | Coder | GREEN | Writes MINIMAL production code to pass all tests — no extra features |
226
+ | 4 | Unit Tester | VERIFY | Runs full suite, enforces ≥90% coverage threshold |
227
+ | 5 | Reviewer | REFACTOR | Audits tests + implementation for quality, security, patterns |
228
+ | 6 | Tracker | DOCUMENT | Records pipeline results to `docs/tracker-log.md` |
229
+
230
+ **Key TDD rules enforced:**
231
+ - Tests are ALWAYS written first (RED phase) — no implementation until tests exist
232
+ - Coverage gate: if <90%, loop back to RED phase (up to 3 iterations)
233
+ - Every test suite tracked in `memory-bank/tasks/`
234
+ - Lessons learned persisted to `.agents/instructions/learned-knowledge.instructions.md`
235
+
236
+ **How to invoke:**
237
+
238
+ ```bash
239
+ @orchestrator Add user authentication with login/logout endpoints
240
+ ```
241
+
242
+ The TDD orchestrator uses `subagent_type "tdd-orchestrator"` and auto-selects the strict TDD pipeline when testable code changes are requested.
243
+
244
+ ### 🧠 Memory Bank — Persistent Project Context
245
+
246
+ The memory bank preserves project knowledge across AI sessions, preventing context loss after resets:
247
+
248
+ ```
249
+ projectbrief.md → productContext.md / systemPatterns.md / techContext.md → activeContext.md → progress.md / tasks/
250
+ ```
251
+
252
+ | File | Purpose |
253
+ |------|---------|
254
+ | `memory-bank/projectbrief.md` | Core requirements, goals, and scope |
255
+ | `memory-bank/productContext.md` | Problem solved, UX goals |
256
+ | `memory-bank/systemPatterns.md` | Architecture, design patterns, component relationships |
257
+ | `memory-bank/techContext.md` | Technologies, dev setup, constraints |
258
+ | `memory-bank/activeContext.md` | Current focus, recent changes, next steps |
259
+ | `memory-bank/progress.md` | What works, what's left, known issues |
260
+ | `memory-bank/tasks/` | Per-task tracking with `_index.md` |
261
+
262
+ **Task commands:** `add task`, `update task [ID]`, `show tasks [filter]`
263
+
264
+ ---
265
+
182
266
  ## 📦 Versioning
183
267
 
184
268
  Husky automatically bumps versions on every commit:
@@ -219,10 +303,29 @@ npm run sync -- --dry-run
219
303
  # Test package creation
220
304
  npm pack --json
221
305
 
222
- # Run Playwright tests
306
+ # Run Playwright E2E tests
223
307
  npm test
308
+
309
+ # Run unit tests (Vitest)
310
+ npm run test:unit
311
+
312
+ # Run unit tests with coverage (90% threshold)
313
+ npm run test:unit:coverage
314
+
315
+ # Watch mode for unit tests
316
+ npm run test:unit:watch
224
317
  ```
225
318
 
319
+ ### Testing
320
+
321
+ | Type | Framework | Command | Coverage |
322
+ |------|-----------|---------|----------|
323
+ | E2E | Playwright | `npm test` | — |
324
+ | Unit | Vitest | `npm run test:unit` | `npm run test:unit:coverage` (≥90%) |
325
+
326
+ - **E2E tests** live in `tests/*.spec.ts` — browser automation via Playwright
327
+ - **Unit tests** live in `scripts/*.test.{js,ts}` — component tests via Vitest with v8 coverage
328
+
226
329
  ---
227
330
 
228
331
  ## 🔄 Updating the Shared Template
@@ -6,6 +6,11 @@
6
6
  "command": ["npx", "-y", "chrome-devtools-mcp@latest"],
7
7
  "enabled": true
8
8
  },
9
+ "angular-cli": {
10
+ "type": "local",
11
+ "command": ["npx", "-y", "@angular/cli", "mcp"],
12
+ "enabled": true
13
+ },
9
14
  "ddg-search": {
10
15
  "type": "local",
11
16
  "command": ["npx", "-y", "ddg-mcp-search"],
@@ -54,6 +59,7 @@
54
59
  "ddg-search_*": "allow",
55
60
  "github_*": "allow",
56
61
  "mcp-everything_*": "allow",
62
+ "angular-cli_*": "allow",
57
63
  "playwright_*": "allow"
58
64
  }
59
65
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abarcenas/ai-workflow-template",
3
- "version": "1.21.0",
3
+ "version": "1.25.0",
4
4
  "description": "A comprehensive template repository for AI-assisted development workflows using GitHub Copilot. This template provides a structured approach to leveraging AI assistance through pre-configured skills, prompts, agents, and coding standards.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -9,6 +9,9 @@
9
9
  "test:ui": "playwright test --ui",
10
10
  "test:debug": "playwright test --debug",
11
11
  "test:report": "playwright show-report",
12
+ "test:unit": "vitest run",
13
+ "test:unit:coverage": "vitest run --coverage",
14
+ "test:unit:watch": "vitest",
12
15
  "prepare": "husky",
13
16
  "sync": "node ./scripts/sync.js",
14
17
  "postinstall": "node ./scripts/sync.js"
@@ -37,7 +40,9 @@
37
40
  ],
38
41
  "devDependencies": {
39
42
  "@playwright/test": "^1.59.1",
43
+ "@vitest/coverage-v8": "^4.1.8",
40
44
  "dotenv": "^17.4.2",
41
- "husky": "^9.0.0"
45
+ "husky": "^9.0.0",
46
+ "vitest": "^4.1.8"
42
47
  }
43
48
  }
@@ -0,0 +1,12 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ describe('sync utility functions', () => {
4
+ it('should validate basic assertions work', () => {
5
+ expect(1 + 1).toBe(2)
6
+ })
7
+
8
+ it('should handle string operations', () => {
9
+ const result = 'ai-workflow-template'.split('-').join(' ')
10
+ expect(result).toBe('ai workflow template')
11
+ })
12
+ })