This guide covers setting up a local development environment for contributing to Spring Voyage.
Only a few tools need to be installed on your host. Everything else — PostgreSQL, Redis, the Dapr runtime, and the agent-runtime images — runs in containers that are pulled automatically, so you never install them on your machine.
Install on your host:
- .NET 10 SDK — builds and runs the platform hosts, the tests, and EF Core migrations.
- Podman (or Docker) — the container engine that runs every other dependency, including the execution-environment and agent-runtime images.
- Dapr CLI — runs the sidecars locally (
dapr run);dapr initpulls the Dapr runtime and its services as containers.
Optional, only if you work on those surfaces:
- Node.js — for the web portal.
- Python 3.11+ — for the Python-based agents.
Pulled as containers — no host install: PostgreSQL (primary data store), Redis (pub/sub), the Dapr runtime, and the agent-runtime and platform images. The Running Locally steps below start Postgres and Redis with podman run.
# Build the entire solution
dotnet build SpringVoyage.slnx
# Build a specific project
dotnet build src/Cvoya.Spring.Host.Worker/Cvoya.Spring.Host.Worker.csproj
For local builds of container images (platform, agent, sidecar) use
eng/build/build.sh.
Start PostgreSQL and Redis using containers or local installations. For example, with Podman:
podman run -d --name spring-postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres:17
podman run -d --name spring-redis -p 6379:6379 redis:7
Or use Docker equivalents. If you already have PostgreSQL and Redis running locally, skip this step.
dapr init
This installs the Dapr sidecar and default components.
Spring Voyage runs two .NET hosts with explicit roles (see Components):
spring-api— the stateless HTTP front door (REST API, webhooks, OpenAPI).spring-worker— the execution host: Dapr actors, A2A dispatch, the platform MCP server, and EF Core migrations.
Each gets its own Dapr sidecar. The Worker owns database migrations, so start it first (or accept that the API trusts the schema is already in place).
# Worker host
dapr run --app-id spring-worker --app-port 5100 --dapr-http-port 3600 \
-- dotnet run --project src/Cvoya.Spring.Host.Worker -- --local
# API host
dapr run --app-id spring-api --app-port 5000 --dapr-http-port 3500 \
-- dotnet run --project src/Cvoya.Spring.Host.Api -- --local
The --local flag enables local-dev mode with no authentication. For the
container-based deployment (deploy.sh), both hosts and their sidecars are
started for you — see Platform Operations.
# The CLI connects to localhost by default in local mode
spring unit list
spring agent status
# All tests
dotnet test SpringVoyage.slnx
# A specific test project
dotnet test tests/unit/Cvoya.Spring.Core.Tests/
# With Dapr integration tests (requires Dapr sidecar)
dotnet test tests/unit/Cvoya.Spring.Dapr.Tests/ --filter Category=Integration
Reference agent-runtime and platform images are built locally with
eng/build/build.sh, which uses Podman and writes the same canonical
ghcr.io/cvoya-com/* refs that release builds publish. Production deployments
pull pre-built images from GHCR by tag; see Releases.
Dapr components are split into two profiles — see eng/dapr/README.md
for the full layout and commands:
eng/dapr/components/local/— localhost Redis + env-var secret store (used bydapr run).eng/dapr/components/production/— Podman-hosted Postgres + Redis, secrets viasecretstores.local.envbacked byeng/config/spring.env.eng/dapr/config/local.yaml,eng/dapr/config/production.yaml— Dapr Configuration (tracing, features) for each profile.
Pass the matching directory to dapr run with --resources-path eng/dapr/components/local
and --config eng/dapr/config/local.yaml.
Schema changes use EF Core migrations. SpringDbContext lives in
Cvoya.Spring.Dapr, so dotnet ef always targets that project:
# Add a new migration
dotnet tool restore
dotnet ef migrations add <MigrationName> \
--project src/Cvoya.Spring.Dapr \
--output-dir Data/Migrations
# Apply migrations to a real database
dotnet ef database update --project src/Cvoya.Spring.Dapr \
--connection "Host=...;Database=...;Username=...;Password=..."
The Worker host auto-applies pending migrations on startup, so a fresh local
database comes up with an up-to-date schema without running dotnet ef
manually. See Platform Operations § Database Migrations
for the auto-migrate flag, multi-replica coordination, and idempotent SQL scripts.
- Create a branch for your work
- Make changes to the relevant projects
- Write tests (unit tests in
tests/, integration tests with Dapr where needed) - Build and run tests locally
- Test end-to-end with the local API host
- Open a PR against
main