Port and Instance Lifecycle
How console, agent, service, and extension coordinate on port allocation, invocation routing, and runtime lifecycle
Port and Instance Lifecycle
This page explains one thing: how console, agent, service, and extension work together at runtime, especially who allocates ports, how commands are routed, and when instances are created or removed.
1) Unified Rule
- Agent ports are allocated by
console. city agent start/restartno longer expose--port.service/extensioncommands do not rely on a fixed port by default. They resolve target agent first, then resolve endpoint by priority.
2) Runtime Roles
console (global control plane)
- Maintains global registry (
~/.ship/console/agents.json). - Manages agent daemon lifecycle (start/stop/restart/status aggregation).
- Allocates runtime ports for agents.
agent (project runtime plane)
- Each agent project maps to one daemon process.
- Daemon startup args are persisted to project debug metadata (
.ship/.debug/downcity.daemon.json). - This process hosts runtime HTTP APIs (
/api/services/*,/api/extensions/*).
service (capability domain)
city service ...andcity <service> <action>call agent runtime APIs.- They resolve target project first, then host/port, then call
/api/services/*.
extension (extension domain)
city extension ...andcity <extension> <action>call/api/extensions/*.voicehas a local fallback path for selected actions when runtime is unreachable.
3) Agent Port Allocation and Instance Creation
city agent start
- Validate console is running.
- Validate project init files (
ship.json,PROFILE.md). - Console allocates an available port.
- Spawn daemon foreground child:
agent start <projectRoot> --foreground true --port <allocatedPort> --host <host>- Persist pid/log/meta under
.ship/.debug. - Upsert console registry record.
Auto-allocation algorithm (current behavior)
- Allocation module:
console/daemon/PortAllocator - Default range:
5314-6399(with5315reserved for Console UI) - Probe host: the actual agent bind host (default
0.0.0.0) - Strategy: scan ports in ascending order and pick the first listenable one
- Failure: startup fails if no port is available in range
Equivalent pseudo code:
host = start.host || "0.0.0.0"
for port in [5314..6399]:
if port == 5315:
continue
if canListen(host, port):
return port
throw "No available port"Implementation notes:
- No central lock is used (no cross-process strong lock); final truth is actual
listensuccess. - Probing on target host avoids false positives like "
127.0.0.1is free but0.0.0.0conflicts". - Daemon startup args are persisted in
.ship/.debug/downcity.daemon.json, and service/extension routing prefers this source.
city agent restart
- Stop old daemon.
- Console allocates a port again and starts new daemon.
- Refresh registry entry.
Note: port can change after restart by design.
Console UI port interaction
- Console UI default port is fixed to
5315. - Agent auto-allocation skips
5315, avoiding collisions with UI.
4) How service/extension resolve target agent
service target resolution order:
--agent <name>- if path is default
., preferDC_AGENT_NAME --path/ current directory- if
.andDC_AGENT_PATHexists, prefer that path
Then hard checks:
- target must be registered in console registry
- target must contain
ship.jsonandPROFILE.md(for service commands)
extension commands resolve target project by --path / current directory, then resolve endpoint.
5) Endpoint resolution order (host/port)
For runtime API calls (service/extension/action):
- explicit CLI
--host/--port(debug use only) DC_SERVER_HOST/PORTDC_CTX_SERVER_HOST/PORT- daemon meta
--host/--port - default
127.0.0.1:5314
Normalization:
0.0.0.0/::are converted to127.0.0.1for client connections.
6) Common port issues
state=stale + pid file exists but process is not alive
Daemon started and crashed. Port conflict is the common cause.
Fix:
city agent doctor <path> --fix
city agent restart <path>“One agent is running, second agent fails to start”
Typical cause: stale state or old flow still trying to bind the same port.
Check:
city console agents
lsof -nP -iTCP:<port> -sTCP:LISTEN
tail -n 200 <agentPath>/.ship/.debug/downcity.daemon.log7) Recommendations
- In multi-agent scenarios, prefer
city service ... --agent <name>. - Do not keep manually exported
DC_SERVER_PORTin shell profile. - For abnormal status, run
doctor --fix, thenrestart, then inspect daemon log.