@mindfoldhq/trellis 0.3.5 → 0.3.7

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.
Files changed (65) hide show
  1. package/README.md +17 -4
  2. package/dist/cli/index.js +1 -0
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/init.d.ts +1 -0
  5. package/dist/commands/init.d.ts.map +1 -1
  6. package/dist/commands/init.js +243 -49
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/update.d.ts +12 -0
  9. package/dist/commands/update.d.ts.map +1 -1
  10. package/dist/commands/update.js +92 -2
  11. package/dist/commands/update.js.map +1 -1
  12. package/dist/migrations/index.d.ts.map +1 -1
  13. package/dist/migrations/index.js +3 -1
  14. package/dist/migrations/index.js.map +1 -1
  15. package/dist/migrations/manifests/0.3.6.json +9 -0
  16. package/dist/migrations/manifests/0.3.7.json +9 -0
  17. package/dist/templates/claude/commands/trellis/brainstorm.md +13 -0
  18. package/dist/templates/claude/commands/trellis/record-session.md +4 -1
  19. package/dist/templates/claude/commands/trellis/start.md +20 -4
  20. package/dist/templates/claude/hooks/inject-subagent-context.py +1 -1
  21. package/dist/templates/claude/hooks/session-start.py +86 -23
  22. package/dist/templates/claude/settings.json +10 -0
  23. package/dist/templates/codex/skills/brainstorm/SKILL.md +13 -0
  24. package/dist/templates/codex/skills/record-session/SKILL.md +4 -1
  25. package/dist/templates/codex/skills/start/SKILL.md +20 -4
  26. package/dist/templates/cursor/commands/trellis-brainstorm.md +13 -0
  27. package/dist/templates/cursor/commands/trellis-record-session.md +4 -1
  28. package/dist/templates/cursor/commands/trellis-start.md +20 -4
  29. package/dist/templates/gemini/commands/trellis/brainstorm.toml +15 -0
  30. package/dist/templates/gemini/commands/trellis/record-session.toml +4 -1
  31. package/dist/templates/gemini/commands/trellis/start.toml +60 -3
  32. package/dist/templates/iflow/commands/trellis/brainstorm.md +13 -0
  33. package/dist/templates/iflow/commands/trellis/record-session.md +4 -1
  34. package/dist/templates/iflow/commands/trellis/start.md +20 -4
  35. package/dist/templates/iflow/hooks/inject-subagent-context.py +1 -1
  36. package/dist/templates/iflow/hooks/session-start.py +86 -23
  37. package/dist/templates/kilo/workflows/brainstorm.md +13 -0
  38. package/dist/templates/kilo/workflows/record-session.md +4 -1
  39. package/dist/templates/kilo/workflows/start.md +64 -3
  40. package/dist/templates/kiro/skills/brainstorm/SKILL.md +13 -0
  41. package/dist/templates/kiro/skills/record-session/SKILL.md +4 -1
  42. package/dist/templates/kiro/skills/start/SKILL.md +20 -4
  43. package/dist/templates/markdown/spec/backend/directory-structure.md +292 -0
  44. package/dist/templates/markdown/spec/backend/script-conventions.md +220 -38
  45. package/dist/templates/opencode/commands/trellis/brainstorm.md +13 -0
  46. package/dist/templates/opencode/commands/trellis/record-session.md +4 -1
  47. package/dist/templates/opencode/commands/trellis/start.md +9 -1
  48. package/dist/templates/opencode/plugin/session-start.js +149 -16
  49. package/dist/templates/qoder/skills/brainstorm/SKILL.md +13 -0
  50. package/dist/templates/qoder/skills/record-session/SKILL.md +4 -1
  51. package/dist/templates/qoder/skills/start/SKILL.md +60 -3
  52. package/dist/templates/trellis/config.yaml +18 -0
  53. package/dist/templates/trellis/index.d.ts.map +1 -1
  54. package/dist/templates/trellis/index.js.map +1 -1
  55. package/dist/templates/trellis/scripts/common/config.py +20 -0
  56. package/dist/templates/trellis/scripts/common/git_context.py +160 -12
  57. package/dist/templates/trellis/scripts/common/task_queue.py +4 -0
  58. package/dist/templates/trellis/scripts/common/worktree.py +78 -11
  59. package/dist/templates/trellis/scripts/create_bootstrap.py +3 -0
  60. package/dist/templates/trellis/scripts/task.py +312 -17
  61. package/dist/utils/template-fetcher.d.ts +60 -7
  62. package/dist/utils/template-fetcher.d.ts.map +1 -1
  63. package/dist/utils/template-fetcher.js +183 -14
  64. package/dist/utils/template-fetcher.js.map +1 -1
  65. package/package.json +7 -9
@@ -66,6 +66,60 @@ def run_script(script_path: Path) -> str:
66
66
  return "No context available"
67
67
 
68
68
 
69
+ def _get_task_status(trellis_dir: Path) -> str:
70
+ """Check current task status and return structured status string."""
71
+ current_task_file = trellis_dir / ".current-task"
72
+ if not current_task_file.is_file():
73
+ return "Status: NO ACTIVE TASK\nNext: Describe what you want to work on"
74
+
75
+ task_ref = current_task_file.read_text(encoding="utf-8").strip()
76
+ if not task_ref:
77
+ return "Status: NO ACTIVE TASK\nNext: Describe what you want to work on"
78
+
79
+ # Resolve task directory
80
+ if Path(task_ref).is_absolute():
81
+ task_dir = Path(task_ref)
82
+ elif task_ref.startswith(".trellis/"):
83
+ task_dir = trellis_dir.parent / task_ref
84
+ else:
85
+ task_dir = trellis_dir / "tasks" / task_ref
86
+ if not task_dir.is_dir():
87
+ return f"Status: STALE POINTER\nTask: {task_ref}\nNext: Task directory not found. Run: python3 ./.trellis/scripts/task.py finish"
88
+
89
+ # Read task.json
90
+ task_json_path = task_dir / "task.json"
91
+ task_data = {}
92
+ if task_json_path.is_file():
93
+ try:
94
+ task_data = json.loads(task_json_path.read_text(encoding="utf-8"))
95
+ except (json.JSONDecodeError, PermissionError):
96
+ pass
97
+
98
+ task_title = task_data.get("title", task_ref)
99
+ task_status = task_data.get("status", "unknown")
100
+
101
+ if task_status == "completed":
102
+ return f"Status: COMPLETED\nTask: {task_title}\nNext: Archive with `python3 ./.trellis/scripts/task.py archive {task_dir.name}` or start a new task"
103
+
104
+ # Check if context is configured (jsonl files exist and non-empty)
105
+ has_context = False
106
+ for jsonl_name in ("implement.jsonl", "check.jsonl", "spec.jsonl"):
107
+ jsonl_path = task_dir / jsonl_name
108
+ if jsonl_path.is_file() and jsonl_path.stat().st_size > 0:
109
+ has_context = True
110
+ break
111
+
112
+ has_prd = (task_dir / "prd.md").is_file()
113
+
114
+ if not has_prd:
115
+ return f"Status: NOT READY\nTask: {task_title}\nMissing: prd.md not created\nNext: Write PRD, then research → init-context → start"
116
+
117
+ if not has_context:
118
+ return f"Status: NOT READY\nTask: {task_title}\nMissing: Context not configured (no jsonl files)\nNext: Complete Phase 2 (research → init-context → start) before implementing"
119
+
120
+ return f"Status: READY\nTask: {task_title}\nNext: Continue with implement or check"
121
+
122
+
69
123
  def main():
70
124
  if should_skip_injection():
71
125
  sys.exit(0)
@@ -95,28 +149,31 @@ Read and follow all instructions below carefully.
95
149
  output.write("\n</workflow>\n\n")
96
150
 
97
151
  output.write("<guidelines>\n")
98
-
99
- output.write("## Frontend\n")
100
- frontend_index = read_file(
101
- trellis_dir / "spec" / "frontend" / "index.md", "Not configured"
102
- )
103
- output.write(frontend_index)
104
- output.write("\n\n")
105
-
106
- output.write("## Backend\n")
107
- backend_index = read_file(
108
- trellis_dir / "spec" / "backend" / "index.md", "Not configured"
109
- )
110
- output.write(backend_index)
111
- output.write("\n\n")
112
-
113
- output.write("## Guides\n")
114
- guides_index = read_file(
115
- trellis_dir / "spec" / "guides" / "index.md", "Not configured"
116
- )
117
- output.write(guides_index)
118
-
119
- output.write("\n</guidelines>\n\n")
152
+ output.write("**Note**: The guidelines below are index files — they list available guideline documents and their locations.\n")
153
+ output.write("During actual development, you MUST read the specific guideline files listed in each index's Pre-Development Checklist.\n\n")
154
+
155
+ spec_dir = trellis_dir / "spec"
156
+ if spec_dir.is_dir():
157
+ for sub in sorted(spec_dir.iterdir()):
158
+ if not sub.is_dir() or sub.name.startswith("."):
159
+ continue
160
+ index_file = sub / "index.md"
161
+ if index_file.is_file():
162
+ output.write(f"## {sub.name}\n")
163
+ output.write(read_file(index_file))
164
+ output.write("\n\n")
165
+ else:
166
+ # Check for nested package dirs (monorepo: spec/<pkg>/<layer>/index.md)
167
+ for nested in sorted(sub.iterdir()):
168
+ if not nested.is_dir():
169
+ continue
170
+ nested_index = nested / "index.md"
171
+ if nested_index.is_file():
172
+ output.write(f"## {sub.name}/{nested.name}\n")
173
+ output.write(read_file(nested_index))
174
+ output.write("\n\n")
175
+
176
+ output.write("</guidelines>\n\n")
120
177
 
121
178
  output.write("<instructions>\n")
122
179
  start_md = read_file(
@@ -125,8 +182,14 @@ Read and follow all instructions below carefully.
125
182
  output.write(start_md)
126
183
  output.write("\n</instructions>\n\n")
127
184
 
185
+ # R2: Check task status and inject structured tag
186
+ task_status = _get_task_status(trellis_dir)
187
+ output.write(f"<task-status>\n{task_status}\n</task-status>\n\n")
188
+
128
189
  output.write("""<ready>
129
- Context loaded. Wait for user's first message, then follow <instructions> to handle their request.
190
+ Context loaded. Steps 1-3 (workflow, context, guidelines) are already injected above do NOT re-read them.
191
+ Start from Step 4. Wait for user's first message, then follow <instructions> to handle their request.
192
+ If there is an active task, ask whether to continue it.
130
193
  </ready>""")
131
194
 
132
195
  result = {
@@ -387,6 +387,19 @@ Here's my understanding of the complete requirements:
387
387
  Does this look correct? If yes, I'll proceed with implementation.
388
388
  ```
389
389
 
390
+ ### Subtask Decomposition (Complex Tasks)
391
+
392
+ For complex tasks with multiple independent work items, create subtasks:
393
+
394
+ ```bash
395
+ # Create child tasks
396
+ CHILD1=$(python3 ./.trellis/scripts/task.py create "Child task 1" --slug child1 --parent "$TASK_DIR")
397
+ CHILD2=$(python3 ./.trellis/scripts/task.py create "Child task 2" --slug child2 --parent "$TASK_DIR")
398
+
399
+ # Or link existing tasks
400
+ python3 ./.trellis/scripts/task.py add-subtask "$TASK_DIR" "$CHILD_DIR"
401
+ ```
402
+
390
403
  ---
391
404
 
392
405
  ## PRD Target Structure (final)
@@ -12,7 +12,10 @@
12
12
  python3 ./.trellis/scripts/get_context.py --mode record
13
13
  ```
14
14
 
15
- [!] If MY ACTIVE TASKS shows any completed tasks, archive them FIRST:
15
+ [!] Archive tasks whose work is **actually done** — judge by work status, not the `status` field in task.json:
16
+ - Code committed? → Archive it (don't wait for PR)
17
+ - All acceptance criteria met? → Archive it
18
+ - Don't skip archiving just because `status` still says `planning` or `in_progress`
16
19
 
17
20
  ```bash
18
21
  python3 ./.trellis/scripts/task.py archive <task-name>
@@ -45,6 +45,10 @@ cat .trellis/spec/backend/index.md # Backend guidelines
45
45
  cat .trellis/spec/guides/index.md # Thinking guides
46
46
  ```
47
47
 
48
+ > **Important**: The index files are navigation — they list the actual guideline files (e.g., `error-handling.md`, `conventions.md`, `mock-strategies.md`).
49
+ > At this step, just read the indexes to understand what's available.
50
+ > When you start actual development, you MUST go back and read the specific guideline files relevant to your task, as listed in the index's Pre-Development Checklist.
51
+
48
52
  ### Step 4: Report and Ask
49
53
 
50
54
  Report what you learned and ask: "What would you like to work on?"
@@ -58,12 +62,28 @@ When user describes a task, classify it:
58
62
  | Type | Criteria | Workflow |
59
63
  |------|----------|----------|
60
64
  | **Question** | User asks about code, architecture, or how something works | Answer directly |
61
- | **Trivial Fix** | Typo fix, comment update, single-line change, < 5 minutes | Direct Edit |
62
- | **Development Task** | Any code change that: modifies logic, adds features, fixes bugs, touches multiple files | **Task Workflow** |
65
+ | **Trivial Fix** | Typo fix, comment update, single-line change | Direct Edit |
66
+ | **Simple Task** | Clear goal, 1-2 files, well-defined scope | Quick confirm Implement |
67
+ | **Complex Task** | Vague goal, multiple files, architectural decisions | **Brainstorm → Task Workflow** |
68
+
69
+ ### Classification Signals
70
+
71
+ **Trivial/Simple indicators:**
72
+ - User specifies exact file and change
73
+ - "Fix the typo in X"
74
+ - "Add field Y to component Z"
75
+ - Clear acceptance criteria already stated
76
+
77
+ **Complex indicators:**
78
+ - "I want to add a feature for..."
79
+ - "Can you help me improve..."
80
+ - Mentions multiple areas or systems
81
+ - No clear implementation path
82
+ - User seems unsure about approach
63
83
 
64
84
  ### Decision Rule
65
85
 
66
- > **If in doubt, use Task Workflow.**
86
+ > **If in doubt, use Brainstorm + Task Workflow.**
67
87
  >
68
88
  > Task Workflow ensures specs are injected to agents, resulting in higher quality code.
69
89
  > The overhead is minimal, but the benefit is significant.
@@ -79,6 +99,43 @@ For questions or trivial fixes, work directly:
79
99
 
80
100
  ---
81
101
 
102
+ ## Simple Task
103
+
104
+ For simple, well-defined tasks:
105
+
106
+ 1. Quick confirm: "I understand you want to [goal]. Shall I proceed?"
107
+ 2. If no, clarify and confirm again
108
+ 3. **If yes: execute ALL steps below without stopping. Do NOT ask for additional confirmation between steps.**
109
+ - Create task directory (Phase 1 Path B, Step 2)
110
+ - Write PRD (Step 3)
111
+ - Research codebase (Phase 2, Step 5)
112
+ - Configure context (Step 6)
113
+ - Activate task (Step 7)
114
+ - Implement (Phase 3, Step 8)
115
+ - Check quality (Step 9)
116
+ - Complete (Step 10)
117
+
118
+ ---
119
+
120
+ ## Complex Task - Brainstorm First
121
+
122
+ For complex or vague tasks, **automatically start the brainstorm process** — do NOT skip directly to implementation.
123
+
124
+ See `/trellis:brainstorm` for the full process. Summary:
125
+
126
+ 1. **Acknowledge and classify** - State your understanding
127
+ 2. **Create task directory** - Track evolving requirements in `prd.md`
128
+ 3. **Ask questions one at a time** - Update PRD after each answer
129
+ 4. **Propose approaches** - For architectural decisions
130
+ 5. **Confirm final requirements** - Get explicit approval
131
+ 6. **Proceed to Task Workflow** - With clear requirements in PRD
132
+
133
+ > **Subtask Decomposition**: If brainstorm reveals multiple independent work items,
134
+ > consider creating subtasks using `--parent` flag or `add-subtask` command.
135
+ > See `/trellis:brainstorm` Step 8 for details.
136
+
137
+ ---
138
+
82
139
  ## Task Workflow (Development Tasks)
83
140
 
84
141
  **Why this workflow?**
@@ -100,6 +157,10 @@ From Simple Task:
100
157
 
101
158
  **Key principle: Research happens AFTER requirements are clear (PRD exists).**
102
159
 
160
+ > **Subtask Decomposition**: For complex tasks with multiple independent work items,
161
+ > consider creating subtasks using `--parent` flag or `add-subtask` command.
162
+ > See `/trellis:brainstorm` Step 8 for details.
163
+
103
164
  ---
104
165
 
105
166
  ### Phase 1: Establish Requirements
@@ -392,6 +392,19 @@ Here's my understanding of the complete requirements:
392
392
  Does this look correct? If yes, I'll proceed with implementation.
393
393
  ```
394
394
 
395
+ ### Subtask Decomposition (Complex Tasks)
396
+
397
+ For complex tasks with multiple independent work items, create subtasks:
398
+
399
+ ```bash
400
+ # Create child tasks
401
+ CHILD1=$(python3 ./.trellis/scripts/task.py create "Child task 1" --slug child1 --parent "$TASK_DIR")
402
+ CHILD2=$(python3 ./.trellis/scripts/task.py create "Child task 2" --slug child2 --parent "$TASK_DIR")
403
+
404
+ # Or link existing tasks
405
+ python3 ./.trellis/scripts/task.py add-subtask "$TASK_DIR" "$CHILD_DIR"
406
+ ```
407
+
395
408
  ---
396
409
 
397
410
  ## PRD Target Structure (final)
@@ -17,7 +17,10 @@ description: "Record work progress after human has tested and committed code"
17
17
  python3 ./.trellis/scripts/get_context.py --mode record
18
18
  ```
19
19
 
20
- [!] If MY ACTIVE TASKS shows any completed tasks, archive them FIRST:
20
+ [!] Archive tasks whose work is **actually done** — judge by work status, not the `status` field in task.json:
21
+ - Code committed? → Archive it (don't wait for PR)
22
+ - All acceptance criteria met? → Archive it
23
+ - Don't skip archiving just because `status` still says `planning` or `in_progress`
21
24
 
22
25
  ```bash
23
26
  python3 ./.trellis/scripts/task.py archive <task-name>
@@ -50,6 +50,10 @@ cat .trellis/spec/backend/index.md # Backend guidelines
50
50
  cat .trellis/spec/guides/index.md # Thinking guides
51
51
  ```
52
52
 
53
+ > **Important**: The index files are navigation — they list the actual guideline files (e.g., `error-handling.md`, `conventions.md`, `mock-strategies.md`).
54
+ > At this step, just read the indexes to understand what's available.
55
+ > When you start actual development, you MUST go back and read the specific guideline files relevant to your task, as listed in the index's Pre-Development Checklist.
56
+
53
57
  ### Step 4: Report and Ask
54
58
 
55
59
  Report what you learned and ask: "What would you like to work on?"
@@ -74,6 +78,10 @@ When user describes a task, classify it:
74
78
  > Task Workflow ensures code-specs are injected to the right context, resulting in higher quality code.
75
79
  > The overhead is minimal, but the benefit is significant.
76
80
 
81
+ > **Subtask Decomposition**: If brainstorm reveals multiple independent work items,
82
+ > consider creating subtasks using `--parent` flag or `add-subtask` command.
83
+ > See the brainstorm skill's Step 8 for details.
84
+
77
85
  ---
78
86
 
79
87
  ## Question / Trivial Fix
@@ -89,15 +97,23 @@ For questions or trivial fixes, work directly:
89
97
 
90
98
  For simple, well-defined tasks:
91
99
 
92
- 1. Quick confirm: "I understand you want to [goal]. Ready to proceed?"
93
- 2. If yes, proceed to **Task Workflow Phase 1 Path B** (create task, write PRD, then research)
94
- 3. If no, clarify and confirm again
100
+ 1. Quick confirm: "I understand you want to [goal]. Shall I proceed?"
101
+ 2. If no, clarify and confirm again
102
+ 3. **If yes: execute ALL steps below without stopping. Do NOT ask for additional confirmation between steps.**
103
+ - Create task directory (Phase 1 Path B, Step 2)
104
+ - Write PRD (Step 3)
105
+ - Research codebase (Phase 2, Step 5)
106
+ - Configure context (Step 6)
107
+ - Activate task (Step 7)
108
+ - Implement (Phase 3, Step 8)
109
+ - Check quality (Step 9)
110
+ - Complete (Step 10)
95
111
 
96
112
  ---
97
113
 
98
114
  ## Complex Task - Brainstorm First
99
115
 
100
- For complex or vague tasks, use the brainstorm process to clarify requirements.
116
+ For complex or vague tasks, **automatically start the brainstorm process** — do NOT skip directly to implementation.
101
117
 
102
118
  See `$brainstorm` for the full process. Summary:
103
119
 
@@ -0,0 +1,292 @@
1
+ # Directory Structure
2
+
3
+ > How backend/CLI code is organized in this project.
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ This project is a **TypeScript CLI tool** using ES modules. The source code follows a **dogfooding architecture** - Trellis uses its own configuration files (`.cursor/`, `.claude/`, `.trellis/`) as templates for new projects.
10
+
11
+ ---
12
+
13
+ ## Directory Layout
14
+
15
+ ```
16
+ src/
17
+ ├── cli/ # CLI entry point and argument parsing
18
+ │ └── index.ts # Main CLI entry (Commander.js setup)
19
+ ├── commands/ # Command implementations
20
+ │ └── init.ts # Each command in its own file
21
+ ├── configurators/ # Configuration generators
22
+ │ ├── index.ts # Platform registry (PLATFORM_FUNCTIONS, derived helpers)
23
+ │ ├── shared.ts # Shared utilities (resolvePlaceholders)
24
+ │ ├── claude.ts # Claude Code configurator
25
+ │ ├── cursor.ts # Cursor configurator
26
+ │ ├── iflow.ts # iFlow CLI configurator
27
+ │ ├── opencode.ts # OpenCode configurator
28
+ │ └── workflow.ts # Creates .trellis/ structure
29
+ ├── constants/ # Shared constants and paths
30
+ │ └── paths.ts # Path constants (centralized)
31
+ ├── templates/ # Template utilities and generic templates
32
+ │ ├── markdown/ # Generic markdown templates
33
+ │ │ ├── spec/ # Spec templates (*.md.txt)
34
+ │ │ ├── init-agent.md # Project root file template
35
+ │ │ ├── agents.md # Project root file template
36
+ │ │ ├── worktree.yaml.txt # Generic worktree config
37
+ │ │ └── index.ts # Template exports
38
+ │ └── extract.ts # Template extraction utilities
39
+ ├── types/ # TypeScript type definitions
40
+ │ └── ai-tools.ts # AI tool types and registry
41
+ ├── utils/ # Shared utility functions
42
+ │ ├── compare-versions.ts # Semver comparison with prerelease support
43
+ │ ├── file-writer.ts # File writing with conflict handling
44
+ │ ├── project-detector.ts # Project type detection
45
+ │ ├── template-fetcher.ts # Remote template download from GitHub
46
+ │ └── template-hash.ts # Template hash tracking for update detection
47
+ └── index.ts # Package entry point (exports public API)
48
+ ```
49
+
50
+ ### Dogfooding Directories (Project Root)
51
+
52
+ These directories are copied to `dist/` during build and used as templates:
53
+
54
+ ```
55
+ .cursor/ # Cursor configuration (dogfooded)
56
+ ├── commands/ # Slash commands for Cursor
57
+ │ ├── start.md
58
+ │ ├── finish-work.md
59
+ │ └── ...
60
+
61
+ .claude/ # Claude Code configuration (dogfooded)
62
+ ├── commands/ # Slash commands
63
+ ├── agents/ # Multi-agent pipeline agents
64
+ ├── hooks/ # Context injection hooks
65
+ └── settings.json # Hook configuration
66
+
67
+ .trellis/ # Trellis workflow (partially dogfooded)
68
+ ├── scripts/ # Python scripts (dogfooded)
69
+ │ ├── common/ # Shared utilities (paths.py, developer.py, etc.)
70
+ │ ├── multi_agent/ # Pipeline scripts (start.py, status.py, etc.)
71
+ │ ├── hooks/ # Lifecycle hook scripts (project-specific, NOT dogfooded)
72
+ │ └── *.py # Main scripts (task.py, get_context.py, etc.)
73
+ ├── workspace/ # Developer progress tracking
74
+ │ └── index.md # Index template (dogfooded)
75
+ ├── spec/ # Project guidelines (NOT dogfooded)
76
+ │ ├── backend/ # Backend development docs
77
+ │ ├── frontend/ # Frontend development docs
78
+ │ └── guides/ # Thinking guides
79
+ ├── workflow.md # Workflow documentation (dogfooded)
80
+ ├── worktree.yaml # Worktree config (Trellis-specific)
81
+ └── .gitignore # Git ignore rules (dogfooded)
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Dogfooding Architecture
87
+
88
+ ### What is Dogfooded
89
+
90
+ Files that are copied directly from Trellis project to user projects:
91
+
92
+ | Source | Destination | Description |
93
+ |--------|-------------|-------------|
94
+ | `.cursor/` | `.cursor/` | Entire directory copied |
95
+ | `.claude/` | `.claude/` | Entire directory copied |
96
+ | `.trellis/scripts/` | `.trellis/scripts/` | All scripts copied |
97
+ | `.trellis/workflow.md` | `.trellis/workflow.md` | Direct copy |
98
+ | `.trellis/.gitignore` | `.trellis/.gitignore` | Direct copy |
99
+ | `.trellis/workspace/index.md` | `.trellis/workspace/index.md` | Direct copy |
100
+
101
+ ### What is NOT Dogfooded
102
+
103
+ Files that use generic templates (in `src/templates/`):
104
+
105
+ | Template Source | Destination | Reason |
106
+ |----------------|-------------|--------|
107
+ | `src/templates/markdown/spec/**/*.md.txt` | `.trellis/spec/**/*.md` | User fills with project-specific content |
108
+ | `src/templates/markdown/worktree.yaml.txt` | `.trellis/worktree.yaml` | Language-agnostic template |
109
+ | `src/templates/markdown/init-agent.md` | `init-agent.md` | Project root file |
110
+ | `src/templates/markdown/agents.md` | `AGENTS.md` | Project root file |
111
+
112
+ ### Build Process
113
+
114
+ ```bash
115
+ # scripts/copy-templates.js copies dogfooding sources to dist/
116
+ pnpm build
117
+
118
+ # Result:
119
+ dist/
120
+ ├── .cursor/ # From project root .cursor/
121
+ ├── .claude/ # From project root .claude/
122
+ ├── .trellis/ # From project root .trellis/ (filtered)
123
+ │ ├── scripts/ # All scripts
124
+ │ ├── workspace/
125
+ │ │ └── index.md # Only index.md, no developer subdirs
126
+ │ ├── workflow.md
127
+ │ ├── worktree.yaml
128
+ │ └── .gitignore
129
+ └── templates/ # From src/templates/ (no .ts files)
130
+ └── markdown/
131
+ └── spec/ # Generic templates
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Module Organization
137
+
138
+ ### Layer Responsibilities
139
+
140
+ | Layer | Directory | Responsibility |
141
+ |-------|-----------|----------------|
142
+ | CLI | `cli/` | Parse arguments, display help, call commands |
143
+ | Commands | `commands/` | Implement CLI commands, orchestrate actions |
144
+ | Configurators | `configurators/` | Copy/generate configuration for tools |
145
+ | Templates | `templates/` | Extract template content, provide utilities |
146
+ | Types | `types/` | TypeScript type definitions |
147
+ | Utils | `utils/` | Reusable utility functions |
148
+ | Constants | `constants/` | Shared constants (paths, names) |
149
+
150
+ ### Configurator Pattern
151
+
152
+ Configurators use `cpSync` for direct directory copy (dogfooding):
153
+
154
+ ```typescript
155
+ // configurators/cursor.ts
156
+ export async function configureCursor(cwd: string): Promise<void> {
157
+ const sourcePath = getCursorSourcePath(); // dist/.cursor/ or .cursor/
158
+ const destPath = path.join(cwd, ".cursor");
159
+ cpSync(sourcePath, destPath, { recursive: true });
160
+ }
161
+ ```
162
+
163
+ ### Template Extraction
164
+
165
+ `extract.ts` provides utilities for reading dogfooded files:
166
+
167
+ ```typescript
168
+ // Get path to .trellis/ (works in dev and production)
169
+ getTrellisSourcePath(): string
170
+
171
+ // Read file from .trellis/
172
+ readTrellisFile(relativePath: string): string
173
+
174
+ // Copy directory from .trellis/ with executable scripts
175
+ copyTrellisDir(srcRelativePath: string, destPath: string, options?: { executable?: boolean }): void
176
+ ```
177
+
178
+ ---
179
+
180
+ ## Naming Conventions
181
+
182
+ ### Files and Directories
183
+
184
+ | Convention | Example | Usage |
185
+ |------------|---------|-------|
186
+ | `kebab-case` | `file-writer.ts` | All TypeScript files |
187
+ | `kebab-case` | `multi-agent/` | All directories |
188
+ | `*.ts` | `init.ts` | TypeScript source files |
189
+ | `*.md.txt` | `index.md.txt` | Template files for markdown |
190
+ | `*.yaml.txt` | `worktree.yaml.txt` | Template files for yaml |
191
+
192
+ ### Why `.txt` Extension for Templates
193
+
194
+ Templates use `.txt` extension to:
195
+ - Prevent IDE markdown preview from rendering templates
196
+ - Make clear these are template sources, not actual docs
197
+ - Avoid confusion with actual markdown files
198
+
199
+ ---
200
+
201
+ ## DO / DON'T
202
+
203
+ ### DO
204
+
205
+ - Dogfood from project's own config files when possible
206
+ - Use `cpSync` for copying entire directories
207
+ - Keep generic templates in `src/templates/markdown/`
208
+ - Use `.md.txt` or `.yaml.txt` for template files
209
+ - Update dogfooding sources (`.cursor/`, `.claude/`, `.trellis/scripts/`) when making changes
210
+ - Always use `python3` explicitly when documenting script invocation (Windows compatibility)
211
+
212
+ ### DON'T
213
+
214
+ - Don't hardcode file lists - copy entire directories instead
215
+ - Don't duplicate content between templates and dogfooding sources
216
+ - Don't put project-specific content in generic templates
217
+ - Don't use dogfooding for spec/ (users fill these in)
218
+
219
+ ---
220
+
221
+ ## Design Decisions
222
+
223
+ ### Remote Template Download (giget)
224
+
225
+ **Context**: Need to download GitHub subdirectories for remote template support.
226
+
227
+ **Options Considered**:
228
+ 1. `degit` / `tiged` - Simple, but no programmatic API
229
+ 2. `giget` - TypeScript native, has programmatic API, used by Nuxt/UnJS
230
+ 3. Manual GitHub API - Too complex
231
+
232
+ **Decision**: Use `giget` because:
233
+ - TypeScript native with programmatic API
234
+ - Supports GitHub subdirectory: `gh:user/repo/path/to/subdir`
235
+ - Built-in caching for offline support
236
+ - Actively maintained by UnJS ecosystem
237
+
238
+ **Example**:
239
+ ```typescript
240
+ import { downloadTemplate } from "giget";
241
+
242
+ await downloadTemplate("gh:mindfold-ai/Trellis/marketplace/specs/electron-fullstack", {
243
+ dir: destDir,
244
+ preferOffline: true,
245
+ });
246
+ ```
247
+
248
+ ### Directory Conflict Strategy (skip/overwrite/append)
249
+
250
+ **Context**: When downloading remote templates, target directory may already exist.
251
+
252
+ **Decision**: Three strategies with `skip` as default:
253
+ - `skip` - Don't download if directory exists (safe default)
254
+ - `overwrite` - Delete existing, download fresh
255
+ - `append` - Only copy files that don't exist (merge)
256
+
257
+ **Why**: giget doesn't support append natively, so we:
258
+ 1. Download to temp directory
259
+ 2. Walk and copy missing files only
260
+ 3. Clean up temp directory
261
+
262
+ **Example**:
263
+ ```typescript
264
+ // append strategy implementation
265
+ const tempDir = path.join(os.tmpdir(), `trellis-template-${Date.now()}`);
266
+ await downloadTemplate(source, { dir: tempDir });
267
+ await copyMissing(tempDir, destDir); // Only copy non-existing files
268
+ await fs.promises.rm(tempDir, { recursive: true });
269
+ ```
270
+
271
+ ### Extensible Template Type Mapping
272
+
273
+ **Context**: Currently only `spec` templates, but future needs `skill`, `command`, `full` types.
274
+
275
+ **Decision**: Use type field + mapping table for extensibility:
276
+
277
+ ```typescript
278
+ const INSTALL_PATHS: Record<string, string> = {
279
+ spec: ".trellis/spec",
280
+ skill: ".claude/skills",
281
+ command: ".claude/commands",
282
+ full: ".", // Entire project root
283
+ };
284
+
285
+ // Usage: auto-detect install path from template type
286
+ const destDir = INSTALL_PATHS[template.type] || INSTALL_PATHS.spec;
287
+ ```
288
+
289
+ **Extensibility**: To add new template type:
290
+ 1. Add entry to `INSTALL_PATHS`
291
+ 2. Add templates to `index.json` with new type
292
+ 3. No code changes needed for download logic