From 97c6dea34ff2d6021281f0a582a9b82d2b97c4ac Mon Sep 17 00:00:00 2001 From: Oleksii Kurinnyi Date: Tue, 30 Jun 2026 16:25:56 +0300 Subject: [PATCH 1/3] docs: Add Claude Code configuration persistence guides Add documentation for persisting and sharing Claude Code configuration across Eclipse Che workspaces under a new "AI coding tools in workspaces" section in the User Guide. New pages: - Overview of Claude Code configuration files and available approaches - Dedicated PVC with automount (Option A: direct mount, Option B: /tmp copy) - GitOps approach using a central Git repository - Troubleshooting known issues with configuration persistence Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Oleksii Kurinnyi --- modules/end-user-guide/nav.adoc | 4 + .../persisting-claude-code-configuration.adoc | 110 ++++++++ ...de-configuration-with-a-dedicated-pvc.adoc | 262 ++++++++++++++++++ ...claude-code-configuration-with-gitops.adoc | 43 +++ ...claude-code-configuration-persistence.adoc | 180 ++++++++++++ 5 files changed, 599 insertions(+) create mode 100644 modules/end-user-guide/pages/persisting-claude-code-configuration.adoc create mode 100644 modules/end-user-guide/pages/sharing-claude-code-configuration-with-a-dedicated-pvc.adoc create mode 100644 modules/end-user-guide/pages/sharing-claude-code-configuration-with-gitops.adoc create mode 100644 modules/end-user-guide/pages/troubleshooting-claude-code-configuration-persistence.adoc diff --git a/modules/end-user-guide/nav.adoc b/modules/end-user-guide/nav.adoc index 67375c870a..24b4fb6b5f 100644 --- a/modules/end-user-guide/nav.adoc +++ b/modules/end-user-guide/nav.adoc @@ -40,6 +40,10 @@ * xref:using-ai-assistants-in-workspaces.adoc[] ** xref:configuring-an-ai-provider-api-key.adoc[] ** xref:changing-the-ai-tool-on-a-workspace.adoc[] +** xref:persisting-claude-code-configuration.adoc[] +*** xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[] +*** xref:sharing-claude-code-configuration-with-gitops.adoc[] +*** xref:troubleshooting-claude-code-configuration-persistence.adoc[] * xref:using-credentials-and-configurations-in-workspaces.adoc[] ** xref:mounting-secrets.adoc[] *** xref:creating-image-pull-secrets.adoc[] diff --git a/modules/end-user-guide/pages/persisting-claude-code-configuration.adoc b/modules/end-user-guide/pages/persisting-claude-code-configuration.adoc new file mode 100644 index 0000000000..0cdd7a9785 --- /dev/null +++ b/modules/end-user-guide/pages/persisting-claude-code-configuration.adoc @@ -0,0 +1,110 @@ +:_content-type: ASSEMBLY +:description: Persist and share Claude Code configuration across {prod-short} workspaces. +:keywords: user-guide, claude-code, ai, configuration, persistence, pvc +:navtitle: Persisting Claude Code configuration +:page-aliases: + +[id="persisting-claude-code-configuration"] += Persisting Claude Code configuration in {prod-short} workspaces + +New {prod-short} workspaces start without Claude Code configuration. Developers must set up skills, settings, MCP servers, and plugins from scratch in each workspace. + +To avoid repeating this setup, persist the Claude Code configuration in a shared volume or a Git repository and reuse it across workspaces. + +== Claude Code configuration files + +Claude Code stores configuration in two separate locations in the user home directory: + +|=== +| Path | Contents + +| `{prod-home}/.claude/` +| Settings, plugins, custom agents, hooks, per-project memory. + +| `{prod-home}/.claude.json` +| Application settings and MCP server configurations. +|=== + +[IMPORTANT] +==== +MCP server configurations are stored in `{prod-home}/.claude.json`, a separate file at the home directory root, not inside `{prod-home}/.claude/`. Both locations must be persisted. +==== + +[NOTE] +==== +Claude Code writes runtime state to both `{prod-home}/.claude/` and `{prod-home}/.claude.json` during every session, including session files, caches, and usage statistics. These paths must be writable. Mounting a read-only ConfigMap or Secret directly to these paths causes Claude Code to fail. +==== + +== Available approaches + +|=== +| Approach | Summary + +| xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[] +| A dedicated PVC in the user {orch-namespace} shares configuration across all workspaces. The {devworkspace} Operator automatically mounts PVCs labeled with `controller.devfile.io/mount-to-devworkspace: true` into every workspace pod. + +| xref:sharing-claude-code-configuration-with-gitops.adoc[] +| A Git repository stores the baseline Claude Code configuration. The {devworkspace} Operator clones the repository at startup, and a `postStart` command copies the configuration into the home directory. +|=== + +== Claude Code file reference + +|=== +| Path | Purpose | Size | Regeneratable + +| `~/.claude/settings.json` +| Permissions, hooks, enabled plugins, model preferences. +| Small +| No + +| `~/.claude/settings.local.json` +| Local setting overrides. +| Small +| No + +| `~/.claude/CLAUDE.md` +| User-level instructions for Claude. +| Small +| No + +| `~/.claude/plugins/` +| Installed plugins and caches. +| Large (100{nbsp}MB+) +| Partially + +| `~/.claude/agents/` +| Custom agent definitions. +| Small +| No + +| `~/.claude/hooks/` +| Shell scripts for session lifecycle. +| Small +| No + +| `~/.claude/projects/` +| Per-project memory and settings. +| Medium +| No + +| `~/.claude.json` +| Application settings and MCP server configurations. +| Small +| No + +| `~/.claude/history.jsonl` +| Conversation history. +| Large +| Optional + +| `~/.claude/plugins/cache/` +| Plugin download cache. +| Large +| Yes +|=== + +.Additional resources + +* xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[] +* xref:sharing-claude-code-configuration-with-gitops.adoc[] +* xref:troubleshooting-claude-code-configuration-persistence.adoc[] diff --git a/modules/end-user-guide/pages/sharing-claude-code-configuration-with-a-dedicated-pvc.adoc b/modules/end-user-guide/pages/sharing-claude-code-configuration-with-a-dedicated-pvc.adoc new file mode 100644 index 0000000000..92d7f90bfd --- /dev/null +++ b/modules/end-user-guide/pages/sharing-claude-code-configuration-with-a-dedicated-pvc.adoc @@ -0,0 +1,262 @@ +:_content-type: PROCEDURE +:description: Share Claude Code configuration across {prod-short} workspaces by using a dedicated PVC with automount. +:keywords: user-guide, claude-code, ai, configuration, persistence, pvc, automount +:navtitle: Sharing configuration with a dedicated PVC +:page-aliases: + +[id="sharing-claude-code-configuration-with-a-dedicated-pvc"] += Sharing Claude Code configuration across workspaces with a dedicated PVC + +A dedicated PVC in the user {orch-namespace} shares Claude Code configuration across all workspaces. The {devworkspace} Operator automatically mounts PVCs labeled with `controller.devfile.io/mount-to-devworkspace: true` into every workspace pod. + +Two options are available: + +* *Option A: Direct mount* — both `{prod-home}/.claude/` and `{prod-home}/.claude.json` are mounted directly from the PVC. All changes persist automatically. Requires a one-time init pod to pre-create `.claude.json`. +* *Option B: Full `/tmp` copy* — the entire PVC is mounted at `/tmp/claude`. A `postStart` command copies everything into the home directory. No init pod is required, but changes must be synced back manually before stopping the workspace. + +|=== +| Feature | Option A: Direct mount | Option B: Full `/tmp` copy + +| Init pod required +| Yes (one-time) +| No + +| `postStart` required +| No +| Yes + +| Manual sync before stop +| No +| Yes + +| AZ affinity risk +| Yes (RWO on multi-AZ clusters) +| Yes (RWO on multi-AZ clusters) +|=== + +For an overview of all approaches, see xref:persisting-claude-code-configuration.adoc[]. + +.Prerequisites + +* An active `{orch-cli}` session with permissions to create PVCs in your {orch-namespace}. See {orch-cli-link}. + +* Claude Code installed in the workspace container image. + +* For concurrent workspaces: a storage class that supports `ReadWriteMany` (RWX) access mode, such as AWS EFS or NFS. Standard block storage (gp2, gp3) supports only `ReadWriteOnce` (RWO). + +== Option A: Direct mount + +All Claude Code configuration is mounted directly from the PVC. Changes persist automatically without any `postStart` commands or manual sync steps. + +=== Creating the PVC + +. Create a file `claude-config-pvc.yaml` with the following PVC definition: ++ +==== +[source,yaml,subs="+quotes,+attributes"] +---- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: claude-config + annotations: + controller.devfile.io/mount-path: >- + [{"path":"{prod-home}/.claude","subPath":".claude"}, + {"path":"{prod-home}/.claude.json","subPath":".claude.json"}] + labels: + controller.devfile.io/mount-to-devworkspace: 'true' +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi +---- +==== + +. Apply the PVC to your {orch-namespace}: ++ +[subs="+quotes,+attributes"] +---- +$ {orch-cli} apply -f claude-config-pvc.yaml -n ____ +---- + +=== Initializing the PVC with an init pod + +The `{prod-home}/.claude.json` subPath target must exist as a *file* on the PVC before any workspace starts. Without this step, {kubernetes} kubelet creates a directory instead of a file, and Claude Code fails to parse it. + +. Create a file `claude-config-init-pod.yaml` with the following pod definition: ++ +==== +[source,yaml,subs="+quotes,+attributes"] +---- +apiVersion: v1 +kind: Pod +metadata: + name: claude-config-init +spec: + containers: + - image: registry.access.redhat.com/ubi9/ubi-minimal + name: init + command: + - sh + - -c + - | + mkdir -p /mnt/.claude + echo '{}' > /mnt/.claude.json + echo "=== Initialization complete ===" + ls -la /mnt/ + tail -f /dev/null + volumeMounts: + - mountPath: /mnt + name: vol + volumes: + - name: vol + persistentVolumeClaim: + claimName: claude-config +---- +==== + +. Apply the init pod, wait for it to initialize, verify, and delete: ++ +[subs="+quotes,+attributes"] +---- +$ {orch-cli} apply -f claude-config-init-pod.yaml -n ____ +$ {orch-cli} wait pod/claude-config-init --for=condition=Ready --timeout=120s +$ {orch-cli} logs claude-config-init +$ {orch-cli} delete pod claude-config-init +---- + +=== Using workspaces + +Start any workspace. The PVC auto-mounts into every workspace pod. Claude Code finds its configuration at `{prod-home}/.claude/` and `{prod-home}/.claude.json` on startup. All changes, including new MCP servers, plugins, and settings, are written directly to the PVC and available in every workspace. + +No `postStart` commands or manual sync steps are required. + +[WARNING] +==== +On multi-AZ clusters using `WaitForFirstConsumer` storage classes (gp2, gp3), the init pod may bind the PV to a different availability zone than workspace pods. See xref:troubleshooting-claude-code-configuration-persistence.adoc#pvc-scheduling-failure-after-init-pod-setup[PVC scheduling failure after init pod setup]. +==== + +=== Verification + +. Start a workspace and configure Claude Code (add an MCP server, install a plugin, or modify settings). +. Stop and restart the workspace. Verify the configuration is preserved. +. Start a different workspace. Verify the same configuration is available. + +== Option B: Full `/tmp` copy + +The entire PVC is mounted at `/tmp/claude`. A `postStart` command copies everything into the home directory. No init pod is required and there are no subPath limitations. + +=== Creating the PVC + +. Create a file `claude-config-pvc.yaml` with the following PVC definition: ++ +==== +[source,yaml,subs="+quotes,+attributes"] +---- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: claude-config + annotations: + controller.devfile.io/mount-path: '[{"path":"/tmp/claude","subPath":"claude"}]' + labels: + controller.devfile.io/mount-to-devworkspace: 'true' +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi +---- +==== + +. Apply the PVC to your {orch-namespace}: ++ +[subs="+quotes,+attributes"] +---- +$ {orch-cli} apply -f claude-config-pvc.yaml -n ____ +---- + +=== Adding a `postStart` command to copy configurations + +Add a `postStart` command to your devfile to copy all configuration from the PVC into the home directory: + +==== +[source,yaml,subs="+quotes,+attributes"] +---- +commands: + - id: init-claude-config + exec: + commandLine: | + mkdir -p {prod-home}/.claude + cp -a /tmp/claude/.claude/. {prod-home}/.claude/ 2>/dev/null || true + cp /tmp/claude/.claude.json {prod-home}/.claude.json 2>/dev/null || true + component: ____ # <1> +events: + postStart: + - init-claude-config +---- +<1> Replace with the name of your editor container component in the devfile. +==== + +=== Syncing changes before stopping + +Changes to both `{prod-home}/.claude/` and `{prod-home}/.claude.json` are written to the home directory, not the PVC. Sync everything back before stopping: + +[subs="+quotes,+attributes"] +---- +$ cp -a {prod-home}/.claude/. /tmp/claude/.claude/ && \ + cp {prod-home}/.claude.json /tmp/claude/.claude.json +---- + +=== Verification + +. Start a workspace and configure Claude Code. +. Sync changes back to the PVC. +. Start a different workspace. +. Verify that the Claude Code configuration from the first workspace is available. + +== Shared options for both variants + +=== Filtering by workspace name + +Control which workspaces mount the PVC by adding annotations: + +[source,yaml,subs="+quotes,+attributes"] +---- +annotations: + controller.devfile.io/mount-to-devworkspace-include: '____' # <1> + controller.devfile.io/mount-to-devworkspace-exclude: '____' # <2> +---- +<1> Mount the PVC only to workspaces whose names match the pattern. +<2> Mount the PVC to all workspaces except those whose names match the pattern. + +Supported patterns: `*` (all), `prefix*`, `*suffix`, `*contains*`, `exact-name`. Matching is on the {devworkspace} resource name. + +=== Concurrent workspaces + +|=== +| Access mode | Behavior + +| ReadWriteOnce (RWO) +| One workspace at a time. Two workspaces on different nodes cause a multi-attach error. + +| ReadWriteMany (RWX) +| Concurrent workspaces work. Requires a storage class that supports RWX, such as AWS EFS or NFS. Standard block storage (gp2, gp3) does not support RWX. +|=== + +== Limitations + +* Requires manual PVC setup per user {orch-namespace}. +* Can be combined with `persistUserHome`. The dedicated PVC at `{prod-home}/.claude` and the persistent home PVC at `{prod-home}/` coexist correctly as nested mounts. +* RWX storage may not be available on all clusters. +* On clusters with only block storage and multi-AZ topology, the Option A init pod may cause scheduling failures. Use Option B instead. + +.Additional resources + +* xref:persisting-claude-code-configuration.adoc[] +* xref:sharing-claude-code-configuration-with-gitops.adoc[] +* xref:troubleshooting-claude-code-configuration-persistence.adoc[] +* xref:requesting-persistent-storage-for-workspaces.adoc[] diff --git a/modules/end-user-guide/pages/sharing-claude-code-configuration-with-gitops.adoc b/modules/end-user-guide/pages/sharing-claude-code-configuration-with-gitops.adoc new file mode 100644 index 0000000000..e1f6e9f9b1 --- /dev/null +++ b/modules/end-user-guide/pages/sharing-claude-code-configuration-with-gitops.adoc @@ -0,0 +1,43 @@ +:_content-type: CONCEPT +:description: Share Claude Code configuration across {prod-short} workspaces by storing it in a Git repository. +:keywords: user-guide, claude-code, ai, configuration, persistence, gitops, git +:navtitle: Sharing configuration with GitOps +:page-aliases: + +[id="sharing-claude-code-configuration-with-gitops"] += Sharing Claude Code configuration across workspaces with GitOps + +Instead of using a shared PVC, you can store Claude Code configuration in a Git repository and pull it into workspaces at startup. Each workspace gets its own isolated, writable copy of the configuration. + +This approach eliminates multi-attach errors and last-write-wins data corruption risks that can occur with shared PVCs on clusters without RWX storage. + +== How it works + +A central Git repository stores the baseline Claude Code configuration. The repository is listed in the `projects` section of the devfile, and the {devworkspace} Operator's project-clone init container clones it automatically at workspace startup. A `postStart` command then copies the configuration files from the cloned repository into the home directory. + +Two usage patterns are possible: + +* *Read-only baseline* — administrators maintain a shared repository with team-wide settings such as security hooks, API proxies, and approved plugins. The configuration is cloned at startup and copied into the home directory. Developers do not push changes back. This is suitable for enforcing organization-wide policies. + +* *User-specific persistence* — each developer maintains a private branch or repository with personal configuration. The repository is cloned at startup and copied into the home directory. Optionally, a `preStop` command or manual step commits and pushes changes back before the workspace stops. + +== Advantages + +* No RWX storage requirement. Each workspace uses its own local storage. +* No multi-attach errors. Concurrent workspaces are not affected. +* Git history provides an audit trail of configuration changes. +* Works across clusters and {prod-short} instances. + +== Limitations + +* Requires a Git repository accessible from the workspace. +* Changes must be committed and pushed to persist. Unsaved changes are lost when the workspace stops. +* Large files such as plugin caches (`~/.claude/plugins/cache/`) are not suitable for Git storage. Consider adding them to `.gitignore`. +* Merge conflicts can occur when multiple workspaces push changes to the same branch concurrently. + +.Additional resources + +* xref:persisting-claude-code-configuration.adoc[] +* xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[] +* xref:troubleshooting-claude-code-configuration-persistence.adoc[] +* xref:authenticating-to-a-git-server-from-a-workspace.adoc[] diff --git a/modules/end-user-guide/pages/troubleshooting-claude-code-configuration-persistence.adoc b/modules/end-user-guide/pages/troubleshooting-claude-code-configuration-persistence.adoc new file mode 100644 index 0000000000..551ebfc2f9 --- /dev/null +++ b/modules/end-user-guide/pages/troubleshooting-claude-code-configuration-persistence.adoc @@ -0,0 +1,180 @@ +:_content-type: REFERENCE +:description: Troubleshoot known issues with persisting Claude Code configuration in {prod-short} workspaces. +:keywords: user-guide, claude-code, ai, configuration, persistence, troubleshooting +:navtitle: Troubleshooting Claude Code configuration persistence +:page-aliases: + +[id="troubleshooting-claude-code-configuration-persistence"] += Troubleshooting Claude Code configuration persistence + +This section describes known issues with persisting Claude Code configuration in {prod-short} workspaces and how to resolve them. + +== `.claude.json` corrupted on first start + +=== Symptom + +---- +Claude configuration file at /home/user/.claude.json is corrupted: JSON Parse error: Unexpected EOF +---- + +=== Cause + +The `.claude.json` file was pre-created as an empty file, for example with `touch`, instead of valid JSON. + +=== Solution + +Initialize the file with valid JSON content: + +---- +$ echo '{}' > .claude.json +---- + +If you already see this error, select *Reset with default configuration* when prompted. This is a one-time prompt that does not recur. + +== `.claude.json` mounted as a directory + +=== Symptom + +Claude Code fails to start or reports that `{prod-home}/.claude.json` is not a valid file. Inspecting the mount shows a directory instead of a file: + +---- +$ stat {prod-home}/.claude.json + File: {prod-home}/.claude.json + Size: 4096 Blocks: 8 IO Block: 4096 directory +---- + +=== Cause + +When a PVC `subPath` mount target does not exist on the volume, {kubernetes} kubelet creates it as a *directory*, not a file. The mount point is locked and cannot be replaced from inside the container. + +=== Solution + +Do not mount `{prod-home}/.claude.json` as a direct subPath from a PVC without pre-creating the file. Either use an init pod to pre-create it (Option A) or use the `/tmp` copy pattern (Option B). See xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[]. + +== Permission denied writing to `~/.claude/session-env` + +=== Symptom + +---- +The workspace environment blocks write access to /home/user/.claude/session-env +---- + +=== Cause + +On OpenShift, the Security Context Constraints (SCC) assign a random UID per {orch-namespace}. If the PVC contents were created with a different UID or group, write access fails. + +=== Solution + +On OpenShift, PVC filesystems typically receive a setgid bit (`drwxrwsr-x`) with group `0`, and workspace containers run with GID `0`. When both conditions are met, writes succeed without manual permission changes. + +If you encounter this error, verify that: + +* The PVC was created in the same {orch-namespace} as the workspace. +* The PVC contents have group `0` ownership: ++ +---- +$ stat {prod-home}/.claude +---- ++ +If the group is not `0` (root), the PVC contents were likely created by a process with a different GID. Regular workspace users cannot fix this with `chgrp` because OpenShift assigns a random UID without permission to change file groups. Delete the PVC, recreate it, and let a workspace pod be the first consumer. Files created by the workspace process will have the correct group ownership. + +== Multi-attach error when starting a second workspace + +=== Symptom + +---- +Multi-Attach error for volume "pvc-xxx": Volume is already exclusively attached to one node +---- + +=== Cause + +The PVC uses `ReadWriteOnce` (RWO) access mode. RWO volumes can only attach to a single node at a time. When two workspace pods are scheduled on different nodes, the second pod cannot mount the volume. + +=== Solution + +Choose one of the following: + +* Run only one workspace at a time. +* Use `ReadWriteMany` (RWX) access mode with a storage class that supports it, such as AWS EFS or NFS. Standard block storage classes (gp2, gp3) do not support RWX. + +To check available storage classes: + +[subs="+quotes,+attributes"] +---- +$ {orch-cli} get storageclasses +---- + +Look for classes using EFS (`efs.csi.aws.com`) or NFS provisioners. + +== Dedicated PVC and persistent user home interaction + +A dedicated PVC mounted at `{prod-home}/.claude` and the persistent home PVC mounted at `{prod-home}/` coexist correctly as nested mounts. + +Writes to `~/.claude/` go to the dedicated PVC. Writes to other paths under `{prod-home}/` go to the persistent home PVC. There is no conflict. + +If you only need persistence within a single workspace and not cross-workspace sharing, `persistUserHome` alone is sufficient. A dedicated PVC is not needed. + +== Changes to `~/.claude.json` not persisting after restart + +=== Symptom + +After restarting a workspace, MCP server configurations added during the previous session are lost. + +=== Cause + +This applies to Option B (full `/tmp` copy) from the xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[dedicated PVC guide]. The `postStart` command copies configurations from the PVC into the home directory. Changes made during the session are written to the home directory, not back to the PVC. + +Option A (direct mount) does not have this issue because changes are written directly to the PVC. + +=== Solution + +Sync changes back to the PVC before stopping the workspace: + +[subs="+quotes,+attributes"] +---- +$ cp -a {prod-home}/.claude/. /tmp/claude/.claude/ && \ + cp {prod-home}/.claude.json /tmp/claude/.claude.json +---- + +[id="pvc-scheduling-failure-after-init-pod-setup"] +== PVC scheduling failure after init pod setup + +=== Symptom + +---- +0/N nodes are available: X node(s) didn't match PersistentVolume's node affinity +---- + +A workspace fails to start after a PVC was initialized using a temporary pod. + +=== Cause + +On multi-AZ clusters using RWO block storage (gp2, gp3), the PersistentVolume is provisioned in a single availability zone. + +This issue does not affect single-AZ clusters or clusters using RWX storage (EFS, NFS). + +=== Solution + +Do not use a separate init pod to initialize PVC contents on clusters with `WaitForFirstConsumer` storage classes. Instead: + +. Let the workspace pod be the first consumer of the PVC. +. Handle file initialization with `postStart` commands from inside the workspace. + +If you already have a PVC stuck in the wrong availability zone: + +. Stop all workspaces using the PVC. +. Delete the PVC: ++ +[subs="+quotes,+attributes"] +---- +$ {orch-cli} delete pvc ____ -n __<{orch-namespace}>__ +---- +. Recreate the PVC and start a workspace. The PV is provisioned in the correct zone. + +For clusters where this is a recurring issue, use Option B (full `/tmp` copy) from the xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[dedicated PVC guide], which does not require an init pod. + +.Additional resources + +* xref:persisting-claude-code-configuration.adoc[] +* xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[] +* xref:sharing-claude-code-configuration-with-gitops.adoc[] From 3e47bf20e43fc42bc25d312197af0f71956f799c Mon Sep 17 00:00:00 2001 From: Oleksii Kurinnyi Date: Mon, 6 Jul 2026 14:30:33 +0300 Subject: [PATCH 2/3] docs: Address review feedback on Claude Code configuration persistence - Rename all pages to imperative titles (CQA P10) - Split PVC page into two separate procedures: direct mount and tmp copy (CQA P12) - Change overview content type from ASSEMBLY to CONCEPT (CQA P3/P5) - Rewrite abstracts to lead with user goal (CQA P11/JTBD) - Merge adjacent admonitions (CQA Q10) - Use {prod-home} consistently, replace bare ~/ paths (CQA Q20) - Add full GitOps procedure with devfile snippets (JTBD) - Split multi-command init pod step into separate steps (CQA Q14) - Replace tail -f /dev/null with restartPolicy: Never in init pod - Move persistUserHome compatibility note to overview (CQA Q5) - Move non-troubleshooting section out of troubleshooting page - Rewrite troubleshooting intro to user-centric language (CQA Q4/Q5) - Add "how it works" flow summaries to both PVC procedure pages - Add page-aliases for old filenames to preserve redirects Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Oleksii Kurinnyi --- modules/end-user-guide/nav.adoc | 9 +- .../persist-claude-code-configuration.adoc | 152 ++++++++++ .../persisting-claude-code-configuration.adoc | 110 -------- ...claude-code-configuration-with-gitops.adoc | 117 ++++++++ ...e-configuration-with-pvc-direct-mount.adoc | 145 ++++++++++ ...-code-configuration-with-pvc-tmp-copy.adoc | 103 +++++++ ...de-configuration-with-a-dedicated-pvc.adoc | 262 ------------------ ...claude-code-configuration-with-gitops.adoc | 43 --- ...laude-code-configuration-persistence.adoc} | 35 +-- 9 files changed, 536 insertions(+), 440 deletions(-) create mode 100644 modules/end-user-guide/pages/persist-claude-code-configuration.adoc delete mode 100644 modules/end-user-guide/pages/persisting-claude-code-configuration.adoc create mode 100644 modules/end-user-guide/pages/share-claude-code-configuration-with-gitops.adoc create mode 100644 modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-direct-mount.adoc create mode 100644 modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-tmp-copy.adoc delete mode 100644 modules/end-user-guide/pages/sharing-claude-code-configuration-with-a-dedicated-pvc.adoc delete mode 100644 modules/end-user-guide/pages/sharing-claude-code-configuration-with-gitops.adoc rename modules/end-user-guide/pages/{troubleshooting-claude-code-configuration-persistence.adoc => troubleshoot-claude-code-configuration-persistence.adoc} (72%) diff --git a/modules/end-user-guide/nav.adoc b/modules/end-user-guide/nav.adoc index 24b4fb6b5f..ad1e63b669 100644 --- a/modules/end-user-guide/nav.adoc +++ b/modules/end-user-guide/nav.adoc @@ -40,10 +40,11 @@ * xref:using-ai-assistants-in-workspaces.adoc[] ** xref:configuring-an-ai-provider-api-key.adoc[] ** xref:changing-the-ai-tool-on-a-workspace.adoc[] -** xref:persisting-claude-code-configuration.adoc[] -*** xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[] -*** xref:sharing-claude-code-configuration-with-gitops.adoc[] -*** xref:troubleshooting-claude-code-configuration-persistence.adoc[] +** xref:persist-claude-code-configuration.adoc[] +*** xref:share-claude-code-configuration-with-pvc-direct-mount.adoc[] +*** xref:share-claude-code-configuration-with-pvc-tmp-copy.adoc[] +*** xref:share-claude-code-configuration-with-gitops.adoc[] +*** xref:troubleshoot-claude-code-configuration-persistence.adoc[] * xref:using-credentials-and-configurations-in-workspaces.adoc[] ** xref:mounting-secrets.adoc[] *** xref:creating-image-pull-secrets.adoc[] diff --git a/modules/end-user-guide/pages/persist-claude-code-configuration.adoc b/modules/end-user-guide/pages/persist-claude-code-configuration.adoc new file mode 100644 index 0000000000..609b160568 --- /dev/null +++ b/modules/end-user-guide/pages/persist-claude-code-configuration.adoc @@ -0,0 +1,152 @@ +:_content-type: CONCEPT +:description: Persist and share Claude Code configuration across {prod-short} workspaces. +:keywords: user-guide, claude-code, ai, configuration, persistence, pvc +:navtitle: Persist Claude Code configuration +:page-aliases: persisting-claude-code-configuration.adoc + +[id="persist-claude-code-configuration"] += Persist Claude Code configuration in {prod-short} workspaces + +To reuse Claude Code skills, settings, MCP servers, and plugins across {prod-short} workspaces, persist the configuration in a shared volume or a Git repository. Without persistence, each new workspace requires a fresh setup. + +== Claude Code configuration files + +Claude Code stores configuration in two separate locations in the user's home directory: + +|=== +| Path | Contents + +| `{prod-home}/.claude/` +| Settings, plugins, custom agents, hooks, per-project memory. + +| `{prod-home}/.claude.json` +| Application settings and MCP server configurations. +|=== + +[IMPORTANT] +==== +MCP server configurations are stored in `{prod-home}/.claude.json`, a separate file at the home directory root, not inside `{prod-home}/.claude/`. Both locations must be persisted. + +Claude Code writes runtime state to both paths during every session, including session files, caches, and usage statistics. These paths must be writable. Mounting a read-only ConfigMap or Secret directly to these paths causes Claude Code to fail. +==== + +== Available approaches + +|=== +| Approach | Summary + +| xref:share-claude-code-configuration-with-pvc-direct-mount.adoc[] +| Both `{prod-home}/.claude/` and `{prod-home}/.claude.json` are mounted directly from a dedicated PVC. All changes persist automatically. Requires a one-time init pod to pre-create `.claude.json`. + +| xref:share-claude-code-configuration-with-pvc-tmp-copy.adoc[] +| A dedicated PVC is mounted at `/tmp/claude`. A `postStart` command copies everything into the home directory. No init pod is required, but changes must be synced back manually before stopping the workspace. + +| xref:share-claude-code-configuration-with-gitops.adoc[] +| A Git repository stores the baseline Claude Code configuration. The {devworkspace} Operator clones the repository at startup, and a `postStart` command copies the configuration into the home directory. +|=== + +== PVC shared options + +The following options apply to both PVC approaches (direct mount and tmp copy). + +=== Filtering by workspace name + +Control which workspaces mount the PVC by adding annotations: + +[source,yaml,subs="+quotes,+attributes"] +---- +annotations: + controller.devfile.io/mount-to-devworkspace-include: '____' # <1> + controller.devfile.io/mount-to-devworkspace-exclude: '____' # <2> +---- +<1> Mount the PVC only to workspaces whose names match the pattern. +<2> Mount the PVC to all workspaces except those whose names match the pattern. + +Supported patterns: `*` (all), `prefix*`, `*suffix`, `*contains*`, `exact-name`. Matching is on the {devworkspace} resource name. + +=== Concurrent workspaces + +|=== +| Access mode | Behavior + +| ReadWriteOnce (RWO) +| One workspace at a time. Two workspaces on different nodes cause a multi-attach error. + +| ReadWriteMany (RWX) +| Concurrent workspaces work. Requires a storage class that supports RWX, such as AWS EFS or NFS. Standard block storage (gp2, gp3) does not support RWX. +|=== + +=== Compatibility with `persistUserHome` + +A dedicated PVC mounted at `{prod-home}/.claude` and the persistent home PVC mounted at `{prod-home}/` coexist correctly as nested mounts. Writes to `{prod-home}/.claude/` go to the dedicated PVC. Writes to other paths under `{prod-home}/` go to the persistent home PVC. + +If you only need persistence within a single workspace and not cross-workspace sharing, `persistUserHome` alone is sufficient. + +=== Limitations + +* Requires manual PVC setup per user {orch-namespace}. +* RWX storage may not be available on all clusters. +* On clusters with only block storage and multi-AZ topology, the direct mount init pod may cause scheduling failures. Use the tmp copy approach instead. + +== Claude Code file reference + +|=== +| Path | Purpose | Size | Regeneratable + +| `{prod-home}/.claude/settings.json` +| Permissions, hooks, enabled plugins, model preferences. +| Small +| No + +| `{prod-home}/.claude/settings.local.json` +| Local setting overrides. +| Small +| No + +| `{prod-home}/.claude/CLAUDE.md` +| User-level instructions for Claude. +| Small +| No + +| `{prod-home}/.claude/plugins/` +| Installed plugins and caches. +| Large (100{nbsp}MB+) +| Partially + +| `{prod-home}/.claude/agents/` +| Custom agent definitions. +| Small +| No + +| `{prod-home}/.claude/hooks/` +| Shell scripts for session lifecycle. +| Small +| No + +| `{prod-home}/.claude/projects/` +| Per-project memory and settings. +| Medium +| No + +| `{prod-home}/.claude.json` +| Application settings and MCP server configurations. +| Small +| No + +| `{prod-home}/.claude/history.jsonl` +| Conversation history. +| Large +| Optional + +| `{prod-home}/.claude/plugins/cache/` +| Plugin download cache. +| Large +| Yes +|=== + +.Additional resources + +* xref:share-claude-code-configuration-with-pvc-direct-mount.adoc[] +* xref:share-claude-code-configuration-with-pvc-tmp-copy.adoc[] +* xref:share-claude-code-configuration-with-gitops.adoc[] +* xref:troubleshoot-claude-code-configuration-persistence.adoc[] diff --git a/modules/end-user-guide/pages/persisting-claude-code-configuration.adoc b/modules/end-user-guide/pages/persisting-claude-code-configuration.adoc deleted file mode 100644 index 0cdd7a9785..0000000000 --- a/modules/end-user-guide/pages/persisting-claude-code-configuration.adoc +++ /dev/null @@ -1,110 +0,0 @@ -:_content-type: ASSEMBLY -:description: Persist and share Claude Code configuration across {prod-short} workspaces. -:keywords: user-guide, claude-code, ai, configuration, persistence, pvc -:navtitle: Persisting Claude Code configuration -:page-aliases: - -[id="persisting-claude-code-configuration"] -= Persisting Claude Code configuration in {prod-short} workspaces - -New {prod-short} workspaces start without Claude Code configuration. Developers must set up skills, settings, MCP servers, and plugins from scratch in each workspace. - -To avoid repeating this setup, persist the Claude Code configuration in a shared volume or a Git repository and reuse it across workspaces. - -== Claude Code configuration files - -Claude Code stores configuration in two separate locations in the user home directory: - -|=== -| Path | Contents - -| `{prod-home}/.claude/` -| Settings, plugins, custom agents, hooks, per-project memory. - -| `{prod-home}/.claude.json` -| Application settings and MCP server configurations. -|=== - -[IMPORTANT] -==== -MCP server configurations are stored in `{prod-home}/.claude.json`, a separate file at the home directory root, not inside `{prod-home}/.claude/`. Both locations must be persisted. -==== - -[NOTE] -==== -Claude Code writes runtime state to both `{prod-home}/.claude/` and `{prod-home}/.claude.json` during every session, including session files, caches, and usage statistics. These paths must be writable. Mounting a read-only ConfigMap or Secret directly to these paths causes Claude Code to fail. -==== - -== Available approaches - -|=== -| Approach | Summary - -| xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[] -| A dedicated PVC in the user {orch-namespace} shares configuration across all workspaces. The {devworkspace} Operator automatically mounts PVCs labeled with `controller.devfile.io/mount-to-devworkspace: true` into every workspace pod. - -| xref:sharing-claude-code-configuration-with-gitops.adoc[] -| A Git repository stores the baseline Claude Code configuration. The {devworkspace} Operator clones the repository at startup, and a `postStart` command copies the configuration into the home directory. -|=== - -== Claude Code file reference - -|=== -| Path | Purpose | Size | Regeneratable - -| `~/.claude/settings.json` -| Permissions, hooks, enabled plugins, model preferences. -| Small -| No - -| `~/.claude/settings.local.json` -| Local setting overrides. -| Small -| No - -| `~/.claude/CLAUDE.md` -| User-level instructions for Claude. -| Small -| No - -| `~/.claude/plugins/` -| Installed plugins and caches. -| Large (100{nbsp}MB+) -| Partially - -| `~/.claude/agents/` -| Custom agent definitions. -| Small -| No - -| `~/.claude/hooks/` -| Shell scripts for session lifecycle. -| Small -| No - -| `~/.claude/projects/` -| Per-project memory and settings. -| Medium -| No - -| `~/.claude.json` -| Application settings and MCP server configurations. -| Small -| No - -| `~/.claude/history.jsonl` -| Conversation history. -| Large -| Optional - -| `~/.claude/plugins/cache/` -| Plugin download cache. -| Large -| Yes -|=== - -.Additional resources - -* xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[] -* xref:sharing-claude-code-configuration-with-gitops.adoc[] -* xref:troubleshooting-claude-code-configuration-persistence.adoc[] diff --git a/modules/end-user-guide/pages/share-claude-code-configuration-with-gitops.adoc b/modules/end-user-guide/pages/share-claude-code-configuration-with-gitops.adoc new file mode 100644 index 0000000000..d07801961a --- /dev/null +++ b/modules/end-user-guide/pages/share-claude-code-configuration-with-gitops.adoc @@ -0,0 +1,117 @@ +:_content-type: PROCEDURE +:description: Share Claude Code configuration across {prod-short} workspaces by storing it in a Git repository. +:keywords: user-guide, claude-code, ai, configuration, persistence, gitops, git +:navtitle: Share configuration with GitOps +:page-aliases: sharing-claude-code-configuration-with-gitops.adoc + +[id="share-claude-code-configuration-with-gitops"] += Share Claude Code configuration across workspaces with GitOps + +Instead of using a shared PVC, you can store Claude Code configuration in a Git repository and pull it into workspaces at startup. Each workspace gets its own isolated, writable copy of the configuration. + +This approach eliminates multi-attach errors and last-write-wins data corruption risks that can occur with shared PVCs on clusters without RWX storage. + +== How it works + +A central Git repository stores the baseline Claude Code configuration. The repository is listed in the `projects` section of the devfile, and the {devworkspace} Operator's project-clone init container clones it automatically at workspace startup. A `postStart` command then copies the configuration files from the cloned repository into the home directory. + +Two usage patterns are possible: + +* *Read-only baseline* — administrators maintain a shared repository with team-wide settings such as security hooks, API proxies, and approved plugins. The configuration is cloned at startup and copied into the home directory. Developers do not push changes back. This is suitable for enforcing organization-wide policies. + +* *User-specific persistence* — each developer maintains a private branch or repository with personal configuration. The repository is cloned at startup and copied into the home directory. Optionally, a `preStop` command or manual step commits and pushes changes back before the workspace stops. + +For a comparison with other approaches, see xref:persist-claude-code-configuration.adoc[]. + +.Prerequisites + +* An active `{orch-cli}` session with permissions to create resources in your {orch-namespace}. See {orch-cli-link}. + +* Claude Code installed in the workspace container image. + +* A Git repository containing Claude Code configuration files. The repository must be accessible from the workspace. At minimum, the repository should contain: ++ +---- +.claude/ + settings.json + CLAUDE.md +.claude.json +---- + +* Git credentials configured in the workspace if the repository is private. See xref:authenticating-to-a-git-server-from-a-workspace.adoc[]. + +.Procedure + +. Add the configuration repository to the `projects` section of your devfile: ++ +==== +[source,yaml,subs="+quotes,+attributes"] +---- +projects: + - name: claude-config + git: + remotes: + origin: '____' # <1> +---- +<1> Replace with the URL of your Claude Code configuration repository. +==== + +. Add a `postStart` command to copy the configuration from the cloned repository into the home directory: ++ +==== +[source,yaml,subs="+quotes,+attributes"] +---- +commands: + - id: init-claude-config + exec: + commandLine: | + cp -a /projects/claude-config/.claude/. {prod-home}/.claude/ 2>/dev/null || true + cp /projects/claude-config/.claude.json {prod-home}/.claude.json 2>/dev/null || true + component: ____ # <1> +events: + postStart: + - init-claude-config +---- +<1> Replace with the name of your editor container component in the devfile. +==== + +. Start the workspace. + +. Optional: To persist changes back to the Git repository before stopping, commit and push from within the workspace: ++ +[subs="+quotes,+attributes"] +---- +$ cp -a {prod-home}/.claude/. /projects/claude-config/.claude/ +$ cp {prod-home}/.claude.json /projects/claude-config/.claude.json +$ cd /projects/claude-config +$ git add -A && git commit -m "Update Claude Code configuration" && git push +---- + +.Verification + +. Start a workspace with the devfile containing the configuration repository. +. Verify Claude Code starts with the expected configuration (settings, MCP servers, plugins). +. Make a configuration change, sync back to the repository, and push. +. Start a new workspace with the same devfile. Verify the updated configuration is available. + +== Advantages + +* No RWX storage requirement. Each workspace uses its own local storage. +* No multi-attach errors. Concurrent workspaces are not affected. +* Git history provides an audit trail of configuration changes. +* Works across clusters and {prod-short} instances. + +== Limitations + +* Requires a Git repository accessible from the workspace. +* Changes must be committed and pushed to persist. Unsaved changes are lost when the workspace stops. +* Large files such as plugin caches (`{prod-home}/.claude/plugins/cache/`) are not suitable for Git storage. Consider adding them to `.gitignore`. +* Merge conflicts can occur when multiple workspaces push changes to the same branch concurrently. + +.Additional resources + +* xref:persist-claude-code-configuration.adoc[] +* xref:share-claude-code-configuration-with-pvc-direct-mount.adoc[] +* xref:share-claude-code-configuration-with-pvc-tmp-copy.adoc[] +* xref:troubleshoot-claude-code-configuration-persistence.adoc[] +* xref:authenticating-to-a-git-server-from-a-workspace.adoc[] diff --git a/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-direct-mount.adoc b/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-direct-mount.adoc new file mode 100644 index 0000000000..c34e93d669 --- /dev/null +++ b/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-direct-mount.adoc @@ -0,0 +1,145 @@ +:_content-type: PROCEDURE +:description: Share Claude Code configuration across {prod-short} workspaces by mounting a dedicated PVC directly to the configuration paths. +:keywords: user-guide, claude-code, ai, configuration, persistence, pvc, direct-mount +:navtitle: Share configuration with PVC direct mount +:page-aliases: + +[id="share-claude-code-configuration-with-pvc-direct-mount"] += Share Claude Code configuration with PVC direct mount + +Both `{prod-home}/.claude/` and `{prod-home}/.claude.json` are mounted directly from a dedicated PVC. All changes persist automatically. + +The direct mount flow: + +. A one-time init pod creates an empty skeleton on the PVC: `{}` in `.claude.json` and an empty `.claude/` directory. +. The first workspace starts. The PVC mounts to `{prod-home}/.claude/` and `{prod-home}/.claude.json`. Claude Code sees valid, empty configuration. +. You configure Claude Code — install plugins, add MCP servers, change settings. All writes go directly to the PVC. +. The second workspace starts. The same PVC mounts, and all configuration from the previous workspace is available. + +For a comparison with other approaches, see xref:persist-claude-code-configuration.adoc[]. + +.Prerequisites + +* An active `{orch-cli}` session with permissions to create PVCs in your {orch-namespace}. See {orch-cli-link}. + +* Claude Code installed in the workspace container image. + +* For concurrent workspaces: a storage class that supports `ReadWriteMany` (RWX) access mode, such as AWS EFS or NFS. Standard block storage (gp2, gp3) supports only `ReadWriteOnce` (RWO). + +.Procedure + +. Create a file `claude-config-pvc.yaml` with the following PVC definition: ++ +==== +[source,yaml,subs="+quotes,+attributes"] +---- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: claude-config + annotations: + controller.devfile.io/mount-path: >- + [{"path":"{prod-home}/.claude","subPath":".claude"}, + {"path":"{prod-home}/.claude.json","subPath":".claude.json"}] + labels: + controller.devfile.io/mount-to-devworkspace: 'true' +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi +---- +==== + +. Apply the PVC to your {orch-namespace}: ++ +[subs="+quotes,+attributes"] +---- +$ {orch-cli} apply -f claude-config-pvc.yaml -n ____ +---- + +. Create the init pod to initialize the PVC. ++ +The `{prod-home}/.claude.json` subPath target must exist as a *file* on the PVC before any workspace starts. Without this step, {kubernetes} kubelet creates a directory instead of a file, and Claude Code fails to parse it. ++ +Create a file `claude-config-init-pod.yaml`: ++ +==== +[source,yaml,subs="+quotes,+attributes"] +---- +apiVersion: v1 +kind: Pod +metadata: + name: claude-config-init +spec: + restartPolicy: Never + containers: + - image: registry.access.redhat.com/ubi9/ubi-minimal + name: init + command: + - sh + - -c + - | + mkdir -p /mnt/.claude + echo '{}' > /mnt/.claude.json + echo "=== Initialization complete ===" + ls -la /mnt/ + volumeMounts: + - mountPath: /mnt + name: vol + volumes: + - name: vol + persistentVolumeClaim: + claimName: claude-config +---- +==== + +. Apply the init pod: ++ +[subs="+quotes,+attributes"] +---- +$ {orch-cli} apply -f claude-config-init-pod.yaml -n ____ +---- + +. Wait for the pod to complete: ++ +[subs="+quotes,+attributes"] +---- +$ {orch-cli} wait pod/claude-config-init --for=condition=Ready --timeout=120s +---- + +. Verify the initialization: ++ +[subs="+quotes,+attributes"] +---- +$ {orch-cli} logs claude-config-init +---- + +. Delete the init pod: ++ +[subs="+quotes,+attributes"] +---- +$ {orch-cli} delete pod claude-config-init +---- + +. Start any workspace. The PVC auto-mounts into every workspace pod. + +[WARNING] +==== +On multi-AZ clusters using `WaitForFirstConsumer` storage classes (gp2, gp3), the init pod may bind the PV to a different availability zone than workspace pods. See xref:troubleshoot-claude-code-configuration-persistence.adoc#pvc-scheduling-failure-after-init-pod-setup[PVC scheduling failure after init pod setup]. +==== + +.Verification + +. Start a workspace and configure Claude Code (add an MCP server, install a plugin, or modify settings). +. Stop and restart the workspace. Verify the configuration is preserved. +. Start a different workspace. Verify the same configuration is available. + +.Additional resources + +* xref:persist-claude-code-configuration.adoc[] +* xref:share-claude-code-configuration-with-pvc-tmp-copy.adoc[] +* xref:share-claude-code-configuration-with-gitops.adoc[] +* xref:troubleshoot-claude-code-configuration-persistence.adoc[] +* xref:requesting-persistent-storage-for-workspaces.adoc[] diff --git a/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-tmp-copy.adoc b/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-tmp-copy.adoc new file mode 100644 index 0000000000..f03f5568f8 --- /dev/null +++ b/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-tmp-copy.adoc @@ -0,0 +1,103 @@ +:_content-type: PROCEDURE +:description: Share Claude Code configuration across {prod-short} workspaces by copying files from a dedicated PVC mounted at /tmp. +:keywords: user-guide, claude-code, ai, configuration, persistence, pvc, tmp-copy +:navtitle: Share configuration with PVC tmp copy +:page-aliases: + +[id="share-claude-code-configuration-with-pvc-tmp-copy"] += Share Claude Code configuration with PVC tmp copy + +The entire PVC is mounted at `/tmp/claude`. A `postStart` command copies everything into the home directory. No init pod is required and there are no subPath limitations. Changes must be synced back manually before stopping the workspace. + +The tmp copy flow: + +. The first workspace starts. The PVC mounts at `/tmp/claude` (empty on first run). The `postStart` command copies configuration into `{prod-home}/.claude/` and `{prod-home}/.claude.json`. On first run, nothing is copied. +. You configure Claude Code — install plugins, add MCP servers, change settings. All writes go to the home directory, not the PVC. +. Before stopping the workspace, you sync changes back to the PVC at `/tmp/claude`. +. The second workspace starts. The `postStart` command copies the saved configuration from the PVC into the home directory. + +For a comparison with other approaches, see xref:persist-claude-code-configuration.adoc[]. + +.Prerequisites + +* An active `{orch-cli}` session with permissions to create PVCs in your {orch-namespace}. See {orch-cli-link}. + +* Claude Code installed in the workspace container image. + +* For concurrent workspaces: a storage class that supports `ReadWriteMany` (RWX) access mode, such as AWS EFS or NFS. Standard block storage (gp2, gp3) supports only `ReadWriteOnce` (RWO). + +.Procedure + +. Create a file `claude-config-pvc.yaml` with the following PVC definition: ++ +==== +[source,yaml,subs="+quotes,+attributes"] +---- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: claude-config + annotations: + controller.devfile.io/mount-path: '[{"path":"/tmp/claude","subPath":"claude"}]' + labels: + controller.devfile.io/mount-to-devworkspace: 'true' +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi +---- +==== + +. Apply the PVC to your {orch-namespace}: ++ +[subs="+quotes,+attributes"] +---- +$ {orch-cli} apply -f claude-config-pvc.yaml -n ____ +---- + +. Add a `postStart` command to your devfile to copy all configuration from the PVC into the home directory: ++ +==== +[source,yaml,subs="+quotes,+attributes"] +---- +commands: + - id: init-claude-config + exec: + commandLine: | + mkdir -p {prod-home}/.claude + cp -a /tmp/claude/.claude/. {prod-home}/.claude/ 2>/dev/null || true + cp /tmp/claude/.claude.json {prod-home}/.claude.json 2>/dev/null || true + component: ____ # <1> +events: + postStart: + - init-claude-config +---- +<1> Replace with the name of your editor container component in the devfile. +==== + +. Start the workspace. + +. Before stopping the workspace, sync changes back to the PVC: ++ +[subs="+quotes,+attributes"] +---- +$ cp -a {prod-home}/.claude/. /tmp/claude/.claude/ && \ + cp {prod-home}/.claude.json /tmp/claude/.claude.json +---- + +.Verification + +. Start a workspace and configure Claude Code. +. Sync changes back to the PVC. +. Start a different workspace. +. Verify that the Claude Code configuration from the first workspace is available. + +.Additional resources + +* xref:persist-claude-code-configuration.adoc[] +* xref:share-claude-code-configuration-with-pvc-direct-mount.adoc[] +* xref:share-claude-code-configuration-with-gitops.adoc[] +* xref:troubleshoot-claude-code-configuration-persistence.adoc[] +* xref:requesting-persistent-storage-for-workspaces.adoc[] diff --git a/modules/end-user-guide/pages/sharing-claude-code-configuration-with-a-dedicated-pvc.adoc b/modules/end-user-guide/pages/sharing-claude-code-configuration-with-a-dedicated-pvc.adoc deleted file mode 100644 index 92d7f90bfd..0000000000 --- a/modules/end-user-guide/pages/sharing-claude-code-configuration-with-a-dedicated-pvc.adoc +++ /dev/null @@ -1,262 +0,0 @@ -:_content-type: PROCEDURE -:description: Share Claude Code configuration across {prod-short} workspaces by using a dedicated PVC with automount. -:keywords: user-guide, claude-code, ai, configuration, persistence, pvc, automount -:navtitle: Sharing configuration with a dedicated PVC -:page-aliases: - -[id="sharing-claude-code-configuration-with-a-dedicated-pvc"] -= Sharing Claude Code configuration across workspaces with a dedicated PVC - -A dedicated PVC in the user {orch-namespace} shares Claude Code configuration across all workspaces. The {devworkspace} Operator automatically mounts PVCs labeled with `controller.devfile.io/mount-to-devworkspace: true` into every workspace pod. - -Two options are available: - -* *Option A: Direct mount* — both `{prod-home}/.claude/` and `{prod-home}/.claude.json` are mounted directly from the PVC. All changes persist automatically. Requires a one-time init pod to pre-create `.claude.json`. -* *Option B: Full `/tmp` copy* — the entire PVC is mounted at `/tmp/claude`. A `postStart` command copies everything into the home directory. No init pod is required, but changes must be synced back manually before stopping the workspace. - -|=== -| Feature | Option A: Direct mount | Option B: Full `/tmp` copy - -| Init pod required -| Yes (one-time) -| No - -| `postStart` required -| No -| Yes - -| Manual sync before stop -| No -| Yes - -| AZ affinity risk -| Yes (RWO on multi-AZ clusters) -| Yes (RWO on multi-AZ clusters) -|=== - -For an overview of all approaches, see xref:persisting-claude-code-configuration.adoc[]. - -.Prerequisites - -* An active `{orch-cli}` session with permissions to create PVCs in your {orch-namespace}. See {orch-cli-link}. - -* Claude Code installed in the workspace container image. - -* For concurrent workspaces: a storage class that supports `ReadWriteMany` (RWX) access mode, such as AWS EFS or NFS. Standard block storage (gp2, gp3) supports only `ReadWriteOnce` (RWO). - -== Option A: Direct mount - -All Claude Code configuration is mounted directly from the PVC. Changes persist automatically without any `postStart` commands or manual sync steps. - -=== Creating the PVC - -. Create a file `claude-config-pvc.yaml` with the following PVC definition: -+ -==== -[source,yaml,subs="+quotes,+attributes"] ----- -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: claude-config - annotations: - controller.devfile.io/mount-path: >- - [{"path":"{prod-home}/.claude","subPath":".claude"}, - {"path":"{prod-home}/.claude.json","subPath":".claude.json"}] - labels: - controller.devfile.io/mount-to-devworkspace: 'true' -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 1Gi ----- -==== - -. Apply the PVC to your {orch-namespace}: -+ -[subs="+quotes,+attributes"] ----- -$ {orch-cli} apply -f claude-config-pvc.yaml -n ____ ----- - -=== Initializing the PVC with an init pod - -The `{prod-home}/.claude.json` subPath target must exist as a *file* on the PVC before any workspace starts. Without this step, {kubernetes} kubelet creates a directory instead of a file, and Claude Code fails to parse it. - -. Create a file `claude-config-init-pod.yaml` with the following pod definition: -+ -==== -[source,yaml,subs="+quotes,+attributes"] ----- -apiVersion: v1 -kind: Pod -metadata: - name: claude-config-init -spec: - containers: - - image: registry.access.redhat.com/ubi9/ubi-minimal - name: init - command: - - sh - - -c - - | - mkdir -p /mnt/.claude - echo '{}' > /mnt/.claude.json - echo "=== Initialization complete ===" - ls -la /mnt/ - tail -f /dev/null - volumeMounts: - - mountPath: /mnt - name: vol - volumes: - - name: vol - persistentVolumeClaim: - claimName: claude-config ----- -==== - -. Apply the init pod, wait for it to initialize, verify, and delete: -+ -[subs="+quotes,+attributes"] ----- -$ {orch-cli} apply -f claude-config-init-pod.yaml -n ____ -$ {orch-cli} wait pod/claude-config-init --for=condition=Ready --timeout=120s -$ {orch-cli} logs claude-config-init -$ {orch-cli} delete pod claude-config-init ----- - -=== Using workspaces - -Start any workspace. The PVC auto-mounts into every workspace pod. Claude Code finds its configuration at `{prod-home}/.claude/` and `{prod-home}/.claude.json` on startup. All changes, including new MCP servers, plugins, and settings, are written directly to the PVC and available in every workspace. - -No `postStart` commands or manual sync steps are required. - -[WARNING] -==== -On multi-AZ clusters using `WaitForFirstConsumer` storage classes (gp2, gp3), the init pod may bind the PV to a different availability zone than workspace pods. See xref:troubleshooting-claude-code-configuration-persistence.adoc#pvc-scheduling-failure-after-init-pod-setup[PVC scheduling failure after init pod setup]. -==== - -=== Verification - -. Start a workspace and configure Claude Code (add an MCP server, install a plugin, or modify settings). -. Stop and restart the workspace. Verify the configuration is preserved. -. Start a different workspace. Verify the same configuration is available. - -== Option B: Full `/tmp` copy - -The entire PVC is mounted at `/tmp/claude`. A `postStart` command copies everything into the home directory. No init pod is required and there are no subPath limitations. - -=== Creating the PVC - -. Create a file `claude-config-pvc.yaml` with the following PVC definition: -+ -==== -[source,yaml,subs="+quotes,+attributes"] ----- -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: claude-config - annotations: - controller.devfile.io/mount-path: '[{"path":"/tmp/claude","subPath":"claude"}]' - labels: - controller.devfile.io/mount-to-devworkspace: 'true' -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 1Gi ----- -==== - -. Apply the PVC to your {orch-namespace}: -+ -[subs="+quotes,+attributes"] ----- -$ {orch-cli} apply -f claude-config-pvc.yaml -n ____ ----- - -=== Adding a `postStart` command to copy configurations - -Add a `postStart` command to your devfile to copy all configuration from the PVC into the home directory: - -==== -[source,yaml,subs="+quotes,+attributes"] ----- -commands: - - id: init-claude-config - exec: - commandLine: | - mkdir -p {prod-home}/.claude - cp -a /tmp/claude/.claude/. {prod-home}/.claude/ 2>/dev/null || true - cp /tmp/claude/.claude.json {prod-home}/.claude.json 2>/dev/null || true - component: ____ # <1> -events: - postStart: - - init-claude-config ----- -<1> Replace with the name of your editor container component in the devfile. -==== - -=== Syncing changes before stopping - -Changes to both `{prod-home}/.claude/` and `{prod-home}/.claude.json` are written to the home directory, not the PVC. Sync everything back before stopping: - -[subs="+quotes,+attributes"] ----- -$ cp -a {prod-home}/.claude/. /tmp/claude/.claude/ && \ - cp {prod-home}/.claude.json /tmp/claude/.claude.json ----- - -=== Verification - -. Start a workspace and configure Claude Code. -. Sync changes back to the PVC. -. Start a different workspace. -. Verify that the Claude Code configuration from the first workspace is available. - -== Shared options for both variants - -=== Filtering by workspace name - -Control which workspaces mount the PVC by adding annotations: - -[source,yaml,subs="+quotes,+attributes"] ----- -annotations: - controller.devfile.io/mount-to-devworkspace-include: '____' # <1> - controller.devfile.io/mount-to-devworkspace-exclude: '____' # <2> ----- -<1> Mount the PVC only to workspaces whose names match the pattern. -<2> Mount the PVC to all workspaces except those whose names match the pattern. - -Supported patterns: `*` (all), `prefix*`, `*suffix`, `*contains*`, `exact-name`. Matching is on the {devworkspace} resource name. - -=== Concurrent workspaces - -|=== -| Access mode | Behavior - -| ReadWriteOnce (RWO) -| One workspace at a time. Two workspaces on different nodes cause a multi-attach error. - -| ReadWriteMany (RWX) -| Concurrent workspaces work. Requires a storage class that supports RWX, such as AWS EFS or NFS. Standard block storage (gp2, gp3) does not support RWX. -|=== - -== Limitations - -* Requires manual PVC setup per user {orch-namespace}. -* Can be combined with `persistUserHome`. The dedicated PVC at `{prod-home}/.claude` and the persistent home PVC at `{prod-home}/` coexist correctly as nested mounts. -* RWX storage may not be available on all clusters. -* On clusters with only block storage and multi-AZ topology, the Option A init pod may cause scheduling failures. Use Option B instead. - -.Additional resources - -* xref:persisting-claude-code-configuration.adoc[] -* xref:sharing-claude-code-configuration-with-gitops.adoc[] -* xref:troubleshooting-claude-code-configuration-persistence.adoc[] -* xref:requesting-persistent-storage-for-workspaces.adoc[] diff --git a/modules/end-user-guide/pages/sharing-claude-code-configuration-with-gitops.adoc b/modules/end-user-guide/pages/sharing-claude-code-configuration-with-gitops.adoc deleted file mode 100644 index e1f6e9f9b1..0000000000 --- a/modules/end-user-guide/pages/sharing-claude-code-configuration-with-gitops.adoc +++ /dev/null @@ -1,43 +0,0 @@ -:_content-type: CONCEPT -:description: Share Claude Code configuration across {prod-short} workspaces by storing it in a Git repository. -:keywords: user-guide, claude-code, ai, configuration, persistence, gitops, git -:navtitle: Sharing configuration with GitOps -:page-aliases: - -[id="sharing-claude-code-configuration-with-gitops"] -= Sharing Claude Code configuration across workspaces with GitOps - -Instead of using a shared PVC, you can store Claude Code configuration in a Git repository and pull it into workspaces at startup. Each workspace gets its own isolated, writable copy of the configuration. - -This approach eliminates multi-attach errors and last-write-wins data corruption risks that can occur with shared PVCs on clusters without RWX storage. - -== How it works - -A central Git repository stores the baseline Claude Code configuration. The repository is listed in the `projects` section of the devfile, and the {devworkspace} Operator's project-clone init container clones it automatically at workspace startup. A `postStart` command then copies the configuration files from the cloned repository into the home directory. - -Two usage patterns are possible: - -* *Read-only baseline* — administrators maintain a shared repository with team-wide settings such as security hooks, API proxies, and approved plugins. The configuration is cloned at startup and copied into the home directory. Developers do not push changes back. This is suitable for enforcing organization-wide policies. - -* *User-specific persistence* — each developer maintains a private branch or repository with personal configuration. The repository is cloned at startup and copied into the home directory. Optionally, a `preStop` command or manual step commits and pushes changes back before the workspace stops. - -== Advantages - -* No RWX storage requirement. Each workspace uses its own local storage. -* No multi-attach errors. Concurrent workspaces are not affected. -* Git history provides an audit trail of configuration changes. -* Works across clusters and {prod-short} instances. - -== Limitations - -* Requires a Git repository accessible from the workspace. -* Changes must be committed and pushed to persist. Unsaved changes are lost when the workspace stops. -* Large files such as plugin caches (`~/.claude/plugins/cache/`) are not suitable for Git storage. Consider adding them to `.gitignore`. -* Merge conflicts can occur when multiple workspaces push changes to the same branch concurrently. - -.Additional resources - -* xref:persisting-claude-code-configuration.adoc[] -* xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[] -* xref:troubleshooting-claude-code-configuration-persistence.adoc[] -* xref:authenticating-to-a-git-server-from-a-workspace.adoc[] diff --git a/modules/end-user-guide/pages/troubleshooting-claude-code-configuration-persistence.adoc b/modules/end-user-guide/pages/troubleshoot-claude-code-configuration-persistence.adoc similarity index 72% rename from modules/end-user-guide/pages/troubleshooting-claude-code-configuration-persistence.adoc rename to modules/end-user-guide/pages/troubleshoot-claude-code-configuration-persistence.adoc index 551ebfc2f9..47339d4923 100644 --- a/modules/end-user-guide/pages/troubleshooting-claude-code-configuration-persistence.adoc +++ b/modules/end-user-guide/pages/troubleshoot-claude-code-configuration-persistence.adoc @@ -1,13 +1,13 @@ :_content-type: REFERENCE -:description: Troubleshoot known issues with persisting Claude Code configuration in {prod-short} workspaces. +:description: Diagnose and resolve issues with persisting Claude Code configuration in {prod-short} workspaces. :keywords: user-guide, claude-code, ai, configuration, persistence, troubleshooting -:navtitle: Troubleshooting Claude Code configuration persistence -:page-aliases: +:navtitle: Troubleshoot Claude Code configuration persistence +:page-aliases: troubleshooting-claude-code-configuration-persistence.adoc -[id="troubleshooting-claude-code-configuration-persistence"] -= Troubleshooting Claude Code configuration persistence +[id="troubleshoot-claude-code-configuration-persistence"] += Troubleshoot Claude Code configuration persistence -This section describes known issues with persisting Claude Code configuration in {prod-short} workspaces and how to resolve them. +If you encounter issues with Claude Code configuration persistence in {prod-short} workspaces, use the following symptoms and solutions to diagnose and resolve them. == `.claude.json` corrupted on first start @@ -49,7 +49,7 @@ When a PVC `subPath` mount target does not exist on the volume, {kubernetes} kub === Solution -Do not mount `{prod-home}/.claude.json` as a direct subPath from a PVC without pre-creating the file. Either use an init pod to pre-create it (Option A) or use the `/tmp` copy pattern (Option B). See xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[]. +Do not mount `{prod-home}/.claude.json` as a direct subPath from a PVC without pre-creating the file. Either use an init pod to pre-create it (xref:share-claude-code-configuration-with-pvc-direct-mount.adoc[direct mount]) or use the xref:share-claude-code-configuration-with-pvc-tmp-copy.adoc[tmp copy] approach. == Permission denied writing to `~/.claude/session-env` @@ -106,14 +106,6 @@ $ {orch-cli} get storageclasses Look for classes using EFS (`efs.csi.aws.com`) or NFS provisioners. -== Dedicated PVC and persistent user home interaction - -A dedicated PVC mounted at `{prod-home}/.claude` and the persistent home PVC mounted at `{prod-home}/` coexist correctly as nested mounts. - -Writes to `~/.claude/` go to the dedicated PVC. Writes to other paths under `{prod-home}/` go to the persistent home PVC. There is no conflict. - -If you only need persistence within a single workspace and not cross-workspace sharing, `persistUserHome` alone is sufficient. A dedicated PVC is not needed. - == Changes to `~/.claude.json` not persisting after restart === Symptom @@ -122,9 +114,9 @@ After restarting a workspace, MCP server configurations added during the previou === Cause -This applies to Option B (full `/tmp` copy) from the xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[dedicated PVC guide]. The `postStart` command copies configurations from the PVC into the home directory. Changes made during the session are written to the home directory, not back to the PVC. +This applies to the xref:share-claude-code-configuration-with-pvc-tmp-copy.adoc[tmp copy] approach. The `postStart` command copies configurations from the PVC into the home directory. Changes made during the session are written to the home directory, not back to the PVC. -Option A (direct mount) does not have this issue because changes are written directly to the PVC. +The xref:share-claude-code-configuration-with-pvc-direct-mount.adoc[direct mount] approach does not have this issue because changes are written directly to the PVC. === Solution @@ -171,10 +163,11 @@ $ {orch-cli} delete pvc ____ -n __<{orch-namespace}>__ ---- . Recreate the PVC and start a workspace. The PV is provisioned in the correct zone. -For clusters where this is a recurring issue, use Option B (full `/tmp` copy) from the xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[dedicated PVC guide], which does not require an init pod. +For clusters where this is a recurring issue, use the xref:share-claude-code-configuration-with-pvc-tmp-copy.adoc[tmp copy] approach, which does not require an init pod. .Additional resources -* xref:persisting-claude-code-configuration.adoc[] -* xref:sharing-claude-code-configuration-with-a-dedicated-pvc.adoc[] -* xref:sharing-claude-code-configuration-with-gitops.adoc[] +* xref:persist-claude-code-configuration.adoc[] +* xref:share-claude-code-configuration-with-pvc-direct-mount.adoc[] +* xref:share-claude-code-configuration-with-pvc-tmp-copy.adoc[] +* xref:share-claude-code-configuration-with-gitops.adoc[] From 47370cdbebdad71f0777e8a8248ec50784347347 Mon Sep 17 00:00:00 2001 From: Oleksii Kurinnyi Date: Tue, 7 Jul 2026 13:04:34 +0300 Subject: [PATCH 3/3] docs: Address tolusha's review feedback - Add DWO automount docs link to additional resources - Fix asterisk rendering in pattern list - Move PVC shared options (filtering, concurrent workspaces, persistUserHome compatibility, limitations) from overview to individual PVC procedure pages - Add include/exclude annotations as multi-attach workaround in troubleshooting - Add prerequisite about stopping workspaces before PVC creation on direct mount page Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Oleksii Kurinnyi --- .../persist-claude-code-configuration.adoc | 44 +------------------ ...e-configuration-with-pvc-direct-mount.adoc | 41 +++++++++++++++++ ...-code-configuration-with-pvc-tmp-copy.adoc | 39 ++++++++++++++++ ...claude-code-configuration-persistence.adoc | 1 + 4 files changed, 82 insertions(+), 43 deletions(-) diff --git a/modules/end-user-guide/pages/persist-claude-code-configuration.adoc b/modules/end-user-guide/pages/persist-claude-code-configuration.adoc index 609b160568..dd0be2788d 100644 --- a/modules/end-user-guide/pages/persist-claude-code-configuration.adoc +++ b/modules/end-user-guide/pages/persist-claude-code-configuration.adoc @@ -45,49 +45,6 @@ Claude Code writes runtime state to both paths during every session, including s | A Git repository stores the baseline Claude Code configuration. The {devworkspace} Operator clones the repository at startup, and a `postStart` command copies the configuration into the home directory. |=== -== PVC shared options - -The following options apply to both PVC approaches (direct mount and tmp copy). - -=== Filtering by workspace name - -Control which workspaces mount the PVC by adding annotations: - -[source,yaml,subs="+quotes,+attributes"] ----- -annotations: - controller.devfile.io/mount-to-devworkspace-include: '____' # <1> - controller.devfile.io/mount-to-devworkspace-exclude: '____' # <2> ----- -<1> Mount the PVC only to workspaces whose names match the pattern. -<2> Mount the PVC to all workspaces except those whose names match the pattern. - -Supported patterns: `*` (all), `prefix*`, `*suffix`, `*contains*`, `exact-name`. Matching is on the {devworkspace} resource name. - -=== Concurrent workspaces - -|=== -| Access mode | Behavior - -| ReadWriteOnce (RWO) -| One workspace at a time. Two workspaces on different nodes cause a multi-attach error. - -| ReadWriteMany (RWX) -| Concurrent workspaces work. Requires a storage class that supports RWX, such as AWS EFS or NFS. Standard block storage (gp2, gp3) does not support RWX. -|=== - -=== Compatibility with `persistUserHome` - -A dedicated PVC mounted at `{prod-home}/.claude` and the persistent home PVC mounted at `{prod-home}/` coexist correctly as nested mounts. Writes to `{prod-home}/.claude/` go to the dedicated PVC. Writes to other paths under `{prod-home}/` go to the persistent home PVC. - -If you only need persistence within a single workspace and not cross-workspace sharing, `persistUserHome` alone is sufficient. - -=== Limitations - -* Requires manual PVC setup per user {orch-namespace}. -* RWX storage may not be available on all clusters. -* On clusters with only block storage and multi-AZ topology, the direct mount init pod may cause scheduling failures. Use the tmp copy approach instead. - == Claude Code file reference |=== @@ -150,3 +107,4 @@ If you only need persistence within a single workspace and not cross-workspace s * xref:share-claude-code-configuration-with-pvc-tmp-copy.adoc[] * xref:share-claude-code-configuration-with-gitops.adoc[] * xref:troubleshoot-claude-code-configuration-persistence.adoc[] +* link:https://github.com/devfile/devworkspace-operator/blob/main/docs/additional-configuration.adoc#automatically-mounting-volumes-configmaps-and-secrets[Automatically mounting volumes, configmaps, and secrets] diff --git a/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-direct-mount.adoc b/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-direct-mount.adoc index c34e93d669..0f2c82a866 100644 --- a/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-direct-mount.adoc +++ b/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-direct-mount.adoc @@ -26,6 +26,8 @@ For a comparison with other approaches, see xref:persist-claude-code-configurati * For concurrent workspaces: a storage class that supports `ReadWriteMany` (RWX) access mode, such as AWS EFS or NFS. Standard block storage (gp2, gp3) supports only `ReadWriteOnce` (RWO). +* All running workspaces must be stopped before creating the PVC. If a workspace is running when the PVC with the automount label is created, `{prod-home}/.claude.json` may be mounted as a directory instead of a file. + .Procedure . Create a file `claude-config-pvc.yaml` with the following PVC definition: @@ -136,6 +138,45 @@ On multi-AZ clusters using `WaitForFirstConsumer` storage classes (gp2, gp3), th . Stop and restart the workspace. Verify the configuration is preserved. . Start a different workspace. Verify the same configuration is available. +== Filtering by workspace name + +Control which workspaces mount the PVC by adding annotations: + +[source,yaml,subs="+quotes,+attributes"] +---- +annotations: + controller.devfile.io/mount-to-devworkspace-include: '____' # <1> + controller.devfile.io/mount-to-devworkspace-exclude: '____' # <2> +---- +<1> Mount the PVC only to workspaces whose names match the pattern. +<2> Mount the PVC to all workspaces except those whose names match the pattern. + +Supported patterns: exact match (`name`), prefix (`name\*`), suffix (`\*name`), contains (`\*name\*`). Matching is on the {devworkspace} resource name. + +== Concurrent workspaces + +|=== +| Access mode | Behavior + +| ReadWriteOnce (RWO) +| One workspace at a time. Two workspaces on different nodes cause a multi-attach error. + +| ReadWriteMany (RWX) +| Concurrent workspaces work. Requires a storage class that supports RWX, such as AWS EFS or NFS. Standard block storage (gp2, gp3) does not support RWX. +|=== + +== Compatibility with `persistUserHome` + +A dedicated PVC mounted at `{prod-home}/.claude` and the persistent home PVC mounted at `{prod-home}/` coexist correctly as nested mounts. Writes to `{prod-home}/.claude/` go to the dedicated PVC. Writes to other paths under `{prod-home}/` go to the persistent home PVC. + +If you only need persistence within a single workspace and not cross-workspace sharing, `persistUserHome` alone is sufficient. + +== Limitations + +* Requires manual PVC setup per user {orch-namespace}. +* RWX storage may not be available on all clusters. +* On clusters with only block storage and multi-AZ topology, the init pod may cause scheduling failures. Use the xref:share-claude-code-configuration-with-pvc-tmp-copy.adoc[tmp copy] approach instead. + .Additional resources * xref:persist-claude-code-configuration.adoc[] diff --git a/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-tmp-copy.adoc b/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-tmp-copy.adoc index f03f5568f8..338e039a1b 100644 --- a/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-tmp-copy.adoc +++ b/modules/end-user-guide/pages/share-claude-code-configuration-with-pvc-tmp-copy.adoc @@ -94,6 +94,45 @@ $ cp -a {prod-home}/.claude/. /tmp/claude/.claude/ && \ . Start a different workspace. . Verify that the Claude Code configuration from the first workspace is available. +== Filtering by workspace name + +Control which workspaces mount the PVC by adding annotations: + +[source,yaml,subs="+quotes,+attributes"] +---- +annotations: + controller.devfile.io/mount-to-devworkspace-include: '____' # <1> + controller.devfile.io/mount-to-devworkspace-exclude: '____' # <2> +---- +<1> Mount the PVC only to workspaces whose names match the pattern. +<2> Mount the PVC to all workspaces except those whose names match the pattern. + +Supported patterns: exact match (`name`), prefix (`name\*`), suffix (`\*name`), contains (`\*name\*`). Matching is on the {devworkspace} resource name. + +== Concurrent workspaces + +|=== +| Access mode | Behavior + +| ReadWriteOnce (RWO) +| One workspace at a time. Two workspaces on different nodes cause a multi-attach error. + +| ReadWriteMany (RWX) +| Concurrent workspaces work. Requires a storage class that supports RWX, such as AWS EFS or NFS. Standard block storage (gp2, gp3) does not support RWX. +|=== + +== Compatibility with `persistUserHome` + +A dedicated PVC mounted at `{prod-home}/.claude` and the persistent home PVC mounted at `{prod-home}/` coexist correctly as nested mounts. Writes to `{prod-home}/.claude/` go to the dedicated PVC. Writes to other paths under `{prod-home}/` go to the persistent home PVC. + +If you only need persistence within a single workspace and not cross-workspace sharing, `persistUserHome` alone is sufficient. + +== Limitations + +* Requires manual PVC setup per user {orch-namespace}. +* RWX storage may not be available on all clusters. +* Changes must be synced back to the PVC manually before stopping the workspace. Unsaved changes are lost. + .Additional resources * xref:persist-claude-code-configuration.adoc[] diff --git a/modules/end-user-guide/pages/troubleshoot-claude-code-configuration-persistence.adoc b/modules/end-user-guide/pages/troubleshoot-claude-code-configuration-persistence.adoc index 47339d4923..cc06fe2308 100644 --- a/modules/end-user-guide/pages/troubleshoot-claude-code-configuration-persistence.adoc +++ b/modules/end-user-guide/pages/troubleshoot-claude-code-configuration-persistence.adoc @@ -96,6 +96,7 @@ Choose one of the following: * Run only one workspace at a time. * Use `ReadWriteMany` (RWX) access mode with a storage class that supports it, such as AWS EFS or NFS. Standard block storage classes (gp2, gp3) do not support RWX. +* Use `controller.devfile.io/mount-to-devworkspace-include` or `controller.devfile.io/mount-to-devworkspace-exclude` annotations on the PVC to control which workspaces mount it. See xref:share-claude-code-configuration-with-pvc-direct-mount.adoc#_filtering_by_workspace_name[Filtering by workspace name]. To check available storage classes: