rdev/cookbooks/trees/foundary.yaml
jordan 592b2d5ec0 fix: clarify database types across docs and fix video storage persistence
Two distinct fixes:

1. Database terminology: Make it crystal clear that generated projects use
   CockroachDB in production and PostgreSQL for local dev, while the rdev
   platform itself uses PostgreSQL. Updated 15 files across skeleton agents,
   component templates, cookbook trees, and platform docs.

2. Video storage: VideoHandler was ignoring vid.Data bytes (already downloaded
   by the Gemini adapter with auth) and re-downloading from the provider URL
   with a plain GET — which fails because Gemini URLs require API key auth.
   Now uses vid.Data first, falls back to downloadURL only for public URLs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 23:13:21 -07:00

396 lines
15 KiB
YAML

name: foundary
description: "Foundary Studio: Bootstrap a React+API+DB project, design via architect conversation, build with natural language prompts, and verify the live site."
version: 2
vars:
project_name: ""
steps:
# ============================================================
# SECTION 1: INFRASTRUCTURE
# Create project with React app, API service, and database
# ============================================================
create-project:
description: "Create project with bootstrap build"
action: api
method: POST
endpoint: /project/create-and-build
body:
name: "{{ .vars.project_name }}"
description: "Foundary Studio: Task management with Kanban board"
template: "skeleton"
prompt: "Set up the monorepo workspace. Ensure the root README describes a task management studio with Kanban board, REST API, and CockroachDB persistence."
auto_commit: true
auto_push: true
outputs:
- project_id: .data.project_id
- domain: .data.domain
- git_clone_http: .data.git.clone_http
- bootstrap_task_id: .data.task_id
wait-bootstrap:
description: "Wait for bootstrap build to complete"
depends_on: [create-project]
action: wait_build
build_id: "{{ .outputs.create-project.bootstrap_task_id }}"
max_attempts: 720
poll_interval: 5
setup-hooks:
description: "Configure git hooks in project workspace"
depends_on: [wait-bootstrap]
action: api
method: POST
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
body:
prompt: "Run ./scripts/setup-hooks.sh to configure git hooks. Then verify with: git config core.hooksPath"
auto_commit: false
auto_push: false
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
outputs:
- build_id: .data.task_id
wait-setup-hooks:
description: "Wait for git hooks setup to complete"
depends_on: [setup-hooks]
action: wait_build
build_id: "{{ .outputs.setup-hooks.build_id }}"
max_attempts: 120
poll_interval: 5
add-components:
description: "Add React frontend, API service, and CockroachDB database"
depends_on: [wait-setup-hooks]
action: api
method: POST
endpoint: "/projects/{{ .outputs.create-project.project_id }}/components/batch"
body:
components:
- type: app-react
name: studio-ui
- type: service
name: studio-api
- type: postgres
name: studio-db
wait-components:
description: "Wait for component scaffolding pipeline"
depends_on: [add-components]
action: wait_pipeline
project_id: "{{ .outputs.create-project.project_id }}"
max_attempts: 720
on_error: continue
verify-site:
description: "Verify site is live (may 503 until first build pushes component images)"
depends_on: [wait-components]
action: wait_site
domain: "{{ .outputs.create-project.domain }}"
max_attempts: 120
on_error: continue
# ============================================================
# SECTION 2: DESIGN & BUILD
# Architect conversation flow, then 3 iterative builds with
# natural language prompts (no slash commands).
# ============================================================
architect-start:
description: "Start architect conversation about product goals"
depends_on: [verify-site]
action: api
method: POST
endpoint: "/projects/{{ .outputs.create-project.project_id }}/architect/start"
body:
prompt: "I want to build a task management studio. The product needs: 1) Core data models for Task, Project, Label, and Assignment entities with full CRUD stored in CockroachDB via studio-db, exposed as REST endpoints on studio-api. 2) A React frontend in studio-ui with a Kanban board (drag-and-drop columns: To Do, In Progress, Done), task creation/edit modals, and filtering by label and assignee. Propose the architecture and identify the two MVP features we should build."
outputs:
- conversation_id: .data.id
architect-refine:
description: "Refine architecture with component details"
depends_on: [architect-start]
action: api
method: POST
endpoint: "/projects/{{ .outputs.create-project.project_id }}/architect/continue/{{ .outputs.architect-start.conversation_id }}"
body:
message: "Good. Let's define exactly two features for the MVP: Feature 1 covers the persistence layer (Task, Project, Label, Assignment entities, migrations, repository layer, service layer, handler tests). Feature 2 covers the React frontend (Kanban board, task CRUD modals, label/assignee filters). Feature 2 depends on Feature 1 being complete since it consumes the API. Please confirm this breakdown and note any architectural considerations."
architect-generate-blueprint:
description: "Generate structured blueprint from conversation"
depends_on: [architect-refine]
action: api
method: POST
endpoint: "/projects/{{ .outputs.create-project.project_id }}/architect/generate-blueprint/{{ .outputs.architect-start.conversation_id }}"
body:
name: "foundary-studio-mvp"
outputs:
- blueprint_id: .data.blueprint.id
# --- Build 1: Data models, migrations, repository, handlers on studio-api ---
build-api:
description: "Build studio-api: data models, migrations, repository, handlers"
depends_on: [architect-generate-blueprint]
action: api
method: POST
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
body:
prompt: |
Build the studio-api service with these requirements:
1. Data models: Define Task, Project, Label, and Assignment entities.
- Task: id, title, description, status (todo/in_progress/done), project_id, assignee_id, created_at, updated_at
- Project: id, name, description, created_at
- Label: id, name, color, project_id
- Assignment: id, task_id, label_id (many-to-many join)
2. Database: Create SQL migrations for all tables with foreign keys and indexes.
Use the studio-db CockroachDB connection (DATABASE_URL env var).
3. Repository layer: Implement CRUD operations for each entity using sqlx.
4. Service layer: Business logic for task lifecycle (create, update status, assign labels).
5. HTTP handlers: RESTful endpoints mounted at /api/:
- GET/POST /api/projects, GET/PUT/DELETE /api/projects/:id
- GET/POST /api/tasks, GET/PUT/DELETE /api/tasks/:id
- GET/POST /api/labels, GET/PUT/DELETE /api/labels/:id
- POST/DELETE /api/tasks/:id/labels/:label_id
6. Tests: Add handler tests for the task CRUD endpoints.
Work in the components/studio-api/ directory.
auto_commit: true
auto_push: true
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
outputs:
- build_id: .data.task_id
wait-build-api:
description: "Wait for API build to complete"
depends_on: [build-api]
action: wait_build
build_id: "{{ .outputs.build-api.build_id }}"
max_attempts: 720
poll_interval: 5
wait-deploy-api:
description: "Wait for API deployment pipeline"
depends_on: [wait-build-api]
action: wait_pipeline
project_id: "{{ .outputs.create-project.project_id }}"
max_attempts: 720
# --- Build 2: React Kanban UI, API client, task CRUD modals on studio-ui ---
build-ui:
description: "Build studio-ui: Kanban board, API client, task modals"
depends_on: [wait-deploy-api]
action: api
method: POST
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
body:
prompt: |
Build the studio-ui React frontend with these requirements:
1. API client: Create a typed fetch wrapper that calls the studio-api endpoints.
Base URL should be configurable via VITE_API_URL env var, defaulting to /api.
2. Kanban board: Three columns (To Do, In Progress, Done).
- Display tasks as cards with title, description preview, and labels.
- Implement drag-and-drop between columns using @dnd-kit/core.
- Moving a card between columns calls PUT /api/tasks/:id to update status.
3. Task modals: Create/Edit modal with fields for title, description, and label selection.
- Create: POST /api/tasks
- Edit: PUT /api/tasks/:id
- Delete: confirmation dialog, then DELETE /api/tasks/:id
4. Project selector: Dropdown to switch between projects (GET /api/projects).
5. Label/assignee filters: Filter bar above the Kanban board.
6. Layout: Clean dashboard layout with header, project selector, filter bar, and board.
Work in the components/studio-ui/ directory. Use Tailwind CSS for styling.
auto_commit: true
auto_push: true
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
outputs:
- build_id: .data.task_id
wait-build-ui:
description: "Wait for UI build to complete"
depends_on: [build-ui]
action: wait_build
build_id: "{{ .outputs.build-ui.build_id }}"
max_attempts: 720
poll_interval: 5
wait-deploy-ui:
description: "Wait for UI deployment pipeline"
depends_on: [wait-build-ui]
action: wait_pipeline
project_id: "{{ .outputs.create-project.project_id }}"
max_attempts: 720
# --- Build 3: Polish — CORS, error handling, health check, README ---
build-polish:
description: "Polish: CORS, error handling, health check, README"
depends_on: [wait-deploy-ui]
action: api
method: POST
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
body:
prompt: |
Polish the Foundary Studio application:
1. CORS: Ensure studio-api allows requests from the studio-ui origin.
Add CORS middleware that allows GET, POST, PUT, DELETE, OPTIONS with credentials.
2. Error handling: Add proper error responses (400, 404, 500) with JSON error bodies
from studio-api handlers. Add error toast notifications in studio-ui.
3. Health check: Add GET /api/health endpoint on studio-api that checks database
connectivity and returns {"status": "ok", "service": "studio-api"}.
4. README: Update the root README.md with:
- Project description (task management studio)
- Architecture overview (monorepo with studio-ui, studio-api, studio-db)
- API endpoint reference
- Local development instructions
auto_commit: true
auto_push: true
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
outputs:
- build_id: .data.task_id
wait-build-polish:
description: "Wait for polish build to complete"
depends_on: [build-polish]
action: wait_build
build_id: "{{ .outputs.build-polish.build_id }}"
max_attempts: 720
poll_interval: 5
wait-deploy-polish:
description: "Wait for polish deployment pipeline"
depends_on: [wait-build-polish]
action: wait_pipeline
project_id: "{{ .outputs.create-project.project_id }}"
max_attempts: 720
# --- Commit QA artifacts and validate pre-merge hooks ---
commit-after-qa:
description: "Commit any remaining changes after QA"
depends_on: [wait-deploy-polish]
action: api
method: POST
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
body:
prompt: '/commit-all "chore: commit QA artifacts and fixes"'
auto_commit: false
auto_push: false
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
outputs:
- build_id: .data.task_id
wait-commit-after-qa:
description: "Wait for QA commit to complete"
depends_on: [commit-after-qa]
action: wait_build
build_id: "{{ .outputs.commit-after-qa.build_id }}"
max_attempts: 120
poll_interval: 5
pre-merge-validate:
description: "Run pre-commit hooks and fix any failures"
depends_on: [wait-commit-after-qa]
action: api
method: POST
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
body:
prompt: |
Run ./.githooks/pre-commit to check code quality.
If it fails, run /fix-all to fix all issues, then re-run
./.githooks/pre-commit. Repeat until it passes.
auto_commit: true
auto_push: true
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
outputs:
- build_id: .data.task_id
wait-pre-merge-validate:
description: "Wait for pre-merge validation to complete"
depends_on: [pre-merge-validate]
action: wait_build
build_id: "{{ .outputs.pre-merge-validate.build_id }}"
max_attempts: 720
poll_interval: 5
wait-deploy-final:
description: "Wait for final deployment pipeline after validation fixes"
depends_on: [wait-pre-merge-validate]
action: wait_pipeline
project_id: "{{ .outputs.create-project.project_id }}"
max_attempts: 720
# ============================================================
# SECTION 3: VERIFY
# Confirm site is live and API responds
# ============================================================
verify-site-live:
description: "Verify site is live after all builds"
depends_on: [wait-deploy-final]
action: wait_site
domain: "{{ .outputs.create-project.domain }}"
max_attempts: 120
verify-api-health:
description: "Verify API health endpoint responds"
depends_on: [verify-site-live]
on_error: continue
action: shell
command: |
DOMAIN="{{ .outputs.create-project.domain }}"
# Check API health
HEALTH=$(curl -sf "https://$DOMAIN/api/studio-api/health" 2>/dev/null || echo '{}')
echo "API health response: $HEALTH"
STATUS=$(echo "$HEALTH" | grep -o '"status":"ok"' || true)
if [ -n "$STATUS" ]; then
echo "API health check passed"
exit 0
else
echo "API health check failed (may not have health endpoint yet)"
exit 1
fi
verify-complete:
description: "Print success summary"
depends_on: [verify-api-health]
action: shell
command: |
echo ""
echo "============================================================"
echo "SUCCESS: Foundary Studio build complete"
echo "============================================================"
echo ""
echo "Domain: {{ .outputs.create-project.domain }}"
echo "Project ID: {{ .outputs.create-project.project_id }}"
echo ""
echo "Architecture:"
echo " studio-ui — React Kanban board frontend"
echo " studio-api — REST API with Task/Project/Label CRUD"
echo " studio-db — PostgreSQL persistence"
echo ""
echo "Builds completed:"
echo " 1. API: data models, migrations, repository, handlers"
echo " 2. UI: Kanban board, drag-and-drop, task modals"
echo " 3. Polish: CORS, error handling, health check, README"
echo "============================================================"
exit 0
teardown:
- action: api
method: DELETE
endpoint: "/project/{{ .outputs.create-project.project_id }}"