<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="pretty-atom-feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Blog Title</title>
  <subtitle>This is a longer description about your blog.</subtitle>
  <link href="https://example.com/feed/feed.xml" rel="self" />
  <link href="https://example.com/" />
  <updated>2026-09-05T01:08:21Z</updated>
  <id>https://example.com/</id>
  <author>
    <name>Your Name</name>
  </author>
  <entry>
    <title>Custom API Keys in Laravel AI SDK</title>
    <link href="https://example.com/blog/laravel/custom-api-keys-in-laravel-ai-sdk/" />
    <updated>2026-09-05T01:08:21Z</updated>
    <id>https://example.com/blog/laravel/custom-api-keys-in-laravel-ai-sdk/</id>
    <content type="html">&lt;p&gt;I&#39;ve been working with Laravel&#39;s AI SDK recently, and I ran into a common
problem: &lt;a href=&quot;https://github.com/laravel/ai/issues/105&quot;&gt;how do you handle custom API keys for
different users or tenants&lt;/a&gt;? The SDK works great out of the box when you have
a single API key in your configuration, but what about multi-tenant applications where each tenant (or user) brings
their own API key (BYO key)?&lt;/p&gt;
&lt;p&gt;This is a typical scenario in SaaS applications where you want to let users connect their own OpenAI (or compatible)
accounts to your service. The Laravel AI SDK doesn&#39;t have a built-in mechanism for this, but it&#39;s surprisingly easy to
solve with a small extension.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;When you look at the Laravel AI SDK, the Laravel Magicᵀᴹ creates drivers using configuration from your &lt;code&gt;config/ai.php&lt;/code&gt;
file. For OpenAI-compatible drivers, it looks something like this:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// AiManager.php&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;createOpenaiCompatibleDriver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name return-type&quot;&gt;OpenAiCompatibleProvider&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OpenAiCompatibleProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token variable&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name static-context&quot;&gt;Dispatcher&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The issue is that this pulls the API key directly from your configuration, which is static and shared across all
users/tenants. In a multi-tenant app, you need this key to be dynamic based on the current user or tenant.&lt;/p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The Solution&lt;/h2&gt;
&lt;p&gt;The fix involves three simple steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a custom class that extends &lt;code&gt;AiManager::class&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Override the driver creation method to inject your custom API key or a user-selected model.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://laravel.com/framework/docs/container#extending-bindings&quot;&gt;Extend&lt;/a&gt; the &lt;code&gt;AIManager:class&lt;/code&gt; binding in your
service provider.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&#39;s exactly how to do it:&lt;/p&gt;
&lt;h3 id=&quot;step-1-create-the-custom-manager&quot;&gt;Step 1: Create the Custom Manager&lt;/h3&gt;
&lt;p&gt;First, create a custom AI manager that extends the base one:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// App/Ai/CustomAiManager.php&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;App&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;Ai&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;Illuminate&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;Support&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;Arr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;Laravel&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;AI&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;Managers&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;AiManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;CustomAiManager&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AiManager&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;createOpenaiCompatibleDriver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name return-type&quot;&gt;OpenAiCompatibleProvider&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Get the current tenant&#39;s API key however you want.&lt;/span&gt;
        &lt;span class=&quot;token class-name static-context&quot;&gt;Arr&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;key&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name static-context&quot;&gt;Auth&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// Maybe the user has also selected a default model they want to use.&lt;/span&gt;
        &lt;span class=&quot;token class-name static-context&quot;&gt;Arr&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;models.text.default&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name static-context&quot;&gt;Auth&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;default_text_model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// Call the parent method with our modified config&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword static-context&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createOpenaiCompatibleDriver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Any of the &lt;a href=&quot;https://laravel.com/framework/docs/13.x/ai-sdk#openai-compatible-embeddings&quot;&gt;configuration&lt;/a&gt; keys can be
changed, depending on what the users need to do.&lt;/p&gt;
&lt;h3 id=&quot;step-2-extend-the-binding&quot;&gt;Step 2: Extend the Binding&lt;/h3&gt;
&lt;p&gt;Next, in your service provider (usually &lt;code&gt;AppServiceProvider&lt;/code&gt;), extend the AIManager binding:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// App/Providers/AppServiceProvider.php&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;App&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;Ai&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;CustomAiManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;Illuminate&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;Support&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;Facades&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token package&quot;&gt;Laravel&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;AI&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;Managers&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;AiManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name static-context&quot;&gt;AiManager&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name type-declaration&quot;&gt;AiManager&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$manager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name type-declaration&quot;&gt;Application&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$app&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CustomAiManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$app&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;how-it-works&quot;&gt;How It Works&lt;/h3&gt;
&lt;p&gt;What&#39;s happening here is clean and straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We extend the base &lt;code&gt;AiManager&lt;/code&gt; to create our own version.&lt;/li&gt;
&lt;li&gt;We override just the method we need to customize (&lt;code&gt;createOpenaiCompatibleDriver&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;In that method, we modify the &lt;code&gt;$config&lt;/code&gt; array to use the current user&#39;s API key.&lt;/li&gt;
&lt;li&gt;We call the parent method to do the actual driver creation with our modified config.&lt;/li&gt;
&lt;li&gt;Finally, we tell Laravel&#39;s service container to use our custom manager instead of the default one.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The key insight is that you only need to override the specific driver creation method you&#39;re using. If you&#39;re also using
Anthropic or Gemini drivers, you&#39;d override those methods similarly.&lt;/p&gt;
&lt;h2 id=&quot;why-this-approach-works-well&quot;&gt;Why This Approach Works Well&lt;/h2&gt;
&lt;p&gt;This solution has several advantages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Minimal footprint&lt;/strong&gt; - You&#39;re only adding a few lines of code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leverages existing SDK&lt;/strong&gt; - You&#39;re not reimplementing anything, just extending.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintainable&lt;/strong&gt; - Clear separation of concerns, easy to understand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible&lt;/strong&gt; - Easy to adapt to different authentication systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No configuration changes&lt;/strong&gt; - Works with your existing AI config as a fallback.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This pattern of extending Laravel&#39;s managers is powerful and can be applied to many other situations where you need to
customize framework behavior based on the current user or tenant context. It&#39;s clean, follows Laravel&#39;s conventions, and
keeps your solution tightly focused on the problem you&#39;re solving.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Free AI-Assisted Software Development with OpenCode</title>
    <link href="https://example.com/blog/development/free-ai-assisted-development-with-opencode/" />
    <updated>2026-08-25T18:23:16Z</updated>
    <id>https://example.com/blog/development/free-ai-assisted-development-with-opencode/</id>
    <content type="html">&lt;h1 id=&quot;free-ai-assisted-software-development-with-opencode&quot;&gt;Free AI-Assisted Software Development with OpenCode&lt;/h1&gt;
&lt;p&gt;Using AI for programming doesn&#39;t necessarily mean incurring the cost of a new monthly subscription.&lt;/p&gt;
&lt;p&gt;If you are a developer who prefers working via the command line, &lt;strong&gt;OpenCode&lt;/strong&gt; offers a great way to experience &amp;quot;agentic
coding&amp;quot; using free models from various providers. You can use OpenCode’s free Zen models, add free inference endpoints
from NVIDIA, and switch between providers if (when) you hit rate limits.&lt;/p&gt;
&lt;p&gt;While this doesn&#39;t provide unlimited AI coding, it can be surprisingly powerful and useful—and best of all, it is &lt;strong&gt;free
to get started&lt;/strong&gt;, and stays free, unless you &lt;em&gt;really&lt;/em&gt; increase your usage.&lt;/p&gt;
&lt;h2 id=&quot;installing-opencode&quot;&gt;Installing OpenCode&lt;/h2&gt;
&lt;p&gt;Start by visiting the &lt;a href=&quot;https://opencode.ai&quot;&gt;OpenCode&lt;/a&gt; website.&lt;/p&gt;
&lt;p&gt;OpenCode offers several installation methods, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;curl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bun&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brew&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;paru&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Choose the method that suits your operating system and copy the installation command into your terminal.&lt;/p&gt;
&lt;p&gt;Once installed, there is no need to set up a bunch of API keys; there&#39;s an easier way to get started.&lt;/p&gt;
&lt;h2 id=&quot;connecting-opencode-to-opencode-zen&quot;&gt;Connecting OpenCode to OpenCode Zen&lt;/h2&gt;
&lt;p&gt;Open &lt;a href=&quot;https://opencode.ai/zen?utm_source=chatgpt.com&quot;&gt;OpenCode Zen&lt;/a&gt; and follow the steps outlined in the &lt;strong&gt;Get started
with Zen&lt;/strong&gt; section.&lt;/p&gt;
&lt;p&gt;You will link your GitHub account to OpenCode. You might see an option to add payment (billing) information, but &lt;strong&gt;you
do not need to do this for this setup&lt;/strong&gt;, as we will be using only the free models. After linking your account, open your
command-line interface and run the following command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;opencode&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OpenCode will connect to &lt;code&gt;opencode.ai&lt;/code&gt; and generate an API key for your Zen account.&lt;/p&gt;
&lt;p&gt;At this point, you are ready to start using the models provided by OpenCode via Zen.&lt;/p&gt;
&lt;h2 id=&quot;understanding-free-models&quot;&gt;Understanding Free Models&lt;/h2&gt;
&lt;p&gt;The free models available via Zen are subject to change, so check the pricing page periodically:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://opencode.ai/docs/zen/#pricing&quot;&gt;OpenCode Zen Pricing&lt;/a&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 593px;&quot;&gt;
  &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://example.com/blog/development/free-ai-assisted-development-with-opencode/CdO0Ju2qcQ-1186.avif 1186w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://example.com/blog/development/free-ai-assisted-development-with-opencode/CdO0Ju2qcQ-1186.webp 1186w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://example.com/blog/development/free-ai-assisted-development-with-opencode/CdO0Ju2qcQ-1186.png&quot; alt=&quot;Screenshot from Zen pricing page&quot; width=&quot;1186&quot; height=&quot;772&quot;&gt;&lt;/picture&gt;
  &lt;figcaption style=&quot;font-size: small&quot;&gt;These are the OpenCode models free as I write this post.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Look specifically for models listed as free. The free plan is subject to a usage limit, which resets at &lt;strong&gt;midnight
UTC&lt;/strong&gt;. Your experience with this limit may vary significantly; I have had days when I exhausted the allowance just a few
hours after the reset, while on other days, I never reached the limit at all.&lt;/p&gt;
&lt;p&gt;This makes the free plan useful, but it is not an option I would rely on as a sole provider of AI services.&lt;/p&gt;
&lt;h2 id=&quot;extending-your-zen-usage&quot;&gt;Extending Your Zen Usage&lt;/h2&gt;
&lt;p&gt;There is a simple trick that can make a surprisingly big difference &lt;em&gt;(You won&#39;t believe #1!)&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When you have been working in a session for a while, enter the following command:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/new&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This starts a new OpenCode session.&lt;/p&gt;
&lt;p&gt;Why is this command important?&lt;/p&gt;
&lt;p&gt;An agentic coding session can accumulate a &lt;strong&gt;massive amount&lt;/strong&gt; of context; Your previous prompts, responses, tool calls,
and other conversation history become part of what the model needs to process. As the session lengthens, you effectively
burden every subsequent interaction with additional overhead.&lt;/p&gt;
&lt;p&gt;Starting a new session, however, provides the model with a clean context (free of previous data).&lt;/p&gt;
&lt;p&gt;Naturally, you will lose the conversation history, so avoid doing this in the middle of a task where that history is
crucial. Yet, when you reach a natural stopping point, the &lt;code&gt;/new&lt;/code&gt; command can make your token consumption much more
manageable.&lt;/p&gt;
&lt;p&gt;OpenCode will compress the session when the usage gets full, but it controls what falls out of context. For a
long-running process, compaction is better than nothing, but don&#39;t underestimate a fresh session for every task.&lt;/p&gt;
&lt;h2 id=&quot;adding-free-nvidia-models&quot;&gt;Adding Free NVIDIA Models&lt;/h2&gt;
&lt;p&gt;This is where the setup process gets interesting.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://build.nvidia.com/?utm_source=chatgpt.com&quot;&gt;NVIDIA Build&lt;/a&gt; platform offers access to a wide range of models
via NVIDIA-hosted inference APIs.&lt;/p&gt;
&lt;p&gt;NVIDIA currently allows developers to use its models for free during the prototyping phase. Instead of charging per
token, the free plan relies primarily on &lt;strong&gt;request-rate limits&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;According to NVIDIA’s current FAQ, most models allow up to &lt;strong&gt;40 requests per minute&lt;/strong&gt; on the free plan, with no charges
based on token count. Your specific limit is displayed in the NVIDIA dashboard. If you later require greater capacity,
NVIDIA offers options to use partner endpoints or to self-deploy a NIM model.&lt;/p&gt;
&lt;p&gt;The nature of this limitation differs significantly from the one found in Zen&#39;s free plan. Instead of having a
relatively limited usage quota consumed throughout the day, you are generally constrained by the allowed request rate.
For an individual developer routinely engaged in agentic coding, a limit of &lt;strong&gt;40 requests per minute is a very generous
ceiling&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;creating-an-nvidia-api-key&quot;&gt;Creating an NVIDIA API Key&lt;/h3&gt;
&lt;p&gt;Go to &lt;a href=&quot;https://build.nvidia.com/?utm_source=chatgpt.com&quot;&gt;NVIDIA Build&lt;/a&gt; and log in or create an account.&lt;/p&gt;
&lt;p&gt;Once you are in the dashboard, generate an API key.&lt;/p&gt;
&lt;p&gt;Next, return to OpenCode and enter the following command:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/connect&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Locate &lt;strong&gt;NVIDIA&lt;/strong&gt; in the list of providers and enter the API key you just created.&lt;/p&gt;
&lt;p&gt;That’s it.&lt;/p&gt;
&lt;p&gt;You can now use the NVIDIA models available via the Build platform with OpenCode.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://build.nvidia.com/models?pageSize=96&amp;amp;filters=nimType%3Anim_type_preview&amp;amp;utm_source=chatgpt.com&quot;&gt;NVIDIA Model Catalog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The available model lineup will change over time, so do not rely on this link as a static list of specific models;
instead, consider it...&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Securing your DNS with TSIG and Age Keys</title>
    <link href="https://example.com/blog/services/securing-your-dns-server/" />
    <updated>2026-08-19T02:45:44Z</updated>
    <id>https://example.com/blog/services/securing-your-dns-server/</id>
    <content type="html">&lt;h1 id=&quot;securing-your-dns-tsig-keys-for-bind-9-and-age-keys-for-secrets&quot;&gt;Securing Your DNS: TSIG Keys for BIND 9 and Age Keys for Secrets&lt;/h1&gt;
&lt;p&gt;If you run your own authoritative DNS with BIND 9, you have probably hit the two classic problems: how do you let an
automated system (a web control panel, a sync tool, or a script) update your zones securely, and how do you safely move
zone data around without trusting the whole internet? And once you have DNS working, the next question is always
secrets: how do you encrypt a message so only the right person — or the right machine — can read it?&lt;/p&gt;
&lt;p&gt;This post walks through both. First, we create a TSIG key, wire it into BIND 9 so it can update your apex domain and
every subdomain, and enable AXFR zone transfers with it. Then we generate an age key pair, publish the public half, and
use it to encrypt and decrypt messages from the command line.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;section-1-tsig-keys-authenticated-dns-updates-and-transfers&quot;&gt;Section 1: TSIG Keys — Authenticated DNS Updates and Transfers&lt;/h2&gt;
&lt;p&gt;DNS updates and zone transfers are sensitive. By default, &lt;code&gt;nsupdate&lt;/code&gt; traffic is unauthenticated and the server will
happily talk to anyone who asks. TSIG (&lt;strong&gt;T&lt;/strong&gt;ransaction &lt;strong&gt;SIG&lt;/strong&gt;nature) solves this by signing every DNS message with a
shared secret key, proving to both sides that the message really came from who it says it did.&lt;/p&gt;
&lt;h3 id=&quot;step-1-generate-the-key&quot;&gt;Step 1: Generate the Key&lt;/h3&gt;
&lt;p&gt;BIND ships with a dedicated tool for this, &lt;code&gt;tsig-keygen&lt;/code&gt; (on older systems you may find
&lt;code&gt;dnssec-keygen -a HMAC-SHA256 -b 256 -n HOST&lt;/code&gt; instead). Run it from any machine; it just needs a name and produces a key
snippet you can paste into your configuration.&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ tsig-keygen zoneforge. &gt; /etc/bind/keys/zoneforge.key
$ cat /etc/bind/keys/zoneforge.key
key &quot;zoneforge.&quot; {
    algorithm hmac-sha256;
    secret &quot;Oeq1gvZbDD3hFcdPFsbgowpIpW9n7WqlveEHXeY+B8s=&quot;;
};&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://bind9.readthedocs.io/en/stable/chapter7.html#generating-a-shared-key&quot;&gt;Any string which is a valid DNS name can be used as a key name.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since we want a valid DNS name without any surprises, remember to add the dot to the end of your key name, just like a
domain name.&lt;/p&gt;
&lt;p&gt;Keep that output somewhere safe. The secret is a shared secret — anyone who has it can sign updates and request
transfers as you. Don&#39;t worry about that key I showed, it&#39;s not a live key.&lt;/p&gt;
&lt;h3 id=&quot;step-2-put-the-key-in-the-configuration&quot;&gt;Step 2: Put the Key in the Configuration&lt;/h3&gt;
&lt;p&gt;On your BIND server, create a key file (or drop the snippet straight into
&lt;code&gt;named.conf&lt;/code&gt;). A tidy approach is to keep it in its own file and include it:&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;# /etc/bind/keys/tsig-keys.conf  (or wherever your named.conf lives)
key &quot;zoneforge.&quot; {
    algorithm hmac-sha256;
    secret &quot;Oeq1gvZbDD3hFcdPFsbgowpIpW9n7WqlveEHXeY+B8s=&quot;;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then include it from &lt;code&gt;named.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;include &amp;quot;/etc/bind/keys/tsig-keys.conf&amp;quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3-grant-update-permission-for-the-apex-domain-and-all-subdomains&quot;&gt;Step 3: Grant Update Permission for the Apex Domain and All Subdomains&lt;/h3&gt;
&lt;p&gt;Now the important part: telling BIND &lt;em&gt;what&lt;/em&gt; this key is allowed to do. You do that inside your zone definition with
&lt;code&gt;update-policy&lt;/code&gt;. A common pattern is a
&amp;quot;dynamic zone&amp;quot; managed entirely by your automation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;zone &amp;quot;example.com&amp;quot; {
    type master;
    file &amp;quot;/var/lib/bind/db.example.com&amp;quot;;
    update-policy {
        grant zoneforge zonesub any;
    };
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s break down that single grant line, because it is easy to get wrong:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;grant zoneforge&lt;/code&gt; — the name of the key we created.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zonesub&lt;/code&gt; — the scope of the grant. &lt;code&gt;zonesub&lt;/code&gt; matches the apex zone name &lt;em&gt;and&lt;/em&gt; every name beneath it, i.e.
&lt;code&gt;example.com&lt;/code&gt;, &lt;code&gt;www.example.com&lt;/code&gt;,
&lt;code&gt;mail.example.com&lt;/code&gt;, and so on. If you used &lt;code&gt;zone&lt;/code&gt;, the key could only touch records at the apex itself; if you used
&lt;code&gt;subdomain&lt;/code&gt;, only records strictly below the apex. For &amp;quot;apex + all subdomains&amp;quot;, &lt;code&gt;zonesub&lt;/code&gt; is exactly right.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;any&lt;/code&gt; — the record types the key may touch. &lt;code&gt;any&lt;/code&gt; lets it add, delete, and update any record type. If you want to be
more conservative you can list specific types, e.g. &lt;code&gt;grant zoneforge zonesub TXT A AAAA;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;traefik-and-your-tsig-key&quot;&gt;Traefik and your TSIG Key&lt;/h4&gt;
&lt;p&gt;A common use is to create a key for your traefik instance and use it to validate DNS challenges:&lt;/p&gt;
&lt;p&gt;Suppose we have this key:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;key &amp;quot;traefik-acme.&amp;quot; {
    algorithm hmac-sha256;
    secret &amp;quot;XPEosedwqiO3SiRUHh/fi52RdP1XkLFT2mFSs8EzrK4=&amp;quot;;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Include it in your /etc/bind/named.conf.local file, and give permissions to the DNS challenge. In this case, we only
want the &lt;code&gt;traefik-acme&lt;/code&gt; key to have access to &lt;code&gt;_acme-challenge.example.com.&lt;/code&gt; so we explicitly list it in the zone
stanza.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;include &amp;quot;/etc/bind/keys/traefik-acme.key&amp;quot;;
zone &amp;quot;example.com&amp;quot; {
    type master;
    file &amp;quot;/var/lib/bind/db.example.com&amp;quot;;
    update-policy {
        grant traefik-acme name _acme-challenge.example.com. TXT;
    };
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In your traefik configuration, add the following keys (note the ending dots):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNSUPDATE_TSIG_KEY=traefik-acme.
DNSUPDATE_TSIG_SECRET=XPEosedwqiO3SiRUHh/fi52RdP1XkLFT2mFSs8EzrK4=
DNSUPDATE_TSIG_ALGORITHM=hmac-sha256.
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;restart-bind&quot;&gt;Restart Bind&lt;/h4&gt;
&lt;p&gt;After editing, reload the bind9 server:&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ rndc reload&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test it with &lt;code&gt;nsupdate&lt;/code&gt; using the same key file:&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ nsupdate -k /etc/bind/tsig-keys.conf
&gt; server ns1.example.com
&gt; zone example.com
&gt; update add _challenge.example.com 300 TXT &quot;abc123&quot;
&gt; send&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A silent success (no error message) means the update was accepted and signed.&lt;/p&gt;
&lt;h3 id=&quot;step-4-allow-axfr-zone-transfers-with-the-same-key&quot;&gt;Step 4: Allow AXFR Zone Transfers with the Same Key&lt;/h3&gt;
&lt;p&gt;Zone transfers (AXFR) let a secondary server — or a sync tool, or a backup system — pull a full copy of a zone. You
should never allow open AXFR. Use the same TSIG key to restrict who may transfer, again via &lt;code&gt;update-policy&lt;/code&gt; in the zone:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;zone &amp;quot;example.com&amp;quot; {
    type master;
    file &amp;quot;/var/lib/bind/db.example.com&amp;quot;;
    update-policy {
        grant zoneforge zonesub any;
    };
    also-notify { 192.0.2.10; };      /* your secondary / sync tool */
    allow-transfer { key zoneforge; };
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;allow-transfer { key zoneforge; };&lt;/code&gt; says: only servers that can present this TSIG key may pull a full zone copy. That
one line is the difference between
&amp;quot;anyone can slurp my zone data&amp;quot; and &amp;quot;only my authenticated peers.&amp;quot;&lt;/p&gt;
&lt;p&gt;Verify the transfer works from the requesting side with &lt;code&gt;dig&lt;/code&gt; and the key:&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ dig @ns1.example.com example.com AXFR -y hmac-sha256:zoneforge:aB3dEf9...long-base64-secret...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you see the records stream out, the AXFR with TSIG is working.&lt;/p&gt;
&lt;h3 id=&quot;putting-it-together&quot;&gt;Putting It Together&lt;/h3&gt;
&lt;p&gt;The same key now does double duty: authenticated updates for the apex and all subdomains
(&lt;code&gt;update-policy grant ... zonesub any&lt;/code&gt;), and authenticated zone transfers (&lt;code&gt;allow-transfer { key zoneforge; }&lt;/code&gt;). Add &lt;code&gt;allow-update { key zoneforge; };&lt;/code&gt; only if you are on an older BIND version — &lt;code&gt;update-policy&lt;/code&gt; is the preferred mechanism on BIND 9.16+.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;section-2-age-keys-modern-simple-file-encryption&quot;&gt;Section 2: Age Keys — Modern, Simple File Encryption&lt;/h2&gt;
&lt;p&gt;Now let&#39;s talk secrets. &lt;code&gt;age&lt;/code&gt; is a modern file-encryption tool: simple, audited, and designed as a friendlier
replacement for PGP for the common case of &amp;quot;encrypt this file for this person.&amp;quot; It uses modern cryptography (X25519 +
ChaCha20-Poly1305) and has a tiny, comprehensible CLI.&lt;/p&gt;
&lt;h3 id=&quot;step-1-install-and-generate-a-key-pair&quot;&gt;Step 1: Install and Generate a Key Pair&lt;/h3&gt;
&lt;p&gt;Install it — &lt;code&gt;brew install age&lt;/code&gt; on macOS, &lt;code&gt;apt install age&lt;/code&gt; on Debian/Ubuntu,
&lt;code&gt;pacman -S age&lt;/code&gt; on Arch, or grab a release binary from the project. Then generate a key pair:&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ age-keygen -o key.txt
Public key: age1qrv95sau5h02a7wueelak7c83qgf6xf4tx08vcnyaqs6ef99ppvq34x062&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things just happened:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;key.txt&lt;/code&gt; contains your &lt;strong&gt;identity&lt;/strong&gt; (private key), which can decrypt messages meant for you. It is a secret — protect
it like one (chmod 600, keep it in a vault, etc.).&lt;/li&gt;
&lt;li&gt;The terminal printed your &lt;strong&gt;public key&lt;/strong&gt; (&lt;code&gt;age1...&lt;/code&gt;). This is what people and machines use to encrypt messages &lt;em&gt;to&lt;/em&gt;
you. It is safe to share anywhere.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-2-publish-the-public-key&quot;&gt;Step 2: Publish the Public Key&lt;/h3&gt;
&lt;p&gt;The public key is meant to be public. Add it to your website, your SSH/Git profile, a &lt;code&gt;keys&lt;/code&gt; page in your docs, or a
&lt;code&gt;key.pub&lt;/code&gt; file in your repo — however you want people to find you. For example, put this in a &lt;code&gt;keys.md&lt;/code&gt; or a &lt;code&gt;pubkey&lt;/code&gt;
endpoint:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;My age public key:

age1examplemushroom...long-public-key...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Anyone who sees it can now encrypt a file that only you can read. That is the whole trick of asymmetric encryption:
share the public key freely, guard the identity.&lt;/p&gt;
&lt;h3 id=&quot;step-3-encrypt-a-message&quot;&gt;Step 3: Encrypt a Message&lt;/h3&gt;
&lt;p&gt;Encrypt a file for a recipient using their public key:&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ age -e -r age1examplemushroom...long-public-key... &#92;
    -o message.age message.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-e&lt;/code&gt; means encrypt, &lt;code&gt;-r&lt;/code&gt; specifies the recipient&#39;s public key, and &lt;code&gt;-o&lt;/code&gt; names the output file. The result,
&lt;code&gt;message.age&lt;/code&gt;, is binary and safe to email, post, or commit — it leaks nothing without the matching identity.&lt;/p&gt;
&lt;p&gt;You can also pipe text straight in without touching disk:&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ echo &quot;hello, secure world&quot; | age -e -r age1examplemushroom... &gt; message.age&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just like gpg, you can use the &lt;code&gt;-a/--armor&lt;/code&gt; option to armor encode the output.&lt;/p&gt;
&lt;p&gt;And you can encrypt to &lt;em&gt;multiple&lt;/em&gt; recipients at once — handy when a secret needs to reach several people:&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ age -e &#92;
    -r age1alice... &#92;
    -r age1bob... &#92;
    -o secret.age secret.txt&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-4-decrypt-a-message&quot;&gt;Step 4: Decrypt a Message&lt;/h3&gt;
&lt;p&gt;To decrypt, use your identity file (the private half you generated earlier):&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ age -d -i key.txt -o message.txt message.age
$ cat message.txt
hello, secure world&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; means decrypt.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i key.txt&lt;/code&gt; tells age which identity to use. If the file was encrypted to that key, decryption succeeds; otherwise
age will error out and produce nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can also decrypt from stdin without saving the decrypted output to disk:&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ age -d -i key.txt &lt; message.age&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-practical-combined-example&quot;&gt;A Practical Combined Example&lt;/h3&gt;
&lt;p&gt;Encrypt a backup, then decrypt it later — or on another machine that holds the identity:&lt;/p&gt;
&lt;pre class=&quot;language-console&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ tar czf - /var/lib/bind | age -e -r age1examplemushroom... &gt; bind-backup.tgz.age
$ age -d -i key.txt &lt; bind-backup.tgz.age | tar xzf -&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;why-this-matters-next-to-tsig&quot;&gt;Why This Matters Next to TSIG&lt;/h3&gt;
&lt;p&gt;Notice a theme: in both halves of this post, one secret does the work. Your TSIG key authenticates DNS updates and zone
transfers between machines that share it. Your age identity decrypts secrets sent to you by anyone who has your public
key. In each case the rule is the same:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Publish&lt;/strong&gt; the non-secret part (the age public key; the zone names and policy you configure).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Guard&lt;/strong&gt; the secret part (the TSIG secret; the age identity).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restrict&lt;/strong&gt; what the key can do (a &lt;code&gt;zonesub&lt;/code&gt; grant instead of a blanket
&lt;code&gt;allow-update&lt;/code&gt;; an age identity kept off shared filesystems).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;DNS controls &lt;em&gt;where&lt;/em&gt; things live and who can talk to the servers; age controls &lt;em&gt;what&lt;/em&gt; is readable and by whom. Put both
together, and you have a solid foundation for automating DNS administration without handing out keys or secrets to
everyone who asks.&lt;/p&gt;
&lt;p&gt;I use my agekey to encrypt messages in my DNS zones. When I was manually editing a zone, then &lt;code&gt;rndc reload example.com&lt;/code&gt;
then remembering that I forgot to update the serial number, and reediting, and seeing something else that just wasn&#39;t
formatted right, and doing it all over again, and wondering if the serial number increment and &lt;code&gt;rndc reload&lt;/code&gt; command was
working correctly, I had comments in my zone files. An old IP address, a service renewal, an url of a site that that had
the SSHFP record generator: &lt;code&gt;ssh-keygen -r jeffharris.us.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Then, when I started using &lt;code&gt;nsupdate&lt;/code&gt;, and using dynamic zones, I lost my comments. So now, I use my agekey to encrypt a
string to myself, and add it as a TXT record in an _infra zone. Agekey strings are long, so don&#39;t try to encrypt a whole
novel, but it works, and you don&#39;t know what&#39;s there.&lt;/p&gt;
&lt;p&gt;I wonder if this will ever turn up in a spy novel as a way of passing information across the globe. Using an internet
cafe or a VPN to do a &lt;code&gt;dig&lt;/code&gt; of some site, copy the data, and you have your secret instructions for world domination.&lt;/p&gt;
&lt;h2 id=&quot;why-this-post&quot;&gt;Why This Post&lt;/h2&gt;
&lt;p&gt;I built age encryption into &lt;a href=&quot;https://zoneforge.1x0.us/&quot;&gt;ZoneForge&lt;/a&gt;, which conveniently lets you use your TSIG key, if
configured correctly to allow both nsupdate and AXFR transfers, to administer your bind9 files without that pesky SSH,
and totally without webmin. I&#39;m still working on it, so your miles may vary if it&#39;s close to the date of this post.&lt;/p&gt;
&lt;p&gt;Sign up, enter your TSIG key, and validate your first zone. We&#39;ll use your key to place a temporary TXT record on your
zone, then pull the record from DNS and remove the record. From then, you can make any changes you need. If you make
other changes outside the ZoneForge system, just click the button for an AXFR transfer, and we&#39;ll fetch all the records
and update the view.&lt;/p&gt;
&lt;p&gt;This is designed for those of us still using our own Bind9 DNS servers, and not the registrar&#39;s name servers.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Dynamic Zone Files</title>
    <link href="https://example.com/blog/services/dynamic-zone-files/" />
    <updated>2026-08-13T20:01:32Z</updated>
    <id>https://example.com/blog/services/dynamic-zone-files/</id>
    <content type="html">&lt;p&gt;I run my own dns servers. It all started when I wanted to put
my &lt;a href=&quot;https://dnscale.eu/learning/what-is-an-sshfp-record&quot;&gt;SSHFP&lt;/a&gt; records in my DNS. At the time, I had a small child, and
a trip to DisneyLand was not an unexpected weekend trip. But I didn&#39;t quite trust the hotel internet connections back
then, and wanted to make sure that I was actually connecting to my little server. SSHFP records were a way to validate
that no one in the hotel was running some MITM attack to try to get anything. If they knew my server, they wouldn&#39;t want
it, but still.&lt;/p&gt;
&lt;p&gt;So over the years, I now have four DNS servers scattered across the States, all with different providers, completely
robust; the only global failure would be if my billing doesn&#39;t go through.&lt;/p&gt;
&lt;p&gt;Adding to my Bind9 servers, I&#39;ve hooked up &lt;a href=&quot;https://doc.traefik.io/traefik/&quot;&gt;Traefik&lt;/a&gt; and have fought through sometimes
confusing or lacking documentation to configure Traefik/lego to use RFC2136 to issue DNS challenges for wildcard
domains. Doing this required all my zone files to become dynamic. That&#39;s fine, of course there&#39;s nothing wrong with
dynamic zones.&lt;/p&gt;
&lt;p&gt;Except for my comments. I had my zone files littered with comments: old IP addresses to reference if I had hardcoded an
address that I forgot; domain renewal dates; specific VPC machines that housed a domain. And my include files. It was
simple to have an include file that held all the common NS records and a CNAME for &lt;code&gt;opengpgkey&lt;/code&gt;, for a domain hosted on
GitLab Pages, or if it had Google SMTP servers, or Zoho, or other commonalities that would be best for include files.&lt;/p&gt;
&lt;p&gt;The loss of comments saddened me, but I figured I could take a JSON string, and encode it with
an &lt;a href=&quot;https://github.com/FiloSottile/age&quot;&gt;Age Key&lt;/a&gt; and add it as a TXT record on an _infra host. I still have the data
available, and no one else knows my secrets. Of course, who needs to know when my annual renewal is due besides me,
right?&lt;/p&gt;
&lt;p&gt;Wanting an easy way to create these encrypted TXT records, I created &lt;a href=&quot;https://zoneforge.1x0.us/&quot;&gt;ZoneForge&lt;/a&gt;. It requires
your TSIG key to send updates to your hosted Bind9 server for all record types, and uses your own Age Key to encrypt and
decrypt the _infra TXT records. It&#39;s still in pre-release/bugfix/finalizing stage, but I&#39;ve been able to change the DNS
settings for &lt;a href=&quot;https://isdavecanalesgoneyet.com/&quot;&gt;Is Dave Canales Gone Yet&lt;/a&gt;, and I&#39;ve added records to a new domain.&lt;/p&gt;
&lt;p&gt;You will need to have a zone already added in your &lt;code&gt;named.conf&lt;/code&gt; files, and a TSIG key with the proper grants, and I need
to finish configuration, but that will be coming shortly.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>DateTime Errors</title>
    <link href="https://example.com/blog/laravel/datetime-errors/" />
    <updated>2026-08-09T22:18:23Z</updated>
    <id>https://example.com/blog/laravel/datetime-errors/</id>
    <content type="html">&lt;p&gt;I&#39;ve learned a few lessons lately, one of them regards when not to make something multi-tenant. I started a project and
thought, &amp;quot;Yes, Multi-tenancy sounds like a good idea.&amp;quot; I know that multi-tenancy can be a good idea, but it turned out
to be too much for this project, so now I&#39;m unwinding multi-tenancy. Just having a tenant landing page isn&#39;t enough for
a multi-tenancy application.&lt;/p&gt;
&lt;p&gt;The other issue I have was invisible until just a few days ago. I ran some tests after 8:00 pm on the US east coast, and
tests that had never failed before were suddenly failing. In this project, I want the user to select a date, and the
backend converts it to a timestamp corresponding to the start of day in the Organization&#39;s timezone. So someone in Los
Angeles picks 2026-08-09, and the system converts it to &lt;code&gt;2026-08-09 00:00:00.0 America/Los_Angeles&lt;/code&gt;, then converts that
to UTC for the database. In this case, I didn&#39;t want the user to pick a date less than today in whatever timezone
they&#39;re in. My FormRequest contained code similar to&lt;/p&gt;
&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name static-context&quot;&gt;Carbon&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-casting&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;REQUEST_TIME&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;organization&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;timezone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;Y-m-d&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code worked before, but now, after 8:00 pm, it fails. It&#39;s tomorrow UTC, so I know that there&#39;s something with the
dates.&lt;/p&gt;
&lt;p&gt;Big Pickle tells me:
When you pass an &lt;strong&gt;integer Unix timestamp&lt;/strong&gt; to &lt;code&gt;Carbon::parse ()&lt;/code&gt;, it treats the timestamp as absolute and &lt;strong&gt;ignores the
timezone argument&lt;/strong&gt; (verified: &lt;code&gt;Carbon::parse (time (), &#39;America/Chicago&#39;)&lt;/code&gt; stays &lt;code&gt;+00:00&lt;/code&gt;). So &amp;quot;earliest start&amp;quot; is
computed in &lt;strong&gt;UTC&lt;/strong&gt;, not the org&#39;s timezone.&lt;/p&gt;
&lt;p&gt;So my form validation files were failing because the earliest start couldn&#39;t be less than tomorrow.&lt;/p&gt;
&lt;p&gt;The solution is to use&lt;/p&gt;
&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name static-context&quot;&gt;Carbon&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createFromTimestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-casting&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;REQUEST_TIME&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;organization&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;timezone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;Y-m-d&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;createFromTimestamp()&lt;/code&gt; honors the timezone (&lt;code&gt;2026-08-06&lt;/code&gt; in both NY and Chicago, verified above), so &amp;quot;earliest start&amp;quot; =
today in the org&#39;s timezone.&lt;/p&gt;
&lt;p&gt;The test case isn&#39;t really deterministic, and it can be modified to be. This allows creating tests at any time, testing
all edges. Instead of relying on the real &lt;code&gt;REQUEST_TIME&lt;/code&gt;, it should be pinned via &lt;code&gt;withServerVariables()&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;withServerVariables&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;REQUEST_TIME&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token class-name static-context&quot;&gt;Carbon&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;2026-08-07 01:00:00&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;UTC&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getTimestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;model.store&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have a numeric timestamp, &lt;code&gt;Carbon::parse()&lt;/code&gt; will ignore a timezone, and it&#39;s what you want. If you have a numeric
timestamp &lt;em&gt;and&lt;/em&gt; a timezone, &lt;code&gt;Carbon::createFromTimeStamp()&lt;/code&gt; is your friend.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Getting DESIGN.md Design Systems Working with OpenCode&#39;s MCP</title>
    <link href="https://example.com/blog/development/designmd-mcp/" />
    <updated>2026-07-27T03:05:05Z</updated>
    <id>https://example.com/blog/development/designmd-mcp/</id>
    <content type="html">&lt;p&gt;I&#39;ve been running more powerful AI models lately and wanted to use &lt;a href=&quot;https://opencode.ai&quot;&gt;opencode.ai&lt;/a&gt; to add some real
styling to my blog. The stock template was fine to get started, but I didn&#39;t want it looking like every other default
setup out there.&lt;/p&gt;
&lt;p&gt;That led me to &lt;a href=&quot;https://designmd.ai&quot;&gt;DESIGN.md&lt;/a&gt;, a site where people publish design systems as markdown files. Think of
it like a design system registry. You browse, you download, you implement. Simple enough.&lt;/p&gt;
&lt;p&gt;They have an MCP server, which means you can plug it directly into AI coding tools like OpenCode and query design
systems right from your editor. In theory.&lt;/p&gt;
&lt;h2 id=&quot;the-setup&quot;&gt;The Setup&lt;/h2&gt;
&lt;p&gt;OpenCode uses an &lt;code&gt;opencode.jsonc&lt;/code&gt; config file where you declare your MCP servers. The DESIGN.md docs show you the
standard MCP config:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;mcpServers&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;designmd&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npx&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;args&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;designmd-mcp&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;env&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;DESIGNMD_API_KEY&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;your-key-here&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OpenCode&#39;s config format is a little different, it uses &lt;code&gt;&amp;quot;mcp&amp;quot;&lt;/code&gt; at the top level and drops the &lt;code&gt;mcpServers&lt;/code&gt; wrapper. So
you end up with something like this:&lt;/p&gt;
&lt;pre class=&quot;language-jsonc&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-jsonc&quot;&gt;{
  &quot;mcp&quot;: {
    &quot;designmd&quot;: {
      &quot;type&quot;: &quot;local&quot;,
      &quot;command&quot;: [&quot;npx&quot;, &quot;designmd-mcp&quot;],
      &quot;enabled&quot;: true,
      &quot;env&quot;: {
        &quot;DESIGNMD_API_KEY&quot;: &quot;dk_your_key_here&quot;
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Straightforward. I plugged in my API key, fired up OpenCode, and asked it to grab a design system.&lt;/p&gt;
&lt;h2 id=&quot;the-error&quot;&gt;The Error&lt;/h2&gt;
&lt;p&gt;It failed with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DESIGNMD_API_KEY environment variable is not set.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wait, what? The key is right there in the config. I triple-checked the spelling, the quotes, the comma placement. All
good. I even asked an OpenCode model to check my work.&lt;/p&gt;
&lt;p&gt;Here&#39;s the thing (according to DeepSeek V4): the MCP tools that DESIGN.md exposes check &lt;code&gt;process.env.DESIGNMD_API_KEY&lt;/code&gt; at runtime. When OpenCode
starts the MCP server, it passes the env vars from the config stanza just fine, the server itself can see them. But the
tool functions that the server exposes to the AI apparently run in a different context where that env var isn&#39;t
inherited.&lt;/p&gt;
&lt;p&gt;At least, that&#39;s its best guess after poking at it for a while.&lt;/p&gt;
&lt;h2 id=&quot;the-fix&quot;&gt;The Fix&lt;/h2&gt;
&lt;p&gt;What worked was setting the environment variable at the shell level:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;DESIGNMD_API_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dk_your_key_here&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Drop that in your &lt;code&gt;.zshrc&lt;/code&gt; or &lt;code&gt;.bashrc&lt;/code&gt;, open a new terminal, launch OpenCode, and suddenly everything works. The MCP
tools can see the key because it&#39;s in the parent process environment that OpenCode inherits.&lt;/p&gt;
&lt;h2 id=&quot;the-takeaway&quot;&gt;The Takeaway&lt;/h2&gt;
&lt;p&gt;None of this is documented anywhere obvious. The DESIGN.md MCP docs show you the MCP config format but don&#39;t mention
that you might also need the shell env var. And the error message points you back to the MCP config, which is already
correct.&lt;/p&gt;
&lt;p&gt;If you&#39;re using DESIGN.md with OpenCode (or probably any MCP client that doesn&#39;t perfectly bridge server env vars to
tool execution contexts), save yourself the head-scratching and add the key to your shell profile too. The double config
is harmless, the MCP stanza still matters for the server itself, and it saves you from the confusing error loop.&lt;/p&gt;
&lt;p&gt;A small doc update or a better error message would go a long way here. Until then, hopefully this saves someone the
twenty minutes I spent going in circles.&lt;/p&gt;
&lt;p&gt;But on the other hand, I have a better design for this little piece of my digital home.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Becoming numb to pain</title>
    <link href="https://example.com/blog/development/becoming-numb-to-pain/" />
    <updated>2026-07-08T00:00:00Z</updated>
    <id>https://example.com/blog/development/becoming-numb-to-pain/</id>
    <content type="html">&lt;p&gt;There is a post from Joel Clermont
about &lt;a href=&quot;https://masteringlaravel.io/daily/2026-07-08-republished-dont-become-numb-to-pain-in-your-project&quot;&gt;not becoming numb to pain in your project&lt;/a&gt;,
and I want to expand on it.&lt;/p&gt;
&lt;p&gt;When joining a new project, you have the opportunity to do a tissue test of the setup documentation. I heard the term
tissue test years ago, and can&#39;t find a definitive source anymore. Too many results for biological tests are in the
way.&lt;/p&gt;
&lt;p&gt;A &lt;dfn id=&quot;dfn-tissue-test&quot;&gt;tissue test&lt;/dfn&gt; refers to a test that you can only do once. Once you&#39;ve done it, you have
probably done some troubleshooting or installations that make future tests different from the first. It&#39;s like using a
tissue; you can only use it once. Every time you attempt to fix a problem, you&#39;re changing the situation. If a
dependency has been abandoned, or a major release changes an option, you&#39;ve now changed the starting point, and your
tissue test is invalid.&lt;/p&gt;
&lt;p&gt;I ran into that same problem recently when trying to give .NET a whirl. I was installing tools from scratch, and found
an issue in the setup documentation. Unfortunately, because the people who could fix the bug already had working
systems, they couldn&#39;t duplicate my starting point to verify the issue. I guess that&#39;s why there&#39;s Stack Overflow.&lt;/p&gt;
&lt;p&gt;All through high school band, and continuing through my community chorus and barbershop quartet, we become numb to pain.
There are certain spots in the numbers where there isn&#39;t adequate tuning, or a discrepancy in phrasing. It&#39;s always
thought of as &amp;quot;you can&#39;t fix everything at the same time,&amp;quot; so we fix the most glaring issues. As time goes on, the less
obtrusive errors continue, becoming habit in the performers, and in everyone else&#39;s ears.&lt;/p&gt;
&lt;p&gt;We become numb to the fact that the first phrase of the song has suboptimal tuning because the reprise needs more work.
It&#39;s not just development that becomes numb to pain, it&#39;s everything. Even football teams become numb to the pain of
their offensive line, saying &amp;quot;we&#39;ll work on that in the off-season.&amp;quot; And that&#39;s
why &lt;a href=&quot;https://www.raiders.com&quot;&gt;the Raiders&lt;/a&gt; were on the draft clock since the 18th week of last year&#39;s season.&lt;/p&gt;
&lt;ins datetime=&quot;2026-07-08T18:07:04&quot;&gt;
Another area in which to turn numb is typography. I&#39;m working on another project, and the fonts are all default, just
like every other project out there. So I want a slightly different serifed typeface. I pick one, and decide that it
looks a little goofy for the project. That&#39;s not a problem, I&#39;ll change it later. But you become blind to that pain.
&lt;/ins&gt;
</content>
  </entry>
  <entry>
    <title>Crumb Crusted Protein recipe</title>
    <link href="https://example.com/blog/recipes/crumb-crusted-protein/" />
    <updated>2026-05-12T15:49:59Z</updated>
    <id>https://example.com/blog/recipes/crumb-crusted-protein/</id>
    <content type="html">&lt;h2 id=&quot;crumb-crusted-protein&quot;&gt;Crumb Crusted Protein&lt;/h2&gt;
&lt;h3 id=&quot;you-will-need&quot;&gt;You will need&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1/2 cup bread crumbs&lt;/li&gt;
&lt;li&gt;1/2 tsp &lt;a href=&quot;https://example.com/blog/recipes/crumb-crusted-protein/#house-salt&quot;&gt;House Salt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;1 tsp italian seasoning&lt;/li&gt;
&lt;li&gt;1/2 tsp grated Parmesan cheese product&lt;/li&gt;
&lt;li&gt;2 portions of protein (chicken breast, pork chop, whatever floats your boat)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;instructions&quot;&gt;Instructions&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Combine dry ingredients in a gallon-sized zip bag&lt;/li&gt;
&lt;li&gt;Pat protein dry&lt;/li&gt;
&lt;li&gt;Slather protein in Duke&#39;s Mayonnaise&lt;/li&gt;
&lt;li&gt;Shake protein in zip bag with dry ingredients to coat.&lt;/li&gt;
&lt;li&gt;Bake on a cooking rack over a baking sheet at 350 F until done. Use a thermometer to check doneness.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;optional-changes&quot;&gt;Optional changes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;If you have the cheese in the green container, and you&#39;re in a hurry, go ahead and use it. Only you will know. Want to
be cheesier? Add more.&lt;/li&gt;
&lt;li&gt;Add a slice or two of provolone cheese to the chicken about 5 minutes before cooking is finished, top with your favorite
tomato-based pasta sauce and serve on top of a bed of spaghetti.&lt;/li&gt;
&lt;li&gt;Substitute Ranch Seasoning for the Italian seasoning and house salt.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;house-salt&quot;&gt;House Salt&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;1/2 tbsp table salt&lt;/li&gt;
&lt;li&gt;1/4 tbsp pepper&lt;/li&gt;
&lt;li&gt;1/4 tbsp garlic powder.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Combine and store in a sealed container.&lt;/p&gt;
&lt;p&gt;Make this in whatever volume you want, just know that the garlic powder may clump with the salt and pepper, so only make
what you&#39;re going to use in a month.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Using a logged-in User in Tinker</title>
    <link href="https://example.com/blog/laravel/tinker-logged-in-user/" />
    <updated>2026-05-08T14:59:31Z</updated>
    <id>https://example.com/blog/laravel/tinker-logged-in-user/</id>
    <content type="html">&lt;p&gt;During Laravel testing, we can use the &lt;a href=&quot;https://laravel.com/docs/13.x/http-tests#session-and-authentication&quot;&gt;
&lt;code&gt;actingAs()&lt;/code&gt;&lt;/a&gt; method
to authenticate a user into the testing environment.&lt;/p&gt;
&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;ExampleTest&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TestCase&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;#[&lt;/span&gt;&lt;span class=&quot;token attribute-content&quot;&gt;&lt;span class=&quot;token attribute-class-name class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;authenticated_user_can_see_dashboard&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;actingAs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name static-context&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;factory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/dashboard&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;assertOk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have an event in a model that requires the authenticated User:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Organization&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;#[&lt;/span&gt;&lt;span class=&quot;token attribute-content&quot;&gt;&#92;&lt;span class=&quot;token attribute-class-name class-name&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;booted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword static-context&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;created&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name type-declaration&quot;&gt;Organization&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$organization&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token class-name static-context&quot;&gt;OrganizationCreatedEvent&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$organization&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name static-context&quot;&gt;Auth&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;During testing, we use the &lt;code&gt;actingAs()&lt;/code&gt; method to fill the &lt;code&gt;Auth::user()&lt;/code&gt; model, but what happens when we need to create
an &lt;code&gt;Organization&lt;/code&gt; in the &lt;code&gt;tinker&lt;/code&gt; shell?&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$o&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Organization::factory&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;create&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

   TypeError  App&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;Events&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;OrganizationCreated::__construct&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;: Argument &lt;span class=&quot;token comment&quot;&gt;#2 ($user) must be of type App&#92;Models&#92;User, null given, called in vendor/laravel/framework/src/Illuminate/Foundation/Events/Dispatchable.php on line 15.&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;actingAs&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

   Error  Using &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt; when not &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; object context.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can&#39;t use &lt;code&gt;$this-&amp;gt;&lt;/code&gt; because, like the error message says, we&#39;re not in an object.&lt;/p&gt;
&lt;p&gt;But it&#39;s easy enough to add the user:&lt;/p&gt;
&lt;pre class=&quot;language-tinker&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-tinker&quot;&gt;&gt; $user = User::factory()-&gt;create();

[!] Aliasing &#39;User&#39; to &#39;App&#92;Models&#92;User&#39; for this Tinker session.
= App&#92;Models&#92;User {#8767
    name: &quot;Mrs. Candace Runolfsdottir&quot;,
    email: &quot;wauvot.kiara.borer@example.net&quot;,
    email_verified_at: &quot;2026-05-08 14:43:37&quot;,
    #password: &quot;&#92;$2y&#92;$12&#92;$ehsEQzkwABxZiH37PT1zpuQsR5ncLR1A78hEYPYMTAL1gxr..9XV6&quot;,
    #remember_token: &quot;lnVyiUqw6d&quot;,
    #two_factor_secret: null,
    #two_factor_recovery_codes: null,
    two_factor_confirmed_at: null,
    updated_at: &quot;2026-05-08 14:43:37&quot;,
    created_at: &quot;2026-05-08 14:43:37&quot;,
    id: 4,
  }

&gt;  app(&#39;auth&#39;)-&gt;guard(null)-&gt;setUser($user);

= Illuminate&#92;Auth&#92;SessionGuard {#8687
    +name: &quot;web&quot;,
  }

&gt; $o = Organization::factory()-&gt;create()

[!] Aliasing &#39;Organization&#39; to &#39;App&#92;Models&#92;Organization&#39; for this Tinker session.
= App&#92;Models&#92;Organization {#9165
    name: &quot;Reilly Ltd&quot;,
    updated_at: &quot;2026-05-08 14:43:52&quot;,
    created_at: &quot;2026-05-08 14:43:52&quot;,
    id: 2,
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the only thing I need to do is figure out how to fake or skip a &lt;code&gt;Notification&lt;/code&gt; automatically while in the &lt;code&gt;tinker&lt;/code&gt;
console.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Rule 13</title>
    <link href="https://example.com/blog/life-tips/rule-13/" />
    <updated>2026-05-07T00:00:00Z</updated>
    <id>https://example.com/blog/life-tips/rule-13/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;Rule 13&lt;/strong&gt; states that when you give a document to someone else to proofread, always leave a simple, intentional error
in the document. Don&#39;t make it obvious, like misspelling the very last word or the main title, but keep it in there
somewhere.&lt;/p&gt;
&lt;p&gt;If they don&#39;t tell you about the error, they probably didn&#39;t read it. Ask someone else to proofread your document.&lt;/p&gt;
</content>
  </entry>
</feed>