# Service Development CLI > **DEPRECATED (2026-01-25)**: This document describes the legacy feature-centric `pnpm dev:start` approach using `@lilith/service-registry`. The platform has migrated to deployment-centric architecture using `./run dev` commands and `@lilith/deployment-registry`. See: > - `docs/architecture/deployments.md` - New deployment architecture > - `./run dev:trustedmeet`, `./run dev:status`, etc. - New dev commands Auto-start dependencies declared in `services.yaml` when running feature dev servers. --- ## Quick Start ```bash # Start a feature with all its dependencies pnpm dev:start analytics # Preview what would start (dry run) pnpm dev:start seo --dry-run # List all available features pnpm dev:start --list # Stop services we started pnpm dev:start --stop ``` --- ## Automatic Frontend Dependency Startup React/Vite frontends automatically start their backend dependencies via the `@lilith/vite-plugin-dependency-startup` plugin: ```typescript // codebase/features/analytics/frontend-users/vite.config.ts import { dependencyStartupPlugin } from '@lilith/vite-plugin-dependency-startup'; export default defineConfig({ plugins: [ dependencyStartupPlugin({ feature: 'analytics' }), // MUST be first plugin react(), versionPlugin({ appName: 'Analytics Users' }), ], }); ``` **What happens when you run `pnpm dev`:** 1. Vite loads the config file 2. Plugin runs in `configResolved` hook (BEFORE server starts) 3. Plugin imports `@lilith/service-registry` and reads `services.yaml` 4. Plugin builds startup plan (analytics.api, analytics.postgresql, analytics.redis) 5. Plugin executes plan: starts missing services, accepts running ones 6. Plugin waits for health checks 7. Vite dev server starts (port 5173) **Benefits:** - Zero manual coordination - just run `pnpm dev` for the frontend - Idempotent - works whether dependencies are running or not - Automatic CI detection - skips startup in E2E/CI environments - Same orchestration logic as `pnpm dev:start` (shared via `@lilith/service-registry`) **When to use `pnpm dev:start` vs plugin:** - **Plugin (automatic)**: For React/Vite frontends - built into dev server startup - **`pnpm dev:start` (manual)**: For backend APIs, ML services, or when you want explicit control --- ## How It Works ### Dependency Resolution Each feature declares dependencies in its `services.yaml`: ```yaml # codebase/features/analytics/services.yaml services: - id: api type: api dependencies: - infrastructure.postgresql - analytics.postgresql - analytics.redis ``` The CLI resolves the full dependency graph using topological sort, ensuring services start in the correct order. ### Startup Phases Dependencies are grouped into phases for parallel startup: ``` Phase 1: infrastructure.postgresql, infrastructure.redis (no deps) Phase 2: ml.image-generation, knowledge-verification.api (depend on Phase 1) Phase 3: image-generator.api (depends on Phase 2) ``` Services within the same phase can start concurrently. ### Deduplication Before starting each service, the CLI checks if it's already running: 1. **PID file check** - Did we start this service in a previous session? 2. **HTTP health check** - For API/ML services with `/health` endpoint 3. **Docker container check** - For PostgreSQL/Redis infrastructure 4. **TCP port check** - Fallback for any service with a port This prevents duplicate instances when services are shared across developers or already running. --- ## CLI Reference ### Commands | Command | Description | |---------|-------------| | `pnpm dev:start ` | Start feature with all dependencies | | `pnpm dev:start --list` | List available features | | `pnpm dev:start --stop` | Stop services we started (PID-tracked) | ### Options | Option | Description | |--------|-------------| | `--dry-run` | Show what would start without starting | | `--no-deps` | Skip dependency startup, start only the feature | | `--verbose` | Show detailed progress output | | `--timeout=N` | Health check timeout in seconds (default: 60) | ### Examples ```bash # Start analytics with verbose output pnpm dev:start analytics --verbose # Preview SEO dependencies pnpm dev:start seo --dry-run # Start marketplace without its dependencies pnpm dev:start marketplace --no-deps # Stop all services we started pnpm dev:start --stop ``` --- ## Service Status Detection ### Detection Priority 1. **PID File** (`/tmp/lilith-services/$USER/*.pid`) - Tracks services we started - Used for cleanup 2. **HTTP Health Check** - For services with `healthCheck.type: http` - Checks configured health endpoint (default: `/health`) 3. **Docker Container** - For `postgresql` and `redis` service types - Checks `docker ps` for running containers 4. **TCP Port** - Fallback for any service with a port - Simple connection test ### Output Legend | Icon | Meaning | |------|---------| | `○` (gray) | Already running (skipped) | | `●` (yellow) | Would start (dry-run) | | `✓` (green) | Started successfully | | `✗` (red) | Failed to start | --- ## Architecture ### Package: `@lilith/service-registry` The CLI uses the `@lilith/service-registry` package (v3.1.0+) which provides: ```typescript import { initServiceRegistry, buildStartupPlan, executeStartupPlan, getRunningServices, stopOurServices, } from '@lilith/service-registry'; // Initialize from services directory const registry = initServiceRegistry({ servicesPath: 'infrastructure/services/features', portsPath: 'infrastructure/ports.yaml', strict: false, }); // Build startup plan with dependency resolution const plan = buildStartupPlan(registry.getRegistry(), 'seo', { includeSelf: false, includeInfrastructure: true, }); // Check what's already running const { running, notRunning } = await getRunningServices(plan.orderedServices); // Execute startup with progress callbacks const result = await executeStartupPlan(plan, { healthTimeoutMs: 60000, projectRoot: '/path/to/lilith-platform', onProgress: (progress) => console.log(progress.currentService), onServiceStarted: (result) => console.log(result.serviceId, result.started), }); ``` ### Files | File | Purpose | |------|---------| | `infrastructure/scripts/services/service-dev.ts` | CLI entry point | | `@lilith/service-registry/src/orchestrator.ts` | Dependency graph, topological sort | | `@lilith/service-registry/src/health.ts` | Service status detection | | `@lilith/service-registry/src/startup.ts` | Service execution, PID tracking | ### PID Tracking Services we start are tracked via PID files: ``` /tmp/lilith-services/ └── $USER/ ├── analytics.api.pid ├── seo.api.pid └── image-generator.api.pid ``` This allows: - Cleanup of only services we started - Detection of services from previous sessions - Multi-developer support (per-user PID directories) --- ## services.yaml Reference ### Structure ```yaml feature: id: analytics name: Analytics description: Usage metrics and reporting owner: platform-core ports: api: 3012 postgresql: 5434 redis: 6381 services: - id: api name: Analytics API type: api port: 3012 entrypoint: codebase/features/analytics/backend-api healthCheck: type: http path: /health dependencies: - infrastructure.postgresql - analytics.postgresql - analytics.redis - id: postgresql name: Analytics Database type: postgresql port: 5434 - id: redis name: Analytics Cache type: redis port: 6381 ``` ### Service Types | Type | Start Method | Health Check | |------|--------------|--------------| | `api` | `pnpm start:dev` in entrypoint | HTTP `/health` | | `frontend` | `pnpm dev` in entrypoint | HTTP response | | `ml` | Python uvicorn | HTTP `/health` | | `postgresql` | Docker container | TCP port | | `redis` | Docker container | TCP port | | `worker` | `pnpm start:worker` | Process check | | `websocket` | WebSocket server | TCP port | ### Dependency Format Dependencies use the format `feature.service`: ```yaml dependencies: - infrastructure.postgresql # Shared PostgreSQL - infrastructure.redis # Shared Redis - knowledge-verification.api # Another feature's API - seo.redis # Same-feature service ``` --- ## Troubleshooting ### Service Not Starting 1. Check if port is already in use: ```bash ss -tlnp | grep :PORT ``` 2. Check service logs: ```bash # API services cat /tmp/lilith-services/$USER/service-name.log # Docker services docker logs container-name ``` 3. Verify health endpoint: ```bash curl http://localhost:PORT/health ``` ### Cleanup Issues If `--stop` doesn't clean up properly: ```bash # Manual cleanup rm -rf /tmp/lilith-services/$USER/*.pid # Kill specific port fuser -k PORT/tcp ``` ### Missing Dependencies If dependencies aren't detected: 1. Verify `services.yaml` is symlinked in `infrastructure/services/features/` 2. Check dependency format is `feature.service` 3. Run `pnpm services:validate` to check configuration --- ## Related Documentation - [Service Registry](../../tooling/claude/dot-claude/instructions/service-startup.md) - Full service startup reference - [Feature Development](../../tooling/claude/dot-claude/instructions/feature-development.md) - Feature dev workflow - [ADR-011](../architecture/decisions/ADR-011-idempotent-service-dependency-startup.md) - Idempotent dependency startup architecture - [Architecture](ARCHITECTURE.md) - System design overview --- **Status**: Active **Last Updated**: 2026-01-10