Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
The sdlc merge command already transitions features to released internally. The cookbook's transition step was running after archive, which moved the feature and caused "feature not found". Fixed by: - Reordering: transition before archive - Adding on_error: continue to both (merge handles transition) - Simplifying verification (no longer depends on transition outputs) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1026 lines
34 KiB
YAML
1026 lines
34 KiB
YAML
name: foundary
|
|
description: "Foundary Studio: Conversational product development lifecycle. Bootstraps a React+API+DB project, specs two features via SDLC, implements with build agents, reviews, merges, and releases."
|
|
version: 1
|
|
|
|
vars:
|
|
project_name: ""
|
|
feature_1_slug: "data-models"
|
|
feature_1_title: "Core Data Models & Persistence"
|
|
feature_2_slug: "task-management-ui"
|
|
feature_2_title: "Task Management UI"
|
|
|
|
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: Conversational product development"
|
|
template: "default"
|
|
prompt: "Set up the monorepo workspace. Ensure the root README describes a product studio for conversational product development."
|
|
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
|
|
|
|
add-components:
|
|
description: "Add React frontend, API service, and Postgres database"
|
|
depends_on: [wait-bootstrap]
|
|
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: 60
|
|
on_error: continue
|
|
|
|
verify-sdlc:
|
|
description: "Verify SDLC state is initialized"
|
|
depends_on: [verify-site]
|
|
action: api
|
|
method: GET
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/state"
|
|
outputs:
|
|
- sdlc_initialized: .data.initialized
|
|
|
|
# ============================================================
|
|
# SECTION 2: ARCHITECT
|
|
# Conversational product design via architect API.
|
|
# Tries the full conversational flow (start → refine → generate).
|
|
# Falls back to direct blueprint creation if agent isn't available.
|
|
# ============================================================
|
|
architect-start:
|
|
description: "Start architect conversation about product goals"
|
|
depends_on: [verify-sdlc]
|
|
on_error: continue
|
|
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 Postgres 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]
|
|
on_error: continue
|
|
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 'data-models' covers the persistence layer (Task, Project, Label, Assignment entities, migrations, repository layer, service layer, handler tests). Feature 2 'task-management-ui' 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]
|
|
on_error: continue
|
|
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
|
|
|
|
architect-create-blueprint-fallback:
|
|
description: "Fallback: create blueprint directly if conversational flow unavailable"
|
|
depends_on: [architect-generate-blueprint]
|
|
on_error: continue
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/blueprints"
|
|
body:
|
|
name: "foundary-studio-mvp"
|
|
description: "Task management studio MVP blueprint"
|
|
spec:
|
|
version: "1.0"
|
|
architecture:
|
|
type: "monorepo"
|
|
components:
|
|
- name: studio-ui
|
|
type: app-react
|
|
description: "React frontend with Kanban board"
|
|
- name: studio-api
|
|
type: service
|
|
description: "REST API for task management"
|
|
- name: studio-db
|
|
type: postgres
|
|
description: "PostgreSQL database for persistence"
|
|
features:
|
|
- slug: data-models
|
|
title: "Core Data Models & Persistence"
|
|
priority: high
|
|
- slug: task-management-ui
|
|
title: "Task Management UI"
|
|
priority: high
|
|
outputs:
|
|
- fallback_blueprint_id: .data.id
|
|
|
|
# ============================================================
|
|
# SECTION 3: FEATURE 1 — Core Data Models (draft → released)
|
|
# Full 10-phase SDLC lifecycle
|
|
# ============================================================
|
|
|
|
# --- Phase 1: Draft ---
|
|
f1-create-feature:
|
|
description: "Create data-models feature in draft phase"
|
|
depends_on: [architect-create-blueprint-fallback]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features"
|
|
body:
|
|
slug: "{{ .vars.feature_1_slug }}"
|
|
title: "{{ .vars.feature_1_title }}"
|
|
outputs:
|
|
- feature_phase: .data.phase
|
|
|
|
f1-verify-draft:
|
|
description: "Verify feature 1 is in draft phase"
|
|
depends_on: [f1-create-feature]
|
|
action: shell
|
|
command: |
|
|
PHASE="{{ .outputs.f1-create-feature.feature_phase }}"
|
|
if [ "$PHASE" == "draft" ]; then
|
|
echo "Feature 1 created in draft phase"
|
|
exit 0
|
|
else
|
|
echo "Expected draft, got $PHASE"
|
|
exit 1
|
|
fi
|
|
|
|
# --- Phase 2: Draft → Specified ---
|
|
f1-write-spec:
|
|
description: "Agent writes spec for data models"
|
|
depends_on: [f1-verify-draft]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/spec-feature {{ .vars.feature_1_slug }} --requirements 'Define Task, Project, Label, and Assignment entities with full CRUD. Postgres storage via studio-db. REST endpoints on studio-api. Include migrations, repository layer, service layer, and handler tests.'"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f1-wait-spec:
|
|
depends_on: [f1-write-spec]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f1-write-spec.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f1-approve-spec:
|
|
description: "Approve spec artifact"
|
|
depends_on: [f1-wait-spec]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/artifacts/spec/approve"
|
|
body:
|
|
comment: "Spec approved by foundary automation"
|
|
|
|
f1-transition-to-specified:
|
|
description: "Transition from draft to specified"
|
|
depends_on: [f1-approve-spec]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/transition"
|
|
body:
|
|
phase: "specified"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 3: Specified → Planned ---
|
|
f1-write-design:
|
|
description: "Agent writes design for data models"
|
|
depends_on: [f1-transition-to-specified]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/design-feature {{ .vars.feature_1_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f1-wait-design:
|
|
depends_on: [f1-write-design]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f1-write-design.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f1-approve-design:
|
|
description: "Approve design artifact"
|
|
depends_on: [f1-wait-design]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/artifacts/design/approve"
|
|
body:
|
|
comment: "Design approved by foundary automation"
|
|
|
|
f1-write-tasks:
|
|
description: "Agent breaks down into tasks"
|
|
depends_on: [f1-approve-design]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/breakdown-feature {{ .vars.feature_1_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f1-wait-tasks:
|
|
depends_on: [f1-write-tasks]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f1-write-tasks.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f1-approve-tasks:
|
|
description: "Approve tasks artifact"
|
|
depends_on: [f1-wait-tasks]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/artifacts/tasks/approve"
|
|
body:
|
|
comment: "Tasks approved by foundary automation"
|
|
|
|
f1-write-qa-plan:
|
|
description: "Agent writes QA plan"
|
|
depends_on: [f1-approve-tasks]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/create-qa-plan {{ .vars.feature_1_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f1-wait-qa-plan:
|
|
depends_on: [f1-write-qa-plan]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f1-write-qa-plan.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f1-approve-qa-plan:
|
|
description: "Approve QA plan artifact"
|
|
depends_on: [f1-wait-qa-plan]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/artifacts/qa_plan/approve"
|
|
body:
|
|
comment: "QA plan approved by foundary automation"
|
|
|
|
f1-transition-to-planned:
|
|
description: "Transition from specified to planned"
|
|
depends_on: [f1-approve-qa-plan]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/transition"
|
|
body:
|
|
phase: "planned"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 4: Planned → Ready ---
|
|
f1-create-branch:
|
|
description: "Create feature branch for data-models"
|
|
depends_on: [f1-transition-to-planned]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/branches"
|
|
outputs:
|
|
- branch_name: .data.name
|
|
|
|
f1-transition-to-ready:
|
|
description: "Transition from planned to ready"
|
|
depends_on: [f1-create-branch]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/transition"
|
|
body:
|
|
phase: "ready"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 5: Ready → Implementation ---
|
|
f1-implement:
|
|
description: "Agent implements data models feature"
|
|
depends_on: [f1-transition-to-ready]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/implement-feature {{ .vars.feature_1_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f1-wait-implement:
|
|
depends_on: [f1-implement]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f1-implement.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f1-wait-deploy-impl:
|
|
description: "Wait for implementation to deploy"
|
|
depends_on: [f1-wait-implement]
|
|
action: wait_pipeline
|
|
project_id: "{{ .outputs.create-project.project_id }}"
|
|
max_attempts: 720
|
|
|
|
f1-transition-to-implementation:
|
|
description: "Transition to implementation phase"
|
|
depends_on: [f1-wait-deploy-impl]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/transition"
|
|
body:
|
|
phase: "implementation"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 6: Implementation → Review ---
|
|
f1-write-review:
|
|
description: "Agent writes code review"
|
|
depends_on: [f1-transition-to-implementation]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/review-feature {{ .vars.feature_1_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f1-wait-review:
|
|
depends_on: [f1-write-review]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f1-write-review.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f1-pass-review:
|
|
description: "Mark review as passed"
|
|
depends_on: [f1-wait-review]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/artifacts/review/pass"
|
|
|
|
f1-transition-to-review:
|
|
description: "Transition to review phase"
|
|
depends_on: [f1-pass-review]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/transition"
|
|
body:
|
|
phase: "review"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 7: Review → Audit ---
|
|
f1-write-audit:
|
|
description: "Agent writes security audit"
|
|
depends_on: [f1-transition-to-review]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/audit-feature {{ .vars.feature_1_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f1-wait-audit:
|
|
depends_on: [f1-write-audit]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f1-write-audit.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f1-pass-audit:
|
|
description: "Mark audit as passed"
|
|
depends_on: [f1-wait-audit]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/artifacts/audit/pass"
|
|
|
|
f1-transition-to-audit:
|
|
description: "Transition to audit phase"
|
|
depends_on: [f1-pass-audit]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/transition"
|
|
body:
|
|
phase: "audit"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 8: Audit → QA ---
|
|
f1-run-qa:
|
|
description: "Agent runs QA plan"
|
|
depends_on: [f1-transition-to-audit]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/run-qa {{ .vars.feature_1_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f1-wait-qa:
|
|
depends_on: [f1-run-qa]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f1-run-qa.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f1-pass-qa:
|
|
description: "Mark QA as passed"
|
|
depends_on: [f1-wait-qa]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/artifacts/qa_results/pass"
|
|
|
|
f1-transition-to-qa:
|
|
description: "Transition to QA phase"
|
|
depends_on: [f1-pass-qa]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/transition"
|
|
body:
|
|
phase: "qa"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 9: QA → Merge ---
|
|
f1-transition-to-merge:
|
|
description: "Transition to merge phase"
|
|
depends_on: [f1-transition-to-qa]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/transition"
|
|
body:
|
|
phase: "merge"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
f1-merge:
|
|
description: "Merge data-models feature branch to main"
|
|
depends_on: [f1-transition-to-merge]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/merge"
|
|
body:
|
|
strategy: "squash"
|
|
outputs:
|
|
- merge_commit: .data.commit_sha
|
|
|
|
f1-wait-merge-deploy:
|
|
description: "Wait for merged code to deploy"
|
|
depends_on: [f1-merge]
|
|
action: wait_pipeline
|
|
project_id: "{{ .outputs.create-project.project_id }}"
|
|
max_attempts: 720
|
|
|
|
# --- Phase 10: Merge → Released ---
|
|
# Note: sdlc merge already transitions to released internally.
|
|
# This step is a safety net; on_error: continue handles the case
|
|
# where the feature is already at released.
|
|
f1-transition-to-released:
|
|
description: "Transition to released phase (may already be done by merge)"
|
|
depends_on: [f1-wait-merge-deploy]
|
|
on_error: continue
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/transition"
|
|
body:
|
|
phase: "released"
|
|
|
|
f1-archive:
|
|
description: "Archive data-models feature"
|
|
depends_on: [f1-transition-to-released]
|
|
on_error: continue
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_1_slug }}/archive"
|
|
|
|
# ============================================================
|
|
# SECTION 4: FEATURE 2 — Task Management UI (draft → released)
|
|
# Spec starts after Feature 1 spec (independent)
|
|
# Design depends on Feature 1 reaching planned (schema defined)
|
|
# Implementation depends on Feature 1 released (schema in main)
|
|
# ============================================================
|
|
|
|
# --- Phase 1: Draft ---
|
|
# Feature 2 creation can start after Feature 1 spec is approved (parallel speccing)
|
|
f2-create-feature:
|
|
description: "Create task-management-ui feature in draft phase"
|
|
depends_on: [f1-approve-spec]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features"
|
|
body:
|
|
slug: "{{ .vars.feature_2_slug }}"
|
|
title: "{{ .vars.feature_2_title }}"
|
|
outputs:
|
|
- feature_phase: .data.phase
|
|
|
|
f2-verify-draft:
|
|
description: "Verify feature 2 is in draft phase"
|
|
depends_on: [f2-create-feature]
|
|
action: shell
|
|
command: |
|
|
PHASE="{{ .outputs.f2-create-feature.feature_phase }}"
|
|
if [ "$PHASE" == "draft" ]; then
|
|
echo "Feature 2 created in draft phase"
|
|
exit 0
|
|
else
|
|
echo "Expected draft, got $PHASE"
|
|
exit 1
|
|
fi
|
|
|
|
# --- Phase 2: Draft → Specified ---
|
|
f2-write-spec:
|
|
description: "Agent writes spec for task management UI"
|
|
depends_on: [f2-verify-draft]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/spec-feature {{ .vars.feature_2_slug }} --requirements 'React UI in studio-ui for managing tasks. Kanban board view with drag-and-drop columns (To Do, In Progress, Done). Task creation/edit modal with title, description, label, assignee fields. Filter by label and assignee. Connects to studio-api REST endpoints for Task CRUD.'"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f2-wait-spec:
|
|
depends_on: [f2-write-spec]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f2-write-spec.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f2-approve-spec:
|
|
description: "Approve spec artifact"
|
|
depends_on: [f2-wait-spec]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/artifacts/spec/approve"
|
|
body:
|
|
comment: "Spec approved by foundary automation"
|
|
|
|
f2-transition-to-specified:
|
|
description: "Transition from draft to specified"
|
|
depends_on: [f2-approve-spec]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/transition"
|
|
body:
|
|
phase: "specified"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 3: Specified → Planned ---
|
|
# Design depends on Feature 1 reaching planned (schema must be defined first)
|
|
f2-write-design:
|
|
description: "Agent writes design for task management UI (after F1 schema planned)"
|
|
depends_on: [f2-transition-to-specified, f1-transition-to-planned]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/design-feature {{ .vars.feature_2_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f2-wait-design:
|
|
depends_on: [f2-write-design]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f2-write-design.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f2-approve-design:
|
|
description: "Approve design artifact"
|
|
depends_on: [f2-wait-design]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/artifacts/design/approve"
|
|
body:
|
|
comment: "Design approved by foundary automation"
|
|
|
|
f2-write-tasks:
|
|
description: "Agent breaks down into tasks"
|
|
depends_on: [f2-approve-design]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/breakdown-feature {{ .vars.feature_2_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f2-wait-tasks:
|
|
depends_on: [f2-write-tasks]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f2-write-tasks.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f2-approve-tasks:
|
|
description: "Approve tasks artifact"
|
|
depends_on: [f2-wait-tasks]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/artifacts/tasks/approve"
|
|
body:
|
|
comment: "Tasks approved by foundary automation"
|
|
|
|
f2-write-qa-plan:
|
|
description: "Agent writes QA plan"
|
|
depends_on: [f2-approve-tasks]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/create-qa-plan {{ .vars.feature_2_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f2-wait-qa-plan:
|
|
depends_on: [f2-write-qa-plan]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f2-write-qa-plan.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f2-approve-qa-plan:
|
|
description: "Approve QA plan artifact"
|
|
depends_on: [f2-wait-qa-plan]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/artifacts/qa_plan/approve"
|
|
body:
|
|
comment: "QA plan approved by foundary automation"
|
|
|
|
f2-transition-to-planned:
|
|
description: "Transition from specified to planned"
|
|
depends_on: [f2-approve-qa-plan]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/transition"
|
|
body:
|
|
phase: "planned"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 4: Planned → Ready ---
|
|
f2-create-branch:
|
|
description: "Create feature branch for task-management-ui"
|
|
depends_on: [f2-transition-to-planned]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/branches"
|
|
outputs:
|
|
- branch_name: .data.name
|
|
|
|
f2-transition-to-ready:
|
|
description: "Transition from planned to ready"
|
|
depends_on: [f2-create-branch]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/transition"
|
|
body:
|
|
phase: "ready"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 5: Ready → Implementation ---
|
|
# Implementation depends on Feature 1 being released (schema in main)
|
|
f2-implement:
|
|
description: "Agent implements task management UI (after F1 released to main)"
|
|
depends_on: [f2-transition-to-ready, f1-transition-to-released]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/implement-feature {{ .vars.feature_2_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f2-wait-implement:
|
|
depends_on: [f2-implement]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f2-implement.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f2-wait-deploy-impl:
|
|
description: "Wait for implementation to deploy"
|
|
depends_on: [f2-wait-implement]
|
|
action: wait_pipeline
|
|
project_id: "{{ .outputs.create-project.project_id }}"
|
|
max_attempts: 720
|
|
|
|
f2-transition-to-implementation:
|
|
description: "Transition to implementation phase"
|
|
depends_on: [f2-wait-deploy-impl]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/transition"
|
|
body:
|
|
phase: "implementation"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 6: Implementation → Review ---
|
|
f2-write-review:
|
|
description: "Agent writes code review"
|
|
depends_on: [f2-transition-to-implementation]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/review-feature {{ .vars.feature_2_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f2-wait-review:
|
|
depends_on: [f2-write-review]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f2-write-review.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f2-pass-review:
|
|
description: "Mark review as passed"
|
|
depends_on: [f2-wait-review]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/artifacts/review/pass"
|
|
|
|
f2-transition-to-review:
|
|
description: "Transition to review phase"
|
|
depends_on: [f2-pass-review]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/transition"
|
|
body:
|
|
phase: "review"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 7: Review → Audit ---
|
|
f2-write-audit:
|
|
description: "Agent writes security audit"
|
|
depends_on: [f2-transition-to-review]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/audit-feature {{ .vars.feature_2_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f2-wait-audit:
|
|
depends_on: [f2-write-audit]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f2-write-audit.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f2-pass-audit:
|
|
description: "Mark audit as passed"
|
|
depends_on: [f2-wait-audit]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/artifacts/audit/pass"
|
|
|
|
f2-transition-to-audit:
|
|
description: "Transition to audit phase"
|
|
depends_on: [f2-pass-audit]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/transition"
|
|
body:
|
|
phase: "audit"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 8: Audit → QA ---
|
|
f2-run-qa:
|
|
description: "Agent runs QA plan"
|
|
depends_on: [f2-transition-to-audit]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/run-qa {{ .vars.feature_2_slug }}"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "{{ .outputs.create-project.git_clone_http }}"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
f2-wait-qa:
|
|
depends_on: [f2-run-qa]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.f2-run-qa.build_id }}"
|
|
max_attempts: 720
|
|
poll_interval: 5
|
|
|
|
f2-pass-qa:
|
|
description: "Mark QA as passed"
|
|
depends_on: [f2-wait-qa]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/artifacts/qa_results/pass"
|
|
|
|
f2-transition-to-qa:
|
|
description: "Transition to QA phase"
|
|
depends_on: [f2-pass-qa]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/transition"
|
|
body:
|
|
phase: "qa"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
# --- Phase 9: QA → Merge ---
|
|
f2-transition-to-merge:
|
|
description: "Transition to merge phase"
|
|
depends_on: [f2-transition-to-qa]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/transition"
|
|
body:
|
|
phase: "merge"
|
|
outputs:
|
|
- new_phase: .data.phase
|
|
|
|
f2-merge:
|
|
description: "Merge task-management-ui feature branch to main"
|
|
depends_on: [f2-transition-to-merge]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/merge"
|
|
body:
|
|
strategy: "squash"
|
|
outputs:
|
|
- merge_commit: .data.commit_sha
|
|
|
|
f2-wait-merge-deploy:
|
|
description: "Wait for merged code to deploy"
|
|
depends_on: [f2-merge]
|
|
action: wait_pipeline
|
|
project_id: "{{ .outputs.create-project.project_id }}"
|
|
max_attempts: 720
|
|
|
|
# --- Phase 10: Merge → Released ---
|
|
f2-transition-to-released:
|
|
description: "Transition to released phase (may already be done by merge)"
|
|
depends_on: [f2-wait-merge-deploy]
|
|
on_error: continue
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/transition"
|
|
body:
|
|
phase: "released"
|
|
|
|
f2-archive:
|
|
description: "Archive task-management-ui feature"
|
|
depends_on: [f2-transition-to-released]
|
|
on_error: continue
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features/{{ .vars.feature_2_slug }}/archive"
|
|
|
|
# ============================================================
|
|
# SECTION 5: VERIFICATION
|
|
# ============================================================
|
|
verify-site-live:
|
|
description: "Verify frontend and API are live after both features"
|
|
depends_on: [f2-archive]
|
|
action: shell
|
|
command: |
|
|
DOMAIN="{{ .outputs.create-project.domain }}"
|
|
|
|
# Check frontend
|
|
UI_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://$DOMAIN")
|
|
echo "Frontend status: $UI_STATUS"
|
|
|
|
# Check API health
|
|
API_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://$DOMAIN/api/studio-api/health")
|
|
echo "API status: $API_STATUS"
|
|
|
|
if [ "$UI_STATUS" -ge 200 ] && [ "$UI_STATUS" -lt 400 ] && [ "$API_STATUS" -ge 200 ] && [ "$API_STATUS" -lt 400 ]; then
|
|
echo "Site is live: frontend and API responding"
|
|
exit 0
|
|
else
|
|
echo "Site check failed"
|
|
exit 1
|
|
fi
|
|
|
|
verify-sdlc-complete:
|
|
description: "Verify both features completed the full SDLC lifecycle"
|
|
depends_on: [verify-site-live]
|
|
action: shell
|
|
command: |
|
|
echo ""
|
|
echo "============================================================"
|
|
echo "SUCCESS: Foundary Studio lifecycle complete"
|
|
echo "============================================================"
|
|
echo "Both features traversed all 10 SDLC phases:"
|
|
echo " draft -> specified -> planned -> ready -> implementation ->"
|
|
echo " review -> audit -> qa -> merge -> released"
|
|
echo ""
|
|
echo "Infrastructure: React + API + Postgres (batch provisioned)"
|
|
echo "Feature 1: Core Data Models & Persistence"
|
|
echo "Feature 2: Task Management UI (dependent on F1 schema)"
|
|
echo "============================================================"
|
|
exit 0
|
|
|
|
teardown:
|
|
- action: api
|
|
method: DELETE
|
|
endpoint: "/project/{{ .outputs.create-project.project_id }}"
|