generalize runtime ownership with doctor and local skill migration

This commit is contained in:
Jason Woltje
2026-02-17 12:10:06 -06:00
parent 967c9c462b
commit db2ec9524f
25 changed files with 3974 additions and 6 deletions

View File

@@ -0,0 +1,206 @@
---
name: jarvis
description: "Jarvis Platform development context. Use when working on the jetrich/jarvis repository. Provides architecture knowledge, coding patterns, and component locations."
---
# Jarvis Platform Development
## Project Overview
Jarvis is a self-hosted AI assistant platform built with:
- **Backend:** FastAPI (Python 3.11+)
- **Frontend:** Next.js 14+ (App Router)
- **Database:** PostgreSQL with pgvector
- **Plugins:** Modular LLM providers and integrations
Repository: `jetrich/jarvis`
---
## Architecture
```
jarvis/
├── apps/
│ ├── api/ # FastAPI backend
│ │ └── src/
│ │ ├── routes/ # API endpoints
│ │ ├── services/ # Business logic
│ │ ├── models/ # SQLAlchemy models
│ │ └── core/ # Config, deps, security
│ └── web/ # Next.js frontend
│ └── src/
│ ├── app/ # App router pages
│ ├── components/ # React components
│ └── lib/ # Utilities
├── packages/
│ └── plugins/ # jarvis_plugins package
│ └── jarvis_plugins/
│ ├── llm/ # LLM providers (ollama, claude, etc.)
│ └── integrations/# External integrations
├── docs/
│ └── scratchpads/ # Agent working docs
└── scripts/ # Utility scripts
```
---
## Key Patterns
### LLM Provider Pattern
All LLM providers implement `BaseLLMProvider`:
```python
# packages/plugins/jarvis_plugins/llm/base.py
class BaseLLMProvider(ABC):
@abstractmethod
async def generate(self, prompt: str, **kwargs) -> str: ...
@abstractmethod
async def stream(self, prompt: str, **kwargs) -> AsyncIterator[str]: ...
```
### Integration Pattern
External integrations (GitHub, Calendar, etc.) follow:
```python
# packages/plugins/jarvis_plugins/integrations/base.py
class BaseIntegration(ABC):
@abstractmethod
async def authenticate(self, credentials: dict) -> bool: ...
@abstractmethod
async def execute(self, action: str, params: dict) -> dict: ...
```
### API Route Pattern
FastAPI routes use dependency injection:
```python
@router.get("/items")
async def list_items(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
service: ItemService = Depends(get_item_service)
):
return await service.list(db, current_user.id)
```
### Frontend Component Pattern
Use shadcn/ui + server components by default:
```tsx
// Server component (default)
export default async function DashboardPage() {
const data = await fetchData();
return <Dashboard data={data} />;
}
// Client component (when needed)
"use client"
export function InteractiveWidget() {
const [state, setState] = useState();
// ...
}
```
---
## Database
- **ORM:** SQLAlchemy 2.0+
- **Migrations:** Alembic
- **Vector Store:** pgvector extension
### Creating Migrations
```bash
cd apps/api
alembic revision --autogenerate -m "description"
alembic upgrade head
```
---
## Testing
### Backend
```bash
cd apps/api
pytest
pytest --cov=src
```
### Frontend
```bash
cd apps/web
npm test
npm run test:e2e
```
---
## Quality Commands
```bash
# Backend
cd apps/api
ruff check .
ruff format .
mypy src/
# Frontend
cd apps/web
npm run lint
npm run typecheck
npm run format
```
---
## Active Development Areas
| Issue | Feature | Priority |
|-------|---------|----------|
| #84 | Per-function LLM routing | High |
| #85 | Ralph autonomous coding loop | High |
| #86 | Thinking models (CoT UI) | Medium |
| #87 | Local image generation | Medium |
| #88 | Deep research mode | Medium |
| #89 | Uncensored models + alignment | Medium |
| #90 | OCR capabilities | Medium |
| #91 | Authentik SSO | Medium |
| #40 | Claude Max + Claude Code | High |
---
## Environment Setup
```bash
# Backend
cd apps/api
cp .env.example .env
pip install -e ".[dev]"
# Frontend
cd apps/web
cp .env.example .env.local
npm install
# Database
docker-compose up -d postgres
alembic upgrade head
```
---
## Commit Convention
```
<type>(#issue): Brief description
Detailed explanation if needed.
Fixes #123
```
Types: `feat`, `fix`, `docs`, `test`, `refactor`, `chore`

View File

@@ -0,0 +1,32 @@
---
name: mosaic-standards
description: Load machine-wide Mosaic standards and enforce the repository lifecycle contract. Use at session start for any coding runtime (Codex, Claude, OpenCode, etc.).
---
# Mosaic Standards
## Load Order
1. `~/.mosaic/STANDARDS.md`
2. Repository `AGENTS.md`
3. Repo-local `.mosaic/repo-hooks.sh` when present
## Session Lifecycle
- Start: `scripts/agent/session-start.sh`
- Priority scan: `scripts/agent/critical.sh`
- End: `scripts/agent/session-end.sh`
If wrappers are available, you may use:
- `mosaic-session-start`
- `mosaic-critical`
- `mosaic-session-end`
## Enforcement Rules
- Treat `~/.mosaic` as canonical for shared guides, rails, profiles, and skills.
- Do not edit generated project views directly when the repo defines canonical data sources.
- Pull/rebase before edits in shared repositories.
- Run project verification commands before claiming completion.
- Use non-destructive git workflow unless explicitly instructed otherwise.

240
skills-local/prd/SKILL.md Normal file
View File

@@ -0,0 +1,240 @@
---
name: prd
description: "Generate a Product Requirements Document (PRD) for a new feature. Use when planning a feature, starting a new project, or when asked to create a PRD. Triggers on: create a prd, write prd for, plan this feature, requirements for, spec out."
---
# PRD Generator
Create detailed Product Requirements Documents that are clear, actionable, and suitable for implementation.
---
## The Job
1. Receive a feature description from the user
2. Ask 3-5 essential clarifying questions (with lettered options)
3. Generate a structured PRD based on answers
4. Save to `tasks/prd-[feature-name].md`
**Important:** Do NOT start implementing. Just create the PRD.
---
## Step 1: Clarifying Questions
Ask only critical questions where the initial prompt is ambiguous. Focus on:
- **Problem/Goal:** What problem does this solve?
- **Core Functionality:** What are the key actions?
- **Scope/Boundaries:** What should it NOT do?
- **Success Criteria:** How do we know it's done?
### Format Questions Like This:
```
1. What is the primary goal of this feature?
A. Improve user onboarding experience
B. Increase user retention
C. Reduce support burden
D. Other: [please specify]
2. Who is the target user?
A. New users only
B. Existing users only
C. All users
D. Admin users only
3. What is the scope?
A. Minimal viable version
B. Full-featured implementation
C. Just the backend/API
D. Just the UI
```
This lets users respond with "1A, 2C, 3B" for quick iteration.
---
## Step 2: PRD Structure
Generate the PRD with these sections:
### 1. Introduction/Overview
Brief description of the feature and the problem it solves.
### 2. Goals
Specific, measurable objectives (bullet list).
### 3. User Stories
Each story needs:
- **Title:** Short descriptive name
- **Description:** "As a [user], I want [feature] so that [benefit]"
- **Acceptance Criteria:** Verifiable checklist of what "done" means
Each story should be small enough to implement in one focused session.
**Format:**
```markdown
### US-001: [Title]
**Description:** As a [user], I want [feature] so that [benefit].
**Acceptance Criteria:**
- [ ] Specific verifiable criterion
- [ ] Another criterion
- [ ] Typecheck/lint passes
- [ ] **[UI stories only]** Verify in browser using dev-browser skill
```
**Important:**
- Acceptance criteria must be verifiable, not vague. "Works correctly" is bad. "Button shows confirmation dialog before deleting" is good.
- **For any story with UI changes:** Always include "Verify in browser using dev-browser skill" as acceptance criteria. This ensures visual verification of frontend work.
### 4. Functional Requirements
Numbered list of specific functionalities:
- "FR-1: The system must allow users to..."
- "FR-2: When a user clicks X, the system must..."
Be explicit and unambiguous.
### 5. Non-Goals (Out of Scope)
What this feature will NOT include. Critical for managing scope.
### 6. Design Considerations (Optional)
- UI/UX requirements
- Link to mockups if available
- Relevant existing components to reuse
### 7. Technical Considerations (Optional)
- Known constraints or dependencies
- Integration points with existing systems
- Performance requirements
### 8. Success Metrics
How will success be measured?
- "Reduce time to complete X by 50%"
- "Increase conversion rate by 10%"
### 9. Open Questions
Remaining questions or areas needing clarification.
---
## Writing for Junior Developers
The PRD reader may be a junior developer or AI agent. Therefore:
- Be explicit and unambiguous
- Avoid jargon or explain it
- Provide enough detail to understand purpose and core logic
- Number requirements for easy reference
- Use concrete examples where helpful
---
## Output
- **Format:** Markdown (`.md`)
- **Location:** `tasks/`
- **Filename:** `prd-[feature-name].md` (kebab-case)
---
## Example PRD
```markdown
# PRD: Task Priority System
## Introduction
Add priority levels to tasks so users can focus on what matters most. Tasks can be marked as high, medium, or low priority, with visual indicators and filtering to help users manage their workload effectively.
## Goals
- Allow assigning priority (high/medium/low) to any task
- Provide clear visual differentiation between priority levels
- Enable filtering and sorting by priority
- Default new tasks to medium priority
## User Stories
### US-001: Add priority field to database
**Description:** As a developer, I need to store task priority so it persists across sessions.
**Acceptance Criteria:**
- [ ] Add priority column to tasks table: 'high' | 'medium' | 'low' (default 'medium')
- [ ] Generate and run migration successfully
- [ ] Typecheck passes
### US-002: Display priority indicator on task cards
**Description:** As a user, I want to see task priority at a glance so I know what needs attention first.
**Acceptance Criteria:**
- [ ] Each task card shows colored priority badge (red=high, yellow=medium, gray=low)
- [ ] Priority visible without hovering or clicking
- [ ] Typecheck passes
- [ ] Verify in browser using dev-browser skill
### US-003: Add priority selector to task edit
**Description:** As a user, I want to change a task's priority when editing it.
**Acceptance Criteria:**
- [ ] Priority dropdown in task edit modal
- [ ] Shows current priority as selected
- [ ] Saves immediately on selection change
- [ ] Typecheck passes
- [ ] Verify in browser using dev-browser skill
### US-004: Filter tasks by priority
**Description:** As a user, I want to filter the task list to see only high-priority items when I'm focused.
**Acceptance Criteria:**
- [ ] Filter dropdown with options: All | High | Medium | Low
- [ ] Filter persists in URL params
- [ ] Empty state message when no tasks match filter
- [ ] Typecheck passes
- [ ] Verify in browser using dev-browser skill
## Functional Requirements
- FR-1: Add `priority` field to tasks table ('high' | 'medium' | 'low', default 'medium')
- FR-2: Display colored priority badge on each task card
- FR-3: Include priority selector in task edit modal
- FR-4: Add priority filter dropdown to task list header
- FR-5: Sort by priority within each status column (high to medium to low)
## Non-Goals
- No priority-based notifications or reminders
- No automatic priority assignment based on due date
- No priority inheritance for subtasks
## Technical Considerations
- Reuse existing badge component with color variants
- Filter state managed via URL search params
- Priority stored in database, not computed
## Success Metrics
- Users can change priority in under 2 clicks
- High-priority tasks immediately visible at top of lists
- No regression in task list performance
## Open Questions
- Should priority affect task ordering within a column?
- Should we add keyboard shortcuts for priority changes?
```
---
## Checklist
Before saving the PRD:
- [ ] Asked clarifying questions with lettered options
- [ ] Incorporated user's answers
- [ ] User stories are small and specific
- [ ] Functional requirements are numbered and unambiguous
- [ ] Non-goals section defines clear boundaries
- [ ] Saved to `tasks/prd-[feature-name].md`

257
skills-local/ralph/SKILL.md Normal file
View File

@@ -0,0 +1,257 @@
---
name: ralph
description: "Convert PRDs to prd.json format for the Ralph autonomous agent system. Use when you have an existing PRD and need to convert it to Ralph's JSON format. Triggers on: convert this prd, turn this into ralph format, create prd.json from this, ralph json."
---
# Ralph PRD Converter
Converts existing PRDs to the prd.json format that Ralph uses for autonomous execution.
---
## The Job
Take a PRD (markdown file or text) and convert it to `prd.json` in your ralph directory.
---
## Output Format
```json
{
"project": "[Project Name]",
"branchName": "ralph/[feature-name-kebab-case]",
"description": "[Feature description from PRD title/intro]",
"userStories": [
{
"id": "US-001",
"title": "[Story title]",
"description": "As a [user], I want [feature] so that [benefit]",
"acceptanceCriteria": [
"Criterion 1",
"Criterion 2",
"Typecheck passes"
],
"priority": 1,
"passes": false,
"notes": ""
}
]
}
```
---
## Story Size: The Number One Rule
**Each story must be completable in ONE Ralph iteration (one context window).**
Ralph spawns a fresh Amp instance per iteration with no memory of previous work. If a story is too big, the LLM runs out of context before finishing and produces broken code.
### Right-sized stories:
- Add a database column and migration
- Add a UI component to an existing page
- Update a server action with new logic
- Add a filter dropdown to a list
### Too big (split these):
- "Build the entire dashboard" - Split into: schema, queries, UI components, filters
- "Add authentication" - Split into: schema, middleware, login UI, session handling
- "Refactor the API" - Split into one story per endpoint or pattern
**Rule of thumb:** If you cannot describe the change in 2-3 sentences, it is too big.
---
## Story Ordering: Dependencies First
Stories execute in priority order. Earlier stories must not depend on later ones.
**Correct order:**
1. Schema/database changes (migrations)
2. Server actions / backend logic
3. UI components that use the backend
4. Dashboard/summary views that aggregate data
**Wrong order:**
1. UI component (depends on schema that does not exist yet)
2. Schema change
---
## Acceptance Criteria: Must Be Verifiable
Each criterion must be something Ralph can CHECK, not something vague.
### Good criteria (verifiable):
- "Add `status` column to tasks table with default 'pending'"
- "Filter dropdown has options: All, Active, Completed"
- "Clicking delete shows confirmation dialog"
- "Typecheck passes"
- "Tests pass"
### Bad criteria (vague):
- "Works correctly"
- "User can do X easily"
- "Good UX"
- "Handles edge cases"
### Always include as final criterion:
```
"Typecheck passes"
```
For stories with testable logic, also include:
```
"Tests pass"
```
### For stories that change UI, also include:
```
"Verify in browser using dev-browser skill"
```
Frontend stories are NOT complete until visually verified. Ralph will use the dev-browser skill to navigate to the page, interact with the UI, and confirm changes work.
---
## Conversion Rules
1. **Each user story becomes one JSON entry**
2. **IDs**: Sequential (US-001, US-002, etc.)
3. **Priority**: Based on dependency order, then document order
4. **All stories**: `passes: false` and empty `notes`
5. **branchName**: Derive from feature name, kebab-case, prefixed with `ralph/`
6. **Always add**: "Typecheck passes" to every story's acceptance criteria
---
## Splitting Large PRDs
If a PRD has big features, split them:
**Original:**
> "Add user notification system"
**Split into:**
1. US-001: Add notifications table to database
2. US-002: Create notification service for sending notifications
3. US-003: Add notification bell icon to header
4. US-004: Create notification dropdown panel
5. US-005: Add mark-as-read functionality
6. US-006: Add notification preferences page
Each is one focused change that can be completed and verified independently.
---
## Example
**Input PRD:**
```markdown
# Task Status Feature
Add ability to mark tasks with different statuses.
## Requirements
- Toggle between pending/in-progress/done on task list
- Filter list by status
- Show status badge on each task
- Persist status in database
```
**Output prd.json:**
```json
{
"project": "TaskApp",
"branchName": "ralph/task-status",
"description": "Task Status Feature - Track task progress with status indicators",
"userStories": [
{
"id": "US-001",
"title": "Add status field to tasks table",
"description": "As a developer, I need to store task status in the database.",
"acceptanceCriteria": [
"Add status column: 'pending' | 'in_progress' | 'done' (default 'pending')",
"Generate and run migration successfully",
"Typecheck passes"
],
"priority": 1,
"passes": false,
"notes": ""
},
{
"id": "US-002",
"title": "Display status badge on task cards",
"description": "As a user, I want to see task status at a glance.",
"acceptanceCriteria": [
"Each task card shows colored status badge",
"Badge colors: gray=pending, blue=in_progress, green=done",
"Typecheck passes",
"Verify in browser using dev-browser skill"
],
"priority": 2,
"passes": false,
"notes": ""
},
{
"id": "US-003",
"title": "Add status toggle to task list rows",
"description": "As a user, I want to change task status directly from the list.",
"acceptanceCriteria": [
"Each row has status dropdown or toggle",
"Changing status saves immediately",
"UI updates without page refresh",
"Typecheck passes",
"Verify in browser using dev-browser skill"
],
"priority": 3,
"passes": false,
"notes": ""
},
{
"id": "US-004",
"title": "Filter tasks by status",
"description": "As a user, I want to filter the list to see only certain statuses.",
"acceptanceCriteria": [
"Filter dropdown: All | Pending | In Progress | Done",
"Filter persists in URL params",
"Typecheck passes",
"Verify in browser using dev-browser skill"
],
"priority": 4,
"passes": false,
"notes": ""
}
]
}
```
---
## Archiving Previous Runs
**Before writing a new prd.json, check if there is an existing one from a different feature:**
1. Read the current `prd.json` if it exists
2. Check if `branchName` differs from the new feature's branch name
3. If different AND `progress.txt` has content beyond the header:
- Create archive folder: `archive/YYYY-MM-DD-feature-name/`
- Copy current `prd.json` and `progress.txt` to archive
- Reset `progress.txt` with fresh header
**The ralph.sh script handles this automatically** when you run it, but if you are manually updating prd.json between runs, archive first.
---
## Checklist Before Saving
Before writing prd.json, verify:
- [ ] **Previous run archived** (if prd.json exists with different branchName, archive it first)
- [ ] Each story is completable in one iteration (small enough)
- [ ] Stories are ordered by dependency (schema to backend to UI)
- [ ] Every story has "Typecheck passes" as criterion
- [ ] UI stories have "Verify in browser using dev-browser skill" as criterion
- [ ] Acceptance criteria are verifiable (not vague)
- [ ] No story depends on a later story

View File

@@ -0,0 +1,304 @@
---
name: setup-cicd
description: "Configure CI/CD Docker build, push, and package linking for a project. Use when adding Docker builds to a Woodpecker pipeline, setting up Gitea container registry, or implementing CI/CD for deployment. Triggers on: setup cicd, add docker builds, configure pipeline, add ci/cd, setup ci."
---
# CI/CD Pipeline Setup
Configure Docker build, registry push, and package linking for a Woodpecker CI pipeline using Kaniko and Gitea's container registry.
**Before starting:** Read `~/.mosaic/guides/ci-cd-pipelines.md` for deep background on the patterns used here.
**Reference implementation:** `~/src/mosaic-stack/.woodpecker.yml`
---
## The Job
1. Scan the current project for services, Dockerfiles, and registry info
2. Ask clarifying questions about what to build and how to name images
3. Generate Woodpecker YAML for Docker build/push/link steps
4. Provide secrets configuration commands
5. Output a verification checklist
**Important:** This skill generates YAML to *append* to an existing `.woodpecker.yml`, not replace it. The project should already have quality gate steps (lint, test, typecheck, build).
---
## Step 1: Project Scan
Run these scans and present results to the user:
### 1a. Detect registry info from git remote
```bash
# Extract Gitea host and org/repo from remote
REMOTE_URL=$(git remote get-url origin 2>/dev/null)
# Parse: https://git.example.com/org/repo.git -> host=git.example.com, org=org, repo=repo
```
Present:
- **Registry host:** (extracted from remote)
- **Organization:** (extracted from remote)
- **Repository:** (extracted from remote)
### 1b. Find all Dockerfiles
```bash
find . -name "Dockerfile" -o -name "Dockerfile.*" | grep -v node_modules | grep -v .git | sort
```
For each Dockerfile found, note:
- Path relative to project root
- Whether it's a dev variant (`Dockerfile.dev`) or production
- The service name (inferred from parent directory)
### 1c. Detect existing pipeline
```bash
cat .woodpecker.yml 2>/dev/null || cat .woodpecker/*.yml 2>/dev/null
```
Check:
- Does a `build` step exist? (Docker builds will depend on it)
- Are there already Docker build steps? (avoid duplicating)
- What's the existing dependency chain?
### 1d. Find publishable npm packages (if applicable)
```bash
# Find package.json files without "private": true
find . -name "package.json" -not -path "*/node_modules/*" -exec grep -L '"private": true' {} \;
```
### 1e. Present scan results
Show the user a summary table:
```
=== CI/CD Scan Results ===
Registry: git.example.com
Organization: org-name
Repository: repo-name
Dockerfiles Found:
1. src/backend-api/Dockerfile → backend-api
2. src/web-portal/Dockerfile → web-portal
3. src/ingest-api/Dockerfile → ingest-api
4. src/backend-api/Dockerfile.dev → (dev variant, skip)
Existing Pipeline: .woodpecker.yml
- Has build step: yes (build-all)
- Has Docker steps: no
Publishable npm Packages:
- @scope/schemas (src/schemas)
- @scope/design-system (src/design-system)
```
---
## Step 2: Clarifying Questions
Ask these questions with lettered options (user can respond "1A, 2B, 3C"):
```
1. Which Dockerfiles should be built in CI?
(Select all that apply — list found Dockerfiles with letters)
A. src/backend-api/Dockerfile (backend-api)
B. src/web-portal/Dockerfile (web-portal)
C. src/ingest-api/Dockerfile (ingest-api)
D. All of the above
E. Other: [specify]
2. Image naming convention?
A. {org}/{service} (e.g., usc/uconnect-backend-api) — Recommended
B. {org}/{repo}-{service} (e.g., usc/uconnect-backend-api)
C. Custom: [specify]
3. Do any services need build arguments?
A. No build args needed
B. Yes: [specify service:KEY=VALUE, e.g., web-portal:NEXT_PUBLIC_API_URL=https://api.example.com]
4. Which branches should trigger Docker builds?
A. main and develop (Recommended)
B. main only
C. Custom: [specify]
5. Should npm packages be published? (only if publishable packages found)
A. Yes, to Gitea npm registry
B. Yes, to custom registry: [specify URL]
C. No, skip npm publishing
```
---
## Step 3: Generate Pipeline YAML
### 3a. Add kaniko_setup anchor
If the project's `.woodpecker.yml` doesn't already have a `kaniko_setup` anchor in its `variables:` section, add it:
```bash
~/.mosaic/rails/cicd/generate-docker-steps.sh --kaniko-setup-only --registry REGISTRY_HOST
```
This outputs:
```yaml
# Kaniko base command setup
- &kaniko_setup |
mkdir -p /kaniko/.docker
echo "{\"auths\":{\"REGISTRY\":{\"username\":\"$GITEA_USER\",\"password\":\"$GITEA_TOKEN\"}}}" > /kaniko/.docker/config.json
```
Add this to the existing `variables:` block at the top of `.woodpecker.yml`.
### 3b. Generate Docker build/push/link steps
Use the generator script with the user's answers:
```bash
~/.mosaic/rails/cicd/generate-docker-steps.sh \
--registry REGISTRY \
--org ORG \
--repo REPO \
--service "SERVICE_NAME:DOCKERFILE_PATH" \
--service "SERVICE_NAME:DOCKERFILE_PATH" \
--branches "main,develop" \
--depends-on "BUILD_STEP_NAME" \
[--build-arg "SERVICE:KEY=VALUE"] \
[--npm-package "@scope/pkg:path" --npm-registry "URL"]
```
### 3c. Present generated YAML
Show the full YAML output to the user and ask for confirmation before appending to `.woodpecker.yml`.
### 3d. Append to pipeline
Append the generated YAML to the end of `.woodpecker.yml`. The kaniko_setup anchor goes in the `variables:` section.
---
## Step 4: Secrets Checklist
Present the required Woodpecker secrets and commands to configure them:
```
=== Required Woodpecker Secrets ===
Configure these at: https://WOODPECKER_HOST/repos/ORG/REPO/settings/secrets
1. gitea_username
Value: Your Gitea username or service account
Events: push, manual, tag
2. gitea_token
Value: Gitea token with package:write scope
Generate at: https://REGISTRY_HOST/user/settings/applications
Events: push, manual, tag
CLI commands:
woodpecker secret add ORG/REPO --name gitea_username --value "USERNAME"
woodpecker secret add ORG/REPO --name gitea_token --value "TOKEN"
```
If npm publishing was selected, also list:
```
3. npm_token (if using separate npm registry)
Value: npm registry auth token
Events: push, manual, tag
```
---
## Step 5: Verification Checklist
Present this checklist for the user to follow after implementation:
```
=== Verification Checklist ===
□ 1. Secrets configured in Woodpecker UI
→ gitea_username and gitea_token set
→ Token has package:write scope
□ 2. Update docker-compose.yml to use registry images
→ Change: build: ./src/backend-api
→ To: image: REGISTRY/ORG/SERVICE:${IMAGE_TAG:-dev}
□ 3. Push to develop branch and verify pipeline
→ Quality gates pass
→ Docker build steps run (only on main/develop)
→ Images appear in Gitea Packages
□ 4. Verify package linking
→ Images linked to repository on Gitea Packages tab
→ If linking fails (404), link manually via Gitea web UI
□ 5. Test image pull
→ docker login REGISTRY
→ docker pull REGISTRY/ORG/SERVICE:dev
□ 6. Commit the pipeline changes
→ git add .woodpecker.yml
→ git commit -m "feat: Add Docker build/push/link to CI pipeline"
```
---
## Example Session
```
User: /setup-cicd
Agent: Let me scan this project...
=== CI/CD Scan Results ===
Registry: git.uscllc.com
Organization: usc
Repository: uconnect
Dockerfiles Found:
1. src/backend-api/Dockerfile → backend-api
2. src/web-portal/Dockerfile → web-portal
3. src/ingest-api/Dockerfile → ingest-api
4. src/heartbeat-collector/Dockerfile → heartbeat-collector
5. src/field-agent/Dockerfile → field-agent
6. src/egress-api/Dockerfile → egress-api
Existing Pipeline: .woodpecker.yml
- Has build step: yes (build-all)
- Has Docker steps: no
I have a few questions:
1. Which Dockerfiles should be built in CI?
A. backend-api
B. web-portal
C. ingest-api
...
G. All of the above
User: 1G, 2A, 3A, 4A
Agent: Generating pipeline YAML...
[shows YAML]
Shall I append this to .woodpecker.yml?
User: Yes
Agent: Done. Here are the secrets you need to configure:
[shows secrets checklist]
[shows verification checklist]
```
---
## Notes
- The generator script handles `$$` escaping for Woodpecker shell variables automatically
- Package linking requires Gitea 1.24.0+ (the API endpoint was added in that version)
- If the project has no existing `.woodpecker.yml`, suggest running `init-project.sh` first to set up quality gates
- For the kaniko_setup anchor, the registry hostname must not include `https://` — just the bare hostname
- Build context defaults to `.` (project root) for Dockerfiles under `apps/`, `src/`, or `packages/`. For other locations (like `docker/postgres/`), the context is the Dockerfile's parent directory.