Greenfield Workflow: Starting a New Project with DSP
March 22, 2026 · View on GitHub
A guide for building a new project with DSP from day one — growing the structural graph incrementally alongside your code.
The fastest path: dsp-boilerplate
If you want to skip all manual setup, use dsp-boilerplate — a production-ready fullstack starter (NestJS 11 + React 19 + Vite 7 + Docker Compose) with DSP fully pre-initialized:
git clone https://github.com/k-kolomeitsev/dsp-boilerplate.git my-project
cd my-project
docker-compose up -d
It comes with a complete .dsp/ graph (two roots: backend + frontend), @dsp markers in all source files, DSP skills for all agents, Cursor rules, Claude Code hooks, git hooks, and CI. Your agent has structural memory from the first session.
If you prefer to start from scratch or use a different stack, follow the manual steps below.
Prerequisites
- Python 3.10+
- An AI coding agent (Claude Code, Cursor, or Codex)
1. Install the DSP skill
Choose your agent and run the one-liner:
macOS / Linux:
curl -fsSL https://raw.githubusercontent.com/k-kolomeitsev/data-structure-protocol/main/install.sh | bash -s -- cursor
Windows (PowerShell):
irm https://raw.githubusercontent.com/k-kolomeitsev/data-structure-protocol/main/install.ps1 | iex
Codex (via skill-installer):
$skill-installer install https://github.com/k-kolomeitsev/data-structure-protocol/tree/main/skills/data-structure-protocol
2. Initialize DSP
Right after creating your project scaffold:
# Create project
mkdir my-project && cd my-project
git init
# Initialize DSP
dsp-cli init
# initialized .dsp/
3. Create the first module and register
As you write your first file, immediately register it in DSP.
Example: NestJS backend
# Create and register the app module (root)
dsp-cli create-object "src/app.module.ts" \
"Application root module — bootstraps NestJS app, registers feature modules and global config"
# obj-82e23068
# Create and register the first feature module
dsp-cli create-object "src/health/health.module.ts" \
"Health check module — exposes /health endpoint for load balancer probes"
# obj-a1b2c3d4
# Wire the dependency
dsp-cli add-import obj-82e23068 obj-a1b2c3d4 \
"app module registers health module for uptime monitoring"
# Register external framework dependency
dsp-cli create-object "@nestjs/core" \
"NestJS framework — dependency injection, module system, lifecycle management" \
--kind external
# obj-ext-nest
dsp-cli add-import obj-82e23068 obj-ext-nest \
"app module uses NestJS core for module bootstrapping and DI container"
Example: Next.js frontend
# Register the app layout (root)
dsp-cli create-object "src/app/layout.tsx" \
"Root layout — defines HTML structure, global providers, and shared UI shell"
# obj-layout01
# Register the home page
dsp-cli create-object "src/app/page.tsx" \
"Home page — landing page with hero section and feature highlights"
# obj-home-pg
dsp-cli add-import obj-layout01 obj-home-pg \
"layout renders home page as default route"
Example: Python CLI
# Register the CLI entry point (root)
dsp-cli create-object "src/cli.py" \
"CLI entry point — argument parsing, command dispatch, global error handling"
# obj-cli-main
# Register the first command module
dsp-cli create-object "src/commands/init.py" \
"Init command — scaffolds project directory structure and config files"
# obj-cmd-init
dsp-cli add-import obj-cli-main obj-cmd-init \
"CLI dispatches 'init' subcommand to this handler"
4. Growing the graph incrementally
The key principle: register entities as you create them, not after. This keeps the graph accurate and avoids catch-up work.
When you create a new file
# 1. Write the file
# 2. Register it immediately
dsp-cli create-object "src/users/users.service.ts" \
"Users service — CRUD operations, validation, password hashing"
# obj-usr-svc
# 3. Wire its imports
dsp-cli add-import obj-usr-svc obj-DB_SERVICE \
"users service uses database for persistence"
dsp-cli add-import obj-usr-svc obj-ext-bcrypt \
"uses bcrypt for password hashing"
When you create a public function
# Register the function under its owner
dsp-cli create-function "src/users/users.service.ts#createUser" \
"Creates a new user — validates input, hashes password, persists to database" \
--owner obj-usr-svc
# func-create-usr
# Share it (make it part of the module's public API)
dsp-cli create-shared obj-usr-svc func-create-usr
When another module imports it
# Auth controller imports createUser from users service
dsp-cli add-import obj-auth-ctrl func-create-usr \
"registration endpoint delegates user creation to users service" \
--exporter obj-usr-svc
The growth pattern
As your project grows, the graph grows with it naturally:
Week 1: 3 entities, 4 imports (app root, health, one feature)
Week 2: 12 entities, 25 imports (auth, users, basic CRUD)
Week 3: 28 entities, 67 imports (payments, notifications, admin)
Week 4: 45 entities, 110 imports (full MVP)
Each entity takes seconds to register. The cumulative investment is small; the cumulative value (instant context for every future session) is large.
5. Setting up hooks from day one
On greenfield projects, set up hooks early — it's easier to maintain consistency from the start than to fix it later.
Git hooks
# macOS / Linux
./hooks/install-hooks.sh
# Windows
.\hooks\install-hooks.ps1
Start with warning mode:
export DSP_PRECOMMIT_MODE=warn
This warns you (or the agent) when a commit includes new files not registered in DSP. Switch to block mode once the team is comfortable with the workflow.
CI (GitHub Actions)
Add the DSP consistency workflow to your repo from day one. Copy .github/workflows/dsp-consistency.yml from the DSP repository. This provides:
- Graph stats in PR summaries
- Orphan detection
- Cycle detection
- Coverage check for changed files
Agent hooks
If using Claude Code, set up the session hooks from the integration pack:
- Session start — prints DSP stats summary
- Pre-write check — warns if a file being edited isn't in DSP
- Session end — reminds about unregistered changes
6. Best practices for new projects
Register modules before functions
Start with create-object for each file/module. Add create-function for public APIs once the module is stable. Internal helper functions don't need DSP entries.
Write meaningful purpose fields
The purpose field is the most valuable part of a DSP entity. Write it as if explaining to a new team member:
# Weak
dsp-cli create-object "src/auth.ts" "Authentication"
# Strong
dsp-cli create-object "src/auth/auth.service.ts" \
"Authentication service — JWT token generation/validation, session management, OAuth2 provider integration"
Write meaningful why on imports
The why field on imports explains the reason for the dependency, not just its existence:
# Weak
dsp-cli add-import obj-A obj-B "imports B"
# Strong
dsp-cli add-import obj-ORDER_SVC obj-PAYMENT_SVC \
"order service delegates payment processing to payment service during checkout flow"
Use --toc for multi-root projects
If your project has multiple entry points (e.g., monorepo), use the --toc flag to group entities by root:
# Backend root
dsp-cli create-object "backend/src/main.ts" "Backend entry point" --toc obj-backend-root
# obj-backend-root
# Frontend root
dsp-cli create-object "frontend/src/main.tsx" "Frontend entry point" --toc obj-frontend-root
# obj-frontend-root
# Read a specific TOC
dsp-cli read-toc --toc obj-backend-root
Don't over-register
Not everything needs a DSP entry. Skip:
- Internal helper functions that aren't exported
- Type definition files (unless they define shared contracts)
- Test files (unless they define test utilities used across modules)
- Configuration files (unless they're shared across features)
- Static assets (unless they're imported by code)
DSP tracks structure and contracts. Internal implementation details don't belong in the graph.
Commit .dsp/ with your code
Every commit that changes code structure should include the corresponding .dsp/ changes. This keeps the graph in sync with the codebase at every point in git history.
git add src/users/users.service.ts .dsp/
git commit -m "feat: add users service with CRUD operations"
Run health checks periodically
# Quick graph overview
dsp-cli get-stats
# entities: 28, objects: 22, functions: 6, imports: 67, cycles: 0, orphans: 0
# Find disconnected entities
dsp-cli get-orphans
# no orphans
# Check for circular dependencies
dsp-cli detect-cycles
# no cycles detected
Make this part of your regular development rhythm — weekly or before each release.