@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.
- package/README.md +17 -4
- package/dist/cli/index.js +1 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +243 -49
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts +12 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +92 -2
- package/dist/commands/update.js.map +1 -1
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +3 -1
- package/dist/migrations/index.js.map +1 -1
- package/dist/migrations/manifests/0.3.6.json +9 -0
- package/dist/migrations/manifests/0.3.7.json +9 -0
- package/dist/templates/claude/commands/trellis/brainstorm.md +13 -0
- package/dist/templates/claude/commands/trellis/record-session.md +4 -1
- package/dist/templates/claude/commands/trellis/start.md +20 -4
- package/dist/templates/claude/hooks/inject-subagent-context.py +1 -1
- package/dist/templates/claude/hooks/session-start.py +86 -23
- package/dist/templates/claude/settings.json +10 -0
- package/dist/templates/codex/skills/brainstorm/SKILL.md +13 -0
- package/dist/templates/codex/skills/record-session/SKILL.md +4 -1
- package/dist/templates/codex/skills/start/SKILL.md +20 -4
- package/dist/templates/cursor/commands/trellis-brainstorm.md +13 -0
- package/dist/templates/cursor/commands/trellis-record-session.md +4 -1
- package/dist/templates/cursor/commands/trellis-start.md +20 -4
- package/dist/templates/gemini/commands/trellis/brainstorm.toml +15 -0
- package/dist/templates/gemini/commands/trellis/record-session.toml +4 -1
- package/dist/templates/gemini/commands/trellis/start.toml +60 -3
- package/dist/templates/iflow/commands/trellis/brainstorm.md +13 -0
- package/dist/templates/iflow/commands/trellis/record-session.md +4 -1
- package/dist/templates/iflow/commands/trellis/start.md +20 -4
- package/dist/templates/iflow/hooks/inject-subagent-context.py +1 -1
- package/dist/templates/iflow/hooks/session-start.py +86 -23
- package/dist/templates/kilo/workflows/brainstorm.md +13 -0
- package/dist/templates/kilo/workflows/record-session.md +4 -1
- package/dist/templates/kilo/workflows/start.md +64 -3
- package/dist/templates/kiro/skills/brainstorm/SKILL.md +13 -0
- package/dist/templates/kiro/skills/record-session/SKILL.md +4 -1
- package/dist/templates/kiro/skills/start/SKILL.md +20 -4
- package/dist/templates/markdown/spec/backend/directory-structure.md +292 -0
- package/dist/templates/markdown/spec/backend/script-conventions.md +220 -38
- package/dist/templates/opencode/commands/trellis/brainstorm.md +13 -0
- package/dist/templates/opencode/commands/trellis/record-session.md +4 -1
- package/dist/templates/opencode/commands/trellis/start.md +9 -1
- package/dist/templates/opencode/plugin/session-start.js +149 -16
- package/dist/templates/qoder/skills/brainstorm/SKILL.md +13 -0
- package/dist/templates/qoder/skills/record-session/SKILL.md +4 -1
- package/dist/templates/qoder/skills/start/SKILL.md +60 -3
- package/dist/templates/trellis/config.yaml +18 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/common/config.py +20 -0
- package/dist/templates/trellis/scripts/common/git_context.py +160 -12
- package/dist/templates/trellis/scripts/common/task_queue.py +4 -0
- package/dist/templates/trellis/scripts/common/worktree.py +78 -11
- package/dist/templates/trellis/scripts/create_bootstrap.py +3 -0
- package/dist/templates/trellis/scripts/task.py +312 -17
- package/dist/utils/template-fetcher.d.ts +60 -7
- package/dist/utils/template-fetcher.d.ts.map +1 -1
- package/dist/utils/template-fetcher.js +183 -14
- package/dist/utils/template-fetcher.js.map +1 -1
- 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("
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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.
|
|
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
|
-
[!]
|
|
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
|
|
62
|
-
| **
|
|
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
|
-
[!]
|
|
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].
|
|
93
|
-
2. If
|
|
94
|
-
3. If
|
|
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,
|
|
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
|