From 6870ac263cff35cb44d47b7508e9c0fd07f7e71e Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 17:15:57 +0000 Subject: [PATCH 1/2] chore(dev): use host.docker.internal in dev configs instead of LAN IPs Sandbox containers running under Docker Desktop resolve host.docker.internal to the host machine, so the prior hardcoded LAN IP workarounds are unnecessary. Replace them in gastown wrangler dev vars, cloud-agent(-next) WS_ALLOWED_ORIGINS, and the cloud-agent(-next) .dev.vars.example files. Drop the stale comment that referenced a workerd-network limitation; that issue relates to Hyperdrive, not Sandbox containers. --- services/cloud-agent-next/.dev.vars.example | 18 +++++++++--------- services/cloud-agent-next/wrangler.jsonc | 2 +- services/cloud-agent/.dev.vars.example | 12 ++++++------ services/cloud-agent/wrangler.jsonc | 2 +- services/gastown/worker-configuration.d.ts | 8 ++++---- services/gastown/wrangler.jsonc | 12 ++++++------ 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/services/cloud-agent-next/.dev.vars.example b/services/cloud-agent-next/.dev.vars.example index 96504553ac..e4f2ded396 100644 --- a/services/cloud-agent-next/.dev.vars.example +++ b/services/cloud-agent-next/.dev.vars.example @@ -18,18 +18,18 @@ INTERNAL_API_SECRET=your-internal-api-secret-here #KILOCODE_ORG_ID_OVERRIDE=your-override-org-id-here # Kilocode backend base URL and KILO_OPENROUTER_BASE for API calls and session environment variables -# For local development, point to your local kilocode-backend -# Note: you wanna use your actual privatenet address here and not "localhost" -# pnpm run dev of kilocode-backend usually gives you both addrs on boot. +# For local development, point to your local kilocode-backend. +# Sandbox containers run under Docker Desktop, so `host.docker.internal` +# resolves to the host where Next.js is listening. # @url nextjs -KILOCODE_BACKEND_BASE_URL=http://192.168.x.x:3000 +KILOCODE_BACKEND_BASE_URL=http://host.docker.internal:3000 # @url nextjs/api -KILO_OPENROUTER_BASE=http://192.168.x.x:3000/api +KILO_OPENROUTER_BASE=http://host.docker.internal:3000/api # Worker base URL used by the wrapper to connect to /ingest. -# Use a host-reachable IP (not localhost) so sandbox containers can connect back. +# Sandbox containers reach the host via `host.docker.internal`. # @url cloud-agent-next -WORKER_URL=http://192.168.x.x:8794 +WORKER_URL=http://host.docker.internal:8794 # Timeout overrides (optional) CLI_TIMEOUT_SECONDS=900 @@ -69,9 +69,9 @@ R2_ATTACHMENTS_READONLY_ACCESS_KEY_ID="" R2_ATTACHMENTS_READONLY_SECRET_ACCESS_KEY="" # Session ingest URL used by the wrapper to post session data. -# Use a host-reachable IP (not localhost) so sandbox containers can connect back. +# Sandbox containers reach the host via `host.docker.internal`. # @url cloudflare-session-ingest -KILO_SESSION_INGEST_URL=http://192.168.x.x:8800 +KILO_SESSION_INGEST_URL=http://host.docker.internal:8800 # Local dev worker origins allowed to connect to /stream # @url nextjs,cloud-agent-next diff --git a/services/cloud-agent-next/wrangler.jsonc b/services/cloud-agent-next/wrangler.jsonc index d49cd8d1c0..7c54464655 100644 --- a/services/cloud-agent-next/wrangler.jsonc +++ b/services/cloud-agent-next/wrangler.jsonc @@ -244,7 +244,7 @@ "STALE_THRESHOLD_MS": "600000", "PENDING_START_TIMEOUT_MS": "300000", "R2_ATTACHMENTS_BUCKET": "cloud-agent-attachments-dev", - "WS_ALLOWED_ORIGINS": "http://localhost:3000,http://192.168.200.174:3000", + "WS_ALLOWED_ORIGINS": "http://localhost:3000,http://host.docker.internal:3000", "KILO_SESSION_INGEST_URL": "http://localhost:8800", "PER_SESSION_SANDBOX_ORG_IDS": "*", }, diff --git a/services/cloud-agent/.dev.vars.example b/services/cloud-agent/.dev.vars.example index f0c8aabea5..91e024114d 100644 --- a/services/cloud-agent/.dev.vars.example +++ b/services/cloud-agent/.dev.vars.example @@ -20,16 +20,16 @@ INTERNAL_API_SECRET=your-internal-api-secret-here # Kilocode backend base URL for API calls and session environment variables # Defaults to https://kilo.ai if not set -# For local development, point to your local kilocode-backend -# Note: you wanna use your actual privatenet address here and not "localhost" -# pnpm run dev of kilocode-backend usually gives you both addrs on boot. +# For local development, point to your local kilocode-backend. +# Sandbox containers run under Docker Desktop, so `host.docker.internal` +# resolves to the host where Next.js is listening. # @url nextjs -KILOCODE_BACKEND_BASE_URL=http://192.168.200.70:3000 +KILOCODE_BACKEND_BASE_URL=http://host.docker.internal:3000 # Worker base URL used by the wrapper to connect to /ingest. -# Use a host-reachable IP (not localhost) so sandbox containers can connect back. +# Sandbox containers reach the host via `host.docker.internal`. # @url cloud-agent -WORKER_URL=http://192.168.200.72:8788 +WORKER_URL=http://host.docker.internal:8788 # Timeout overrides (optional) WRAPPER_IDLE_TIMEOUT_MS=120000 diff --git a/services/cloud-agent/wrangler.jsonc b/services/cloud-agent/wrangler.jsonc index df6def473c..b803e76469 100644 --- a/services/cloud-agent/wrangler.jsonc +++ b/services/cloud-agent/wrangler.jsonc @@ -231,7 +231,7 @@ "STALE_THRESHOLD_MS": "600000", "PENDING_START_TIMEOUT_MS": "300000", "R2_ATTACHMENTS_BUCKET": "cloud-agent-attachments-dev", - "WS_ALLOWED_ORIGINS": "http://localhost:3000,http://192.168.200.174:3000", + "WS_ALLOWED_ORIGINS": "http://localhost:3000,http://host.docker.internal:3000", }, "r2_buckets": [ { diff --git a/services/gastown/worker-configuration.d.ts b/services/gastown/worker-configuration.d.ts index d645e0378d..85ea8354d5 100644 --- a/services/gastown/worker-configuration.d.ts +++ b/services/gastown/worker-configuration.d.ts @@ -30,8 +30,8 @@ declare namespace Cloudflare { ENVIRONMENT: "development"; CF_ACCESS_TEAM: "engineering-e11"; CF_ACCESS_AUD: "7f6eda4c0714f6ea2afb74a3f055db65659b67571a913eab42468636a9b8c8be"; - KILO_API_URL: "http://192.168.65.254:3000"; - GASTOWN_API_URL: "http://192.168.65.254:8787"; + KILO_API_URL: "http://host.docker.internal:3000"; + GASTOWN_API_URL: "http://host.docker.internal:8803"; GASTOWN_USER: DurableObjectNamespace; GASTOWN_ORG: DurableObjectNamespace; AGENT_IDENTITY: DurableObjectNamespace; @@ -49,8 +49,8 @@ declare namespace Cloudflare { ENVIRONMENT: "development" | "production"; CF_ACCESS_TEAM: "engineering-e11"; CF_ACCESS_AUD: "7f6eda4c0714f6ea2afb74a3f055db65659b67571a913eab42468636a9b8c8be"; - KILO_API_URL: "http://192.168.65.254:3000" | "https://api.kilo.ai"; - GASTOWN_API_URL: "http://192.168.65.254:8787" | "https://gastown.kiloapps.io"; + KILO_API_URL: "http://host.docker.internal:3000" | "https://api.kilo.ai"; + GASTOWN_API_URL: "http://host.docker.internal:8803" | "https://gastown.kiloapps.io"; GASTOWN_USER: DurableObjectNamespace; GASTOWN_ORG: DurableObjectNamespace; AGENT_IDENTITY: DurableObjectNamespace; diff --git a/services/gastown/wrangler.jsonc b/services/gastown/wrangler.jsonc index 4cc1410810..3ec23d7694 100644 --- a/services/gastown/wrangler.jsonc +++ b/services/gastown/wrangler.jsonc @@ -119,12 +119,12 @@ "ENVIRONMENT": "development", "CF_ACCESS_TEAM": "engineering-e11", "CF_ACCESS_AUD": "7f6eda4c0714f6ea2afb74a3f055db65659b67571a913eab42468636a9b8c8be", - // Wrangler's workerd-network doesn't get Docker Desktop's - // host.docker.internal → host proxy mapping. Use the Docker - // Desktop VM host gateway IP directly so containers can reach - // the host's dev servers. - "KILO_API_URL": "http://192.168.65.254:3000", - "GASTOWN_API_URL": "http://192.168.65.254:8803", + // Cloudflare Sandbox containers run via Docker Desktop and + // resolve `host.docker.internal` to the host. Use it so dev + // containers can reach the host's dev servers (Next.js on + // :3000, gastown worker on :8803). + "KILO_API_URL": "http://host.docker.internal:3000", + "GASTOWN_API_URL": "http://host.docker.internal:8803", }, "containers": [ { From 10668ef8f3b28d0bf0a0df78f0cce17c0cad8ac7 Mon Sep 17 00:00:00 2001 From: Evgeny Shurakov Date: Thu, 7 May 2026 21:05:56 +0200 Subject: [PATCH 2/2] fix(dev): preserve host.docker.internal for cloud-agent-next only Revert host.docker.internal changes from gastown and legacy cloud-agent services. Keep them only for cloud-agent-next where Sandbox containers actually need them. Add env-sync script logic to preserve host.docker.internal in @url annotations when the .dev.vars.example default explicitly uses it, so pnpm dev:env won't overwrite it with the LAN IP. --- dev/local/env-sync/parse.ts | 11 +++++-- dev/local/env-sync/plan.test.ts | 36 ++++++++++++++++++++++ services/cloud-agent/.dev.vars.example | 12 ++++---- services/cloud-agent/wrangler.jsonc | 2 +- services/gastown/worker-configuration.d.ts | 8 ++--- services/gastown/wrangler.jsonc | 12 ++++---- 6 files changed, 62 insertions(+), 19 deletions(-) diff --git a/dev/local/env-sync/parse.ts b/dev/local/env-sync/parse.ts index 886f192a6e..ec8b67738c 100644 --- a/dev/local/env-sync/parse.ts +++ b/dev/local/env-sync/parse.ts @@ -223,8 +223,15 @@ function resolveAnnotatedValue( const isOrigins = key.includes('ORIGINS'); const isHostname = key.includes('HOSTNAME') && !key.includes('URL'); const isWs = key.includes('_WS_'); - // LAN IP for container services, but never for ORIGINS keys - const host = serviceUsesLanIp && !isOrigins && lanIp ? lanIp : 'localhost'; + const defaultUsesDockerHost = entry.defaultValue.includes('host.docker.internal'); + // LAN IP for container services, but never for ORIGINS keys. + // Preserve host.docker.internal when the example default uses it + // (sandbox containers need it to reach the host from inside Docker). + const host = defaultUsesDockerHost + ? 'host.docker.internal' + : serviceUsesLanIp && !isOrigins && lanIp + ? lanIp + : 'localhost'; const protocol = isWs ? 'ws' : 'http'; const resolvedParts: string[] = []; diff --git a/dev/local/env-sync/plan.test.ts b/dev/local/env-sync/plan.test.ts index f3984e37bb..8bfc39f0b0 100644 --- a/dev/local/env-sync/plan.test.ts +++ b/dev/local/env-sync/plan.test.ts @@ -348,3 +348,39 @@ test('keeps .env.local values ahead of wrangler vars for local overrides', () => repo.cleanup(); } }); + +test('preserves host.docker.internal in @url defaults for useLanIp services', () => { + const repo = createRepo({ + '.env.local': '', + [`${workerDir}/package.json`]: JSON.stringify( + { scripts: { dev: "wrangler dev --env 'dev'" } }, + null, + 2 + ), + [`${workerDir}/wrangler.jsonc`]: '{ "dev": { "port": 8794 } }', + [`${workerDir}/.dev.vars.example`]: [ + '# @url nextjs', + 'KILOCODE_BACKEND_BASE_URL=http://host.docker.internal:3000', + '# @url cloud-agent-next', + 'WORKER_URL=http://host.docker.internal:8794', + '# @url nextjs', + 'ALLOWED_ORIGINS=http://localhost:3000', + '', + ].join('\n'), + }); + try { + const plan = computePlan(repo.root, new Set(['cloud-agent-next'])); + assert.equal(plan.missingEnvLocal, false); + assert.equal(plan.devVarsChanges.length, 1); + const [change] = plan.devVarsChanges; + assert.ok(change); + assert.equal(change.isNew, true); + const content = change.newFileContent ?? ''; + assert.ok(content.includes('KILOCODE_BACKEND_BASE_URL=http://host.docker.internal:3000')); + assert.ok(content.includes('WORKER_URL=http://host.docker.internal:8794')); + // ORIGINS keys still use localhost even when example default has host.docker.internal + assert.ok(content.includes('ALLOWED_ORIGINS=http://localhost:3000')); + } finally { + repo.cleanup(); + } +}); diff --git a/services/cloud-agent/.dev.vars.example b/services/cloud-agent/.dev.vars.example index 91e024114d..f0c8aabea5 100644 --- a/services/cloud-agent/.dev.vars.example +++ b/services/cloud-agent/.dev.vars.example @@ -20,16 +20,16 @@ INTERNAL_API_SECRET=your-internal-api-secret-here # Kilocode backend base URL for API calls and session environment variables # Defaults to https://kilo.ai if not set -# For local development, point to your local kilocode-backend. -# Sandbox containers run under Docker Desktop, so `host.docker.internal` -# resolves to the host where Next.js is listening. +# For local development, point to your local kilocode-backend +# Note: you wanna use your actual privatenet address here and not "localhost" +# pnpm run dev of kilocode-backend usually gives you both addrs on boot. # @url nextjs -KILOCODE_BACKEND_BASE_URL=http://host.docker.internal:3000 +KILOCODE_BACKEND_BASE_URL=http://192.168.200.70:3000 # Worker base URL used by the wrapper to connect to /ingest. -# Sandbox containers reach the host via `host.docker.internal`. +# Use a host-reachable IP (not localhost) so sandbox containers can connect back. # @url cloud-agent -WORKER_URL=http://host.docker.internal:8788 +WORKER_URL=http://192.168.200.72:8788 # Timeout overrides (optional) WRAPPER_IDLE_TIMEOUT_MS=120000 diff --git a/services/cloud-agent/wrangler.jsonc b/services/cloud-agent/wrangler.jsonc index b803e76469..df6def473c 100644 --- a/services/cloud-agent/wrangler.jsonc +++ b/services/cloud-agent/wrangler.jsonc @@ -231,7 +231,7 @@ "STALE_THRESHOLD_MS": "600000", "PENDING_START_TIMEOUT_MS": "300000", "R2_ATTACHMENTS_BUCKET": "cloud-agent-attachments-dev", - "WS_ALLOWED_ORIGINS": "http://localhost:3000,http://host.docker.internal:3000", + "WS_ALLOWED_ORIGINS": "http://localhost:3000,http://192.168.200.174:3000", }, "r2_buckets": [ { diff --git a/services/gastown/worker-configuration.d.ts b/services/gastown/worker-configuration.d.ts index 85ea8354d5..d645e0378d 100644 --- a/services/gastown/worker-configuration.d.ts +++ b/services/gastown/worker-configuration.d.ts @@ -30,8 +30,8 @@ declare namespace Cloudflare { ENVIRONMENT: "development"; CF_ACCESS_TEAM: "engineering-e11"; CF_ACCESS_AUD: "7f6eda4c0714f6ea2afb74a3f055db65659b67571a913eab42468636a9b8c8be"; - KILO_API_URL: "http://host.docker.internal:3000"; - GASTOWN_API_URL: "http://host.docker.internal:8803"; + KILO_API_URL: "http://192.168.65.254:3000"; + GASTOWN_API_URL: "http://192.168.65.254:8787"; GASTOWN_USER: DurableObjectNamespace; GASTOWN_ORG: DurableObjectNamespace; AGENT_IDENTITY: DurableObjectNamespace; @@ -49,8 +49,8 @@ declare namespace Cloudflare { ENVIRONMENT: "development" | "production"; CF_ACCESS_TEAM: "engineering-e11"; CF_ACCESS_AUD: "7f6eda4c0714f6ea2afb74a3f055db65659b67571a913eab42468636a9b8c8be"; - KILO_API_URL: "http://host.docker.internal:3000" | "https://api.kilo.ai"; - GASTOWN_API_URL: "http://host.docker.internal:8803" | "https://gastown.kiloapps.io"; + KILO_API_URL: "http://192.168.65.254:3000" | "https://api.kilo.ai"; + GASTOWN_API_URL: "http://192.168.65.254:8787" | "https://gastown.kiloapps.io"; GASTOWN_USER: DurableObjectNamespace; GASTOWN_ORG: DurableObjectNamespace; AGENT_IDENTITY: DurableObjectNamespace; diff --git a/services/gastown/wrangler.jsonc b/services/gastown/wrangler.jsonc index 3ec23d7694..4cc1410810 100644 --- a/services/gastown/wrangler.jsonc +++ b/services/gastown/wrangler.jsonc @@ -119,12 +119,12 @@ "ENVIRONMENT": "development", "CF_ACCESS_TEAM": "engineering-e11", "CF_ACCESS_AUD": "7f6eda4c0714f6ea2afb74a3f055db65659b67571a913eab42468636a9b8c8be", - // Cloudflare Sandbox containers run via Docker Desktop and - // resolve `host.docker.internal` to the host. Use it so dev - // containers can reach the host's dev servers (Next.js on - // :3000, gastown worker on :8803). - "KILO_API_URL": "http://host.docker.internal:3000", - "GASTOWN_API_URL": "http://host.docker.internal:8803", + // Wrangler's workerd-network doesn't get Docker Desktop's + // host.docker.internal → host proxy mapping. Use the Docker + // Desktop VM host gateway IP directly so containers can reach + // the host's dev servers. + "KILO_API_URL": "http://192.168.65.254:3000", + "GASTOWN_API_URL": "http://192.168.65.254:8803", }, "containers": [ {