diff --git a/Dockerfile b/Dockerfile index a7cb98b7d3..354ea12a33 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ # docker build -t kandev:latest . # # Run: -# docker run -p 8080:8080 -v kandev-data:/data kandev:latest +# docker run -p 38429:38429 -v kandev-data:/data kandev:latest # --------------------------------------------------------------------------- # Stage 1: Go builder — compile kandev + agentctl binaries @@ -114,8 +114,10 @@ RUN chown -R kandev:kandev /app /data WORKDIR /app -EXPOSE 8080 +# Only the backend port is exposed — it reverse-proxies the Next.js frontend +# (which listens on 37429 internally), so users hit a single port. +EXPOSE 38429 # tini as PID 1 for signal handling; entrypoint handles privilege drop ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"] -CMD ["kandev", "start", "--backend-port", "8080", "--web-port", "37429", "--verbose"] +CMD ["kandev", "start", "--backend-port", "38429", "--web-port", "37429", "--verbose"] diff --git a/Makefile b/Makefile index ea28b785a6..3c97d013e1 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ help: @echo "" @echo "Development Commands:" @echo " dev Run backend + web via CLI (auto ports)" - @echo " dev-backend Run backend in development mode (port 8080)" + @echo " dev-backend Run backend in development mode (port 38429)" @echo " dev-web Run web app in development mode (port 37429)" @echo " dev Note: Uses apps/cli launcher (auto ports)" @echo "" @@ -114,7 +114,7 @@ endif .PHONY: dev-backend dev-backend: - @echo "Starting backend on http://localhost:8080" + @echo "Starting backend on http://localhost:38429" @trap 'stty sane 2>/dev/null || true' EXIT INT TERM; \ $(MAKE) -C $(BACKEND_DIR) run; \ stty sane 2>/dev/null || true diff --git a/README.md b/README.md index 982e824da2..0dedc3fba2 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ apps/ make dev # Or run separately -make dev-backend # Backend on :8080 +make dev-backend # Backend on :38429 make dev-web # Frontend on :37429 ``` diff --git a/apps/backend/cmd/kandev/main.go b/apps/backend/cmd/kandev/main.go index 180d61b5fb..f082ec9337 100644 --- a/apps/backend/cmd/kandev/main.go +++ b/apps/backend/cmd/kandev/main.go @@ -59,9 +59,14 @@ import ( "github.com/kandev/kandev/internal/db" ) +// defaultServerPort is the fallback HTTP port when neither the CLI flag nor +// the config file / env var sets one. Kept in sync with the viper default in +// internal/common/config.setDefaults. +const defaultServerPort = 38429 + // Command-line flags var ( - flagPort = flag.Int("port", 0, "HTTP server port (default: 8080)") + flagPort = flag.Int("port", 0, fmt.Sprintf("HTTP server port (default: %d)", defaultServerPort)) flagLogLevel = flag.String("log-level", "", "Log level: debug, info, warn, error") flagHelp = flag.Bool("help", false, "Show help message") flagVersion = flag.Bool("version", false, "Show version information") @@ -74,8 +79,8 @@ func init() { fmt.Fprintf(os.Stderr, "Options:\n") flag.PrintDefaults() fmt.Fprintf(os.Stderr, "\nExamples:\n") - fmt.Fprintf(os.Stderr, " kandev # Start with default settings\n") - fmt.Fprintf(os.Stderr, " kandev -port=9000 -log-level=debug # Custom port and log level\n") + fmt.Fprintf(os.Stderr, " kandev # Start with default settings\n") + fmt.Fprintf(os.Stderr, " kandev -port=18080 -log-level=debug # Custom port and log level\n") } } @@ -418,7 +423,7 @@ func startGatewayAndServe( port := cfg.Server.Port if port == 0 { - port = 8080 + port = defaultServerPort } go func() { log.Info("WebSocket server listening", zap.Int("port", port)) @@ -489,7 +494,7 @@ func buildHTTPServer( port := cfg.Server.Port if port == 0 { - port = 8080 + port = defaultServerPort } return &http.Server{ Addr: fmt.Sprintf(":%d", port), diff --git a/apps/backend/dockerfiles/Dockerfile b/apps/backend/dockerfiles/Dockerfile index c6553de0a1..9a49c2db19 100644 --- a/apps/backend/dockerfiles/Dockerfile +++ b/apps/backend/dockerfiles/Dockerfile @@ -53,12 +53,12 @@ WORKDIR /workspace # OPENAI_API_KEY - OpenAI API key for Codex # # agentctl configuration: -# AGENTCTL_PORT - HTTP API port (default: 9999) +# AGENTCTL_PORT - HTTP API port (default: 39429) # AGENTCTL_AGENT_COMMAND - Command to run (e.g., "auggie --acp" or "codex app-server") # AGENTCTL_AUTO_START - Auto-start agent on startup (default: false) # Expose agentctl HTTP API port -EXPOSE 9999 +EXPOSE 39429 # Run agentctl HTTP server ENTRYPOINT ["/agent/entrypoint.sh"] diff --git a/apps/backend/dockerfiles/entrypoint.sh b/apps/backend/dockerfiles/entrypoint.sh index fd79f6cb1e..b62037eaab 100644 --- a/apps/backend/dockerfiles/entrypoint.sh +++ b/apps/backend/dockerfiles/entrypoint.sh @@ -16,6 +16,6 @@ if ! command -v codex &> /dev/null; then fi # Run agentctl HTTP server -echo "Starting agentctl on port ${AGENTCTL_PORT:-9999}..." +echo "Starting agentctl on port ${AGENTCTL_PORT:-39429}..." exec /usr/local/bin/agentctl diff --git a/apps/backend/internal/agent/lifecycle/types.go b/apps/backend/internal/agent/lifecycle/types.go index f604e7f8ba..d9bd72f592 100644 --- a/apps/backend/internal/agent/lifecycle/types.go +++ b/apps/backend/internal/agent/lifecycle/types.go @@ -17,8 +17,9 @@ import ( "go.opentelemetry.io/otel/trace" ) -// Default agentctl port -const AgentCtlPort = 9999 +// Default agentctl port. Clustered near the web port (37429) to avoid +// collisions with commonly used ports (8080, 9090, 9999, etc.). +const AgentCtlPort = 39429 // AgentExecution represents a running agent execution type AgentExecution struct { diff --git a/apps/backend/internal/agentctl/client/launcher/launcher.go b/apps/backend/internal/agentctl/client/launcher/launcher.go index 27db3f2dd9..df7f784600 100644 --- a/apps/backend/internal/agentctl/client/launcher/launcher.go +++ b/apps/backend/internal/agentctl/client/launcher/launcher.go @@ -51,7 +51,7 @@ type Launcher struct { type Config struct { BinaryPath string // Path to agentctl binary (auto-detected if empty) Host string // Host to bind to (default: localhost) - Port int // Control port (default: 9999) + Port int // Control port (default: 39429) } // New creates a new Launcher. @@ -60,7 +60,7 @@ func New(cfg Config, log *logger.Logger) *Launcher { cfg.Host = "localhost" } if cfg.Port == 0 { - cfg.Port = 9999 + cfg.Port = 39429 } if cfg.BinaryPath == "" { cfg.BinaryPath = findAgentctlBinary() diff --git a/apps/backend/internal/agentctl/server/config/config.go b/apps/backend/internal/agentctl/server/config/config.go index 7ca94b1783..112eaeea44 100644 --- a/apps/backend/internal/agentctl/server/config/config.go +++ b/apps/backend/internal/agentctl/server/config/config.go @@ -196,10 +196,10 @@ type InstanceConfig struct { // Load loads the configuration from environment variables. func Load() *Config { cfg := &Config{ - Port: getEnvInt("AGENTCTL_PORT", 9999), + Port: getEnvInt("AGENTCTL_PORT", 39429), Ports: PortConfig{ - Base: getEnvInt("AGENTCTL_INSTANCE_PORT_BASE", 10001), - Max: getEnvInt("AGENTCTL_INSTANCE_PORT_MAX", 10100), + Base: getEnvInt("AGENTCTL_INSTANCE_PORT_BASE", 41001), + Max: getEnvInt("AGENTCTL_INSTANCE_PORT_MAX", 41100), }, Defaults: InstanceDefaults{ Protocol: agent.Protocol(getEnv("AGENTCTL_PROTOCOL", string(agent.ProtocolACP))), diff --git a/apps/backend/internal/common/config/config.go b/apps/backend/internal/common/config/config.go index 3a3c2f940d..a192ac59dc 100644 --- a/apps/backend/internal/common/config/config.go +++ b/apps/backend/internal/common/config/config.go @@ -177,7 +177,7 @@ type AgentConfig struct { // StandaloneHost is the host where standalone agentctl is running (default: localhost) StandaloneHost string `mapstructure:"standaloneHost"` - // StandalonePort is the control port for standalone agentctl (default: 9999) + // StandalonePort is the control port for standalone agentctl (default: 39429) StandalonePort int `mapstructure:"standalonePort"` // StandaloneAuthToken is the per-launch auth token retrieved via handshake. @@ -189,7 +189,7 @@ type AgentConfig struct { // This setting is only for running a separate standalone MCP server process. McpServerEnabled bool `mapstructure:"mcpServerEnabled"` - // McpServerPort is the port for the standalone MCP server (default: 9090) + // McpServerPort is the port for the standalone MCP server (default: 40429) McpServerPort int `mapstructure:"mcpServerPort"` // McpServerURL is the URL of the Kandev MCP server for task management @@ -235,7 +235,7 @@ func detectDefaultLogFormat() string { func setDefaults(v *viper.Viper) { // Server defaults v.SetDefault("server.host", "0.0.0.0") - v.SetDefault("server.port", 8080) + v.SetDefault("server.port", 38429) v.SetDefault("server.readTimeout", 30) v.SetDefault("server.writeTimeout", 30) v.SetDefault("server.webInternalUrl", "") @@ -274,9 +274,9 @@ func setDefaults(v *viper.Viper) { // Agent defaults (runtime selection is now per-task based on executor type) v.SetDefault("agent.standaloneHost", "localhost") - v.SetDefault("agent.standalonePort", 9999) + v.SetDefault("agent.standalonePort", 39429) v.SetDefault("agent.mcpServerEnabled", false) // MCP is now embedded in agentctl - v.SetDefault("agent.mcpServerPort", 9090) + v.SetDefault("agent.mcpServerPort", 40429) v.SetDefault("agent.mcpServerUrl", "") // Auth defaults diff --git a/apps/cli/src/constants.ts b/apps/cli/src/constants.ts index 5300e5052f..74800d11e3 100644 --- a/apps/cli/src/constants.ts +++ b/apps/cli/src/constants.ts @@ -2,10 +2,12 @@ import os from "node:os"; import path from "node:path"; // Default service ports (will auto-fallback if busy). -export const DEFAULT_BACKEND_PORT = 8080; +// Clustered near the web port (37429) to avoid collisions with commonly used +// ports (8080, 9090, 9999, etc.) while keeping the numbers memorable. +export const DEFAULT_BACKEND_PORT = 38429; export const DEFAULT_WEB_PORT = 37429; -export const DEFAULT_AGENTCTL_PORT = 9999; -export const DEFAULT_MCP_PORT = 9090; +export const DEFAULT_AGENTCTL_PORT = 39429; +export const DEFAULT_MCP_PORT = 40429; // Random fallback range for port selection. export const RANDOM_PORT_MIN = 10000; diff --git a/apps/cli/src/run.test.ts b/apps/cli/src/run.test.ts index 5e22956b5e..6e0a8e547e 100644 --- a/apps/cli/src/run.test.ts +++ b/apps/cli/src/run.test.ts @@ -13,9 +13,9 @@ vi.mock("./constants", () => ({ return mockCacheDir.value; }, DATA_DIR: "/tmp/kandev-test-data", - DEFAULT_BACKEND_PORT: 8080, + DEFAULT_BACKEND_PORT: 38429, DEFAULT_WEB_PORT: 37429, - DEFAULT_AGENTCTL_PORT: 9999, + DEFAULT_AGENTCTL_PORT: 39429, HEALTH_TIMEOUT_MS_RELEASE: 15000, RANDOM_PORT_MIN: 10000, RANDOM_PORT_MAX: 60000, diff --git a/apps/web/components/settings/general-settings.tsx b/apps/web/components/settings/general-settings.tsx index fd134b6291..7812a29fb8 100644 --- a/apps/web/components/settings/general-settings.tsx +++ b/apps/web/components/settings/general-settings.tsx @@ -390,7 +390,7 @@ function BackendConnectionCard() { value={displayBackendUrl} readOnly disabled - placeholder="http://localhost:8080" + placeholder="http://localhost:38429" className="cursor-default" />
diff --git a/apps/web/components/task/passthrough-terminal.tsx b/apps/web/components/task/passthrough-terminal.tsx index e7f63f3ea7..721e5c008d 100644 --- a/apps/web/components/task/passthrough-terminal.tsx +++ b/apps/web/components/task/passthrough-terminal.tsx @@ -57,7 +57,7 @@ function useTerminalRefs() { }; } -const WS_BASE_URL_FALLBACK = "ws://localhost:8080"; +const WS_BASE_URL_FALLBACK = "ws://localhost:38429"; function useWsBaseUrl() { return useMemo(() => { try { diff --git a/apps/web/e2e/fixtures/backend.ts b/apps/web/e2e/fixtures/backend.ts index b2681e8d29..bd9f7af981 100644 --- a/apps/web/e2e/fixtures/backend.ts +++ b/apps/web/e2e/fixtures/backend.ts @@ -184,7 +184,7 @@ export const backendFixture = base.extend