Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions api/v1alpha1/claw_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
)

// CredentialType selects the credential injection mechanism used by the proxy.
// +kubebuilder:validation:Enum=apiKey;bearer;gcp;pathToken;oauth2;none;kubernetes
// +kubebuilder:validation:Enum=apiKey;bearer;gcp;pathToken;oauth2;none;kubernetes;codexOAuth
type CredentialType string

const (
Expand All @@ -34,6 +34,7 @@ const (
CredentialTypeOAuth2 CredentialType = "oauth2"
CredentialTypeNone CredentialType = "none"
CredentialTypeKubernetes CredentialType = "kubernetes"
CredentialTypeCodexOAuth CredentialType = "codexOAuth"
)

// ConfigMode controls how operator.json is merged into the user's openclaw.json
Expand Down Expand Up @@ -153,7 +154,7 @@ type OAuth2Config struct {
}

// CredentialSpec defines a single credential entry for proxy injection.
// +kubebuilder:validation:XValidation:rule="has(self.type) || has(self.channel) || (has(self.provider) && self.provider in ['google', 'anthropic', 'openai', 'xai', 'openrouter'])",message="type is required (inferred only for known providers: google, anthropic, openai, xai, openrouter)"
// +kubebuilder:validation:XValidation:rule="has(self.type) || has(self.channel) || (has(self.provider) && self.provider in ['google', 'anthropic', 'openai', 'xai', 'openrouter', 'openai-oauth'])",message="type is required (inferred only for known providers: google, anthropic, openai, xai, openrouter, openai-oauth)"
// +kubebuilder:validation:XValidation:rule="!has(self.provider) || !has(self.channel)",message="provider and channel are mutually exclusive"
// +kubebuilder:validation:XValidation:rule="has(self.channel) || (has(self.type) && self.type == 'none') || has(self.secretRef)",message="secretRef is required unless type is none or channel is set"
// +kubebuilder:validation:XValidation:rule="!has(self.type) || self.type != 'apiKey' || has(self.apiKey) || (has(self.provider) && self.provider in ['google', 'anthropic']) || has(self.channel)",message="apiKey config is required when type is apiKey without inferred defaults"
Expand Down
5 changes: 3 additions & 2 deletions config/crd/bases/claw.sandbox.redhat.com_claws.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -285,16 +285,17 @@ spec:
- oauth2
- none
- kubernetes
- codexOAuth
type: string
required:
- name
type: object
x-kubernetes-validations:
- message: 'type is required (inferred only for known providers:
google, anthropic, openai, xai, openrouter)'
google, anthropic, openai, xai, openrouter, openai-oauth)'
rule: has(self.type) || has(self.channel) || (has(self.provider)
&& self.provider in ['google', 'anthropic', 'openai', 'xai',
'openrouter'])
'openrouter', 'openai-oauth'])
- message: provider and channel are mutually exclusive
rule: '!has(self.provider) || !has(self.channel)'
- message: secretRef is required unless type is none or channel
Expand Down
70 changes: 70 additions & 0 deletions docs/proposals/codex-harness-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Codex App-Server Harness — Design Proposal

**Status:** Early draft — problem statement and high-level direction only

**Date:** 2026-06-03

**Depends on:** [codex-oauth-design.md](codex-oauth-design.md) (Codex OAuth credential type, prerequisite)

---

## Problem Statement

The `codexOAuth` credential type (implemented in the companion design) gives users access to Codex models (GPT-5.5, GPT-5.4-mini, etc.) through OpenClaw's own agent runtime. OpenClaw sends prompts via the `openai-chatgpt-responses` wire format, receives tool call requests, and executes them using its own tool infrastructure (MCP servers, terminal, file editing, etc.).

However, OpenClaw also supports a **native Codex agent harness** — the `codex` plugin spawns a Codex app-server binary as a child process that provides its own agent runtime with sandbox execution, native tool handling, approval flows, and subagent orchestration. Some users may want this full Codex agent experience running inside OpenClaw rather than using OpenClaw's own tool execution layer.

The current `codexOAuth` design intentionally excludes the native harness because:

1. **Security boundary.** The Codex app-server runs inside the gateway pod and needs real OAuth tokens for authentication. Our security model keeps real credentials on the proxy, never the gateway.

2. **Binary dependency.** The Codex app-server is a separate binary that must be installed in the container. The operator's gateway image does not include it today.

3. **Scope.** The operator's purpose is to deploy and secure OpenClaw instances. The `codexOAuth` credential gives users Codex model access, which is the primary ask. The native harness is an enhancement.

---

## High-Level Approach

Support the Codex app-server harness through a new CRD section (e.g., `spec.codexHarness`), following the pattern used for Kubernetes support today. Key concerns to address in the detailed design:

### Binary installation

Install the Codex app-server binary via an init container or OpenClaw's managed binary system. Options include a dedicated sidecar image, a shared volume init container, or letting OpenClaw's plugin system download it at startup.

### Authentication

The app-server authenticates with `chatgpt.com` using OAuth tokens from `auth-profiles.json`. This requires real tokens available to the gateway process — a relaxation of the proxy-only security boundary. The detailed design must define what exactly is exposed (access token only vs. refresh token), whether the proxy can mediate refresh, and what the blast radius is if the gateway is compromised.

### Plugin and model configuration

Enable the `codex` plugin in `openclaw.json`, set `agentRuntime: { id: "codex" }` on configured models, and write `auth-profiles.json` with the appropriate credential. This is mostly configuration wiring — the companion design's `openai-chatgpt-responses` provider config would be replaced or supplemented by the native harness config.

### Coexistence with `codexOAuth`

Define whether users can use both simultaneously (e.g., some models through the proxy path, others through the native harness) or whether the harness mode replaces the proxy path entirely when enabled.

### Container security

The Codex app-server may need a writable filesystem, network access, and potentially elevated capabilities for sandbox execution. Document the impact on pod security context and whether this is compatible with `readOnlyRootFilesystem` and the restricted seccomp profile.

---

## Open Questions

These will be resolved during the detailed design phase:

1. How do we install the Codex app-server binary? Init container, managed download, or bundled image?
2. What is the minimum credential exposure needed for the app-server? Can we limit it to short-lived access tokens with proxy-mediated refresh?
3. Should this be a separate CRD section (`spec.codexHarness`) or an option on the existing `codexOAuth` credential?
4. What pod security changes are required? Is the Codex app-server compatible with our restricted security context?
5. How does this interact with network policies? Does the app-server need direct egress to `chatgpt.com` or can it go through the proxy?
6. What is the upgrade path for users currently using `codexOAuth` who want to switch to the native harness?

---

## References

- [Codex OAuth design](codex-oauth-design.md) — prerequisite credential type
- OpenClaw `extensions/codex/` — plugin source, agent harness, app-server client
- OpenClaw `extensions/codex/src/app-server/` — app-server lifecycle, auth bridge, binary management
Loading
Loading