<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Coding-Assistant on Stephan Michard</title><link>/tags/coding-assistant/</link><description>Recent content in Coding-Assistant on Stephan Michard</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Sun, 13 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="/tags/coding-assistant/" rel="self" type="application/rss+xml"/><item><title>AI-Assisted Coding with OpenShift Dev Spaces</title><link>/2026/ai-assisted-coding-with-openshift-dev-spaces/</link><pubDate>Sun, 13 Sep 2026 00:00:00 +0000</pubDate><guid>/2026/ai-assisted-coding-with-openshift-dev-spaces/</guid><description>&lt;figure&gt;&lt;img
src="/images/posts/post_35/overview_hu_99dd94ba024733fc.webp"
srcset="/images/posts/post_35/overview_hu_3fa6d3adf2aab97d.webp 480w, /images/posts/post_35/overview_hu_eb57dc7f5dbcf98b.webp 800w, /images/posts/post_35/overview_hu_99dd94ba024733fc.webp 1400w"
sizes="(max-width: 42rem) 100vw, 42rem"
width="1400"
height="781"
alt="Comparison between legacy local development and OpenShift Dev Spaces with in-cluster RHAIIS inference — AI generated"
loading="lazy"
decoding="async" title="Comparison between legacy local development and OpenShift Dev Spaces with in-cluster RHAIIS inference — AI generated"&gt;&lt;figcaption&gt;
&lt;h4&gt;Comparison between legacy local development and OpenShift Dev Spaces with in-cluster RHAIIS inference — AI generated&lt;/h4&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this post, I want to describe how to configure &lt;em&gt;Red Hat OpenShift Dev Spaces&lt;/em&gt; for AI-assisted code generation with a private model server by connecting a coding assistant extension to the &lt;em&gt;Red Hat AI Inference Server (RHAIIS)&lt;/em&gt; running on the same cluster. Team mates published a &lt;a href="https://www.opensourcerers.org/2023/11/06/a-personal-ai-assistant-for-developers-that-doesnt-phone-home/" target="_blank" rel="noopener noreferrer"&gt;similar setup&lt;/a&gt;
more than two years ago, using Ollama as the local inference server. The idea was to give developers an AI coding assistant that never sends data to an external API. That principle still applies.&lt;/p&gt;
&lt;p&gt;This post updates the pattern with a different backend. The RHAIIS deploymend was covered in an &lt;a href="/2026/running-the-red-hat-ai-inference-server-on-openshift/"&gt;earlier post in this series&lt;/a&gt;
. The model request goes to an internal Kubernetes service address and never leaves the cluster network.&lt;/p&gt;
&lt;h2 id="openshift-dev-spaces"&gt;OpenShift Dev Spaces&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;OpenShift Dev Spaces&lt;/em&gt; is Red Hat&amp;rsquo;s cloud development environment solution. The upstream project is &lt;a href="https://eclipse.dev/che/" target="_blank" rel="noopener noreferrer"&gt;Ecliptse Che&lt;/a&gt;
. Dev Spaces is available through OperatorHub and is included with an OpenShift subscription.&lt;/p&gt;
&lt;p&gt;After installing the operator, the next step is creating a &lt;em&gt;CheCluster&lt;/em&gt; resource, which provisions the Dev Spaces control plane. Once it is up, the Dev Spaces interface is accessible through the OpenShift web console via the application launcher in the top-right corner.&lt;/p&gt;
&lt;figure&gt;&lt;img
src="/images/posts/post_35/launch_devspaces_hu_ea8e4a2ca4b0266.webp"
srcset="/images/posts/post_35/launch_devspaces_hu_4b9cfc3bf63a53fc.webp 480w, /images/posts/post_35/launch_devspaces_hu_7ec39df5bb3dd09c.webp 800w, /images/posts/post_35/launch_devspaces_hu_ea8e4a2ca4b0266.webp 1400w"
sizes="(max-width: 42rem) 100vw, 42rem"
width="1400"
height="979"
alt="OpenShift web console application launcher with the Red Hat OpenShift Dev Spaces menu entry"
loading="lazy"
decoding="async" title="OpenShift web console application launcher with the Red Hat OpenShift Dev Spaces menu entry"&gt;&lt;figcaption&gt;
&lt;h4&gt;OpenShift web console application launcher with the Red Hat OpenShift Dev Spaces menu entry&lt;/h4&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The core workflow is simple: paste a git repository URL into the Dev Spaces interface, and the platform creates a containerized workspace from a &lt;code&gt;devfile&lt;/code&gt; in the repository root. The workspace runs as a pod on the same cluster, which is what makes the internal service address approach work. A workspace pod and a RHAIIS pod can reach each other the same way any two pods on the same cluster can.&lt;/p&gt;
&lt;figure&gt;&lt;img
src="/images/posts/post_35/start_workspace_hu_2d59afa2385bd46c.webp"
srcset="/images/posts/post_35/start_workspace_hu_6b0ac449f2104b35.webp 480w, /images/posts/post_35/start_workspace_hu_39c6154ddac4b937.webp 800w, /images/posts/post_35/start_workspace_hu_2d59afa2385bd46c.webp 1400w"
sizes="(max-width: 42rem) 100vw, 42rem"
width="1400"
height="986"
alt="Create Workspace by providing a git repository link"
loading="lazy"
decoding="async" title="Create Workspace by providing a git repository link"&gt;&lt;figcaption&gt;
&lt;h4&gt;Create Workspace by providing a git repository link&lt;/h4&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="the-devfile"&gt;The devfile&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;devfile&lt;/code&gt; is the environment definition for a Dev Spaces workspace. It declares the container image, resource limits, source mount path, and lifecycle commands. The &lt;a href="https://github.com/smichard/agent_on_ocp" target="_blank" rel="noopener noreferrer"&gt;smichard/agent_on_ocp&lt;/a&gt;
repository, used throughout this series, contains the following &lt;code&gt;devfile.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;schemaVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2.2.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;code-assistant&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;code-assistant&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;controller.devfile.io/storage-type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ephemeral&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;udi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;quay.io/michard/devspaces_base_image:0.1.29&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;memoryLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;4Gi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;memoryRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;2Gi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cpuLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;4000m&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cpuRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;1000m&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mountSources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;sourceMapping&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/projects&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;copyconfig&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;udi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;commandLine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;mkdir -p /home/user/.continue &amp;amp;&amp;amp; cp /projects/agent-on-ocp/continue-config.yaml /home/user/.continue/config.yaml&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;postStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;copyconfig&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A few things to note. The &lt;code&gt;storage-type: ephemeral&lt;/code&gt; attribute means the workspace uses no persistent volume. Each workspace restart begins from a clean container state.&lt;/p&gt;
&lt;p&gt;The custom image &lt;code&gt;quay.io/michard/devspaces_base_image:0.1.29&lt;/code&gt; bundles the tooling the project needs. Using a project-specific image means the workspace is ready to use the moment it starts, without any post-launch installation steps.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;postStart&lt;/code&gt; event runs the &lt;code&gt;copyconfig&lt;/code&gt; command every time the workspace starts. It copies &lt;code&gt;continue-config.yaml&lt;/code&gt; from the project directory to &lt;code&gt;~/.continue/config.yaml&lt;/code&gt;, which is where the Continue extension reads its configuration. Because the config lives in the repository, any update to it is picked up the next time someone opens a workspace from that repository.&lt;/p&gt;
&lt;h2 id="the-continue-configuration"&gt;The Continue configuration&lt;/h2&gt;
&lt;p&gt;The AI coding extension used here is &lt;a href="https://www.continue.dev/" target="_blank" rel="noopener noreferrer"&gt;Continue&lt;/a&gt;
, an open-source VS Code extension that provides chat, inline editing, autocomplete, and agent mode. It is available through &lt;a href="https://open-vsx.org/" target="_blank" rel="noopener noreferrer"&gt;Open VSX&lt;/a&gt;
, which is the extension registry OpenShift Dev Spaces uses. There are other extensions that work with OpenAI-compatible APIs in the same way, Continue is the example in this post. The repository includes VS Code configuration files that instruct the editor to install the extension automatically on workspace startup, so no manual installation is required.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;continue-config.yaml&lt;/code&gt; below is a minimal example. It defines two model entries against the RHAIIS endpoint and a local embedding model. For a full reference of available options, see the &lt;a href="https://docs.continue.dev/reference" target="_blank" rel="noopener noreferrer"&gt;Continue configuration reference&lt;/a&gt;
:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Agent on OCP&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0.1.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;models&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Qwen3 Coder 30B&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;openai&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Qwen/Qwen3-Coder-30B-A3B-Instruct&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiBase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;http://rhaiis-vllm.rhaiis.svc.cluster.local:8000/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ secrets.RHAIIS_API_KEY }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;chat&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;edit&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;apply&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;summarize&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;tool_use&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;defaultCompletionOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Qwen3 Coder 30B Autocomplete&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;openai&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Qwen/Qwen3-Coder-30B-A3B-Instruct&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiBase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;http://rhaiis-vllm.rhaiis.svc.cluster.local:8000/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ secrets.RHAIIS_API_KEY }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;autocomplete&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;autocompleteOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;debounceDelay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;300&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;maxPromptTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;onlyMyCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;defaultCompletionOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;512&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Local Embeddings&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;transformers.js&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;all-MiniLM-L6-v2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;embed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;apiBase&lt;/code&gt; uses the internal Kubernetes DNS name for the RHAIIS service. Since the Dev Spaces workspace runs as a pod on the same cluster, this address resolves without any additional configuration.&lt;/p&gt;
&lt;p&gt;The config separates the chat and autocomplete roles into two model entries. Autocomplete benefits from lower temperature and a shorter token budget to keep response latency acceptable. The local embedding model handles context search without calling the inference server at all.&lt;/p&gt;
&lt;p&gt;The full configuration also includes a set of context providers (file, diff, terminal, repository map, and others), custom prompt templates for tasks like OpenShift manifest review and security scanning, and rules that constrain suggestions toward &lt;code&gt;oc&lt;/code&gt; CLI examples and away from committing secrets.&lt;/p&gt;
&lt;h2 id="adding-the-api-key"&gt;Adding the API Key&lt;/h2&gt;
&lt;p&gt;The one piece that cannot live in the repository is the API key. Continue reads secrets from a &lt;code&gt;.continue/.env&lt;/code&gt; file in the project directory. The key is the RHAIIS API key that was created when the inference server was deployed.&lt;/p&gt;
&lt;p&gt;Inside the Dev Spaces workspace terminal, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p .continue
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;oc get secret vllm-api-key-secret -n rhaiis -o &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{.data.VLLM_API_KEY}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; base64 -d &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;{print &amp;#34;RHAIIS_API_KEY=&amp;#34;$0}&amp;#39;&lt;/span&gt; &amp;gt; .continue/.env
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This retrieves the key from the &lt;code&gt;rhaiis&lt;/code&gt; namespace and writes it to &lt;code&gt;.continue/.env&lt;/code&gt; as &lt;code&gt;RHAIIS_API_KEY=&amp;lt;value&amp;gt;&lt;/code&gt;. Continue picks it up wherever &lt;code&gt;${{ secrets.RHAIIS_API_KEY }}&lt;/code&gt; appears in the config.&lt;/p&gt;
&lt;p&gt;If the extension does not connect immediately, reload the browser tab. Continue reads its configuration and secrets at startup, and a fresh page load is sometimes needed after the &lt;code&gt;.env&lt;/code&gt; file is created.&lt;/p&gt;
&lt;p&gt;Because the workspace uses ephemeral storage, the &lt;code&gt;.env&lt;/code&gt; file does not survive a workspace restart. Running the two commands again after each restart is the only manual step in the workflow.&lt;/p&gt;
&lt;p&gt;Make sure &lt;code&gt;.continue/.env&lt;/code&gt; is listed in the repository&amp;rsquo;s &lt;code&gt;.gitignore&lt;/code&gt; file to avoid accidentally committing it to the git repository.&lt;/p&gt;
&lt;figure&gt;&lt;img
src="/images/posts/post_35/continue_hu_102df57f8c4e6480.webp"
srcset="/images/posts/post_35/continue_hu_61e23c931ef7bfd0.webp 480w, /images/posts/post_35/continue_hu_2a7072b89f90f7ae.webp 800w, /images/posts/post_35/continue_hu_102df57f8c4e6480.webp 1400w"
sizes="(max-width: 42rem) 100vw, 42rem"
width="1400"
height="907"
alt="Continue extension running inside OpenShift Dev Spaces, using a model served by RHAIIS to answer coding questions"
loading="lazy"
decoding="async" title="Continue extension running inside OpenShift Dev Spaces, using a model served by RHAIIS to answer coding questions"&gt;&lt;figcaption&gt;
&lt;h4&gt;Continue extension running inside OpenShift Dev Spaces, using a model served by RHAIIS to answer coding questions&lt;/h4&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;With RHAIIS and Dev Spaces both on the same OpenShift cluster, the complete path from editor to model runs over the internal service network. The repository carries the workspace definition, the tooling, and the AI extension configuration. The only input that cannot come from the repository is the API key, which is one command to retrieve from an existing Kubernetes secret.&lt;/p&gt;
&lt;p&gt;From there, you have a private model on a private cluster available as a coding assistant. The vibe coding can begin.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A personal AI assistant for developers that doesn&amp;rsquo;t phone home - &lt;a href="https://www.opensourcerers.org/2023/11/06/a-personal-ai-assistant-for-developers-that-doesnt-phone-home/" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Running the Red Hat AI Inference Server on OpenShift - &lt;a href="/2026/running-the-red-hat-ai-inference-server-on-openshift/"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Eclipse Che - upstream project - &lt;a href="https://eclipse.dev/che/" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;smichard/agent_on_ocp - GitHub repository - &lt;a href="https://github.com/smichard/agent_on_ocp" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Continue - project site - &lt;a href="https://www.continue.dev/" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Open VSX Registry - &lt;a href="https://open-vsx.org/" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Continue - configuration reference - &lt;a href="https://docs.continue.dev/reference" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Continue - documentation - &lt;a href="https://docs.continue.dev/" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Red Hat OpenShift Dev Spaces - product page - &lt;a href="https://developers.redhat.com/products/openshift-dev-spaces" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Red Hat OpenShift Dev Spaces - documentation - &lt;a href="https://docs.redhat.com/en/documentation/red_hat_openshift_dev_spaces/" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>