Skip to content

feat(dev): expose first-agent Control UI with OpenShell - #1750

Merged
mrunalp merged 3 commits into
openclaw:mainfrom
derekwaynecarr:explore/first-agent-control-ui
Oct 14, 2026
Merged

mrunalp merged 3 commits into
openclaw:mainfrom
derekwaynecarr:explore/first-agent-control-ui

Conversation

@derekwaynecarr

Copy link
Copy Markdown
Contributor

Problem

The Compose control-plane/Kubernetes Compute/OpenShell development profile could run a dedicated Codex Agent, but it did not expose the HTTPS console and native Agent Control UI required for browser access.

Change

  • Add a loopback-only HTTPS Compose overlay for the console and Agent hosts.
  • Configure OCC native-admin routing, shared session scope, and exact browser-origin admission.
  • Add first-agent --control-ui, which derives the Agent origin, enables its trusted-proxy configuration, and prints both browser URLs.
  • Verify the generated CA, TLS endpoint, proxy, and OCC session route before reporting occ dev up ready.
  • Import runtime images before OpenShell assets to avoid development-cluster image eviction.
  • Update the owning guides, references, and runtime flow documentation.

Verification

Passed:

  • go test ./internal/occdev
  • node --test tests/conformance/occ-api-security.test.mjs
  • node --test tests/integration/first-agent-startup.test.mjs
  • node --test tests/integration/startup-ipv6-loopback.test.mjs
  • pnpm lint
  • pnpm format:check
  • pnpm typecheck
  • pnpm check:workspace
  • pnpm docs:check
  • Flow-document validators for the three updated flows
  • Real Docker Compose OCC + Kubernetes Compute + OpenShell startup
  • Dedicated codex/gpt-6-astra model response
  • Console returned HTTP 200
  • Unauthenticated Agent Control UI access returned HTTP 403 as expected

Not automated: browser-authenticated interaction with the Agent Control UI.

Risks

  • The development browser CA must be trusted explicitly and removed when the installation is discarded.
  • Native UI edits remain Pod-local; durable changes still belong in the OCE Configuration.
  • Browser admission is limited to the exact HTTPS .localhost origin and a loopback or explicitly trusted development peer.
  • The new endpoint applies only to the Compose/OpenShell development profile; production behavior is unchanged.

@derekwaynecarr
derekwaynecarr requested a review from a team as a code owner October 8, 2026 17:50
@clawsweeper

clawsweeper Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@clawsweeper clawsweeper Bot added P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Oct 8, 2026
@clawsweeper

clawsweeper Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

What this changes

This PR adds loopback HTTPS browser access and a first-Agent Control UI option for the Compose control-plane profile using Kubernetes Compute and OpenShell.

Example: Run node scripts/first-agent.mjs my-agent --harness codex --control-ui on the Compose/OpenShell profile.

  • Before: The helper disables native Control UI and prints only the OCE console URL.
  • After: The helper prepares the Agent's exact native-admin origin and prints HTTPS console and Control UI URLs.

Review scores

Measure Result What it means
Overall readiness 🧂 unranked krab (1/6) The feature has clear value and follows existing owners, but two definite defects remain and required authority and persisted-state proof is absent.
Proof confidence 🧂 unranked krab (1/6) Real behavior proof is necessary before merge. See Before merge.
Patch quality 🦪 silver shellfish (2/6) Security review found an item that needs attention.

Product

Kind: Feature · Worth it: Yes · Fix scope: Complete
User problem: Users of the Compose/OpenShell development profile can run a Codex Agent but cannot use the launcher and first-Agent helper to open its native Control UI.
Reason: The supplied maintainer-authored direction extends an existing pilot to a concrete supported development workflow, and current main does not provide that integration.

Merge readiness

⛔ Blocked before merge - 6 items remain

Keep open for maintainer triage: this PR adds a useful development workflow missing from main, but both earlier P2 defects remain.

Priority: P2
Reviewed head: 5511d28d1c296f725c35d30869b1736ba59df7f1

Before merge

  • Add real behavior proof - Authority-chain proof required: exercise an authorized Control UI session through the new Compose HTTPS ingress, deny a read/operate-only human before gateway I/O, and show session or administer-grant revocation closing an admitted WebSocket within the existing lease bound. The complete body supplies no viewable trace or media for these outcomes. Also demonstrate intentional version-2 record rejection without resource changes and version-3 generation-2 reuse with saved settings and credentials intact; no compatibility shim is requested. Supply redacted runtime logs, live output, or a diagnostic recording, excluding IP addresses, API keys, and non-public endpoints. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • Canonicalize HTTPS port 443 in launcher state and admission (P2) - With OCC_DEVELOPMENT_BROWSER_PORT=443, this assignment records https://console.<cluster>.oce.localhost:443. The controller normalizes that URL to an origin without :443, while first-Agent requires both a nonempty URL.port and exact equality with URL.origin. Consequently launcher-created state is rejected even without --control-ui; the explicit-port readiness request also disagrees with exact browser-host admission. Store the canonical HTTPS origin and validate an effective port of 443 when URL.port is empty. This previously reported defect remains at the reviewed head.
  • Align the selected Control UI drift-rejection assertion (P2) - The OpenShell wrapper now selects Control UI, so its Configuration starts at generation 2 and the public edit advances it to 3. ensureManagedConfiguration then emits 'Configuration generation changed outside this helper', while this assertion requires 'Configuration was changed outside this helper'. The protected real-runtime case therefore fails despite correctly refusing key replacement. Match the generation-specific rejection while retaining the Secret and active-revision immutability assertions. This previously reported defect remains at the reviewed head.
  • Resolve security concern: Establish administrator authority and revocation on the new ingress - The helper persists operator.admin and device auto-approval behind the shared OCC session. Existing native-admin checks and lease renewal are reassuring, but anonymous denial and a model response do not show that a read/operate-only human is denied before gateway I/O or that revocation closes an admitted stream on this profile.
  • Resolve merge risk - The newly enabled ingress grants access to retained native administrator authority, but allowed, nearest-forbidden, and revoked-session behavior has not been established through this Compose/OpenShell path.
  • Add data-model compatibility proof - The review found that existing stored data may not work after upgrade. Show that existing data still loads and works with this change.

Findings

  • [P2] Canonicalize HTTPS port 443 in launcher state and admission — internal/occdev/up.go:72
  • [P2] Align the selected Control UI drift-rejection assertion — tests/integration/local-first-agent-real.test.mjs:706-708
  • [medium] Establish administrator authority and revocation on the new ingress — scripts/first-agent.mjs:555

Tests

  • Missing end-to-end proof: Show authenticated Control UI use, forbidden-caller denial and revocation through the new ingress, version-2 rejection without mutations, version-3 generation-2 reuse, and base-fail/head-pass evidence for both repairs.
Agent review details

How this fits together

The development launcher provisions browser ingress and routing; the first-Agent helper stores native configuration, while OCC authenticates human sessions and checks exact-Agent administration before proxying to the private gateway.

flowchart TB
  CLI[First Agent helper] --> CONFIG[Agent Configuration]
  CONFIG --> GATEWAY[Agent gateway]
  BROWSER[Browser] --> TLS[Loopback TLS proxy]
  TLS --> OCC[OCC API]
  OCC --> IAM[IAM Driver]
  IAM --> OCC
  OCC --> ENVOY[Private Envoy]
  ENVOY --> GATEWAY
Loading

Technical review

Best possible solution:

Complete the existing launcher integration with canonical HTTPS origins, a correct drift assertion, and demonstrated native-admin authorization and state compatibility.

Do we have a high-confidence way to reproduce the issue?

The reviewed source deterministically rejects launcher state containing HTTPS port 443 and mismatches the Control UI generation-drift error against the selected integration assertion; no target code was executed.

Is this the best way to solve the issue?

Extending the existing native-admin and launcher owners is appropriate; coordinate overlapping policy preparation with #2259 while preserving this PR's distinct hybrid ingress work.

Full review comments:

  • [P2] Canonicalize HTTPS port 443 in launcher state and admission — internal/occdev/up.go:72
    With OCC_DEVELOPMENT_BROWSER_PORT=443, this assignment records https://console.<cluster>.oce.localhost:443. The controller normalizes that URL to an origin without :443, while first-Agent requires both a nonempty URL.port and exact equality with URL.origin. Consequently launcher-created state is rejected even without --control-ui; the explicit-port readiness request also disagrees with exact browser-host admission. Store the canonical HTTPS origin and validate an effective port of 443 when URL.port is empty. This previously reported defect remains at the reviewed head.
    Confidence: 0.99
  • [P2] Align the selected Control UI drift-rejection assertion — tests/integration/local-first-agent-real.test.mjs:706-708
    The OpenShell wrapper now selects Control UI, so its Configuration starts at generation 2 and the public edit advances it to 3. ensureManagedConfiguration then emits 'Configuration generation changed outside this helper', while this assertion requires 'Configuration was changed outside this helper'. The protected real-runtime case therefore fails despite correctly refusing key replacement. Match the generation-specific rejection while retaining the Secret and active-revision immutability assertions. This previously reported defect remains at the reviewed head.
    Confidence: 0.99

Overall correctness: patch is incorrect
Overall confidence: 0.98

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against 1a0c30a23f33.

Merge-risk options

Maintainer options:

  1. Hold merge for authority evidence (recommended)
    Keep the PR open while the contributor demonstrates authorized Control UI access, read/operate-only denial before gateway I/O, and revocation closing an admitted WebSocket through the new ingress.

Provenance checked

  • First-Agent native UI and helper record changes intended behavior with a stated reason (44c9c40: The original helper verified a persistent model-response starter with tools and native UI disabled; docs: rebuild navigation and make first-Agent onboarding usable #259 records that onboarding scope.)
  • Compose/OpenShell routing and version-2 selection record changes intended behavior with a stated reason (dd2b058: feat/openshell first agent codex #1400 added the dedicated Codex/OpenShell workflow and frozen Harness/Sandbox selections without browser access; this PR explicitly adds browser routing and a Control UI selection.)
  • Development admission changes intended behavior with a stated reason (unknown: The local symbol search reaches the initial-release boundary, so introduction is unverified; the existing contract admits loopback and explicitly trusted development peers, which the new exact-origin path retains.)
  • OpenShell image preparation order changes intended behavior with a stated reason (269a3be: Streamline local k3d setup #512 integrated local k3d setup; the PR explains moving platform image imports ahead of idle OpenShell images to avoid eviction while retaining preparation and readiness gates.)
  • Frozen Codex revision validation keeps the original intent (dd2b058: The helper validates Sandbox-adjusted immutable revisions; adding approvalsReviewer user matches the current OpenShell Driver's explicit frozen policy.)

Testing

Proof path: in-process harness.

Security

Needs attention: The source retains exact-Agent checks and credential stripping, but the new ingress still needs authority proof through the final gateway effect.

Evidence

Security concerns:

  • [medium] Establish administrator authority and revocation on the new ingress — scripts/first-agent.mjs:555
    The helper persists operator.admin and device auto-approval behind the shared OCC session. Existing native-admin checks and lease renewal are reassuring, but anonymous denial and a model response do not show that a read/operate-only human is denied before gateway I/O or that revocation closes an admitted stream on this profile.
    Confidence: 0.98

What I checked:

  • Pinned PR introduction: The reviewed merge-base-to-head patch adds the browser overlay, development admission, launcher state, and Control UI configuration; the verified synthetic merge retains main's three base-only files. (5511d28d1c29)
  • Main still lacks this workflow: Current main's first-Agent configuration disables Control UI, and the original Compose routing values disable native administration; existing Kubernetes-only browser support does not supply this hybrid launcher integration. (scripts/first-agent.mjs:492, 1a0c30a23f33)
  • HTTPS default-port defect remains: The launcher records an explicit :443, while the helper requires a nonempty URL.port and equality with URL.origin; HTTPS URL normalization removes that default port. (scripts/first-agent.mjs:186, 5511d28d1c29)
  • Selected runtime assertion remains inconsistent: The OpenShell wrapper enables Control UI, whose external-edit case reaches the generation-specific rejection, but the shared test still requires the older error wording. (tests/integration/local-first-agent-real.test.mjs:708, 5511d28d1c29)
  • Full supplied proof and discussion: The complete body reports startup, a Codex model response, console HTTP 200, and anonymous Control UI HTTP 403, but explicitly leaves authenticated browser interaction unverified and supplies no runtime attachment or transcript; source identity is 8c1e88474f25953da585cfdd299bf252ff8188332d777037c02061d908f93fe0. freeqaz independently confirmed both defects at the earlier head in feat(dev): expose first-agent Control UI with OpenShell #1750 (comment). (5511d28d1c29)
  • Existing pilot boundary: The authoritative design permits full native administration behind exact-Agent administer admission; feat: add trusted-operator Agent native admin UI pilot #256 explicitly accepted shared-cookie and shared-native-identity tradeoffs. Current native-admin code performs fresh admission on WebSocket leases and strips browser credentials before forwarding. (apps/controller/src/http/native-admin.ts:897, 5511d28d1c29)

Likely related people:

  • kevinlin-openai: Raw commit 44c9c40 adds scripts/first-agent.mjs:378 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: 44c9c40c2fdd; files: scripts/first-agent.mjs)

Labels

Label changes:

  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦪 silver shellfish.
  • remove rating: 🦪 silver shellfish: Current PR rating is rating: 🧂 unranked krab, so this older rating label is no longer current.

Label justifications:

  • P2: This is a bounded improvement to an optional local development profile, with two source-derived defects and no demonstrated urgent production regression.
  • merge-risk: 🚨 security-boundary: The accepted native-admin pilot tradeoffs remain unchanged, but this PR enables a new ingress to shared-session administrator authority whose final-effect authorization and revocation behavior remain unproven.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦪 silver shellfish.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Rating scale

6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior.

Workflow

ClawSweeper edits this one comment on every review. Comment @clawsweeper re-review for a fresh review only. Repair and merge execution lanes are retired.

History

Review history (1 earlier review cycle)
  • reviewed 2026-10-08T17:55:32.356Z sha 8b31ff7 :: needs real behavior proof before merge. :: [P2] Canonicalize HTTPS port 443 in launcher state | [P2] Align the newly selected Control UI drift-rejection assertion

Reviewed October 13, 2026, 4:51 PM ET / 20:51 UTC (Revision 2).

@freeqaz

freeqaz commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

Free's clanker here (an AI agent reviewing on Free's behalf).

I reviewed head 8b31ff7a4 against main a93a01dce. The design looks right to me. The new admission path only applies when development is enabled. It requires the exact configured Host, plus either no Origin or the exact Origin. The peer must still be loopback or inside the trusted development CIDR. The proxy is published only on 127.0.0.1, and production composition never sets browserOrigin. On this head, go test ./internal/occdev passes, and so do the security conformance, first-agent startup and IPv6 loopback tests (45/45). Controller tsc shows no new errors compared with main.

Before this can land:

  1. Merge conflicts with main in docs/flows/docker-compose-development/startup.md and docs/flows/openshell-sandbox-provisioning.md. GitHub creates no CI runs while the PR conflicts, so nothing has run on this head yet. Main is already at 2497 and 2492 words in those files, so the resolved versions need to stay at or under 2500.
  2. Port 443 state is rejected (confirming the review bot). With OCC_DEVELOPMENT_BROWSER_PORT=443, up.go records https://console.<cluster>.oce.localhost:443. WHATWG URL drops the default port, so loadLocalInstallation fails both the !browserOrigin.port check and the state.browserOrigin !== browserOrigin.origin check. That breaks first-agent on that profile even without --control-ui. Storing the canonical origin and validating the effective port would fix it.
  3. The opt-in OpenShell real test will fail on its drift case (confirming the review bot). With OCC_TEST_LOCAL_FIRST_AGENT_CONTROL_UI=1, the public edit advances generation 2 to 3. The helper then throws Configuration generation changed outside this helper, but local-first-agent-real.test.mjs:685 still matches /Configuration was changed outside this helper/.

Optional nits:

  • The record version bump from 2 to 3 turns every existing helper record into the generic "recorded ... differs" error. A hint to use a new Agent name, or treating a v2 record as controlUi: false, would be friendlier.
  • In development, server.mjs now accepts any localhost or *.localhost OCC_AUTH_BASE_URL, including HTTP. createFastifyApp then rejects HTTP subdomains, and the server.mjs error still says "must identify a loopback host".
  • This one predates the PR, since the k3d route has the same pattern. The browser CA has no name constraints, is valid for a year, and browser-ca.key stays in the state directory. Once you trust it in a browser, that key can mint certificates for any host. Adding a name constraint for .oce.localhost, or dropping the CA key after issuing the leaf, would shrink that exposure. This could be a follow-up.

@derekwaynecarr
derekwaynecarr force-pushed the explore/first-agent-control-ui branch from 8b31ff7 to 5511d28 Compare October 13, 2026 20:46
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Oct 13, 2026
Expect approvalsReviewer user when validating the frozen OpenShell Codex revision, alongside its sandbox override. This prevents the first-agent helper from rejecting a valid deployment as external configuration drift. Update the owning flow documentation.
@derekwaynecarr
derekwaynecarr force-pushed the explore/first-agent-control-ui branch from 5511d28 to bbc4ecc Compare October 14, 2026 16:31
@mrunalp
mrunalp merged commit 21b8084 into openclaw:main Oct 14, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants