<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Phobos Blog</title>
        <link>https://phobos.martian-cloud.io/blog</link>
        <description>Phobos Blog</description>
        <lastBuildDate>Fri, 01 May 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Editor Superpowers for Phobos — Introducing the Language Server and VS Code Extension]]></title>
            <link>https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension</link>
            <guid>https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension</guid>
            <pubDate>Fri, 01 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[The Phobos Language Server and VS Code Extension turn pipeline-template authoring into a guided, type-aware experience: live diagnostics, context-aware completion, hover documentation, code actions, and a pipeline-graph webview — all powered by the same analysis pipeline Phobos itself uses.]]></description>
            <content:encoded><![CDATA[<p>Writing a Phobos pipeline template used to be a "save, run, read the error, fix, repeat" loop. Today we're shipping the <strong>Phobos Language Server</strong> and <strong>VS Code extension</strong> — a pair of releases that close that loop in your editor. Type-mismatch on a variable, an unresolved reference to a sibling task, a deprecated namespace, a missing plugin block — every one of these surfaces as you type, with a one-click fix wherever the LSP can synthesise one.</p>
<!-- -->
<p>This post is a tour of what the language server and extension actually do, what's new in this release (notably first-class support for <code>.pbvars</code> variables files), and how to get started.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="what-you-get">What you get<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#what-you-get" class="hash-link" aria-label="Direct link to What you get" title="Direct link to What you get" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="diagnostics-that-catch-problems-before-the-pipeline-runs">Diagnostics that catch problems before the pipeline runs<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#diagnostics-that-catch-problems-before-the-pipeline-runs" class="hash-link" aria-label="Direct link to Diagnostics that catch problems before the pipeline runs" title="Direct link to Diagnostics that catch problems before the pipeline runs" translate="no">​</a></h3>
<p>The language server runs the same validation Phobos itself runs — parse errors, missing required attributes, schema violations, cross-field constraints (<code>interval</code> requires <code>attempts</code>, deployments require <code>environment</code>, <code>mount_point</code> volumes must be declared), <code>stage_order</code> correctness, duplicate names, reserved keywords — plus a dozen Phobos-specific checks the editor is uniquely positioned to surface:</p>
<ul>
<li class="">Unresolved <code>var.&lt;X&gt;</code>, <code>jwt.&lt;X&gt;</code>, <code>vcs_token.&lt;X&gt;</code>, <code>volume.&lt;X&gt;</code> references.</li>
<li class="">Structural typos in <code>pipeline.*</code> / <code>this.*</code> / <code>phobos.*</code> paths anchored to the specific bad segment (<code>pipeline.stage.s.task.t.outp.x</code> flags <code>outp</code> directly, not the whole expression).</li>
<li class="">Missing <code>plugin "&lt;name&gt;" {}</code> configuration blocks for every action that needs one — including the bundled <code>exec</code> plugin.</li>
<li class="">Plugin-alias resolution: <code>action { plugin = &lt;type&gt;.&lt;alias&gt; }</code> traversals that don't resolve, plus the "you must pick one" ambiguity case.</li>
<li class="">Dead action references (<code>this.action.&lt;X&gt;.outputs.*</code> where <code>&lt;X&gt;</code> isn't declared in the same task).</li>
<li class="">Unused <code>variable</code>, <code>jwt</code>, <code>vcs_token</code>, <code>volume</code> declarations.</li>
<li class="">Deprecated <code>phobos.*</code> and <code>action_outputs.*</code> references, rendered with strikethrough.</li>
</ul>
<p>Every diagnostic is anchored at the precise expression range so a long file doesn't bury the cursor under a wall of text.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="context-aware-completion">Context-aware completion<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#context-aware-completion" class="hash-link" aria-label="Direct link to Context-aware completion" title="Direct link to Context-aware completion" translate="no">​</a></h3>
<p>Block types, attribute names, enumerated string values, HCL built-in functions, and the named-value namespaces (<code>var.</code>, <code>jwt.</code>, <code>vcs_token.</code>, <code>system.</code>, <code>pipeline.</code>, <code>this.</code>) all complete with type hints and inline documentation. Inside <code>dependencies = [...]</code> you get the names of sibling tasks, deployments, and nested pipelines in the same stage and phase. Inside <code>action { plugin = &lt;cursor&gt; }</code> you get every declared <code>&lt;type&gt;.&lt;alias&gt;</code> qualified name.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="hover-documentation">Hover documentation<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#hover-documentation" class="hash-link" aria-label="Direct link to Hover documentation" title="Direct link to Hover documentation" translate="no">​</a></h3>
<p>Hover any block, attribute, action label, named value, or output reference to see the schema docs (with type, allowed values, and limits), the description from the plugin schema (for action attributes), or the resolved target — <code>pipeline.stage.&lt;s&gt;.task.&lt;t&gt;.outputs.&lt;o&gt;</code> follows the <code>output "&lt;o&gt;"</code> block back to its declaration.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="code-actions-and-quick-fixes">Code actions and quick-fixes<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#code-actions-and-quick-fixes" class="hash-link" aria-label="Direct link to Code actions and quick-fixes" title="Direct link to Code actions and quick-fixes" translate="no">​</a></h3>
<p>When the LSP knows how to fix a diagnostic, it surfaces a <code>Ctrl+.</code> action:</p>
<ul>
<li class=""><strong>Install plugin</strong> — runs the right <code>phobos plugin install</code> command, including any <code>--version</code> constraint pinned in <code>plugin_requirements</code>.</li>
<li class=""><strong>Declare missing <code>plugin "&lt;name&gt;" {}</code> block</strong> — inserts the block at the natural anchor (after <code>plugin_requirements</code> if present, else after the last <code>plugin</code> block, else at top of file).</li>
<li class=""><strong>Declare aliased plugin block</strong> — when an action references an undeclared <code>plugin = &lt;type&gt;.&lt;alias&gt;</code>.</li>
<li class=""><strong>Set plugin = <code>&lt;type&gt;.&lt;alias&gt;</code></strong> — one action per declared alias when the type has only aliased instances and the action must pick one explicitly.</li>
<li class=""><strong>Migrate deprecation</strong> — rewrites legacy <code>phobos.*</code> / <code>action_outputs.*</code> references to the current <code>pipeline.*</code> / <code>this.action.*</code> shape. Bridging <code>output "&lt;o&gt;"</code> blocks are inserted atomically when needed.</li>
<li class=""><strong>Extract to variable</strong> / <strong>inline variable</strong> — refactors that move a literal in or out of a <code>variable</code> block.</li>
<li class=""><strong>Source-fix-all</strong> — the editor's "fix everything" key applies every preferred deprecation fix in one undoable edit.</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="inlay-hints-and-other-niceties">Inlay hints and other niceties<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#inlay-hints-and-other-niceties" class="hash-link" aria-label="Direct link to Inlay hints and other niceties" title="Direct link to Inlay hints and other niceties" translate="no">​</a></h3>
<p>Inlay hints add quiet annotations the cursor never lands on: variable types, variable defaults, per-task action + output counts (<code>: 2 actions, 1 output</code>), per-stage children counts (<code>: 3 tasks</code>, <code>: 2 tasks, 1 pipeline</code>), deployment environments, and per-action plugin-instance badges (<code>: docker.builder</code> when the action sets <code>plugin = docker.builder</code>). Each category is independently toggleable.</p>
<p>The extension also wires up:</p>
<ul>
<li class=""><strong>Pipeline Graph webview</strong> — a layered DAG of stages, tasks, deployments, and <code>dependencies = [...]</code> edges. Click a node to jump to its declaration.</li>
<li class=""><strong>Evaluated Context panel</strong> — a live tree of every namespace the evaluator exposes at the cursor.</li>
<li class=""><strong>Templates tree</strong> — every <code>pipeline.hcl</code> / <code>release_lifecycle.hcl</code> in the workspace expanded to its outline.</li>
<li class=""><strong>Installed Plugins tree</strong> — the LSP's plugin inventory, with a right-click "Browse Online" to open the plugin's registry page.</li>
<li class=""><strong>Unified Phobos status chip</strong> — one glanceable token consolidating language-server state, CLI presence + version, plugin health, diagnostic counts, and active-file kind.</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="snippets">Snippets<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#snippets" class="hash-link" aria-label="Direct link to Snippets" title="Direct link to Snippets" translate="no">​</a></h3>
<p>Built-in snippets cover the most common shapes — full templates (<code>pipeline</code>, <code>multipipe</code>), block scaffolds (<code>stage</code>, <code>task</code>, <code>taskdeps</code>, <code>taskretry</code>, <code>pre</code>, <code>post</code>, <code>action</code>, <code>output</code>, <code>var</code>, <code>plugins</code>, <code>jwt</code>, <code>vcs</code>, <code>nested</code>), and gates (<code>approval</code> for <code>when = "manual"</code> + <code>approval_rules</code>).</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="new-in-this-release-pbvars-files">New in this release: <code>.pbvars</code> files<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#new-in-this-release-pbvars-files" class="hash-link" aria-label="Direct link to new-in-this-release-pbvars-files" title="Direct link to new-in-this-release-pbvars-files" translate="no">​</a></h2>
<p>Phobos has always supported file-based variable input (analogous to Terraform's <code>.tfvars</code>); this release wires that file format into the LSP as a first-class document type. Open a <code>prod.pbvars</code> next to a <code>pipeline.hcl</code> and you get:</p>
<ul>
<li class=""><strong>Diagnostics against the sibling template</strong> — unknown variable names error out, type mismatches against the declared <code>type</code> produce friendly messages (<code>variable "replicas" has type number but was assigned a value of type string</code>), and unresolved references inside values surface HCL's own evaluation diagnostic.</li>
<li class=""><strong>Snippet-based completion</strong> — declared variable names from the sibling are filtered by typed prefix and inserted as typed snippets shaped to each variable's declared type. <code>string</code> inserts quotes-with-cursor-between, <code>number</code> inserts a <code>0</code> placeholder selected for one-keystroke overwrite, <code>bool</code> inserts a <code>true</code>/<code>false</code> choice dropdown, <code>object({...})</code> types pre-populate every declared field as its own tab stop with <code>=</code> aligned. Already-assigned variables are filtered out so you don't accidentally re-declare them.</li>
<li class=""><strong>Hover</strong> — surface the sibling variable's <code>description</code>, declared <code>type</code>, and default-state.</li>
</ul>
<p>The cross-file analysis is <strong>live</strong> — edits to the sibling template propagate to open <code>.pbvars</code> diagnostics, completions, and hover without saving first.</p>
<div class="language-hcl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">pipeline.hcl</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-hcl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">variable</span><span class="token keyword type variable" style="color:#36acaa"> "environment" </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">type</span><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> string</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">default</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"staging"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">variable</span><span class="token keyword type variable" style="color:#36acaa"> "replicas" </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> number</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">variable</span><span class="token keyword type variable" style="color:#36acaa"> "service" </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> object(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">name</span><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> string</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">timeout</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> number</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<div class="language-hcl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">prod.pbvars</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-hcl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">environment</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"production"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">replicas</span><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">service</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">name</span><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"checkout"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">timeout</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>The CLI's loading precedence (env vars → <code>phobos.pbvars</code> → <code>*.auto.pbvars</code> → <code>--pb-var-file</code> → <code>--pb-var</code>) hasn't changed; see <a class="" href="https://phobos.martian-cloud.io/guides/variables">Variables</a> for the full ordering.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="mixed-tool-workspaces">Mixed-tool workspaces<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#mixed-tool-workspaces" class="hash-link" aria-label="Direct link to Mixed-tool workspaces" title="Direct link to Mixed-tool workspaces" translate="no">​</a></h2>
<p>A common workspace has Phobos templates living next to Terraform, Nomad, or Packer files — all of them <code>.hcl</code>. The extension is intentionally narrow about which <code>.hcl</code> files it claims:</p>
<ul>
<li class=""><code>pipeline.hcl</code> and <code>release_lifecycle.hcl</code> — claimed by exact filename, always.</li>
<li class=""><code>*.pbvars</code> — claimed by extension, always.</li>
<li class="">Any other <code>*.hcl</code> — <strong>not</strong> claimed by default.</li>
</ul>
<p>If you want every <code>.hcl</code> file to be treated as Phobos (e.g. a workspace that's exclusively Phobos), flip <code>phobos.editor.associateAllHclFiles</code> to <code>true</code>. Toggling on takes effect immediately for every currently-open <code>.hcl</code> document; toggling off only affects future opens.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="installation">Installation<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#installation" class="hash-link" aria-label="Direct link to Installation" title="Direct link to Installation" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="vs-code-vscodium-cursor-and-other-vs-code-compatible-editors">VS Code, VSCodium, Cursor, and other VS Code-compatible editors<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#vs-code-vscodium-cursor-and-other-vs-code-compatible-editors" class="hash-link" aria-label="Direct link to VS Code, VSCodium, Cursor, and other VS Code-compatible editors" title="Direct link to VS Code, VSCodium, Cursor, and other VS Code-compatible editors" translate="no">​</a></h3>
<p>The extension is published to two registries — pick the one your editor uses:</p>
<ul>
<li class=""><strong><a href="https://marketplace.visualstudio.com/items?itemName=martian-cloud.mc-phobos" target="_blank" rel="noopener noreferrer" class="">VS Code Marketplace</a></strong> — for VS Code itself, plus Cursor, Kiro, and any other Microsoft-licensed VS Code distribution.</li>
<li class=""><strong><a href="https://open-vsx.org/extension/martian-cloud/mc-phobos" target="_blank" rel="noopener noreferrer" class="">Open VSX Registry</a></strong> — for VSCodium, Code OSS, Gitpod, Theia, and any other Eclipse-licensed VS Code fork that can't legally ship the Microsoft Marketplace.</li>
</ul>
<p>Both registries publish the same VSIX. From the editor's Extensions view, search <strong>Phobos</strong> and install. Marketplace and Open VSX VSIXes ship without the language-server binary to keep the download small — on first launch the extension prompts:</p>
<blockquote>
<p>Phobos language server not found. Install the latest version? <strong>[Install Latest] [Set Path…]</strong></p>
</blockquote>
<p>Choose <strong>Install Latest</strong> and the extension downloads, SHA-256-verifies, and installs the binary into your editor's global storage. You can rerun or upgrade from the command palette (<code>Phobos: Install or Update Language Server</code>).</p>
<p>For air-gapped setups, <a href="https://gitlab.com/infor-cloud/martian-cloud/phobos/vscode-phobos/-/releases" target="_blank" rel="noopener noreferrer" class="">GitLab releases</a> ship platform-specific VSIXes with the language-server bundled — install with <code>code --install-extension mc-phobos-&lt;version&gt;-&lt;platform&gt;.vsix</code> (or your editor's equivalent).</p>
<p>See the <a class="" href="https://phobos.martian-cloud.io/guides/vscode">VS Code Extension guide</a> for the full install matrix and configuration reference.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="neovim-helix-zed-emacs-and-other-editors">Neovim, Helix, Zed, Emacs, and other editors<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#neovim-helix-zed-emacs-and-other-editors" class="hash-link" aria-label="Direct link to Neovim, Helix, Zed, Emacs, and other editors" title="Direct link to Neovim, Helix, Zed, Emacs, and other editors" translate="no">​</a></h3>
<p>The language server is a standalone Go binary that speaks LSP over stdio. Install it from the <a href="https://gitlab.com/infor-cloud/martian-cloud/phobos/phobos-language-server/-/releases" target="_blank" rel="noopener noreferrer" class="">language-server releases page</a> (each release ships a <code>sha256sums.txt</code> manifest), or build from source with <code>make build</code>.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Quick install</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token assign-left variable" style="color:#36acaa">VERSION</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.1</span><span class="token plain">.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token assign-left variable" style="color:#36acaa">PLATFORM</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">linux_amd64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token assign-left variable" style="color:#36acaa">BASE</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"https://gitlab.com/infor-cloud/martian-cloud/phobos/phobos-language-server/-/releases/</span><span class="token string variable" style="color:#36acaa">${VERSION}</span><span class="token string" style="color:#e3116c">/downloads"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">curl</span><span class="token plain"> </span><span class="token flag keyword" style="color:#00009f">-L</span><span class="token plain"> </span><span class="token flag keyword" style="color:#00009f">-o</span><span class="token plain"> phobos-language-server </span><span class="token string" style="color:#e3116c">"</span><span class="token string variable" style="color:#36acaa">${BASE}</span><span class="token string" style="color:#e3116c">/phobos-language-server_</span><span class="token string variable" style="color:#36acaa">${VERSION}</span><span class="token string" style="color:#e3116c">_</span><span class="token string variable" style="color:#36acaa">${PLATFORM}</span><span class="token string" style="color:#e3116c">"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">chmod</span><span class="token plain"> +x phobos-language-server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">mv</span><span class="token plain"> phobos-language-server /usr/local/bin/</span><br></div></code></pre></div></div>
<p>Per-editor configuration snippets are in the <a class="" href="https://phobos.martian-cloud.io/guides/language-server#editor-setup">Language Server guide</a> — Neovim with <code>nvim-lspconfig</code>, Helix's <code>languages.toml</code>, Eglot for Emacs.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="under-the-hood">Under the hood<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#under-the-hood" class="hash-link" aria-label="Direct link to Under the hood" title="Direct link to Under the hood" translate="no">​</a></h2>
<p>Both the language server and extension are open source under MPL 2.0:</p>
<ul>
<li class=""><a href="https://gitlab.com/infor-cloud/martian-cloud/phobos/phobos-language-server" target="_blank" rel="noopener noreferrer" class="">phobos-language-server</a> — Go, ~25k LoC. The same <code>pkg/hcl/config</code> schema constants Phobos itself uses; a reflection-driven schema tree means new HCL-tagged fields on <code>PipelineTemplate</code> / <code>LifecycleTemplate</code> show up in diagnostics, completion, and hover automatically.</li>
<li class=""><a href="https://gitlab.com/infor-cloud/martian-cloud/phobos/vscode-phobos" target="_blank" rel="noopener noreferrer" class="">vscode-phobos</a> — TypeScript, hand-rolled LSP client + status-bar, tree views, and webviews. SHA-256-verified bundled binary on platform-specific releases.</li>
</ul>
<p>The plugin-aware features (action-body diagnostics, completion, hover for installed plugins) work via the same gRPC <code>Schema()</code> endpoint the CLI uses; schemas are cached on disk so cold starts stay fast even when a plugin binary is gone or failing to spawn. A <code>fsnotify</code> watcher on <code>~/.phobos.d/plugins</code> debounced at 500 ms means newly-installed plugins light up in the editor without any explicit refresh.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="whats-next">What's next<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next" translate="no">​</a></h2>
<p>Roadmap items we're already prototyping:</p>
<ul>
<li class=""><strong>Code-action quick fix for "not declared" <code>.pbvars</code> diagnostics</strong> that adds the <code>variable "&lt;name&gt;" { ... }</code> block to the sibling template.</li>
<li class=""><strong>Range-restricted type diagnostics</strong> — point at the offending sub-expression instead of the whole RHS for nested type errors inside object literals.</li>
</ul>
<p>If you have a feature request, please open an issue on either repo. MRs welcome.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="get-started">Get started<a href="https://phobos.martian-cloud.io/blog/2026/05/01/phobos-language-server-and-vscode-extension#get-started" class="hash-link" aria-label="Direct link to Get started" title="Direct link to Get started" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://phobos.martian-cloud.io/guides/vscode">VS Code Extension guide</a> — install matrix, settings reference, FAQ.</li>
<li class=""><a class="" href="https://phobos.martian-cloud.io/guides/language-server">Language Server guide</a> — editor-agnostic setup for Neovim, Helix, Zed, Emacs, and beyond.</li>
<li class=""><a class="" href="https://phobos.martian-cloud.io/guides/variables">Variables guide</a> — including the new <code>.pbvars</code> reference.</li>
<li class=""><a class="" href="https://phobos.martian-cloud.io/reference/pipeline-template-syntax">HCL reference</a> — syntax the LSP validates.</li>
</ul>]]></content:encoded>
            <category>phobos</category>
            <category>language-server</category>
            <category>vscode</category>
            <category>ide</category>
            <category>developer-experience</category>
            <category>productivity</category>
        </item>
    </channel>
</rss>