<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[OpenMake Engineering]]></title><description><![CDATA[OpenMake Engineering]]></description><link>https://openmake.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6a70f639801f357af0157b00/bd2504b5-404d-4f06-b51a-f853d25f281e.png</url><title>OpenMake Engineering</title><link>https://openmake.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 15 Sep 2026 21:39:54 GMT</lastBuildDate><atom:link href="https://openmake.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Building a local-first AI workspace across a Mac mini and NVIDIA DGX Spark]]></title><description><![CDATA[Most AI workspaces call themselves “local-friendly” when they can point at an OpenAI-compatible endpoint. That is useful, but it does not necessarily make the local model the center of the system. Aut]]></description><link>https://openmake.hashnode.dev/building-a-local-first-ai-workspace-across-a-mac-mini-and-nvidia-dgx-spark</link><guid isPermaLink="true">https://openmake.hashnode.dev/building-a-local-first-ai-workspace-across-a-mac-mini-and-nvidia-dgx-spark</guid><category><![CDATA[self-hosted]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[llm]]></category><category><![CDATA[NVIDIA]]></category><dc:creator><![CDATA[이재상 (OpenMake)]]></dc:creator><pubDate>Mon, 03 Aug 2026 20:19:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a70f639801f357af0157b00/8a3b1138-0fe7-408c-93f8-266a8e1c949b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most AI workspaces call themselves “local-friendly” when they can point at an OpenAI-compatible endpoint. That is useful, but it does not necessarily make the local model the center of the system. Authentication, tool execution, fallbacks, and agent workflows may still assume that a cloud provider is the normal path.</p>
<p>We wanted to explore the opposite design: the operator-owned model should be the default, while every external model remains an explicit bring-your-own-key choice.</p>
<p>That experiment became <a href="https://github.com/openmake/openmake_llm">OpenMake LLM</a>, an MIT-licensed, self-hosted AI workspace. This article is not a benchmark or a claim that local inference is always cheaper or better. It is a walkthrough of the architecture we actually run, the boundaries we chose, and the tradeoffs we still have to improve.</p>
<p><img src="https://raw.githubusercontent.com/openmake/openmake_llm/main/assets/screenshot-chat.png" alt="The running OpenMake LLM chat workspace" /></p>
<p><em>The running chat workspace. Conversation titles and account details in the public capture are blurred.</em></p>
<h2>The physical topology</h2>
<p>Our development and live-test setup uses two machines with deliberately different responsibilities:</p>
<pre><code class="language-text">Browser
   |
   v
Mac mini
  - OpenMake API and web app under PM2
  - PostgreSQL and isolated Docker workloads
  - LiteLLM bound to loopback as the inference gateway
   |
   | least-privilege Tailscale path
   v
NVIDIA DGX Spark (GB10 Grace Blackwell Superchip)
  - private vLLM endpoints
  - Qwen generation models
  - BGE embeddings
  - FLUX image generation
</code></pre>
<p>The Mac mini owns the application and policy plane. The DGX Spark owns the GPU-heavy inference plane. vLLM is not exposed directly to the public internet, and LiteLLM remains the single gateway the application talks to.</p>
<p>This hardware is our real setup, not a requirement. OpenMake talks to OpenAI-compatible endpoints, so another vLLM machine, an Ollama endpoint, or an intentionally enabled external provider can take the DGX Spark’s place. The important part is the boundary: the application should not need to know whether a model is in the same process, elsewhere on a private network, or behind an operator-approved service.</p>
<h2>Local-first is a policy decision, not just an endpoint</h2>
<p>A local endpoint alone does not answer the operational questions:</p>
<ul>
<li>Who may enable an external provider?</li>
<li>Which key is used, and how is it stored?</li>
<li>Do local and external models get the same tools?</li>
<li>What happens when a prompt exceeds the model’s context window?</li>
<li>Which actions require human approval?</li>
<li>Does “multi-agent” run for every prompt, or only when the user asks for it?</li>
</ul>
<p>OpenMake sends local and external models through the same provider-gated message pipeline and MCP tool loop. External providers are opt-in and use the operator’s or user’s own key. The local model remains available as the default path rather than becoming a fallback after a cloud model.</p>
<p>The simplified request path looks like this:</p>
<pre><code class="language-text">request
  -&gt; authentication and provider policy
  -&gt; language, memory, style, and tool assembly
  -&gt; selected mode or normal chat
  -&gt; one OpenAI-compatible inference gateway
  -&gt; bounded tool loop
  -&gt; streamed response
</code></pre>
<p>That uniform path has been more valuable than adding many provider-specific features. Tool permissions, audit behavior, and context handling can be reasoned about once instead of being rebuilt for every model vendor.</p>
<h2>Normal chat should stay normal</h2>
<p>One design choice is intentionally unexciting: an ordinary message resolves one model and runs one chat/tool loop.</p>
<p>It does not automatically start a committee of agents. Multi-agent orchestration can improve difficult answers, but invoking it for every prompt increases latency, token use, failure modes, and the difficulty of explaining where an answer came from.</p>
<p>OpenMake therefore makes <strong>Discussion</strong> an explicit mode. When selected, it can:</p>
<ol>
<li>choose relevant expert roles;</li>
<li>run a bounded number of opinions in parallel;</li>
<li>cross-review those opinions;</li>
<li>reuse collected evidence; and</li>
<li>synthesize one final answer.</li>
</ol>
<p>The distinction matters operationally. “Chat” is a predictable single-model interaction. “Discussion” is a more expensive orchestration workflow that the user deliberately requests.</p>
<h2>Model roles without hiding the routing</h2>
<p>Different workloads benefit from different models. A fast summarizer, a tool-using agent, a judge, and a research model do not necessarily need the same latency or reasoning profile.</p>
<p>OpenMake supports role-based model assignment for roles such as agent, judge, research, parallel sub-agents, review, and thinking-summary. Resolution follows visible configuration and falls back to the local default when a role-specific model is unavailable.</p>
<p><img src="https://raw.githubusercontent.com/openmake/openmake_llm/main/assets/screenshot-model-roles.png" alt="Role-based model routing in the admin interface" /></p>
<p>The goal is not to build a mysterious router that asks another model where every prompt should go. It is to let the operator make stable assignments that can be inspected, tested, and changed.</p>
<h2>Agents need an execution boundary</h2>
<p>Once a model can run shell commands, Python, browser actions, or file operations, inference is no longer the main security question. Execution is.</p>
<p>Agent tasks in OpenMake run in persistent Docker sandboxes. A task can keep checkpoints, survive an application restart, and be resumed manually. Approval boundaries stop the workflow before actions that should not be silently automated.</p>
<p><img src="https://raw.githubusercontent.com/openmake/openmake_llm/main/assets/screenshot-agent-tasks.png" alt="Agent task execution and checkpoints" /></p>
<p>Persistence and approval may sound contradictory, but they solve different problems:</p>
<ul>
<li>persistence prevents useful work from disappearing when a process restarts;</li>
<li>approval prevents persistence from becoming uncontrolled autonomy;</li>
<li>checkpoints make it possible to inspect what happened before resuming;</li>
<li>container isolation limits the environment available to the task.</li>
</ul>
<p>The same principle applies to external MCP servers. They run in isolated containers with restricted capabilities and tool allowlists, so connecting a large server does not mean exposing every tool schema to every conversation.</p>
<h2>What remains difficult</h2>
<p>This is not a one-command lightweight application. The current release requires Node.js 24, Docker, PostgreSQL, and an OpenAI-compatible model endpoint. Running a useful local model also requires compatible GPU memory and an operator who understands the deployment.</p>
<p>The split topology creates additional work:</p>
<ul>
<li>private-network reachability must be measured rather than assumed;</li>
<li>model names and context limits must match what the inference server actually exposes;</li>
<li>streaming, tool calls, embeddings, and image generation need separate validation;</li>
<li>gateway telemetry must never block inference;</li>
<li>secrets and model endpoints need narrower access than the public application;</li>
<li>external BYOK models may create charges even when the application itself is open source.</li>
</ul>
<p>We also do not call the current system a finished “AgentOS.” Durable execution, scoped memory, policy, verification, and operator-facing auditability are directions that still need engineering work. Naming the destination is useful; pretending to have arrived is not.</p>
<h2>What we learned</h2>
<p>The strongest lesson is that local-first architecture is mostly about ownership and boundaries:</p>
<ol>
<li>Keep one inference gateway between the application and every model endpoint.</li>
<li>Treat external providers as explicit policy choices, not invisible fallbacks.</li>
<li>Keep ordinary chat separate from expensive multi-agent orchestration.</li>
<li>Give tool-using agents durable state, but stop them at human approval boundaries.</li>
<li>Make role-based routing inspectable instead of adding another opaque LLM decision.</li>
<li>Test the live path: streaming completion, tool execution, rendered sources, and observable errors—not only HTTP 200 responses.</li>
</ol>
<p>If you are building a self-hosted AI workspace, I would be interested in three practical comparisons:</p>
<ul>
<li>Which GPU and open-weight model combinations are reliable for tool-using agents rather than chat alone?</li>
<li>Which actions do you always place behind human approval?</li>
<li>Would you keep the application and inference gateway on one host, or separate them as we did?</li>
</ul>
<p>The source, setup guide, and additional real screenshots are available in the <a href="https://github.com/openmake/openmake_llm">OpenMake LLM repository</a>. There is also a <a href="https://chat.openmake.cc">live demo</a> and an <a href="https://openmake.cc/en/?utm_source=hashnode&amp;utm_medium=community&amp;utm_campaign=openmake_llm">English project overview</a>.</p>
<p>OpenMake is not a company. We are a small team that enjoys open-source software, open hardware, and running services on machines we control.</p>
<p><em>Disclosure: this article was prepared with AI writing assistance and reviewed against the OpenMake LLM source tree, documentation, and running deployment by the maintainers. We are responsible for the technical claims and any mistakes.</em></p>
]]></content:encoded></item></channel></rss>