A local development service registry that eliminates port conflicts across projects.
If you've ever started a new project only to discover port 5432 is already taken by another project's Postgres, or an AI agent assigned a port that collides with something you're already running — portmap solves that.
- Single source of truth — One
registry.jsonfile tracks every project, service, and port on your machine - 10 CLI commands — Check, register, scan, validate, allocate, and detect conflicts
- Auto-scanner — Discovers ports from docker-compose, .NET appsettings, .env files, and start scripts
- AI-agent friendly — Documentation designed so Claude, Cursor, Copilot, or any agent can self-serve port allocation
- Zero dependencies — Python 3.11+ stdlib only. No pip install needed
# Clone it
git clone https://github.com/djcdevelopment/portmap.git
cd portmap
# Copy the example registry and customize it
cp registry.example.json registry.json
# See everything registered
python portmap.py list
# Check if a port is available (also probes if something is listening)
python portmap.py check 8080
# Find available port ranges
python portmap.py gaps
# Register your first project
python portmap.py add-project my-app "My Application" "/path/to/my-app" --category project --stack python,postgres
python portmap.py register my-app api 8080 --protocol http --process python
python portmap.py register my-app postgres 5432 --protocol tcp --process docker
# Auto-discover ports from project config files
python portmap.py scan
# Compare registry to live ports (what's actually listening?)
python portmap.py validate
# Detect conflicts
python portmap.py conflictsWhen you run multiple projects locally — web servers, databases, gRPC services, Docker containers — port conflicts are inevitable. Typical problems:
- Two projects both default their Postgres to port 5433
- An AI agent sets up a new project and picks ports already in use
- You forgot what's running on port 3000 — was that Langfuse or the new React app?
- Docker Compose starts but silently fails because the port is taken
portmap makes every port assignment explicit, discoverable, and conflict-checked.
| Command | What it does |
|---|---|
list [--project ID] [--json] |
Show all registered services |
check <port> |
Who owns this port? (exit 0=free, 1=claimed, 2=unregistered listener) |
register <project> <service> <port> |
Claim a port (--protocol http --process python) |
unregister <project> <service> |
Release a port |
add-project <id> <name> <path> |
Add a project (--category project --stack python,postgres) |
scan [--project ID] |
Auto-discover ports from project files |
validate |
Check live ports vs registry (live / dormant / rogue) |
allocate <project> [--range S-E] [--count N] |
Get next free port(s) |
gaps [--min N] |
Show all unallocated port ranges |
conflicts |
Show port conflicts |
- Python 3.11+
- That's it. No pip install, no virtualenv, no Docker.
git clone https://github.com/djcdevelopment/portmap.git
cd portmap
# Start from the example or create an empty registry
cp registry.example.json registry.json
# Register your projects
python portmap.py add-project my-api "My API" "/home/you/projects/my-api" --category project --stack node,postgres
python portmap.py register my-api server 3000 --protocol http --process node
python portmap.py register my-api postgres 5432 --protocol tcp --process docker
# Or let the scanner find them automatically
python portmap.py scanEdit registry.json and add entries to the ranges object to reserve contiguous blocks for a project:
{
"ranges": {
"my-api": { "start": 3000, "end": 3009 },
"my-other-project": { "start": 4000, "end": 4009 }
}
}Then allocate will prefer those ranges, and gaps will exclude them from "available" output.
This is where portmap gets interesting. Any AI agent pointed at this repo can:
- Read
CLAUDE.md— the agent-facing quick reference with exact commands - Read
registry.json— self-documenting JSON with a schema - Run CLI commands — check ports, allocate, register, all with machine-parseable output
Add a portmap reference to each project's CLAUDE.md (or equivalent agent instructions):
## Ports
This project's ports are registered in portmap (project id: "my-app").
Before changing ports: `python /path/to/portmap/portmap.py check <port>`
Allocate new ports: `python /path/to/portmap/portmap.py allocate my-app`Now any agent working in that repo will discover portmap and use it.
# Entries are tagged with who created them
PORTMAP_AGENT_NAME=claude python portmap.py register my-app api 8080
# source field: "agent:claude"See docs/INTEGRATION.md for the full integration guide covering:
- Human CLI workflows
- AI agent patterns (Claude, Cursor, Copilot)
- Programmatic access from PowerShell, Python, Node.js
- Cross-repo setup
- Scheduled scanning
The scanner reads project config files and extracts port assignments:
| Source | What it extracts |
|---|---|
docker-compose.yml |
ports: mappings (handles env vars, bind addresses, protocols) |
launchSettings.json |
.NET applicationUrl ports |
appsettings.json |
Kestrel endpoint ports |
.env files |
PORT= and *_PORT= assignments (skips dependency URLs) |
start-all.ps1 etc. |
Port = N assignments, localhost:N patterns |
Scanner entries are tagged with source: "scan:*" and auto-update on each scan. Manual and agent entries are never overwritten by the scanner.
# Install a Task Scheduler job (scans every 15 minutes)
.\setup-scheduled-scan.ps1
# Custom interval
.\setup-scheduled-scan.ps1 -IntervalMinutes 30
# Remove
.\setup-scheduled-scan.ps1 -Removeportmap/
├── CLAUDE.md # Agent-facing documentation
├── README.md # You are here
├── registry.json # Your registry (gitignored — local to you)
├── registry.example.json # Example registry to start from
├── schema/
│ └── registry.schema.json # JSON Schema for validation + IDE completion
├── portmap.py # CLI entry point (zero dependencies)
├── scanner/
│ ├── core.py # Scan orchestrator + merge logic
│ ├── conflict.py # Conflict detection
│ └── extractors/ # Per-format parsers
├── docs/
│ └── INTEGRATION.md # Human / Agent / API integration guide
├── setup-scheduled-scan.ps1 # Windows Task Scheduler installer
└── web/ # Future: local dashboard
Eliminate port conflicts and provide a local "application registry" that any developer or AI agent can query to understand what's running, what's claimed, and where to put new things.
- A source of truth for local service port assignments
- A machine-readable manifest with a JSON Schema
- A CLI for querying, registering, and detecting conflicts
- An auto-scanner that discovers ports from project config files
- A reference that any AI agent can read and act on autonomously
- Not a service mesh or proxy (use Traefik for that)
- Not a process manager (it doesn't start/stop services)
- Not a Docker replacement (it works alongside Docker)
- Not cloud infrastructure (it's strictly local dev)
- Zero dependencies — stdlib Python only, no pip install needed
- File-based — registry.json is the only state, checked into git
- Non-destructive scanner — auto-discovery never overwrites manual or agent entries
- No magic — explicit registration, explicit port assignment
- Agent-first docs — CLAUDE.md is the primary interface for AI agents
| Phase | Status | Description |
|---|---|---|
| 1. Foundation | Done | CLI + manifest + schema + docs |
| 2. Scanner | Done | Auto-discover from docker-compose, appsettings, .env, scripts |
| 3. Validator + Allocator | Done | Live port checking, gap finding, port allocation |
| 4. Automation | Done | Scheduled scanning via Task Scheduler |
| 5. Cross-repo | Done | CLAUDE.md integration pattern |
| 6. Web View | Future | Local dashboard for visual overview |
Issues and PRs welcome. The codebase is intentionally small (~500 lines of Python, zero dependencies) — keep it that way.
MIT — see LICENSE.