chore: bootstrap trellis workspace and sync deployment settings
This commit is contained in:
Executable
+293
@@ -0,0 +1,293 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Create Bootstrap Task for First-Time Setup.
|
||||
|
||||
Creates a guided task to help users fill in project guidelines
|
||||
after initializing Trellis for the first time.
|
||||
|
||||
Usage:
|
||||
python3 create_bootstrap.py [project-type]
|
||||
|
||||
Arguments:
|
||||
project-type: frontend | backend | fullstack (default: fullstack)
|
||||
|
||||
Prerequisites:
|
||||
- .trellis/.developer must exist (run init_developer.py first)
|
||||
|
||||
Creates:
|
||||
.trellis/tasks/00-bootstrap-guidelines/
|
||||
- task.json # Task metadata
|
||||
- prd.md # Task description and guidance
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from common.paths import (
|
||||
DIR_WORKFLOW,
|
||||
DIR_SCRIPTS,
|
||||
DIR_TASKS,
|
||||
get_repo_root,
|
||||
get_developer,
|
||||
get_tasks_dir,
|
||||
set_current_task,
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Constants
|
||||
# =============================================================================
|
||||
|
||||
TASK_NAME = "00-bootstrap-guidelines"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PRD Content
|
||||
# =============================================================================
|
||||
|
||||
def write_prd_header() -> str:
|
||||
"""Write PRD header section."""
|
||||
return """# Bootstrap: Fill Project Development Guidelines
|
||||
|
||||
## Purpose
|
||||
|
||||
Welcome to Trellis! This is your first task.
|
||||
|
||||
AI agents use `.trellis/spec/` to understand YOUR project's coding conventions.
|
||||
**Empty templates = AI writes generic code that doesn't match your project style.**
|
||||
|
||||
Filling these guidelines is a one-time setup that pays off for every future AI session.
|
||||
|
||||
---
|
||||
|
||||
## Your Task
|
||||
|
||||
Fill in the guideline files based on your **existing codebase**.
|
||||
"""
|
||||
|
||||
|
||||
def write_prd_backend_section() -> str:
|
||||
"""Write PRD backend section."""
|
||||
return """
|
||||
|
||||
### Backend Guidelines
|
||||
|
||||
| File | What to Document |
|
||||
|------|------------------|
|
||||
| `.trellis/spec/backend/directory-structure.md` | Where different file types go (routes, services, utils) |
|
||||
| `.trellis/spec/backend/database-guidelines.md` | ORM, migrations, query patterns, naming conventions |
|
||||
| `.trellis/spec/backend/error-handling.md` | How errors are caught, logged, and returned |
|
||||
| `.trellis/spec/backend/logging-guidelines.md` | Log levels, format, what to log |
|
||||
| `.trellis/spec/backend/quality-guidelines.md` | Code review standards, testing requirements |
|
||||
"""
|
||||
|
||||
|
||||
def write_prd_frontend_section() -> str:
|
||||
"""Write PRD frontend section."""
|
||||
return """
|
||||
|
||||
### Frontend Guidelines
|
||||
|
||||
| File | What to Document |
|
||||
|------|------------------|
|
||||
| `.trellis/spec/frontend/directory-structure.md` | Component/page/hook organization |
|
||||
| `.trellis/spec/frontend/component-guidelines.md` | Component patterns, props conventions |
|
||||
| `.trellis/spec/frontend/hook-guidelines.md` | Custom hook naming, patterns |
|
||||
| `.trellis/spec/frontend/state-management.md` | State library, patterns, what goes where |
|
||||
| `.trellis/spec/frontend/type-safety.md` | TypeScript conventions, type organization |
|
||||
| `.trellis/spec/frontend/quality-guidelines.md` | Linting, testing, accessibility |
|
||||
"""
|
||||
|
||||
|
||||
def write_prd_footer() -> str:
|
||||
"""Write PRD footer section."""
|
||||
return """
|
||||
|
||||
### Thinking Guides (Optional)
|
||||
|
||||
The `.trellis/spec/guides/` directory contains thinking guides that are already
|
||||
filled with general best practices. You can customize them for your project if needed.
|
||||
|
||||
---
|
||||
|
||||
## How to Fill Guidelines
|
||||
|
||||
### Principle: Document Reality, Not Ideals
|
||||
|
||||
Write what your codebase **actually does**, not what you wish it did.
|
||||
AI needs to match existing patterns, not introduce new ones.
|
||||
|
||||
### Steps
|
||||
|
||||
1. **Look at existing code** - Find 2-3 examples of each pattern
|
||||
2. **Document the pattern** - Describe what you see
|
||||
3. **Include file paths** - Reference real files as examples
|
||||
4. **List anti-patterns** - What does your team avoid?
|
||||
|
||||
---
|
||||
|
||||
## Tips for Using AI
|
||||
|
||||
Ask AI to help analyze your codebase:
|
||||
|
||||
- "Look at my codebase and document the patterns you see"
|
||||
- "Analyze my code structure and summarize the conventions"
|
||||
- "Find error handling patterns and document them"
|
||||
|
||||
The AI will read your code and help you document it.
|
||||
|
||||
---
|
||||
|
||||
## Completion Checklist
|
||||
|
||||
- [ ] Guidelines filled for your project type
|
||||
- [ ] At least 2-3 real code examples in each guideline
|
||||
- [ ] Anti-patterns documented
|
||||
|
||||
When done:
|
||||
|
||||
```bash
|
||||
python3 ./.trellis/scripts/task.py finish
|
||||
python3 ./.trellis/scripts/task.py archive 00-bootstrap-guidelines
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Why This Matters
|
||||
|
||||
After completing this task:
|
||||
|
||||
1. AI will write code that matches your project style
|
||||
2. Relevant `/trellis:before-*-dev` commands will inject real context
|
||||
3. `/trellis:check-*` commands will validate against your actual standards
|
||||
4. Future developers (human or AI) will onboard faster
|
||||
"""
|
||||
|
||||
|
||||
def write_prd(task_dir: Path, project_type: str) -> None:
|
||||
"""Write prd.md file."""
|
||||
content = write_prd_header()
|
||||
|
||||
if project_type == "frontend":
|
||||
content += write_prd_frontend_section()
|
||||
elif project_type == "backend":
|
||||
content += write_prd_backend_section()
|
||||
else: # fullstack
|
||||
content += write_prd_backend_section()
|
||||
content += write_prd_frontend_section()
|
||||
|
||||
content += write_prd_footer()
|
||||
|
||||
prd_file = task_dir / "prd.md"
|
||||
prd_file.write_text(content, encoding="utf-8")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Task JSON
|
||||
# =============================================================================
|
||||
|
||||
def write_task_json(task_dir: Path, developer: str, project_type: str) -> None:
|
||||
"""Write task.json file."""
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
# Generate subtasks and related files based on project type
|
||||
if project_type == "frontend":
|
||||
subtasks = [
|
||||
{"name": "Fill frontend guidelines", "status": "pending"},
|
||||
{"name": "Add code examples", "status": "pending"},
|
||||
]
|
||||
related_files = [".trellis/spec/frontend/"]
|
||||
elif project_type == "backend":
|
||||
subtasks = [
|
||||
{"name": "Fill backend guidelines", "status": "pending"},
|
||||
{"name": "Add code examples", "status": "pending"},
|
||||
]
|
||||
related_files = [".trellis/spec/backend/"]
|
||||
else: # fullstack
|
||||
subtasks = [
|
||||
{"name": "Fill backend guidelines", "status": "pending"},
|
||||
{"name": "Fill frontend guidelines", "status": "pending"},
|
||||
{"name": "Add code examples", "status": "pending"},
|
||||
]
|
||||
related_files = [".trellis/spec/backend/", ".trellis/spec/frontend/"]
|
||||
|
||||
task_data = {
|
||||
"id": TASK_NAME,
|
||||
"name": "Bootstrap Guidelines",
|
||||
"description": "Fill in project development guidelines for AI agents",
|
||||
"status": "in_progress",
|
||||
"dev_type": "docs",
|
||||
"priority": "P1",
|
||||
"creator": developer,
|
||||
"assignee": developer,
|
||||
"createdAt": today,
|
||||
"completedAt": None,
|
||||
"commit": None,
|
||||
"subtasks": subtasks,
|
||||
"children": [],
|
||||
"parent": None,
|
||||
"relatedFiles": related_files,
|
||||
"notes": f"First-time setup task created by trellis init ({project_type} project)",
|
||||
"meta": {},
|
||||
}
|
||||
|
||||
task_json = task_dir / "task.json"
|
||||
task_json.write_text(json.dumps(task_data, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Main
|
||||
# =============================================================================
|
||||
|
||||
def main() -> int:
|
||||
"""Main entry point."""
|
||||
# Parse project type argument
|
||||
project_type = "fullstack"
|
||||
if len(sys.argv) > 1:
|
||||
project_type = sys.argv[1]
|
||||
|
||||
# Validate project type
|
||||
if project_type not in ("frontend", "backend", "fullstack"):
|
||||
print(f"Unknown project type: {project_type}, defaulting to fullstack")
|
||||
project_type = "fullstack"
|
||||
|
||||
repo_root = get_repo_root()
|
||||
developer = get_developer(repo_root)
|
||||
|
||||
# Check developer initialized
|
||||
if not developer:
|
||||
print("Error: Developer not initialized")
|
||||
print(f"Run: python3 ./{DIR_WORKFLOW}/{DIR_SCRIPTS}/init_developer.py <your-name>")
|
||||
return 1
|
||||
|
||||
tasks_dir = get_tasks_dir(repo_root)
|
||||
task_dir = tasks_dir / TASK_NAME
|
||||
relative_path = f"{DIR_WORKFLOW}/{DIR_TASKS}/{TASK_NAME}"
|
||||
|
||||
# Check if already exists
|
||||
if task_dir.exists():
|
||||
print(f"Bootstrap task already exists: {relative_path}")
|
||||
return 0
|
||||
|
||||
# Create task directory
|
||||
task_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Write files
|
||||
write_task_json(task_dir, developer, project_type)
|
||||
write_prd(task_dir, project_type)
|
||||
|
||||
# Set as current task
|
||||
set_current_task(relative_path, repo_root)
|
||||
|
||||
# Silent output - init command handles user-facing messages
|
||||
# Only output the task path for programmatic use
|
||||
print(relative_path)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user