I tried building a local code completion environment in VS Code with DGX Spark × Continue.dev
ちょっと話題の記事

I tried building a local code completion environment in VS Code with DGX Spark × Continue.dev

I connected to a local LLM on a DGX Spark via Tailscale VPN from my MacBook Pro and built a code completion environment using VS Code + Continue.dev. Here I report the setup process and my hands-on impressions. I tested tab completion response times, code generation quality in chat, and how to divide usage between this setup and Claude Code.
2026.02.11

This page has been translated by machine translation. View original

Introduction

Hello, I'm Morishige from Classmethod's Manufacturing Business Technology Department.

In my previous article, I tested running Claude Code + Ollama locally on the DGX Spark's 128GB memory. The conclusion was "it's quite usable, but I'm still a bit nervous leaving it unattended." Separately, I was also curious whether editor code completion could be run locally.

https://build.nvidia.com/playbooks/vibe-coding-vscode

This Playbook introduces steps to build a local LLM-based code completion environment using VS Code + Continue.dev + Ollama. On top of that, there's even an article by the Continue.dev developers themselves saying they use DGX Spark as their main development machine, which made me think "I have to try this."

In this article, I'll introduce the steps and impressions of building a "remote local" code completion environment by connecting from VS Code on a MacBook Pro to Ollama on DGX Spark via Tailscale VPN.

Continue.dev and the Vibe Coding Playbook

What is Continue.dev?

Continue.dev is an open-source AI coding assistant that can integrate local LLMs and cloud APIs into VS Code or JetBrains IDEs. It's gaining attention as an alternative to GitHub Copilot, and lets you freely combine models of your own choosing.

https://www.continue.dev/

There are three main features: Tab completion, which presents suggestions inline while you're writing code; Chat, which lets you ask questions or request code generation in the sidebar; and Edit, which lets you select code and give natural language correction instructions. You can achieve the same experience as GitHub Copilot using your own models.

The config.yaml system assigns roles (chat, autocomplete, embed, edit, etc.) to each model, allowing you to use a small, fast-response model for Tab completion and a large, reasoning-focused model for Chat — all within a single configuration file.

Continue.dev

NVIDIA Vibe Coding Playbook Configuration

The Vibe Coding Playbook published by NVIDIA recommends a simple configuration that assigns all roles — chat / edit / autocomplete — to a single gpt-oss:120b model. Having 128GB of memory makes this possible: a DGX Spark-style approach where one large 120B model handles everything.

However, since Tab completion is called on every keystroke, response speed directly affects the feel of the experience. The Playbook itself recommends responses under 500ms, and with a 120B model, you might find yourself waiting every time a completion is triggered. So this time, I added a tweak to separate Tab completion into a dedicated lightweight model.

This Setup

Based on the Playbook, I split Tab completion to qwen2.5-coder:1.5b and adopted Qwen3-Coder-Next — which performed well in my previous Claude Code testing — for Chat. It's a "remote local" configuration connecting MacBook Pro and DGX Spark via Tailscale VPN.

Feature Model Parameters Reason for Selection
Tab Completion qwen2.5-coder:1.5b 1.5B Ensures response under 500ms
Chat Qwen3-Coder-Next 80B MoE (3B active) SWE-bench 70.6%, proven in previous article
Embeddings nomic-embed-text For @Codebase context

qwen2.5-coder:1.5b is a coding-specialized model trained on 5.5 trillion tokens, supporting 92 languages. There are reports that despite being only 1.5B, it can deliver 80–90% of Codestral (22B) performance, making it a cost-effective choice for Tab completion. Qwen3-Coder-Next is 80B MoE with only 3B active parameters. Memory consumption is around 51GB, so even combined with the 1.5B model, it fits comfortably within 128GB.

No models are placed on the MacBook Pro side — all inference is handled by DGX Spark. The Mac's input environment remains unchanged, with inference delegated entirely to DGX's 128GB memory.

Testing Environment

Item Specs
DGX Spark 128GB LPDDR5x, GB10 (Grace Blackwell)
MacBook Pro M4 32GB
Network Tailscale VPN (within same network, direct connection)
VS Code 1.109.2
Continue.dev v1.2.14
Ollama v0.15.5

Differences from the Previous Article (Claude Code)

Let me summarize the differences from the previous article.

Item Article 1.5 (Claude Code) This Time (Continue.dev)
Tool Claude Code (CLI) Continue.dev (VS Code extension)
Operation Style Terminal prompt input Tab completion + Chat within the editor
Strengths Multi-file editing, test execution, autonomous agent-like behavior Inline code completion, selected range fixes, interactive code generation
Model Relationship One model handles all features Assign the optimal model per feature
Wait Time Feel Tens of seconds to minutes (waiting in background) Sub-second ideal for Tab completion (affects typing rhythm)

If Claude Code is an agent-type "give instructions and wait," then Continue.dev is a completion-type "write yourself while receiving assistance." They serve different purposes, so it's not a question of which is better.

DGX Spark Setup

Ollama Remote Access Configuration

Ollama by default only listens on localhost:11434. To access it from MacBook Pro via Tailscale, change OLLAMA_HOST to 0.0.0.0.

# Create systemd override file
sudo mkdir -p /etc/systemd/system/ollama.service.d
sudo tee /etc/systemd/system/ollama.service.d/override.conf <<'EOF'
[Service]
Environment="OLLAMA_HOST=0.0.0.0"
EOF

# Restart the service
sudo systemctl daemon-reload
sudo systemctl restart ollama

Let's verify connectivity from MacBook Pro.

# Access via Tailscale IP
curl http://100.x.x.x:11434/api/tags

If a JSON list of models is returned, you're good to go.

Downloading Models

Download the three models we'll use.

# For Tab completion (1.5B, lightweight and fast)
ollama pull qwen2.5-coder:1.5b

# For Chat (80B MoE, coding-specialized)
ollama pull qwen3-coder-next

# For Embeddings
ollama pull nomic-embed-text

Qwen3-Coder-Next is about 51GB, so depending on your connection speed, it may take a while. Once downloaded, combined with qwen2.5-coder:1.5b it's around 55GB total — fits comfortably within 128GB.

MacBook Pro Setup

Installing Continue.dev

Search for "Continue" in the VS Code extensions marketplace and install it.

After installation, the Continue icon appears in the sidebar.

config.yaml Configuration

The Continue.dev configuration file is ~/.continue/config.yaml. The older config.json format is now deprecated and has been migrated to YAML format. Configure DGX Spark's Ollama as a remote provider as follows:

~/.continue/config.yaml
name: DGX Spark Remote
version: 0.0.1

models:
  # For Chat (80B MoE — coding-specialized)
  - name: qwen3-coder-next 80b
    provider: ollama
    model: qwen3-coder-next
    apiBase: http://100.x.x.x:11434
    capabilities:
      - tool_use
    contextLength: 65536
    roles:
      - chat
      - edit

  # For Tab completion (1.5B — prioritizing fast response)
  - name: qwen2.5-coder 1.5b
    provider: ollama
    model: qwen2.5-coder:1.5b
    apiBase: http://100.x.x.x:11434
    roles:
      - autocomplete

  # For Embeddings (used for @Codebase context)
  - name: nomic-embed-text
    provider: ollama
    model: nomic-embed-text
    apiBase: http://100.x.x.x:11434
    roles:
      - embed

Since the Tailscale IP is specified in apiBase, there's no need to run Ollama on the Mac side. The Mac's resources can be focused entirely on VS Code and other apps. With roles specified, using a lightweight model for Tab completion and a large model for Chat is handled within a single configuration file. capabilities: [tool_use] is explicitly set for Qwen3-Coder-Next, since Continue.dev's auto-detection doesn't recognize tool_use for Qwen3 models, requiring manual specification.

Note that as of v1.2.14, config.yaml requires top-level name and version fields. Also, for models like gpt-oss:120b with a short default context length, not explicitly specifying contextLength can result in token limit errors when handling slightly longer files.

For those connecting locally to DGX Spark (not remotely), a shorthand notation called Hub Model Blocks is also available.

models:
  - uses: ollama/gpt-oss-120b
  - uses: ollama/qwen2.5-coder-1.5b

Since this time we're connecting remotely via Tailscale, apiBase is explicitly specified, but those using DGX Spark with a keyboard plugged directly in may find Hub Model Blocks more convenient.

Trying It Out

For testing, I used a Todo API written in Express + TypeScript (about 100 lines). I tested each Continue.dev feature with GitHub Copilot disabled.

todo-api.ts
import express, { Request, Response } from "express";

// --- Types ---

interface Todo {
  id: number;
  title: string;
  completed: boolean;
  createdAt: Date;
}

// --- In-memory store ---

let todos: Todo[] = [];
let nextId = 1;

// --- Helper functions ---

// Test point 1: Write "function createTodo(" and wait for Tab completion
function createTodo(title: string): Todo {
  const todo: Todo = {
    id: nextId++,
    title,
    completed: false,
    createdAt: new Date(),
  };
  todos.push(todo);
  return todo;
}

// Test point 2: Start typing "function findTodoBy" and see what it suggests
function findTodoById(id: number): Todo | undefined {
  return todos.find((todo) => todo.id === id);
}

function toggleComplete(id: number): Todo | undefined {
  const todo = findTodoById(id);
  if (todo) {
    todo.completed = !todo.completed;
  }
  return todo;
}

// Test point 3: Start typing "function deleteTodo" and let Tab complete the body
function deleteTodo(id: number): boolean {
  const index = todos.findIndex((todo) => todo.id === id);
  if (index === -1) return false;
  todos.splice(index, 1);
  return true;
}

// --- Express routes ---

const app = express();
app.use(express.json());

// Test point 4: Type "app.get" and wait — does it suggest the route pattern?
app.get("/api/todos", (_req: Request, res: Response) => {
  res.json(todos);
});

app.post("/api/todos", (req: Request, res: Response) => {
  const { title } = req.body;
  if (!title) {
    res.status(400).json({ error: "title is required" });
    return;
  }
  const todo = createTodo(title);
  res.status(201).json(todo);
});

// Test point 5: Type "app.put" and see if it generates the update route
app.put("/api/todos/:id", (req: Request, res: Response) => {
  const id = parseInt(req.params.id, 10);
  const todo = toggleComplete(id);
  if (!todo) {
    res.status(404).json({ error: "not found" });
    return;
  }
  res.json(todo);
});

app.delete("/api/todos/:id", (req: Request, res: Response) => {
  const id = parseInt(req.params.id, 10);
  const success = deleteTodo(id);
  if (!success) {
    res.status(404).json({ error: "not found" });
    return;
  }
  res.status(204).send();
});

// --- Stats endpoint ---
// Test point 6: Type "app.get("/api/stats"" and let it complete the handler

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

Tab Completion Feel

Could the sub-500ms response target the Playbook aims for be cleared even over Tailscale VPN? I measured FIM (Fill-in-the-Middle) benchmarks on DGX Spark when selecting models.

Model Size Generation Speed Response Time FIM Support
qwen2.5-coder:1.5b 986MB 189 tok/s 290–360ms OK
qwen2.5-coder:7b 4.7GB 40.5 tok/s ~1.4 seconds OK
Qwen3-Coder-Next 51GB 37.0 tok/s Several seconds+ OK
gpt-oss:120b 61GB NG

qwen2.5-coder:7b improves completion quality, but at 1.4 seconds response time, it disrupts your typing tempo. Qwen3-Coder-Next is even slower. gpt-oss:120b, being a reasoning model (structured to generate thinking tokens first), doesn't support FIM at all. While the Playbook assigns gpt-oss to autocomplete as well, if you actually use it, you'd be better off separating Tab completion to a different model.

As a result, I adopted qwen2.5-coder:1.5b, which consistently clears the sub-500ms threshold. Even adding Tailscale's direct connection latency (roughly 10–30ms round trip), there's plenty of margin.

When actually writing TypeScript code, the feel was a half-beat slower than Copilot, but not enough to disrupt my typing rhythm. It felt roughly like the difference of tweaking autocomplete's initial settings.

As for the quality of completion suggestions: when typing app.patch partway through writing Express route handlers, it looks at the existing app.delete and app.put patterns and suggests the routing signature ("/api/todos/:id", (req: Request, res: Response) => {. Argument inference is also quite good — starting to write function filterTodos( gets a completion of query: string): Todo[] with types included.

Tab completion suggestion screen

On the other hand, there's a noticeable coarseness compared to Copilot. Where Copilot carefully expands a function's body inline, qwen2.5-coder:1.5b sometimes generates code that calls non-existent functions like getStats() or updateTodo(). It's too much to ask a 1.5B model for inline implementation details, so I think the right attitude is to treat it as "a hint, with the understanding that you'll write the body yourself."

My rough impression: "Copilot from a year ago." It's more restrained than the recent Copilot, which completes aggressively, but that also means you're less likely to be interrupted by unintended completions, and there's a pleasant sense of writing at your own pace.

Code Generation via Chat

For Chat, I use Qwen3-Coder-Next — the same model that performed well in combination with Claude Code in my previous article.

When I asked "Add a validation middleware to this Todo API," the first token appeared in 1–2 seconds, and from there the output streamed smoothly. What was generated was a validateTodoInput function in the Express middleware pattern — a practical piece of code including null checks, type checks, empty string checks, a maximum character length (255 chars), and trim processing.

Chat screen

Since the original file is TypeScript, the generated code comes out in TypeScript correctly. It proposed inserting middleware into the existing route definitions, and didn't assume any non-existent modules. Chat's "Insert Code" button appends to the end of the file, so you need to integrate it into existing code yourself, but the high quality of the code means the effort to incorporate it is minimal.

Edit Mode and Agent Mode

Continue.dev also has an Edit mode for selecting code and giving natural language correction instructions, and an Agent mode for autonomously progressing through tasks. When I tried these with Qwen3-Coder-Next and gpt-oss:120B, Edit sometimes works but the behavior is unstable — code gets broken on Apply, or functions outside the instruction scope get rewritten. Agent mode also tends to fail when reflecting changes to files, even if code suggestions come through.

The reason Chat is stable while Edit/Agent is not is that the models aren't keeping up with the diff application and tool call formatting — this is a model-side issue, not a problem with Continue.dev. The same tendency appeared in my previous Claude Code testing, and it should resolve naturally as local LLM structured output accuracy improves.

Usage Comparison with Claude Code

Claude Code (Ollama local execution) from my previous article, and Continue.dev from this one — both use DGX Spark's local LLM, but they excel in different situations.

Scenario Claude Code Continue.dev
Want to create a new file from scratch ○ Generate with a single prompt △ Generate via Chat and manually integrate
Want to add a few lines to existing code △ Depends on Edit tool accuracy ○ Smooth with Tab completion
Found a bug and want to fix it ○ Autonomously runs Read → Analysis → Edit △ Edit works but behavior is unstable
Want to write and run tests ○ Consistent from file creation to test execution × Test execution requires manual terminal use
Refactoring ○ Make changes across multiple files △ Edit unstable, Chat weak on context
Everyday coding × Writing prompts every time is tedious ○ Receive assistance while writing

Since Edit/Agent may or may not work depending on the model, Tab completion and Chat are currently Continue.dev's main battlegrounds. Even so, I think there's a solid division of roles: use Continue.dev's Tab completion for a rhythmic day-to-day coding workflow, and hand off substantial tasks and refactoring to Claude Code. Being able to ask quick questions in Continue.dev's Chat from the sidebar without switching to a terminal is also convenient.

Since both connect to Ollama on DGX Spark, the machine and models can be shared. The review article by Continue.dev's developers also notes that "being able to handle both development work and AI model inference on a single machine changes how you think about your workflow." It's an interesting perspective — using it as an everyday development machine rather than an inference-dedicated appliance.

Summary

Based on NVIDIA's official Vibe Coding Playbook, I built a local code completion environment connecting from VS Code + Continue.dev on MacBook Pro to Ollama on DGX Spark via Tailscale VPN.

Tab completion felt like "Copilot from a year ago" — fully practical for routine coding. Response latency was barely noticeable even over Tailscale VPN, comfortably clearing the sub-500ms target the Playbook aims for. Chat, thanks to Qwen3-Coder-Next, was fast and generated TypeScript code correctly. Edit and Agent sometimes work and sometimes break, and aren't stable yet.

If Claude Code is an agent-type "delegate to AI and wait," then Continue.dev is a completion-type "write yourself while receiving assistance." Edit/Agent should become usable as local LLM structured output matures a bit more — the pace of model evolution makes me optimistic about the near future.

That said, Tab completion alone makes everyday coding considerably more comfortable, so I hope this serves as a useful reference for anyone who wants to try the same setup.


国内企業 AI活用実態調査2026 配布中

クラスメソッドが独自に行なったAI診断調査をもとに、企業のAI活用の現在地を調査レポートとしてまとめました。企業規模別の活用度傾向に加え、規模を超えてAI活用を進める企業に共通する取り組みまで、自社の現在地を捉えるためのヒントにぜひ。

国内企業 AI活用実態調査2026

無料でダウンロードする

Share this article