Skip to content
Merged
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
79 changes: 78 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Every request is validated against the instance's allowlist policy. Protected co
| **Scalable** | Auto-scaling | HPA integration with CPU and memory metrics, min/max replica bounds, automatic StatefulSet replica management |
| **Resilient** | Self-healing lifecycle | PodDisruptionBudgets, health probes, automatic config rollouts via content hashing, 5-minute drift detection |
| **Backup/Restore** | S3-backed snapshots | Automatic backup to S3-compatible storage on deletion, pre-update, and on a cron schedule; restore into a new instance from any snapshot |
| **Workspace Seeding** | Initial files & dirs | Pre-populate the workspace with files and directories before the agent starts |
| **Workspace Seeding** | Initial files & dirs | Pre-populate the workspace with files and directories before the agent starts; reference an external ConfigMap for GitOps workflows |
| **Gateway Auth** | Auto-generated tokens | Automatic gateway token Secret per instance, bypassing mDNS pairing (unusable in k8s) |
| **Tailscale** | Tailnet access | Expose via Tailscale Serve or Funnel with SSO auth - no Ingress needed |
| **Extensible** | Sidecars & init containers | Chromium for browser automation, Ollama for local LLMs, Tailscale for tailnet access, plus custom init containers and sidecars |
Expand Down Expand Up @@ -477,6 +477,83 @@ spec:

npm lifecycle scripts are disabled globally on the init container (`NPM_CONFIG_IGNORE_SCRIPTS=true`) to mitigate supply chain attacks. Plugins are installed into the PVC-backed `~/.openclaw/node_modules` directory and persist across pod restarts.

### Workspace seeding

Pre-populate the agent workspace with files and directories before the agent starts. Files can be provided inline or referenced from an external ConfigMap -- ideal for GitOps workflows where workspace content is managed alongside your manifests.

**Inline files:**

```yaml
spec:
workspace:
initialDirectories:
- tools/scripts
initialFiles:
README.md: |
# My Workspace
This workspace is managed by OpenClaw.
```

**External ConfigMap reference:**

```yaml
spec:
workspace:
configMapRef:
name: agent-alpha-workspace # all keys become workspace files
initialFiles: # inline files (override configMapRef)
EXTRA.md: "additional content"
```

All keys in the referenced ConfigMap are written as files into the workspace directory. When both `configMapRef` and `initialFiles` are specified, inline files take precedence over ConfigMap entries with the same filename.

**Merge priority** (highest wins): operator-injected files > inline `initialFiles` > external `configMapRef` > skill packs.

The operator sets a `WorkspaceReady` status condition to `False` when the referenced ConfigMap is missing or contains invalid filenames, and `True` once workspace files are seeded successfully. The controller watches external ConfigMaps for changes and re-reconciles automatically.

**GitOps example with Kustomize:**

```yaml
# kustomization.yaml
configMapGenerator:
- name: agent-alpha-workspace
files:
- SOUL.md
- AGENT.md
```

> **Note:** When using Kustomize `configMapGenerator`, disable the default name suffix hashing (`generatorOptions: { disableNameSuffixHash: true }`) or use the generated name in `configMapRef.name`, since the operator looks up the ConfigMap by exact name.

**Additional workspaces (multi-agent):**

When running multiple agents with isolated workspaces, use `additionalWorkspaces` to seed files for each agent. Each entry seeds to `~/.openclaw/workspace-<name>/` -- set matching paths in `spec.config.raw.agents.list[].workspace`.

```yaml
spec:
workspace:
initialFiles:
SOUL.md: "I am the default agent"
additionalWorkspaces:
- name: work
configMapRef:
name: work-agent-files
initialFiles:
SOUL.md: "I am the work agent"
initialDirectories:
- tools
config:
raw:
agents:
list:
- id: home
default: true
workspace: "~/.openclaw/workspace"
- id: work
workspace: "~/.openclaw/workspace-work"
```

Each additional workspace supports the same `configMapRef`, `initialFiles`, and `initialDirectories` as the default workspace. Operator-injected `ENVIRONMENT.md` is included; `BOOTSTRAP.md` is not (only the default agent runs onboarding). Max 10 additional workspaces.

### Self-configure

Allow agents to modify their own configuration by creating `OpenClawSelfConfig` resources via the K8s API. The operator validates each request against the instance's `allowedActions` policy before applying changes:
Expand Down
58 changes: 58 additions & 0 deletions api/v1alpha1/openclawinstance_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,19 @@ type RawConfig struct {
// Files listed in InitialFiles are seeded once (only if they don't already
// exist on the PVC), so agent modifications survive pod restarts.
type WorkspaceSpec struct {
// ConfigMapRef references an external ConfigMap whose keys become workspace files.
// All keys in the referenced ConfigMap are included as workspace files.
// This is useful for GitOps workflows where workspace files (AGENT.md, SOUL.md, etc.)
// are managed as standalone files and bundled via Kustomize configMapGenerator or similar.
//
// Merge priority (highest wins):
// 1. Operator-injected files (ENVIRONMENT.md, BOOTSTRAP.md, SELFCONFIG.md, selfconfig.sh)
// 2. Inline initialFiles
// 3. External configMapRef entries
// 4. Skill pack files
// +optional
ConfigMapRef *ConfigMapNameSelector `json:"configMapRef,omitempty"`

// InitialFiles maps filenames to their content. Each file is written
// to the workspace directory only if it does not already exist.
// +kubebuilder:validation:MaxProperties=50
Expand All @@ -251,6 +264,47 @@ type WorkspaceSpec struct {
// +kubebuilder:validation:MaxItems=20
// +optional
InitialDirectories []string `json:"initialDirectories,omitempty"`

// AdditionalWorkspaces configures workspace files for secondary agents.
// Each entry seeds files to ~/.openclaw/workspace-<name>/, matching the
// workspace path configured in spec.config.raw.agents.list[].workspace.
// +kubebuilder:validation:MaxItems=10
// +optional
AdditionalWorkspaces []AdditionalWorkspace `json:"additionalWorkspaces,omitempty"`
}

// AdditionalWorkspace defines a named workspace for a secondary agent.
// The operator seeds files to ~/.openclaw/workspace-<name>/.
type AdditionalWorkspace struct {
// Name identifies this workspace. The operator seeds files to
// ~/.openclaw/workspace-<name>/. Must match the workspace path
// configured in spec.config.raw.agents.list[].workspace.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Pattern=`^[a-z0-9]([a-z0-9-]*[a-z0-9])?$`
Name string `json:"name"`

// ConfigMapRef references an external ConfigMap whose keys become workspace files.
// +optional
ConfigMapRef *ConfigMapNameSelector `json:"configMapRef,omitempty"`

// InitialFiles maps filenames to their content (same as spec.workspace.initialFiles).
// +kubebuilder:validation:MaxProperties=50
// +optional
InitialFiles map[string]string `json:"initialFiles,omitempty"`

// InitialDirectories is a list of directories to create inside this workspace.
// +kubebuilder:validation:MaxItems=20
// +optional
InitialDirectories []string `json:"initialDirectories,omitempty"`
}

// ConfigMapNameSelector references a ConfigMap by name.
// Unlike ConfigMapKeySelector, all keys in the ConfigMap are used.
type ConfigMapNameSelector struct {
// Name is the name of the ConfigMap to reference.
// +kubebuilder:validation:MinLength=1
Name string `json:"name"`
}

// ResourcesSpec defines compute resource requirements
Expand Down Expand Up @@ -1524,6 +1578,10 @@ const (

// ConditionTypeSkillPacksReady indicates skill packs were resolved successfully
ConditionTypeSkillPacksReady = "SkillPacksReady"

// ConditionTypeWorkspaceReady indicates the workspace configuration is valid
// and any external ConfigMap referenced by spec.workspace.configMapRef exists
ConditionTypeWorkspaceReady = "WorkspaceReady"
)

// Phase constants
Expand Down
59 changes: 59 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -9465,6 +9465,75 @@ spec:
Files are copied once on first boot and never overwritten, so agent
modifications survive pod restarts.
properties:
additionalWorkspaces:
description: |-
AdditionalWorkspaces configures workspace files for secondary agents.
Each entry seeds files to ~/.openclaw/workspace-<name>/, matching the
workspace path configured in spec.config.raw.agents.list[].workspace.
items:
description: |-
AdditionalWorkspace defines a named workspace for a secondary agent.
The operator seeds files to ~/.openclaw/workspace-<name>/.
properties:
configMapRef:
description: ConfigMapRef references an external ConfigMap
whose keys become workspace files.
properties:
name:
description: Name is the name of the ConfigMap to reference.
minLength: 1
type: string
required:
- name
type: object
initialDirectories:
description: InitialDirectories is a list of directories
to create inside this workspace.
items:
type: string
maxItems: 20
type: array
initialFiles:
additionalProperties:
type: string
description: InitialFiles maps filenames to their content
(same as spec.workspace.initialFiles).
maxProperties: 50
type: object
name:
description: |-
Name identifies this workspace. The operator seeds files to
~/.openclaw/workspace-<name>/. Must match the workspace path
configured in spec.config.raw.agents.list[].workspace.
maxLength: 63
minLength: 1
pattern: ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$
type: string
required:
- name
type: object
maxItems: 10
type: array
configMapRef:
description: |-
ConfigMapRef references an external ConfigMap whose keys become workspace files.
All keys in the referenced ConfigMap are included as workspace files.
This is useful for GitOps workflows where workspace files (AGENT.md, SOUL.md, etc.)
are managed as standalone files and bundled via Kustomize configMapGenerator or similar.

Merge priority (highest wins):
1. Operator-injected files (ENVIRONMENT.md, BOOTSTRAP.md, SELFCONFIG.md, selfconfig.sh)
2. Inline initialFiles
3. External configMapRef entries
4. Skill pack files
properties:
name:
description: Name is the name of the ConfigMap to reference.
minLength: 1
type: string
required:
- name
type: object
initialDirectories:
description: |-
InitialDirectories is a list of directories to create (mkdir -p)
Expand Down
Loading
Loading