<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: J Now</title>
    <description>The latest articles on DEV Community by J Now (@palo_alto_ai).</description>
    <link>https://dev.to/palo_alto_ai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3875408%2F4401de35-525d-496b-b2fb-347e8052bfa1.png</url>
      <title>DEV Community: J Now</title>
      <link>https://dev.to/palo_alto_ai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/palo_alto_ai"/>
    <language>en</language>
    <item>
      <title>The OSS tool you built deserves more than one post</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Tue, 07 Jul 2026 12:46:56 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/the-oss-tool-you-built-deserves-more-than-one-post-2i21</link>
      <guid>https://dev.to/palo_alto_ai/the-oss-tool-you-built-deserves-more-than-one-post-2i21</guid>
      <description>&lt;p&gt;You posted your tool on launch day, got a handful of upvotes, and that was it. Not because the tool was bad — because consistent distribution requires showing up weekly across Bluesky, Mastodon, X, Dev.to, and Hashnode, remembering which angle you covered last, respecting per-channel character limits (280 on X, 300 on Bluesky, 150–400 words on Dev.to), and writing copy that doesn't read like a press release. Almost nobody does that work. The tool quietly dies.&lt;/p&gt;

&lt;p&gt;I built marketing-pipeline to handle the recurring part. You onboard a project once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;marketing onboard &lt;span class="nt"&gt;--name&lt;/span&gt; my-tool &lt;span class="nt"&gt;--repo&lt;/span&gt; owner/repo &lt;span class="nt"&gt;--kind&lt;/span&gt; mcp-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That fetches your README, sends it to Claude, and writes &lt;code&gt;problem&lt;/code&gt;, &lt;code&gt;facts&lt;/code&gt;, and &lt;code&gt;angles&lt;/code&gt; into &lt;code&gt;projects.yml&lt;/code&gt;. From there, a daily GitHub Actions cron at 14:00 UTC cycles through projects × angles × channels, picks the least-recently-used angle per project, formats the post to the channel's constraints, and publishes.&lt;/p&gt;

&lt;p&gt;The part I spent the most time on was preventing the output from reading like marketing copy. &lt;code&gt;pipeline/antislop.py&lt;/code&gt; hard-rejects specific tokens before anything gets published: &lt;code&gt;excited&lt;/code&gt;, &lt;code&gt;game-changer&lt;/code&gt;, &lt;code&gt;unlock&lt;/code&gt;, &lt;code&gt;empower&lt;/code&gt;, &lt;code&gt;AI-powered&lt;/code&gt;, emoji, hashtags, exclamation points, and rhetorical questions. If a draft contains any of them, the post is blocked and regenerated. The constraint is aggressive on purpose — most automated content fails because nobody built a gate that actually rejects the slop.&lt;/p&gt;

&lt;p&gt;Cross-posting also handles directory listings. The &lt;code&gt;kind&lt;/code&gt; field routes submissions to type-specific registries: &lt;code&gt;mcp-server&lt;/code&gt; goes to MCP Registry, Smithery, Glama, and PulseMCP; &lt;code&gt;claude-skill&lt;/code&gt; generates a payload for awesome-claude-code (human submission required — their rules); &lt;code&gt;browser-extension&lt;/code&gt; targets Chrome Web Store, Firefox AMO, and Edge Add-ons.&lt;/p&gt;

&lt;p&gt;You need an Anthropic API key and credentials for at least Bluesky, Dev.to, and Hashnode. Mastodon and Slack are optional.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/robertnowell/marketing-pipeline" rel="noopener noreferrer"&gt;https://github.com/robertnowell/marketing-pipeline&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Nobody ever measured whether short blog posts perform better</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Tue, 07 Jul 2026 11:01:39 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/nobody-ever-measured-whether-short-blog-posts-perform-better-192b</link>
      <guid>https://dev.to/palo_alto_ai/nobody-ever-measured-whether-short-blog-posts-perform-better-192b</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg2thvwmj8uy7sbptwpy2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg2thvwmj8uy7sbptwpy2.png" alt="cover" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every content guide cites "80% of readers quit after 350 words." That stat traces to a single founder interview describing internal data — no dataset, no methodology, no third-party verification.&lt;/p&gt;

&lt;p&gt;If you've been cutting posts to hit a word count, you've been optimizing for folklore.&lt;/p&gt;

&lt;p&gt;This matters if you write to build an audience: you have no actual evidence that shorter is better, only a widely repeated assertion from people who also never measured it. Seth Godin, who has published a blog nearly daily for decades: "I don't keep track… I don't know how many people read my blog." 37signals/Basecamp cites brevity as a value, not an outcome. Axios's Smart Brevity framework is real and structured — but the engagement number attached to it is unverified.&lt;/p&gt;

&lt;p&gt;The one format with a documented standard for what earns inclusion: Simon Willison, who has published 7,607 link posts since 2003, requires every entry to credit the creator by name, explain why it's worth reading, quote liberally, and "add something extra" so the reader gains value without clicking through. His weekly digest has one hard filter — external links are excluded if they carry no author-written annotation. Raw links don't get in. The gate is annotation quality, not word count.&lt;/p&gt;

&lt;p&gt;Separately, the only rigorous taxonomy of what humans actually judge as low-quality writing (arXiv 2509.19163, built from 19 expert interviews) found that "verbose text conveying minimal content" was the strongest consistent signal across all annotators — and that automated tools are weak at detecting it.&lt;/p&gt;

&lt;p&gt;The implication: density matters, but the brevity gospel has no data behind it. Write as long as the idea requires. Cut what's empty, not what's long.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt; Axios Smart Brevity framework [Tier 1]; Simon Willison link-blog practice [Tier 1]; arXiv 2509.19163 slop taxonomy [Tier 1]; Godin quote [Tier 3, direct].&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Months of Claude Code sessions, no idea if I was improving</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Mon, 06 Jul 2026 18:36:58 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/months-of-claude-code-sessions-no-idea-if-i-was-improving-2boo</link>
      <guid>https://dev.to/palo_alto_ai/months-of-claude-code-sessions-no-idea-if-i-was-improving-2boo</guid>
      <description>&lt;p&gt;I've been using Claude Code daily for months. Fast, yes. But I started noticing I had the same three moves: ask a question, paste in an error, ask for a refactor. I had no idea whether I was actually developing any depth or just getting faster at a narrow groove.&lt;/p&gt;

&lt;p&gt;Anthropic published a study in February 2026 (9,830 Claude conversations, 11 observable collaboration behaviors) that gave me a concrete baseline to check myself against. I built skill-tree to run that same classification on my own session history.&lt;/p&gt;

&lt;p&gt;Here's what it does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude plugin marketplace add robertnowell/ai-fluency-skill-cards
claude plugin &lt;span class="nb"&gt;install &lt;/span&gt;skill-tree-ai@ai-fluency-skill-cards
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 7-step orchestration takes 30–60 seconds: it finds your local session files, extracts user messages, ships them to a remote Claude Haiku classifier on Fly.io, maps results against the 11 behaviors from the AI Fluency Index, assigns one of seven archetype cards, writes a narrative, renders a visualization, and returns a stable URL. The archetype cards are rendered as tarot cards using curated museum art — see a live example at skill-tree-ai.fly.dev/fixture/illuminator.&lt;/p&gt;

&lt;p&gt;The part I built for myself specifically: a growth quest. After classification, it identifies which of the 11 behaviors are absent or underrepresented in your sessions and surfaces one as a concrete thing to try in your next session. That quest persists across sessions via a SessionStart hook (&lt;code&gt;~/.skill-tree/&lt;/code&gt; in Claude Code).&lt;/p&gt;

&lt;p&gt;The behavior taxonomy comes from Dakan &amp;amp; Feller's 4D AI Fluency Framework — three axes are observable in chat logs (Description, Discernment, Delegation); the fourth (Diligence) isn't captured from logs alone.&lt;/p&gt;

&lt;p&gt;Also available as an MCP server (npm package &lt;code&gt;skill-tree-ai&lt;/code&gt;) for Cursor, VS Code, and Windsurf if you're not on Claude Code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/robertnowell/ai-fluency-skill-cards" rel="noopener noreferrer"&gt;https://github.com/robertnowell/ai-fluency-skill-cards&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Klein blue is invisible as text — here's how I worked around it</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Mon, 06 Jul 2026 17:00:34 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/klein-blue-is-invisible-as-text-heres-how-i-worked-around-it-4808</link>
      <guid>https://dev.to/palo_alto_ai/klein-blue-is-invisible-as-text-heres-how-i-worked-around-it-4808</guid>
      <description>&lt;p&gt;I use Claude Code for hours every day, and most of what I read is prose — tool output, reasoning traces, permission prompts. Terminal themes are built for syntax highlighting: dark backgrounds with fine-tuned keyword colors. That's the wrong optimization when your screen is 80% English paragraphs.&lt;/p&gt;

&lt;p&gt;I wanted a theme tuned for body-size prose legibility over long sessions, anchored to a single color I actually cared about: Yves Klein's IKB, the ultramarine pigment he mixed himself and patented in 1960. Pure IKB is hex 002FA7.&lt;/p&gt;

&lt;p&gt;First thing I found: pure IKB fails as text on a dark background. APCA Lc score of -12 — effectively invisible. You can use it as decoration, borders, highlights. You cannot use it as readable text.&lt;/p&gt;

&lt;p&gt;Claude Code maps its permission-prompt text to the terminal's &lt;code&gt;ansi:blue&lt;/code&gt; slot. If I dropped IKB into &lt;code&gt;ansi:blue&lt;/code&gt;, the prompts would disappear. So I split the role across two slots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="err"&gt;ansi:&lt;/span&gt;&lt;span class="py"&gt;blue&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;002FA7   // pure IKB — decorative borders, structural chrome&lt;/span&gt;
&lt;span class="err"&gt;ansi:&lt;/span&gt;&lt;span class="py"&gt;blueBright&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;A8BEF0   // lifted Klein-family blue — permission-prompt body text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bright slot carries the readable text. The base slot carries the pigment. Neither lies about what it is — one is the color as an object, one is the color as legible language.&lt;/p&gt;

&lt;p&gt;The theme ships in four variations. Klein Void Prot is the one where every color role passes strict APCA gates: body text &amp;gt;= Lc 90, subtle &amp;gt;= 75, muted &amp;gt;= 45, accents &amp;gt;= 60. The others trade some strictness for warmth or brand character — Klein Void Sand &amp;amp; Sea accepts Claude's &lt;code&gt;ansi:redBright&lt;/code&gt; sand color as a second hero instead of neutralizing it.&lt;/p&gt;

&lt;p&gt;One implementation detail worth noting: none of this works unless you set Claude Code's &lt;code&gt;/theme&lt;/code&gt; picker to &lt;code&gt;dark-ansi&lt;/code&gt;. Claude Code ships with a hardcoded RGB palette and will ignore your terminal's ANSI colors entirely unless you explicitly switch it off.&lt;/p&gt;

&lt;p&gt;Built as macOS Terminal.app &lt;code&gt;.terminal&lt;/code&gt; profile files. Includes &lt;code&gt;install.sh&lt;/code&gt; and &lt;code&gt;restore.sh&lt;/code&gt; — fully rollback-able. CommitMono-Regular on the Prot variation, IBM Plex Mono on Gallery.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/robertnowell/klein-void" rel="noopener noreferrer"&gt;https://github.com/robertnowell/klein-void&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I wanted Wikipedia on every page — so I built it</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Mon, 06 Jul 2026 15:02:54 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/i-wanted-wikipedia-on-every-page-so-i-built-it-359j</link>
      <guid>https://dev.to/palo_alto_ai/i-wanted-wikipedia-on-every-page-so-i-built-it-359j</guid>
      <description>&lt;p&gt;Every article I read has words I half-know. Terms I skipped past in undergrad, concepts that would open up the whole paragraph if I just knew what they meant. Opening a new tab to look them up works once. By the third detour I've lost the thread of what I was reading entirely.&lt;/p&gt;

&lt;p&gt;So I built rabbitholes — a Chrome extension that turns any highlighted text into an inline explanation next to your cursor, without leaving the page.&lt;/p&gt;

&lt;p&gt;The tooltip renders in a shadow DOM, so it doesn't touch the host page's styles or layout. Explanations come from Claude Haiku 4.5 directly — requests go from your browser straight to &lt;code&gt;api.anthropic.com&lt;/code&gt;, no intermediary server, zero telemetry.&lt;/p&gt;

&lt;p&gt;The part I use most: every explanation ends with two suggested rabbit-hole topics. Click one and you're one hop deeper. The extension tracks how many hops you've taken — hit 'philosophy' and you get a shareable trail of where you went.&lt;/p&gt;

&lt;p&gt;There are a few other entry points worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click any word in the explanation to explore it further, or drag across words to pick a phrase&lt;/li&gt;
&lt;li&gt;Pencil icon opens a free-form follow-up that inherits the current context as background&lt;/li&gt;
&lt;li&gt;Globe icon re-runs the query enriched with Brave Search results, with source chips you can click through&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API key lives in &lt;code&gt;chrome.storage.sync&lt;/code&gt; (encrypted, never leaves the browser). Manifest V3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Nothing installs on the server side.&lt;/span&gt;
&lt;span class="c1"&gt;// You supply your own Anthropic API key.&lt;/span&gt;
&lt;span class="c1"&gt;// Requests: browser → api.anthropic.com&lt;/span&gt;
&lt;span class="c1"&gt;// That's the whole data path.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The thing that surprised me building this: the rabbit-hole counter makes you want to go deeper rather than feel guilty about it. It reframes the tangent as the point.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/robertnowell/rabbitholes" rel="noopener noreferrer"&gt;https://github.com/robertnowell/rabbitholes&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>When one translation isn't enough: building konid for real language use</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Mon, 06 Jul 2026 13:12:22 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/when-one-translation-isnt-enough-building-konid-for-real-language-use-481g</link>
      <guid>https://dev.to/palo_alto_ai/when-one-translation-isnt-enough-building-konid-for-real-language-use-481g</guid>
      <description>&lt;p&gt;I wanted to tell my girlfriend 'I missed you today' in Farsi — her first language. Google Translate gave me one answer, no context, no sense of whether it sounded tender or clinical or weird. I had no way to know if it would land the way I meant it.&lt;/p&gt;

&lt;p&gt;That's the gap konid fills. For any phrase you want to say, it returns three options ordered casual to formal, with the register explained and cultural context on what separates them. Audio pronunciation plays directly through your speakers — no API key, no copying text into a separate tab — using node-edge-tts under the hood.&lt;/p&gt;

&lt;p&gt;The example that made me build this: 'I missed you today' in Farsi has options that range from something you'd text a close friend to something that reads more poetic and deliberate. A single literal translation gives you none of that. Knowing which to pick — and why — is the actual thing you need.&lt;/p&gt;

&lt;p&gt;Konid works as an MCP server, so it runs inside Claude Code, Cursor, VS Code Copilot, Windsurf, Zed, JetBrains, and Claude Cowork. Install in Claude Code with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add konid-ai &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; konid-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also works as a ChatGPT app via Developer mode using the endpoint &lt;code&gt;https://konid.fly.dev/mcp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The tool supports 13+ languages: Mandarin, Japanese, Korean, Spanish, French, German, Portuguese, Italian, Russian, Arabic, Hindi, and more. MIT licensed.&lt;/p&gt;

&lt;p&gt;I named it after the Farsi word كنيد — 'do,' as in take action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/robertnowell/konid-language-learning" rel="noopener noreferrer"&gt;https://github.com/robertnowell/konid-language-learning&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>node</category>
      <category>showdev</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Why your email designs fail silently (and a scorer that catches it first)</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Mon, 06 Jul 2026 11:31:40 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/why-your-email-designs-fail-silently-and-a-scorer-that-catches-it-first-984</link>
      <guid>https://dev.to/palo_alto_ai/why-your-email-designs-fail-silently-and-a-scorer-that-catches-it-first-984</guid>
      <description>&lt;p&gt;Every email tool I've used hands you a blank canvas, a template library, and silence. You build the campaign, it looks fine on your 27-inch monitor, you send it, and the open rate is fine but the click rate is not. You never find out why.&lt;/p&gt;

&lt;p&gt;The problem isn't the blank canvas. It's that there's no feedback loop between design choices and measurable quality — until the campaign is already out.&lt;/p&gt;

&lt;p&gt;I built kopi to close that loop before send. Every email gets an automated design critique that scores layout hierarchy, mobile readability, CTA contrast, and 12 other criteria on a 0–100 scale. The score isn't decoration: a 93/100 email typically has a single dominant CTA with surrounding whitespace, a font-size stack that scales to 375px without horizontal scroll, and a contrast ratio on the primary button that clears WCAG AA. A 70/100 email usually has two competing CTAs, body text that wraps awkwardly on mobile, or a hero image that pushes the first button below the fold on phone screens.&lt;/p&gt;

&lt;p&gt;You can see the distribution yourself — the public gallery at trykopi.ai/emails shows 400+ emails that scored 80 or above.&lt;/p&gt;

&lt;p&gt;Generation side: you write a prompt describing the campaign (product, offer, tone, audience), and kopi returns a complete HTML email in under 5 minutes. It can learn your brand's fonts, colors, and layout preferences so you're not resetting defaults every session. Direct export to Klaviyo, and it runs as an MCP server if you're working in Claude Code, Cursor, or ChatGPT.&lt;/p&gt;

&lt;p&gt;The part I found most useful building this: the scoring surfaces decisions you didn't realize you made. You dragged a button to the bottom of a long section because it felt natural — the scorer tells you the CTA contrast is 3.2:1 and mobile users are scrolling past it. That's the feedback loop that was missing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trykopi.ai" rel="noopener noreferrer"&gt;https://trykopi.ai&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I built a skill-tree for Claude Code because I couldn't tell if I was improving</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Thu, 02 Jul 2026 18:30:23 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/i-built-a-skill-tree-for-claude-code-because-i-couldnt-tell-if-i-was-improving-2bdb</link>
      <guid>https://dev.to/palo_alto_ai/i-built-a-skill-tree-for-claude-code-because-i-couldnt-tell-if-i-was-improving-2bdb</guid>
      <description>&lt;p&gt;I've used Claude Code daily for months. At some point I noticed I was faster — but faster at the same handful of moves: ask, review, iterate. I had no idea if I was actually developing fluency or just automating my existing habits.&lt;/p&gt;

&lt;p&gt;In February 2026, Anthropic published a study of 9,830 Claude conversations measuring 11 observable collaboration behaviors. I wanted to know what mine looked like against that baseline, and more importantly, which behaviors I never touch.&lt;/p&gt;

&lt;p&gt;skill-tree analyzes your Claude Code session history, classifies those same 11 behaviors using the Dakan &amp;amp; Feller 4D AI Fluency Framework (three axes are visible in chat logs: Description, Discernment, Delegation — Diligence isn't), assigns one of seven archetype cards, and picks a growth quest for your next session.&lt;/p&gt;

&lt;p&gt;The archetype cards are rendered as tarot cards with curated museum art. You can see a live example at skill-tree-ai.fly.dev/fixture/illuminator.&lt;/p&gt;

&lt;p&gt;The 7-step orchestration — find session files, extract user messages, remote classifier (Claude Haiku on Fly.io), archetype assignment, narrative synthesis, render, return URL — takes about 30–60 seconds end-to-end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The interesting design constraint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The growth quest needs to persist across sessions so Claude Code picks it up at the start of your next chat via a &lt;code&gt;SessionStart&lt;/code&gt; hook. In Claude Code that's straightforward: write to &lt;code&gt;~/.skill-tree/&lt;/code&gt; and the path is stable.&lt;/p&gt;

&lt;p&gt;Cowork was the problem. Cowork's &lt;code&gt;$HOME&lt;/code&gt; is ephemeral — it resets between sessions. A state file written to &lt;code&gt;~/&lt;/code&gt; just disappears. The fix was a dual-state-path design: Claude Code uses &lt;code&gt;~/.skill-tree/&lt;/code&gt;, Cowork uses &lt;code&gt;$CLAUDE_PLUGIN_ROOT/.user-state/&lt;/code&gt; which is durable because it lives inside the plugin root rather than the user home.&lt;/p&gt;

&lt;p&gt;This meant every read and write in the orchestration had to resolve the right base path at runtime depending on which host it was running in. Not complicated, but worth knowing if you're building anything stateful for Cowork.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Claude Code install&lt;/span&gt;
claude plugin marketplace add robertnowell/ai-fluency-skill-cards
claude plugin &lt;span class="nb"&gt;install &lt;/span&gt;skill-tree-ai@ai-fluency-skill-cards

&lt;span class="c"&gt;# Cowork: upload skill-tree-ai.zip via plugin manager&lt;/span&gt;

&lt;span class="c"&gt;# Also available as MCP server for Cursor, VS Code, Windsurf&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;skill-tree-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repo and full install docs: &lt;a href="https://github.com/robertnowell/ai-fluency-skill-cards" rel="noopener noreferrer"&gt;https://github.com/robertnowell/ai-fluency-skill-cards&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>"# APCA per-role contrast gates and why WCAG lies on dark terminals\n\</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Thu, 02 Jul 2026 16:35:24 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/-apca-per-role-contrast-gates-and-why-wcag-lies-on-dark-terminalsn-17ge</link>
      <guid>https://dev.to/palo_alto_ai/-apca-per-role-contrast-gates-and-why-wcag-lies-on-dark-terminalsn-17ge</guid>
      <description>&lt;p&gt;"# APCA per-role contrast gates and why WCAG lies on dark terminals\n\nReading paragraphs of tool output for hours through a syntax-highlighting theme is the wrong pairing. Syntax themes optimize for token-level scanning; prose at body size needs different contrast targets. I kept noticing eye strain before I named the problem.\n\nI built four Terminal.app themes (klein-blue) around Yves Klein's IKB pigment, verified with APCA contrast gates per text role rather than a single WCAG ratio.\n\n## The asymmetry WCAG misses\n\nWCAG 2.1's contrast ratio is symmetric — same math for dark-on-light and light-on-dark. APCA is asymmetric because perception is. The same luminance delta reads differently depending on polarity, and terminal themes are always light text on dark ground.\n\nIKB on dark ground is the concrete case. The pigment's hex value produces APCA Lc -12 against near-black: effectively invisible. Some WCAG configurations pass this. APCA fails it, correctly.\n\nThe design fix: split blue across two ANSI slots by function, not aesthetics.\n\n&lt;br&gt;
&lt;br&gt;
&lt;code&gt;\nansi:blue       pure IKB (Lc -12)   # decorative only — Claude Code uses this for borders\nansi:blueBright A8BEF0 (passes Lc 60) # Claude Code uses this for permission-prompt text\n&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
\n\nBorders don't need to be read. Prompts do. Keeping the split means IKB stays unmixed where it's display-only, lifted only where it carries information.\n\n## Gate structure across four variations\n\n&lt;br&gt;
&lt;br&gt;
&lt;code&gt;\nbody   &amp;gt;= Lc 90\nsubtle &amp;gt;= Lc 75\nmuted  &amp;gt;= Lc 45\naccent &amp;gt;= Lc 60\n&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
\n\nKlein Void Prot (V3) passes all gates strictly. Klein Void Gallery trades some accent slots for maximum visual void. Klein Void Sand &amp;amp; Sea accepts the &lt;code&gt;ansi:redBright&lt;/code&gt; brand color as a second hero; Klein Void Refined neutralizes it to keep a single-color interface.\n\nInstalls via &lt;code&gt;bash install.sh&lt;/code&gt; to macOS Terminal.app, fully reversible via &lt;code&gt;bash restore.sh&lt;/code&gt;. Requires the &lt;code&gt;/theme&lt;/code&gt; picker set to &lt;code&gt;dark-ansi&lt;/code&gt; — otherwise the ANSI palette is bypassed entirely.\n\nhttps://github.com/robertnowell/klein-void",&lt;/p&gt;

</description>
    </item>
    <item>
      <title>No server in the middle: how rabbitholes handles your API keys</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Thu, 02 Jul 2026 14:45:03 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/no-server-in-the-middle-how-rabbitholes-handles-your-api-keys-2gfo</link>
      <guid>https://dev.to/palo_alto_ai/no-server-in-the-middle-how-rabbitholes-handles-your-api-keys-2gfo</guid>
      <description>&lt;p&gt;Most Chrome extensions that call external APIs route requests through the developer's backend. You're asking users to trust that their queries — what they're reading, what they don't understand — don't get logged or sold. That's a promise made in a privacy policy, not enforced by architecture.&lt;/p&gt;

&lt;p&gt;I built rabbitholes to highlight any text and get an inline explanation without opening a new tab. The usage pattern is ambient: you're mid-article, you highlight a phrase you half-know, an explanation pops up next to your cursor in a shadow-DOM tooltip. Then you click a word in the explanation to go deeper, or hit the rabbit-hole counter to see how many hops you've taken. That pattern produces a granular record of what you read and what confused you. I didn't want that record to exist on my end.&lt;/p&gt;

&lt;p&gt;So the architecture skips the intermediary entirely. Requests go directly from your browser to &lt;code&gt;api.anthropic.com&lt;/code&gt; (for explanations via Claude Haiku 4.5) and &lt;code&gt;api.search.brave.com&lt;/code&gt; (for the globe-icon web-enriched mode, which appends Brave Search results and source chips). Your API keys live in &lt;code&gt;chrome.storage.sync&lt;/code&gt; — Chrome encrypts them and syncs them to your account; they never hit a server I control because there is no server I control.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Full outbound call — no proxy layer&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.anthropic.com/v1/messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-api-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// retrieved from chrome.storage.sync&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;anthropic-version&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2023-06-01&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Manifest V3 &lt;code&gt;host_permissions&lt;/code&gt; are scoped to exactly those two domains. No analytics SDK, no Sentry, no telemetry pipeline. Zero.&lt;/p&gt;

&lt;p&gt;The cost of this design: you need your own API keys. For personal reading use, Claude Haiku 4.5 runs cheap enough that it's a rounding error. Brave Search has a free tier that covers light use.&lt;/p&gt;

&lt;p&gt;The benefit: your reading habits stay yours. What you looked up, what confused you, how far down a rabbit hole you went — none of that transits my infrastructure, because there isn't any.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/robertnowell/rabbitholes" rel="noopener noreferrer"&gt;https://github.com/robertnowell/rabbitholes&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>When one translation isn't enough: building a language coach as an MCP server</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Thu, 02 Jul 2026 12:37:51 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/when-one-translation-isnt-enough-building-a-language-coach-as-an-mcp-server-2p64</link>
      <guid>https://dev.to/palo_alto_ai/when-one-translation-isnt-enough-building-a-language-coach-as-an-mcp-server-2p64</guid>
      <description>&lt;p&gt;I wanted to tell my girlfriend 'I missed you today' in Farsi and have it land naturally, not like I'd copy-pasted it from Google Translate. Every tool I tried gave me one answer, no register, no sense of whether it was formal or intimate or accidentally weird. For a language you're still learning, that single flat translation teaches you nothing — it just gets you through the moment.&lt;/p&gt;

&lt;p&gt;So I built konid: a language coach that returns three options for anything you want to say, ordered casual to formal, each one with the register explained and the nuances between them compared. It also plays audio pronunciation directly through your speakers using node-edge-tts, no external API key needed.&lt;/p&gt;

&lt;p&gt;The interesting design constraint was the MCP server architecture. I wanted the same tool available everywhere I'm already working — not a separate app to switch to. One install, four clients:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add konid-ai &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; konid-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gets you konid inside Claude Code and Claude Cowork. The same server runs in Cursor, VS Code Copilot, Windsurf, Zed, and JetBrains via their respective MCP config blocks. For ChatGPT, it also works as a Developer mode app pointing at &lt;code&gt;https://konid.fly.dev/mcp&lt;/code&gt; — same logic, no extra code.&lt;/p&gt;

&lt;p&gt;The write-once-run-anywhere part matters because context switching is what kills language learning in a workflow. If I'm translating a work email in Cursor and want to know whether 'I look forward to hearing from you' should be formal or whether there's a warmer register that's still professional in Japanese, I want the answer inline, not in another tab.&lt;/p&gt;

&lt;p&gt;A query against konid in any of those clients returns three ranked options with the cultural context and register difference explained. For 'I missed you today' in Farsi, those three options are genuinely different sentences — not rewording of the same translation — because the intimate/casual/formal split in Farsi operates at the verb level, not just politeness particles.&lt;/p&gt;

&lt;p&gt;konid supports 13+ languages including Mandarin, Japanese, Korean, Spanish, French, German, Portuguese, Italian, Russian, Arabic, and Hindi.&lt;/p&gt;

&lt;p&gt;MIT licensed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/robertnowell/konid-language-learning" rel="noopener noreferrer"&gt;https://github.com/robertnowell/konid-language-learning&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>When you post once and get silence, distribution is the bug</title>
      <dc:creator>J Now</dc:creator>
      <pubDate>Thu, 02 Jul 2026 10:53:57 +0000</pubDate>
      <link>https://dev.to/palo_alto_ai/when-you-post-once-and-get-silence-distribution-is-the-bug-10if</link>
      <guid>https://dev.to/palo_alto_ai/when-you-post-once-and-get-silence-distribution-is-the-bug-10if</guid>
      <description>&lt;p&gt;The first time I shipped an open source tool, I wrote a good README, posted to Hacker News, got three upvotes, and concluded the project wasn't useful. It was useful. I just never showed up again.&lt;/p&gt;

&lt;p&gt;Distribution for OSS isn't a one-day task. It's submitting to directories, writing posts across four platforms, rotating angles so you're not repeating yourself, and doing all of that every week without burning out on it. Most people don't have the time or the inclination, so the project dies.&lt;/p&gt;

&lt;p&gt;I built &lt;code&gt;marketing-pipeline&lt;/code&gt; to run that recurring work without daily intervention. One command onboards a project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;marketing onboard &lt;span class="nt"&gt;--name&lt;/span&gt; my-tool &lt;span class="nt"&gt;--repo&lt;/span&gt; owner/repo &lt;span class="nt"&gt;--kind&lt;/span&gt; mcp-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That fetches the README, sends it to Claude, and writes problem statements, factual claims, and rotation angles to &lt;code&gt;projects.yml&lt;/code&gt;. From there, a GitHub Actions cron at 14:00 UTC on weekdays picks the least-recently-used angle per project, drafts posts for Bluesky, Mastodon, X, Dev.to, and Hashnode, enforces per-channel length limits (Bluesky 300 chars, X 280, Dev.to 150-400 words), and publishes.&lt;/p&gt;

&lt;p&gt;The part I want to highlight here is the anti-slop gate in &lt;code&gt;pipeline/antislop.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;LLM-drafted marketing copy has a fingerprint: "excited to share," "game-changer," "unlock," "empower," "AI-powered," rhetorical questions, emoji, hashtags, exclamation points. These tokens don't just read badly — they signal that nobody with actual opinions wrote this. The antislop gate hard-rejects any draft containing them before it ever reaches a publish step. This is a regex blacklist, not a prompt instruction. Prompting Claude to "sound natural" doesn't hold over time; a regex gate does.&lt;/p&gt;

&lt;p&gt;Directory submission is also automated by project &lt;code&gt;kind&lt;/code&gt;: &lt;code&gt;mcp-server&lt;/code&gt; routes to MCP Registry, Smithery, Glama, and PulseMCP; &lt;code&gt;claude-skill&lt;/code&gt; to awesome-claude-code (payload generated, but their rules require a human to submit via GitHub issue — that one step can't be scripted out); &lt;code&gt;browser-extension&lt;/code&gt; to Chrome Web Store, Firefox AMO, and Edge Add-ons.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/robertnowell/marketing-pipeline" rel="noopener noreferrer"&gt;https://github.com/robertnowell/marketing-pipeline&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
