@404labs/portguard
v0.1.0
Published
Stable per-project localhost port assignment for AI-built apps. Prevents 3000/3001 drift, checks occupancy, and ships as an agent skill plus CLI.
Maintainers
Readme
portguard
Stable localhost ports for AI-built apps. Assign one durable port per project, skip the crowded
3000/3001defaults, check occupancy, and stop framework auto-fallback from scrambling local accounts and password-manager entries.
AI coding agents often start every web app on localhost:3000, then drift to
3001, 3002, or a random framework fallback when something is already
running. That makes browser profiles, OAuth callbacks, cookies, and password
managers point at the wrong project. portguard gives each project a stable
local URL and stores the assignment in a shared registry.
What it does
portguard keeps a local registry at
~/.404labs/portguard/registry.json:
- Assigns once per project - uses the git root when present, otherwise the current directory.
- Avoids common defaults - skips
3000and3001by default. - Checks occupancy - newly assigned ports must be bindable on
127.0.0.1. - Prevents silent reuse - a port that belonged to one project is not given to another project just because the first server is stopped.
- Refuses silent drift - an occupied existing assignment is reported;
the URL changes only when you explicitly run
--reassign.
Install
As an agent skill
Recommended - global install via the
Vercel Labs skills CLI
(supports 55+ agent CLIs and keeps this behavior available in every repo):
npx skills add SpectreMercury/404labs --skill portguard -gInstall to the current detected agent instead:
npx skills add SpectreMercury/404labs --skill portguardInstall to all detected/supported agents:
npx skills add SpectreMercury/404labs --skill portguard --allAs a CLI
Install globally so all projects and agents share one command and one registry:
npm i -g @404labs/portguardOr use it through npx:
npx @404labs/portguard assign --jsonBuilt-in agent installer
The package can also copy the skill into common local agent folders:
npx @404labs/portguard install # auto-detect
npx @404labs/portguard install --target all # install for all 4 supported
npx @404labs/portguard install --target claude,codex
npx @404labs/portguard install --list-targets| Built-in target | CLI | Path |
|---|---|---|
| claude | Claude Code | ~/.claude/skills/portguard/ |
| codex | OpenAI Codex CLI | ~/.agents/skills/portguard/ |
| antigravity | Google Antigravity | ~/.gemini/antigravity/skills/portguard/ |
| kimi | Moonshot Kimi CLI | ~/.kimi/skills/portguard/ |
Restart your CLI after installing the skill so its index refreshes.
Usage
Assign or read the current project's stable port:
portguard assignMachine-readable output:
portguard assign --jsonPrint only the port for scripts:
PORT=$(portguard assign --print) npm run devCheck whether a port is currently occupied:
portguard check 3124List active assignments:
portguard listRetire the current project's assignment without making the port reusable:
portguard releaseReassign only when you intentionally accept a new local URL:
portguard assign --reassignFail if the assigned port is occupied:
portguard assign --strictExample output
portguard assignment
project: /Users/me/work/acme-dashboard
name: acme-dashboard
port: 3104
url: http://localhost:3104
source: new
status: free
registry: /Users/me/.404labs/portguard/registry.json
Use: PORT=3104 npm run devIf the assigned port is occupied, portguard does not silently switch to a
new URL:
status: occupied
The assigned port is occupied. If that is this project already running, keep
using it. If it is a different process, stop the conflict or run
`portguard assign --reassign` intentionally.Wire it into common frameworks
Next.js:
{
"scripts": {
"dev": "next dev -p 3104"
}
}Vite:
{
"scripts": {
"dev": "vite --host 127.0.0.1 --port 3104 --strictPort"
}
}Astro:
{
"scripts": {
"dev": "astro dev --host 127.0.0.1 --port 3104"
}
}More examples are in references/frameworks.md.
Configuration
Flags:
--project <path> Project path. Default: current working directory.
--name <name> Display name stored in the registry.
--range <start-end> Search range. Default: 3100-3999.
--reserved <ports> Comma list to skip. Default: 3000,3001.
--host <host> Bind-check host. Default: 127.0.0.1.
--registry <path> Registry file. Default: ~/.404labs/portguard/registry.json.
--json Machine-readable output.
--print Print only the assigned port.
--strict Exit 1 if the existing assigned port is occupied.
--reassign Explicitly move to a new never-used free port.
--no-git-root Key the exact path instead of the git root.Environment:
PORTGUARD_REGISTRY=/custom/registry.json portguard list
PORTGUARD_RANGE=4100-4999 portguard assign
PORTGUARD_RESERVED=3000,3001,5173 portguard assignExit codes
| Code | Meaning |
|---|---|
| 0 | Command succeeded; check found the port free |
| 1 | Occupied port, no available port, no assignment to release, or partial install failure |
| 2 | Usage/configuration error |
License
MIT - see LICENSE.
