Externalize infra topology hardcoded in ward: hosts, SSM, registry, telemetry (audit bucket C) #395

Closed
opened 2026-07-01 04:26:13 +00:00 by coilysiren · 3 comments
Owner

Bucket C of the dependency-direction audit (agentic-os#308). ward hardcodes infrastructure topology (hosts, ports, SSM paths, registry, telemetry sink) as Go literals. These are infra config, NOT agent config - they do not belong in the aos agents.yaml, they belong resolved from the infrastructure repo, SSM, or env. Several already have an env-override seam that just needs to become the primary path.

Sites

  • Tailnet + host topology - ward-tailnet, mac-proxy, kai-tower-3026, port 11434 (cmd/ward/container_compute.go:93,97,109,112), tower ollama URLs (container_compute.go:116, cmd/ward/forward.go:26), ollama default http://localhost:11434/v1 (cmd/ward/container_bootstrap.go:87).
  • Telemetry sink - http://ser8:4318/v1/logs (cmd/ward/agent_telemetry.go:31).
  • Forgejo base + registry host - https://forgejo.coilysiren.me (cmd/ward/forgejo_ops.go:20), the registry half of the agent image (container_compute.go:16).
  • SSM parameter paths - /forgejo/api-token, /coilysiren/ollama/host (cmd/ward/container.go:43,47).

Fix

ward resolves these from env / SSM / an infra-provided config rather than baking them. The edits land in ward (drop the literals, read the source), likely paired with an infrastructure-repo change to publish the values where ward reads them. Keep ward's URL/connection-construction CODE - only the topology DATA moves out.

Review note: cross-repo (ward + infrastructure). Confirm each host/path still has a live source before removing its literal fallback.

Parent: agentic-os#308. Filed from the read-only director surface (she/her).

Bucket C of the dependency-direction audit (agentic-os#308). ward hardcodes infrastructure topology (hosts, ports, SSM paths, registry, telemetry sink) as Go literals. These are infra config, NOT agent config - they do not belong in the aos agents.yaml, they belong resolved from the infrastructure repo, SSM, or env. Several already have an env-override seam that just needs to become the primary path. ## Sites - **Tailnet + host topology** - `ward-tailnet`, `mac-proxy`, `kai-tower-3026`, port `11434` (`cmd/ward/container_compute.go:93,97,109,112`), tower ollama URLs (`container_compute.go:116`, `cmd/ward/forward.go:26`), ollama default `http://localhost:11434/v1` (`cmd/ward/container_bootstrap.go:87`). - **Telemetry sink** - `http://ser8:4318/v1/logs` (`cmd/ward/agent_telemetry.go:31`). - **Forgejo base + registry host** - `https://forgejo.coilysiren.me` (`cmd/ward/forgejo_ops.go:20`), the registry half of the agent image (`container_compute.go:16`). - **SSM parameter paths** - `/forgejo/api-token`, `/coilysiren/ollama/host` (`cmd/ward/container.go:43,47`). ## Fix ward resolves these from env / SSM / an infra-provided config rather than baking them. The edits land in ward (drop the literals, read the source), likely paired with an infrastructure-repo change to publish the values where ward reads them. Keep ward's URL/connection-construction CODE - only the topology DATA moves out. Review note: cross-repo (ward + infrastructure). Confirm each host/path still has a live source before removing its literal fallback. Parent: agentic-os#308. Filed from the read-only director surface (she/her).
Member

🔎 ward agent advisor

ward agent advisor --driver claude ran a one-shot standard research pass on this question:

Map the ward#395 cluster and post a concrete LANDING PLAN as a comment on ward#395. Read-only, no code changes. Goal: sequence the cluster so it can actually land.

ward#395 externalizes ward's hardcoded infra topology (hosts/ports/tailnet, telemetry sink ser8:4318, forgejo base + registry host, SSM paths /forgejo/api-token and /coilysiren/ollama/host) - cross-repo with the infrastructure repo. It is Bucket C of the agentic-os#308 dependency-direction audit.

DISCOVER the full cluster: read agentic-os#308 and follow its buckets/children, and assess these known siblings - ward#396 (fleet inventory externalization), ward#413 (the ~/.ward/fleet.local.kdl operator-local reader, which today REJECTS the embed-only fleet block so model/endpoint cannot be overridden there yet), ward#487 (in-container ollama reachability probe), and the goose model+backend consolidation (goose model/provider are hardcoded in internal/agents/goose/config.go, endpoint from the /coilysiren/ollama/host SSM path in cmd/ward/container.go - neither host-overridable). Find any other open issues that must move together for #395 to land.

For EACH cluster member report: current state (landed / partial / open, cite commits or code), exact scope, and whether it is ward-only or needs an infrastructure-repo change. Ground every claim in the actual code (cite file:line in /substrate/ward and read the fleetconfig schema in /substrate/cli-guard/pkg/fleetconfig).

DELIVER:

  1. A dependency-ordered landing SEQUENCE - what must land before #395's literals can drop (in particular: does the fleet.local.kdl reader ward#413 have to accept an infra/endpoint override block FIRST to be the host for these values? confirm against docs/fleet-local.md and the fleetconfig parser).
  2. Per step: ward-only vs cross-repo, the exact literals/sites to externalize (from the #395 site list), the source they resolve from (env / SSM / infra-published config), and the green check.
  3. Which steps are SAFELY DISPATCHABLE NOW as autonomous codex engineer runs vs which are gated on a human decision or on the infrastructure repo (not granted here). Flag any genuine fork Kai must decide (e.g. keep-literal-fallback vs fail-closed, or where the override config physically lives).

Public-safe, repo voice rules (no em-dashes, no semicolons in prose, name the actor). This is one-shot research - end by noting it is a plan to verify, not a carried change.


ward#395 landing plan - map the cluster, sequence the drop

One-shot research from the read-only director surface (she/her). This is a plan to verify against a live checkout, not a carried change. Line numbers below are re-grounded against main at 63184f8, since the issue's cites have drifted.

Headline

Two of #395's four site-groups are already externalized by work that landed after the issue was filed, and the remaining two split cleanly into a spec-bundle half (subsumed by ward#453/#503) and a runtime-topology half (genuinely #395's own, ward-only). The ~/.ward/fleet.local.kdl reader (ward#413) is closed but narrow - it accepts only a director block - so it is a host for these values only if Kai wants operator-local file override, which forces a cli-guard fleetconfig widening first. Env override is the top of the precedence chain and needs neither cli-guard nor the infrastructure repo, so most of #395 is dispatchable now without either.

Cluster map (verified state)

  • ward#395 - open - THIS. Bucket C, infra topology.
  • ward#396 - open - Bucket D, fleet org/repo inventory (runner.go primary-orgs, git_clone.go clone allowlist, agent_route.go intake). Sibling, security-adjacent, not a blocker for #395.
  • ward#413 - closed - operator-local reader landed (cmd/ward/fleetlocal.go), but fleetconfig.ParseSource(.., OperatorLocal) rejects the fleet block and accepts only director (cli-guard/pkg/fleetconfig/fleetconfig.go:142-144). So model/endpoint/topology cannot be set there yet.
  • ward#453 - open - move the KDL specs (ops guardfile + fleet manifest) up into aos as a swappable build input. The mechanism landed (examples/ward-specs/, assets-dir convention, refactor: source ward specs from sibling bundle at b7fae91).
  • ward#503 - open - the deferred flip of #453: "ward's tree contains no coilyco-specific endpoint/token/owner values." Its done-condition directly overlaps #395's spec-bundle half (it names base-url forgejo.coilysiren.me/api/v1, the SSM token path, owner/attribution defaults).
  • ward#499 - open - ward doctor host-side Ollama-reachability probe for goose/opencode. This is the live successor to the closed docs-only ward#487 (the task's "in-container ollama probe" - note #487 itself is closed and was doc-symmetry, #499 is the real probe work). Adjacent, not a blocker.
  • ward#487 - closed - docs-symmetry precursor to #499.
  • ward#532 - closed - already replaced the ser8:4318 telemetry literal. agent_telemetry.go now defaults to http://localhost:4318/v1/logs with WARD_AGENT_TELEMETRY_ENDPOINT override. #395's telemetry-sink site is done.
  • Goose model+backend consolidation - no dedicated issue. agentic-os#308 files per-agent model+provider in Bucket A (agents.yaml, agentic-os#306), not Bucket C - so this belongs with #306, even though it shares the fleet.generated.kdl file. Currently internal/agents/goose/config.go:22-23 hardcodes envOr("WARD_GOOSE_PROVIDER","ollama") / envOr("WARD_GOOSE_MODEL","qwen3-coder:30b"), and the agent goose block in the manifest carries no model/endpoint/provider (unlike opencode/codex, which are read via container_bootstrap.go:131-135).

#395 site-by-site, current state

  • Telemetry sink ser8:4318 - LANDED (ward#532). Literal gone. No work.
  • Ollama default http://localhost:11434/v1 - LANDED into the manifest (ward#416). Now opencode.Endpoint from fleet.generated.kdl, read via envOr("WARD_OLLAMA_URL", opencode.Endpoint) at container_bootstrap.go:132. This is the pattern the rest should copy.
  • Registry image forgejo.coilysiren.me/coilyco-flight-deck/agentic-os (container_compute.go:17) - PARTIAL. --image/--tag already source from WARD_AGENT_IMAGE/WARD_AGENT_TAG (agent.go:424-425). Env seam exists, embedded default remains. This value is spec-bundle-shaped -> belongs with #453/#503.
  • Forgejo base https://forgejo.coilysiren.me (forgejo_ops.go:19) - CONTESTED. Its own comment says "Safe to hardcode." The ops guardfile already carries base-url forgejo.coilysiren.me/api/v1 as deployment config (per #453), so this is double-sourced. Per #396's "ward legitimately knows itself," ward's own release/broker forge is arguably identity that stays. Fork for Kai (below).
  • SSM paths /forgejo/api-token (container.go:45), /coilysiren/ollama/host (container.go:49) - OPEN, no seam. Bare consts. Both have live sources confirmed: resolveForgejoToken and resolveOllamaHost read them today, and the guardfile carries the token path (#453). These are spec-bundle/deployment-shaped.
  • Tailnet + host topology - wardTailnetNetwork/ward-tailnet, proxyBoxName/mac-proxy, towerMagicDNSName/kai-tower-3026, towerOllamaPort/11434, towerOllamaURL (container_compute.go:98,102,114,117,121), forwardListenAddr/towerOllamaLocalURL (forward.go:19,26) - OPEN, no seam. Bare consts, no env override, not in the KDL bundle. These are runtime topology and are genuinely #395's own to externalize. Note: the code deliberately keeps these as MagicDNS names, not SSM ("a MagicDNS name, not a secret IP, rides plain" container_compute.go:551), which is consistent with the meaningful-name-hardcodes / opaque-value-to-SSM rule.

The architectural fork: where do the values live?

The precedence chain (docs/fleet-local.md) is env > operator-local > embedded manifest. That gives three candidate homes, and the ward#413 question turns entirely on which one Kai picks:

  • Env only - make the existing/new WARD_* var the primary path, keep the embedded const as the last-resort layer. No cli-guard change, no infra change. Downside: the default still ships in the binary (relocated, not externalized) - exactly the critique #453/#503 make.
  • Embedded fleet manifest - for agent/spec-shaped values (ollama endpoint already here, registry image, models, forge base). These ride #453/#503's move to the aos bundle automatically and become honestly swappable. This is the convergent long-run home for that half.
  • Operator-local file (~/.ward/fleet.local.kdl) - the only home that lets a different operator/host repoint ward without a rebuild. This is gated: fleetconfig's OperatorLocal subset must be widened to accept an infra/endpoint/topology block first. It rejects everything but director today (fleetconfig.go:142-144). ward#413's own boundary note anticipates exactly this: "If fleetconfig's OperatorLocal accepted-node-set needs fleshing... file a cli-guard follow-up - do not fork the parser." So yes, ward#413 has to accept an infra block first, but only for the operator-local design branch - env and embedded-manifest branches do not need it.

Dependency-ordered landing sequence

Step 0 - already done (no work). ward#532 (telemetry) and ward#416 (ollama endpoint into manifest). #395's site list is stale on both. The agent should open by re-scoping #395 to the four remaining site-groups.

Step 1 - Kai decides the home per half (blocking fork, human). Adjudicate: (a) spec-bundle-shaped values (registry image, forge base, SSM token path) -> converge with #453/#503; (b) runtime topology (tailnet/tower) -> env now, or operator-local later; (c) forge base -> keep-as-identity vs externalize. No code moves until this is set.

Step 2 - ward-only, dispatchable NOW: env-primary for the runtime-topology half. Add WARD_* overrides for the tailnet/tower consts (container_compute.go block, forward.go), make env the primary path, keep the embedded const as the fail-safe last layer (never fully removed - it is the only source, so a hard removal breaks the tower path). Source: env. Green check: a new test asserting a WARD_TOWER_OLLAMA/WARD_TAILNET_* override wins over the const, plus existing container_compute tests stay green.

Step 3 - ward-only, dispatchable NOW: goose consolidation (Bucket A / agentic-os#306). Add model/provider/endpoint to the agent goose block in the hand-edited fleet source, make sync-fleet-assets, and project WARD_GOOSE_MODEL/WARD_GOOSE_PROVIDER from the fleet in container_bootstrap.go the way opencode/codex already are (:131-135), so goose/config.go reads the manifest default instead of the baked ollama/qwen3-coder:30b. Source: embedded manifest, env override. Green check: fleetassets_test.go drift check passes and a bootstrap test shows goose model defaulting from the manifest.

Step 4 - cross-repo GATE, only if operator-local design chosen (cli-guard first). Widen fleetconfig OperatorLocal to accept an infra/endpoint block (mount/exec/permission tokens still rejected - the block names topology, not a grant). Then ward wires the operator-local layer into resolution for these sites (env > operator-local > embedded). Green check: fleetconfig_test.go accepts the new block under OperatorLocal and still rejects fleet; a fleetlocal test shows an operator-local endpoint overriding the embedded default.

Step 5 - coordinate with ward#503 for the spec-bundle half. Registry image, forge base, and the SSM token path externalize as part of #503's bundle flip, not as an independent #395 edit (else two runs fight over the same fleetassets/guardfile). If #503 lands first, #395 authors these in the aos bundle; if #395 moves first, they author in ward's manifest and migrate with #453. Green check: TestExampleBundleHasNoCoilycoValues (already in cmd/ward) extends to cover these values.

Dispatchable-now vs gated

  • Safe to dispatch now as autonomous codex/engineer runs (ward-only, no fork): Step 2 (env-primary for tailnet/tower topology) and Step 3 (goose consolidation). Both are additive, reversible, test-backed, and touch no permission or release surface.
  • Gated on a Kai decision: Step 1 (the home fork), and specifically the forge-base keep-vs-externalize call.
  • Gated on cli-guard: Step 4 (only if the operator-local file home is chosen). Not on the critical path otherwise.
  • Gated on ward#503 coordination (not the infrastructure repo): Step 5, the spec-bundle half.

Two forks Kai must call

  1. Home for the runtime topology - env vs operator-local file. Env is dispatchable today and needs nothing else. Operator-local is the honest "another host can repoint ward" answer but pays a cli-guard fleetconfig widening first. Recommendation: land the env seam now (Step 2), file the operator-local widening as a follow-up only if a second host actually needs it.
  2. Forgejo base + SSM token path - externalize vs ward's own identity. #396's principle ("ward legitimately knows itself") and the fact that #453/#503 already claim these as deployment config both argue these are not #395's to move - they belong to the #453/#503 bundle flip. Recommendation: hand the forge base and SSM token path to #503, keep the forgejo_ops.go const as ward's issue-URL rendering identity, and scope #395 down to the runtime topology + goose consolidation.

Correction to the issue's framing

The review note says "cross-repo (ward + infrastructure)" and "likely paired with an infrastructure-repo change to publish the values." Grounded against the code, the infrastructure repo is not on the critical path: every host/path in #395 already has a live source (SSM params exist, tower resolves via MagicDNS, the ollama endpoint is in the manifest), so ward only needs to read from those sources instead of baking literals. The genuine cross-repo dependency is cli-guard (Step 4, conditional) and intra-repo coordination with ward#453/#503, not infrastructure.


Plan to verify against a live checkout before carrying. Filed one-shot from the read-only director surface (she/her).


Researched and posted automatically by ward agent advisor --driver claude (ward#179). This is one-shot research, not a carried change - verify before acting on it.

— Claude (she/her), via ward agent

### 🔎 ward agent advisor `ward agent advisor --driver claude` ran a one-shot **standard** research pass on this question: > Map the ward#395 cluster and post a concrete LANDING PLAN as a comment on ward#395. Read-only, no code changes. Goal: sequence the cluster so it can actually land. > > ward#395 externalizes ward's hardcoded infra topology (hosts/ports/tailnet, telemetry sink ser8:4318, forgejo base + registry host, SSM paths /forgejo/api-token and /coilysiren/ollama/host) - cross-repo with the infrastructure repo. It is Bucket C of the agentic-os#308 dependency-direction audit. > > DISCOVER the full cluster: read agentic-os#308 and follow its buckets/children, and assess these known siblings - ward#396 (fleet inventory externalization), ward#413 (the ~/.ward/fleet.local.kdl operator-local reader, which today REJECTS the embed-only fleet block so model/endpoint cannot be overridden there yet), ward#487 (in-container ollama reachability probe), and the goose model+backend consolidation (goose model/provider are hardcoded in internal/agents/goose/config.go, endpoint from the /coilysiren/ollama/host SSM path in cmd/ward/container.go - neither host-overridable). Find any other open issues that must move together for #395 to land. > > For EACH cluster member report: current state (landed / partial / open, cite commits or code), exact scope, and whether it is ward-only or needs an infrastructure-repo change. Ground every claim in the actual code (cite file:line in /substrate/ward and read the fleetconfig schema in /substrate/cli-guard/pkg/fleetconfig). > > DELIVER: > 1. A dependency-ordered landing SEQUENCE - what must land before #395's literals can drop (in particular: does the fleet.local.kdl reader ward#413 have to accept an infra/endpoint override block FIRST to be the host for these values? confirm against docs/fleet-local.md and the fleetconfig parser). > 2. Per step: ward-only vs cross-repo, the exact literals/sites to externalize (from the #395 site list), the source they resolve from (env / SSM / infra-published config), and the green check. > 3. Which steps are SAFELY DISPATCHABLE NOW as autonomous codex engineer runs vs which are gated on a human decision or on the infrastructure repo (not granted here). Flag any genuine fork Kai must decide (e.g. keep-literal-fallback vs fail-closed, or where the override config physically lives). > > Public-safe, repo voice rules (no em-dashes, no semicolons in prose, name the actor). This is one-shot research - end by noting it is a plan to verify, not a carried change. --- ## ward#395 landing plan - map the cluster, sequence the drop **One-shot research from the read-only director surface (she/her). This is a plan to verify against a live checkout, not a carried change.** Line numbers below are re-grounded against `main` at `63184f8`, since the issue's cites have drifted. ### Headline Two of #395's four site-groups are **already externalized** by work that landed after the issue was filed, and the remaining two split cleanly into a **spec-bundle half** (subsumed by ward#453/#503) and a **runtime-topology half** (genuinely #395's own, ward-only). The `~/.ward/fleet.local.kdl` reader (ward#413) is **closed but narrow** - it accepts only a `director` block - so it is a host for these values **only if** Kai wants operator-local file override, which forces a cli-guard `fleetconfig` widening first. Env override is the top of the precedence chain and needs neither cli-guard nor the infrastructure repo, so most of #395 is dispatchable now without either. ### Cluster map (verified state) * **ward#395** - open - THIS. Bucket C, infra topology. * **ward#396** - open - Bucket D, fleet org/repo inventory (`runner.go` primary-orgs, `git_clone.go` clone allowlist, `agent_route.go` intake). Sibling, security-adjacent, not a blocker for #395. * **ward#413** - **closed** - operator-local reader landed (`cmd/ward/fleetlocal.go`), but `fleetconfig.ParseSource(.., OperatorLocal)` rejects the `fleet` block and accepts only `director` (`cli-guard/pkg/fleetconfig/fleetconfig.go:142-144`). So model/endpoint/topology **cannot** be set there yet. * **ward#453** - open - move the KDL specs (ops guardfile + fleet manifest) up into aos as a swappable build input. The **mechanism** landed (`examples/ward-specs/`, assets-dir convention, `refactor: source ward specs from sibling bundle` at `b7fae91`). * **ward#503** - open - the **deferred flip** of #453: "ward's tree contains no coilyco-specific endpoint/token/owner values." Its done-condition directly overlaps #395's spec-bundle half (it names `base-url forgejo.coilysiren.me/api/v1`, the SSM token path, owner/attribution defaults). * **ward#499** - open - `ward doctor` host-side Ollama-reachability probe for goose/opencode. This is the **live successor** to the closed docs-only ward#487 (the task's "in-container ollama probe" - note #487 itself is closed and was doc-symmetry, #499 is the real probe work). Adjacent, not a blocker. * **ward#487** - **closed** - docs-symmetry precursor to #499. * **ward#532** - **closed** - already replaced the `ser8:4318` telemetry literal. `agent_telemetry.go` now defaults to `http://localhost:4318/v1/logs` with `WARD_AGENT_TELEMETRY_ENDPOINT` override. **#395's telemetry-sink site is done.** * **Goose model+backend consolidation** - no dedicated issue. agentic-os#308 files per-agent model+provider in **Bucket A (agents.yaml, agentic-os#306)**, not Bucket C - so this belongs with #306, even though it shares the `fleet.generated.kdl` file. Currently `internal/agents/goose/config.go:22-23` hardcodes `envOr("WARD_GOOSE_PROVIDER","ollama")` / `envOr("WARD_GOOSE_MODEL","qwen3-coder:30b")`, and the `agent goose` block in the manifest carries no `model`/`endpoint`/`provider` (unlike `opencode`/`codex`, which are read via `container_bootstrap.go:131-135`). ### #395 site-by-site, current state * **Telemetry sink** `ser8:4318` - **LANDED** (ward#532). Literal gone. No work. * **Ollama default** `http://localhost:11434/v1` - **LANDED into the manifest** (ward#416). Now `opencode.Endpoint` from `fleet.generated.kdl`, read via `envOr("WARD_OLLAMA_URL", opencode.Endpoint)` at `container_bootstrap.go:132`. This is the pattern the rest should copy. * **Registry image** `forgejo.coilysiren.me/coilyco-flight-deck/agentic-os` (`container_compute.go:17`) - **PARTIAL**. `--image`/`--tag` already source from `WARD_AGENT_IMAGE`/`WARD_AGENT_TAG` (`agent.go:424-425`). Env seam exists, embedded default remains. This value is spec-bundle-shaped -> belongs with #453/#503. * **Forgejo base** `https://forgejo.coilysiren.me` (`forgejo_ops.go:19`) - **CONTESTED**. Its own comment says "Safe to hardcode." The ops guardfile already carries `base-url forgejo.coilysiren.me/api/v1` as deployment config (per #453), so this is double-sourced. Per #396's "ward legitimately knows itself," ward's own release/broker forge is arguably identity that **stays**. **Fork for Kai** (below). * **SSM paths** `/forgejo/api-token` (`container.go:45`), `/coilysiren/ollama/host` (`container.go:49`) - **OPEN, no seam**. Bare consts. Both have **live sources** confirmed: `resolveForgejoToken` and `resolveOllamaHost` read them today, and the guardfile carries the token path (#453). These are spec-bundle/deployment-shaped. * **Tailnet + host topology** - `wardTailnetNetwork`/`ward-tailnet`, `proxyBoxName`/`mac-proxy`, `towerMagicDNSName`/`kai-tower-3026`, `towerOllamaPort`/`11434`, `towerOllamaURL` (`container_compute.go:98,102,114,117,121`), `forwardListenAddr`/`towerOllamaLocalURL` (`forward.go:19,26`) - **OPEN, no seam**. Bare consts, no env override, **not** in the KDL bundle. These are runtime topology and are genuinely #395's own to externalize. Note: the code deliberately keeps these as MagicDNS names, not SSM ("a MagicDNS name, not a secret IP, rides plain" `container_compute.go:551`), which is consistent with the meaningful-name-hardcodes / opaque-value-to-SSM rule. ### The architectural fork: where do the values live? The precedence chain (`docs/fleet-local.md`) is **env > operator-local > embedded manifest**. That gives three candidate homes, and the ward#413 question turns entirely on which one Kai picks: * **Env only** - make the existing/new `WARD_*` var the primary path, keep the embedded const as the last-resort layer. **No cli-guard change, no infra change.** Downside: the default still ships in the binary (relocated, not externalized) - exactly the critique #453/#503 make. * **Embedded fleet manifest** - for agent/spec-shaped values (ollama endpoint already here, registry image, models, forge base). These ride #453/#503's move to the aos bundle automatically and become honestly swappable. This is the convergent long-run home for that half. * **Operator-local file** (`~/.ward/fleet.local.kdl`) - the only home that lets a **different operator/host** repoint ward without a rebuild. **This is gated:** `fleetconfig`'s `OperatorLocal` subset must be widened to accept an infra/endpoint/topology block first. It rejects everything but `director` today (`fleetconfig.go:142-144`). ward#413's own boundary note anticipates exactly this: "If `fleetconfig`'s `OperatorLocal` accepted-node-set needs fleshing... file a cli-guard follow-up - do not fork the parser." So **yes, ward#413 has to accept an infra block first, but only for the operator-local design branch** - env and embedded-manifest branches do not need it. ### Dependency-ordered landing sequence **Step 0 - already done (no work).** ward#532 (telemetry) and ward#416 (ollama endpoint into manifest). #395's site list is stale on both. The agent should open by re-scoping #395 to the four remaining site-groups. **Step 1 - Kai decides the home per half (blocking fork, human).** Adjudicate: (a) spec-bundle-shaped values (registry image, forge base, SSM token path) -> converge with #453/#503; (b) runtime topology (tailnet/tower) -> env now, or operator-local later; (c) forge base -> keep-as-identity vs externalize. No code moves until this is set. **Step 2 - ward-only, dispatchable NOW: env-primary for the runtime-topology half.** Add `WARD_*` overrides for the tailnet/tower consts (`container_compute.go` block, `forward.go`), make env the primary path, keep the embedded const as the fail-safe last layer (never fully removed - it is the only source, so a hard removal breaks the tower path). Source: env. Green check: a new test asserting a `WARD_TOWER_OLLAMA`/`WARD_TAILNET_*` override wins over the const, plus existing `container_compute` tests stay green. **Step 3 - ward-only, dispatchable NOW: goose consolidation (Bucket A / agentic-os#306).** Add `model`/`provider`/`endpoint` to the `agent goose` block in the hand-edited fleet source, `make sync-fleet-assets`, and project `WARD_GOOSE_MODEL`/`WARD_GOOSE_PROVIDER` from the fleet in `container_bootstrap.go` the way `opencode`/`codex` already are (`:131-135`), so `goose/config.go` reads the manifest default instead of the baked `ollama`/`qwen3-coder:30b`. Source: embedded manifest, env override. Green check: `fleetassets_test.go` drift check passes and a bootstrap test shows goose model defaulting from the manifest. **Step 4 - cross-repo GATE, only if operator-local design chosen (cli-guard first).** Widen `fleetconfig` `OperatorLocal` to accept an infra/endpoint block (mount/exec/permission tokens still rejected - the block names topology, not a grant). Then ward wires the operator-local layer into resolution for these sites (env > operator-local > embedded). Green check: `fleetconfig_test.go` accepts the new block under `OperatorLocal` and still rejects `fleet`; a `fleetlocal` test shows an operator-local endpoint overriding the embedded default. **Step 5 - coordinate with ward#503 for the spec-bundle half.** Registry image, forge base, and the SSM token path externalize as part of #503's bundle flip, not as an independent #395 edit (else two runs fight over the same `fleetassets`/guardfile). If #503 lands first, #395 authors these in the aos bundle; if #395 moves first, they author in ward's manifest and migrate with #453. Green check: `TestExampleBundleHasNoCoilycoValues` (already in `cmd/ward`) extends to cover these values. ### Dispatchable-now vs gated * **Safe to dispatch now as autonomous codex/engineer runs (ward-only, no fork):** Step 2 (env-primary for tailnet/tower topology) and Step 3 (goose consolidation). Both are additive, reversible, test-backed, and touch no permission or release surface. * **Gated on a Kai decision:** Step 1 (the home fork), and specifically the forge-base **keep-vs-externalize** call. * **Gated on cli-guard:** Step 4 (only if the operator-local file home is chosen). Not on the critical path otherwise. * **Gated on ward#503 coordination (not the infrastructure repo):** Step 5, the spec-bundle half. ### Two forks Kai must call 1. **Home for the runtime topology - env vs operator-local file.** Env is dispatchable today and needs nothing else. Operator-local is the honest "another host can repoint ward" answer but pays a cli-guard `fleetconfig` widening first. Recommendation: land the env seam now (Step 2), file the operator-local widening as a follow-up only if a second host actually needs it. 2. **Forgejo base + SSM token path - externalize vs ward's own identity.** #396's principle ("ward legitimately knows itself") and the fact that #453/#503 already claim these as deployment config both argue these are **not** #395's to move - they belong to the #453/#503 bundle flip. Recommendation: hand the forge base and SSM token path to #503, keep the `forgejo_ops.go` const as ward's issue-URL rendering identity, and scope #395 down to the runtime topology + goose consolidation. ### Correction to the issue's framing The review note says "cross-repo (ward + infrastructure)" and "likely paired with an infrastructure-repo change to publish the values." Grounded against the code, the infrastructure repo is **not on the critical path**: every host/path in #395 already has a live source (SSM params exist, tower resolves via MagicDNS, the ollama endpoint is in the manifest), so ward only needs to **read** from those sources instead of baking literals. The genuine cross-repo dependency is **cli-guard** (Step 4, conditional) and **intra-repo coordination with ward#453/#503**, not infrastructure. --- *Plan to verify against a live checkout before carrying. Filed one-shot from the read-only director surface (she/her).* --- Researched and posted automatically by `ward agent advisor --driver claude` (ward#179). This is one-shot research, not a carried change - verify before acting on it. <!-- ward-agent-reply --> <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-395 on host kais-macbook-pro-2.local is carrying this issue (reserved 2026-07-02T16:02:04Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-395` on host `kais-macbook-pro-2.local` is carrying this issue (reserved 2026-07-02T16:02:04Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - tailnet + tower topology (network, proxy box, tower host/port) now resolve through WARD_* env seams with the old literals as fail-safe defaults, landed on main.

Honestly this one was less about the code and more about reading the room. The advisor landing-plan comment did the heavy lifting - it had already scoped #395 down from four site-groups to just the runtime-topology half, so I mostly followed that map instead of re-litigating what to externalize. Forge base, registry image, and SSM paths I left alone (they belong to ward#453/#503), and goose model to agentic-os#306, which matched the bucket split.

What actually fought back was the catalog pre-commit suite, not the Go. The docs are hand-tuned to a 4000-char cap and agent-ts-sidecar.md was already sitting at 3993/4000, so my override section had nowhere to land inline. I split it into a new docs/agent-tailnet-topology.md and added it to the ref-linter contributor-doc set. The 2-line comment cap also made me retrim comments a few times. The code change itself (a const block becoming env-resolved funcs, plus one propagation seam so the in-container forwarder follows a host override) was mechanical and well covered by the existing ts-sidecar/forward tests plus a new override test.

Fairly confident in the result: it is purely additive, every value keeps its literal fallback, and build/vet/test/pre-commit are all green. The one rough edge worth a follow-up: the bash entrypoint still carries a couple of literal localhost:11434 spots on the goose/local path, so the port override is Go-coherent but a port change would not reach those bash lines. Unlikely to bite (11434 is ollama's fixed port), but worth noting if anyone ever genuinely repoints it.

WARD-OUTCOME: done - tailnet + tower topology (network, proxy box, tower host/port) now resolve through WARD_* env seams with the old literals as fail-safe defaults, landed on main. Honestly this one was less about the code and more about reading the room. The advisor landing-plan comment did the heavy lifting - it had already scoped #395 down from four site-groups to just the runtime-topology half, so I mostly followed that map instead of re-litigating what to externalize. Forge base, registry image, and SSM paths I left alone (they belong to ward#453/#503), and goose model to agentic-os#306, which matched the bucket split. What actually fought back was the catalog pre-commit suite, not the Go. The docs are hand-tuned to a 4000-char cap and agent-ts-sidecar.md was already sitting at 3993/4000, so my override section had nowhere to land inline. I split it into a new docs/agent-tailnet-topology.md and added it to the ref-linter contributor-doc set. The 2-line comment cap also made me retrim comments a few times. The code change itself (a const block becoming env-resolved funcs, plus one propagation seam so the in-container forwarder follows a host override) was mechanical and well covered by the existing ts-sidecar/forward tests plus a new override test. Fairly confident in the result: it is purely additive, every value keeps its literal fallback, and build/vet/test/pre-commit are all green. The one rough edge worth a follow-up: the bash entrypoint still carries a couple of literal localhost:11434 spots on the goose/local path, so the port override is Go-coherent but a port change would not reach those bash lines. Unlikely to bite (11434 is ollama's fixed port), but worth noting if anyone ever genuinely repoints it.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#395
No description provided.