<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>Dakota Smith Blog</title>
    <link>https://dak-dev.vercel.app</link>
    <description>High-performance personal blog featuring engineering projects, web development insights, and technical tutorials.</description>
    <language>en-us</language>
    <copyright>© 2026 Dakota Smith</copyright>
    <managingEditor>dakota@twofold.tech (Dakota Smith)</managingEditor>
    <webMaster>dakota@twofold.tech (Dakota Smith)</webMaster>
    <pubDate>Tue, 09 Jun 2026 00:00:00 GMT</pubDate>
    <lastBuildDate>Tue, 09 Jun 2026 00:00:00 GMT</lastBuildDate>
    <generator>Custom RSS generator (Next.js)</generator>
    <docs>https://www.rssboard.org/rss-specification</docs>
    <ttl>60</ttl>
    <atom:link href="https://dak-dev.vercel.app/feed.xml" rel="self" type="application/rss+xml" />
    <image>
      <url>https://dak-dev.vercel.app/og-default.png</url>
      <title>Dakota Smith Blog</title>
      <link>https://dak-dev.vercel.app</link>
    </image>
    <item>
      <title>Building a Deep Research Agent That Verifies Its Sources</title>
      <link>https://dak-dev.vercel.app/blog/deep-research-agent-fan-out-adversarial-verification</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/deep-research-agent-fan-out-adversarial-verification</guid>
      <pubDate>Tue, 09 Jun 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Learn how I built a deep research agent that fans out across sources, then refutes its own findings with three skeptics before reporting a single cited claim.</description>
      <content:encoded><![CDATA[<p>Most "research agents" report whatever they find. They search, they summarize, and they hand you a confident paragraph that launders a forum guess into a fact. My deep research agent does the opposite: before any claim reaches the report, three independent skeptics try to refute it, and two of three votes against kill it. What survives is what could not be argued down.</p>
<p>A deep research agent earns trust through verification, not fluency. I run two research workflows that prove the point from opposite ends. One is a heavyweight harness that fans out across sources and adversarially checks every claim — roughly 100 model calls for a single question. The other is a lightweight daily scanner that makes one model call and never fans out. The lesson is matching the workflow shape to the job, and this post shows both shapes with the real numbers behind them.</p>
<p>Here's the architecture of the heavy one, the verification mechanism that makes it trustworthy, the price that rigor costs, and when the cheap workflow is the right call instead.</p>
<h2>The Shape of a Deep Research Agent</h2>
<p>The harness runs as a Claude Code workflow — a script that fans work out to subagents and collects structured results. The question moves through five phases:</p>
<table>
<thead>
<tr>
<th>Phase</th>
<th>What it does</th>
<th>Fan-out</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Scope</strong></td>
<td>Decompose the question into five complementary search angles</td>
<td>1 agent</td>
</tr>
<tr>
<td><strong>Search</strong></td>
<td>One web searcher per angle, ranking results against the original question</td>
<td>5 in parallel</td>
</tr>
<tr>
<td><strong>Fetch</strong></td>
<td>Deduplicate URLs, fetch the top sources, extract falsifiable claims with quotes</td>
<td>up to 15 in parallel</td>
</tr>
<tr>
<td><strong>Verify</strong></td>
<td>Adversarially test each claim with a panel of skeptics</td>
<td>3 votes × up to 25 claims</td>
</tr>
<tr>
<td><strong>Synthesize</strong></td>
<td>Merge duplicate claims, rank by confidence, write a cited report</td>
<td>1 agent</td>
</tr>
</tbody>
</table>
<p>The first decision is the fan-out. A single agent searching one query sees one slice of the topic. Five agents searching five angles — broad, technical, recent, contrarian, practitioner — surface evidence no single query would. Search and fetch run as a pipeline with no barrier between them, so a source found by the fast "recent news" angle starts extracting while the "academic" angle is still searching:</p>
<pre><code class="language-javascript">phase('Scope');
const scope = await agent(scopePrompt(question), { schema: SCOPE_SCHEMA }); // 5 angles

// Search (parallel) -> dedupe URLs -> fetch + extract. No barrier between stages.
const sources = await pipeline(
  scope.angles,
  (angle) => agent(searchPrompt(angle), { phase: 'Search', schema: SEARCH_SCHEMA }),
  (found) =>
    parallel(
      capToFetchBudget(dedupeByUrl(found), MAX_FETCH).map(
        (src) => () => agent(fetchPrompt(src), { phase: 'Fetch', schema: EXTRACT_SCHEMA }),
      ),
    ),
);
</code></pre>
<p>Each fetched source returns two to five <em>falsifiable</em> claims — concrete, checkable statements — each carrying a direct quote and a rating of central, supporting, or tangential. Vague generalities are rejected at extraction. A claim with no quote behind it never enters the pool.</p>
<h2>Adversarial Verification: Make the Agent Argue With Itself</h2>
<p>This is the part that separates a research agent from a summarizer. Every claim that matters is handed to three skeptics, each told to <em>refute</em> it. Their job is not neutral assessment. They hunt for the source that contradicts it, the overreach past the quote, the stale benchmark, the marketing copy dressed as a finding. A claim survives only if fewer than two of three votes refute it, and only if enough valid votes came back to adjudicate it at all:</p>
<pre><code class="language-javascript">const VOTES_PER_CLAIM = 3;
const REFUTATIONS_REQUIRED = 2;

const voted = await parallel(
  rankedClaims.map((claim) => () =>
    parallel(
      Array.from({ length: VOTES_PER_CLAIM }, (_, v) => () =>
        agent(refutePrompt(claim, v), { phase: 'Verify', schema: VERDICT_SCHEMA }),
      ),
    ).then((verdicts) => {
      const valid = verdicts.filter(Boolean); // a vote can abstain (null) on error or skip
      const refuted = valid.filter((v) => v.refuted).length;
      // Survive only if a quorum actually adjudicated AND fewer than 2 refuted.
      // All-abstain must not pass: refuted=0 would otherwise look like a clean win.
      const survives = valid.length >= REFUTATIONS_REQUIRED &amp;&amp; refuted &lt; REFUTATIONS_REQUIRED;
      return { ...claim, survives };
    }),
  ),
);
const confirmed = voted.filter((c) => c.survives);
</code></pre>
<p>Two details carry the weight. First, the verifier's verdict is structured, not prose:</p>
<pre><code class="language-typescript">interface Verdict {
  refuted: boolean;
  evidence: string; // must be specific — a contradicting source or a misread of the quote
  confidence: 'high' | 'medium' | 'low';
  counterSource?: string;
}
</code></pre>
<p>Second, the prompt sets the default to <strong>refuted=true when uncertain</strong>. A neutral verifier rounds toward "sounds plausible," which is how hallucinations survive. A verifier that must clear a skeptical bar rounds toward "not proven," which is the safer error for research. The abstention handling matters for the same reason: if every voter errors out, the claim has zero refutations, and a naive count would pass it. Requiring a quorum of real votes closes that gap.</p>
<h2>Why Structured Output at Every Hop</h2>
<p>Every phase returns typed JSON against a schema — scope, search results, extracted claims, verdicts, the final report. The orchestrator never parses prose. It reads <code>verdicts.filter(v => v.refuted)</code> and moves on. This is the same lesson from <a href="https://dak-dev.vercel.app/blog/durable-agent-orchestration-claude-managed-agents">moving agent orchestration into code</a>: the model produces data, and plain code makes the decisions. Schemas are the contract that keeps the control flow deterministic while the agents stay creative inside their boxes.</p>
<p>The synthesis step is the one place judgment returns. It receives only the confirmed claims, merges the ones that say the same thing, groups them into findings, assigns a confidence per finding, and writes a short answer with caveats and open questions. The refuted claims ride along in a transparency block, so the report shows its work — what it killed, not only what it kept.</p>
<h2>The Cost of Being Right</h2>
<p>Rigor is not cheap. The total model calls for one question follow a clear formula:</p>
<pre><code class="language-text">1 (scope) + 5 (search angles) + ~15 (sources) + 25 × 3 (verify) + 1 (synthesize) ≈ 97
</code></pre>
<p>Close to a hundred model calls to answer one question well. That is the deliberate trade. Take a one-off, high-stakes question: a technical decision, a medical differential, a market claim you are about to repeat in front of a client. A hundred calls is a rounding error against being confidently wrong. The adversarial panel is the difference between a report you can cite and a paragraph you have to re-check by hand.</p>
<p>It is the wrong trade for anything you do at volume. Run this harness on a schedule across many topics and the call count multiplies past any reasonable budget. That is where the second shape comes in.</p>
<h2>The Other Shape: a Daily Scanner That Doesn't Fan Out</h2>
<p>The contrast is a market scanner I built into an internal tool. It watches a set of competitors and trends and surfaces what changed, ranked by how much it matters. The requirements invert the deep research agent's: it runs every day, across many watches, and a missed item is cheaper than a blown budget. So it makes exactly one model call per scan — <code>claude-sonnet-4-6</code> with the server-side web search tool — and never fans out:</p>
<pre><code class="language-typescript">const res = await client.messages.create({
  model: 'claude-sonnet-4-6',
  max_tokens: 8000,
  tools: [{ type: 'web_search_20250305', name: 'web_search', max_uses: 8 }],
  system: SCAN_SYSTEM, // "Ground every signal in real results. If you can't verify it, drop it."
  messages: [{ role: 'user', content: watchBrief }],
});
</code></pre>
<p>The model searches up to eight times inside that single call, returns structured signals, and plain code does the ranking. Each signal scores on three factors, and the severity tier falls out of the score:</p>
<pre><code class="language-typescript">const score = materiality * relevance * recencyWeight; // each in 0..1
const severity = score >= 0.45 ? 'high' : score >= 0.25 ? 'medium' : 'low';
</code></pre>
<p>Recency is a bucketed decay — a result from today weights 1.0, one from the last month 0.8, anything past 90 days 0.6 — so fresh moves rise without a fragile timestamp formula. Deduplication is a fingerprint, <code>sha1(lane | normalized-title)</code>, checked against history so the same development never surfaces twice. A daily cron at 00:00 UTC runs the scan for every active watch and writes a ranked digest.</p>
<p>The honest limitation: there is no adversarial verification here. The system prompt tells the model to drop anything it cannot ground in a real result, and then it trusts that instruction. For continuous monitoring that is the right floor — a low-stakes feed where a human reviews items before acting. For a claim I am about to stake a decision on, it would not be enough. Different job, different floor.</p>
<h2>Match the Workflow to the Job</h2>
<p>The two workflows are the same idea tuned to opposite constraints. Neither uses Claude Managed Agents, which I reached for in the <a href="https://dak-dev.vercel.app/blog/claude-managed-agents-end-of-diy-infrastructure">durable build pipeline</a> — a reminder that the heavy infrastructure is a choice, not a default. A research workflow needs web access and structured output, not a persistent sandbox.</p>
<table>
<thead>
<tr>
<th>Dimension</th>
<th>Deep research agent</th>
<th>Daily scanner</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Trigger</strong></td>
<td>One-off question</td>
<td>Cron, every watch, every day</td>
</tr>
<tr>
<td><strong>Search</strong></td>
<td>Fan-out: 5 angles, parallel</td>
<td>Single call, ≤8 server-side searches</td>
</tr>
<tr>
<td><strong>Verification</strong></td>
<td>3-vote adversarial, kill on 2</td>
<td>Grounding instruction only</td>
</tr>
<tr>
<td><strong>Model calls</strong></td>
<td>~100 per question</td>
<td>1 per scan</td>
</tr>
<tr>
<td><strong>Right when</strong></td>
<td>High-stakes, must be correct</td>
<td>High-volume, human reviews output</td>
</tr>
</tbody>
</table>
<p><strong>Use the deep research agent when</strong> being wrong is expensive and the question is worth a hundred calls: a one-time investigation, a claim headed into a deliverable, a decision that is hard to reverse. <strong>Skip it when</strong> you need an answer in seconds, the stakes are low, or you are running the same query on a schedule — the verification overhead buys nothing there.</p>
<p><strong>Use the single-call scanner when</strong> volume and cost dominate and a human stays in the loop. <strong>Skip it when</strong> the output feeds an irreversible action with no review, because one ungrounded item can slip through. The scanner is a floor; the deep research agent is a gate.</p>
<h2>Conclusion</h2>
<p>A deep research agent is not a smarter summarizer. It is a workflow that assumes its own sources are guilty until verified, and the adversarial panel is what makes the output worth citing. The cheaper scanner is the same instinct at a different price point — grounded, deduplicated, ranked, and deliberately un-verified because the job tolerates it. Both beat the default research agent that reports its first plausible result.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li>Make the agent argue with itself: three skeptics per claim, kill on two refutations, and default to refuted when uncertain — neutrality is how hallucinations pass</li>
<li>Fan out across distinct angles so no single query defines the answer, and require a quote behind every extracted claim</li>
<li>Keep structured output at every hop so the orchestrator is plain code reading typed JSON, not a parser of prose</li>
<li>Adversarial rigor costs ~100 model calls per question — worth it for high-stakes one-offs, wrong for anything you run at volume</li>
<li>Match the workflow to the job: a single grounded call with web search for continuous monitoring, a fan-out-and-verify harness for decisions you cannot take back</li>
</ul>
<p>This is the companion to <a href="https://dak-dev.vercel.app/blog/durable-agent-orchestration-claude-managed-agents">durable agent orchestration</a>. That post fixed the routing in code; this one shows what to do when the routing is fixed but the <em>evidence</em> cannot be trusted — verify it, adversarially, before it counts.</p>]]></content:encoded>
      <category>ai</category>
      <category>claude</category>
      <category>agents</category>
      <category>research</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/deep-research-agent-fan-out-adversarial-verification/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/deep-research-agent-fan-out-adversarial-verification/thumbnail.jpg" />
    </item>
    <item>
      <title>Durable Agent Orchestration with Claude Managed Agents</title>
      <link>https://dak-dev.vercel.app/blog/durable-agent-orchestration-claude-managed-agents</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/durable-agent-orchestration-claude-managed-agents</guid>
      <pubDate>Tue, 09 Jun 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Learn why I moved agent orchestration into durable workflow steps instead of a coordinator agent, and the model, safety-gate, and cost tradeoffs it carried.</description>
      <content:encoded><![CDATA[<p>The most important agent orchestration decision I made on my last build was to keep the orchestration out of the agents. The tool turns a plain-language request — "audit our analytics tags against the measurement plan and flag duplicate events" — into a validated, installable Claude Code plugin, run by a pipeline of four Claude Managed Agents. The control flow that drives them lives in durable workflow steps I own, not inside a coordinator agent.</p>
<p>Anthropic's <code>callable_agents</code> API lets one coordinator agent delegate to specialists, which is the approach I used in <a href="https://dak-dev.vercel.app/blog/agent-operating-system-multi-agent-pipelines">my multi-agent auto-PR pipeline</a>. Both are legitimate agent orchestration patterns. This time I went the other way. Each stage is a durable step that creates a session, waits for the agent to finish, pulls its output file, and writes it to Postgres before the next stage starts. The control flow is plain TypeScript, not a model's runtime judgment.</p>
<p>Here's the full pipeline, the session-completion bug that cost me a day, the model-routing decision I reversed, the safety gate that stops generated plugins from auto-shipping, and when this approach is the wrong one.</p>
<h2>Two Ways to Handle Agent Orchestration</h2>
<p>There are two honest answers to "how do agents hand work to each other," and they suit different problems.</p>
<p><strong>Agent Orchestration.</strong> One agent holds a <code>callable_agents</code> list and decides who runs next. Handoffs are messages between isolated threads. This fits when the routing itself needs judgment — when the next step depends on what the last agent discovered, or the graph branches in ways you can't enumerate ahead of time. The cost: the control flow lives in a model's head. It is nondeterministic, and it spends tokens having the coordinator reason about routing you may already know. Resuming after a crash at stage four means reconstructing where the coordinator was.</p>
<p><strong>Agent workflow.</strong> The control flow is code. Stage order is fixed and visible in a file. Each step is durable — if the process dies after Scaffold, the run resumes at Review instead of starting over. Every stage writes its artifact to a database row, so a browser refresh replays the run from stored state rather than re-running agents.</p>
<p>I chose durable steps because my routing was fixed. A six-stage assembly line doesn't need a model to decide what comes next. It needs each station to be reliable, observable, and resumable. The orchestrator is <a href="https://useworkflow.dev">Vercel Workflow</a>; each stage is a <code>"use step"</code> function.</p>
<h2>The Pipeline: Six Surfaces, Four Agents</h2>
<p>The run moves through six surfaces. Only four of them are Managed Agents.</p>
<table>
<thead>
<tr>
<th>Stage</th>
<th>Surface</th>
<th>Job</th>
</tr>
</thead>
<tbody>
<tr>
<td>0 · Intake</td>
<td>Messages API (structured output)</td>
<td>Parse the request into a normalized intent spec; ask up to three clarifying questions if it is underspecified</td>
</tr>
<tr>
<td>1 · Design</td>
<td>Managed Agent</td>
<td>Turn the intent into a platform-agnostic plugin design</td>
</tr>
<tr>
<td>2 · Optimize</td>
<td>Managed Agent</td>
<td>Rewrite the design into buildable, checkable rules plus an annotated diff</td>
</tr>
<tr>
<td>3 · Scaffold</td>
<td>Managed Agent</td>
<td>Generate the real Claude Code plugin file tree</td>
</tr>
<tr>
<td>4 · Validate</td>
<td>Reuses the Scaffold session</td>
<td>Assert the bundle is correct; failure blocks handoff</td>
</tr>
<tr>
<td>5 · Review</td>
<td>Managed Agent</td>
<td>Independent critique and risk flags; verdict <code>ship</code> / <code>ship-with-fixes</code> / <code>do-not-ship</code></td>
</tr>
</tbody>
</table>
<p>Stage 0 is the first design lesson. Intake is not a Managed Agent — it is one structured-output Messages API call. Parsing free text into a typed JSON spec needs no container, no tools, and no file output, so a session would add startup latency and cost for nothing. The rule I now follow: reserve Managed Agents for stages that need a sandbox, tools, and a written artifact. Everything else stays a Messages call.</p>
<p>Each Managed-Agent stage is the same durable shape — create a session, send the work, wait for a true finish, persist the output:</p>
<pre><code class="language-typescript">// One pipeline stage as a durable Vercel Workflow step
export async function designStage(runId: string, intent: IntentSpec) {
  'use step';

  const session = await client.beta.sessions.create({
    agent: env.ANTHROPIC_AGENT_ID_DESIGNER,
    environment_id: env.ANTHROPIC_ENVIRONMENT_ID,
  });

  await client.beta.sessions.events.send(session.id, {
    events: [{ type: 'user.message', content: [{ type: 'text', text: designPrompt(intent) }] }],
  });

  const design = await waitForArtifact(session.id, 'design.json');
  await persistArtifact(runId, 'design', design); // -> Postgres: runs · jobs · artifacts
  return design;
}
</code></pre>
<p>Because each stage is its own durable step, the run survives a deploy, a cold start, or a closed laptop. The next stage reads the prior artifact from Postgres, so replaying a stage that already finished returns the stored result instead of paying for the agent twice.</p>
<h2>Running a Managed Agent to True Completion</h2>
<p>This is the part that cost me a day. <strong>Managed Agent sessions start idle.</strong> The naive check waits until the session is idle, then downloads the output. It fires on that initial idle state, before the agent has done any work, and downloads a file that does not exist.</p>
<p>The fix is to detect a <em>true</em> finish: the session reports idle <em>after</em> doing work (its stop reason is not <code>requires_action</code>), or it reports terminated. I poll newest-event-first and gate on both signals:</p>
<pre><code class="language-typescript">const POLL_INTERVAL_MS = 3000;
const MAX_POLLS_PER_STAGE = 200; // 3s × 200 ≈ 10 min ceiling per stage

async function waitForArtifact(sessionId: string, file: string) {
  for (let poll = 0; poll &lt; MAX_POLLS_PER_STAGE; poll++) {
    const { data: events } = await client.beta.sessions.events.list(sessionId, { limit: 100 });
    const latest = events[0]; // newest first
    const done =
      latest?.type === 'session.status_terminated' ||
      (latest?.type === 'session.status_idle' &amp;&amp; latest.stop_reason?.type !== 'requires_action');
    if (done) return downloadArtifact(sessionId, file);
    await sleep(POLL_INTERVAL_MS);
  }
  throw new Error(`Stage timed out after ${MAX_POLLS_PER_STAGE} polls`);
}
</code></pre>
<p>Downloading the artifact has its own trap. The Files API indexes a session's outputs one to three seconds <em>after</em> the session goes idle, so an immediate listing comes back empty. The download needs a short retry loop, and every Files call needs <strong>both</strong> beta headers or the listing fails intermittently:</p>
<pre><code class="language-typescript">const FILE_BETAS = ['managed-agents-2026-04-01', 'files-api-2025-04-14'];

async function downloadArtifact(sessionId: string, name: string) {
  for (let attempt = 0; attempt &lt; 4; attempt++) {
    const files = await client.beta.files.list({ scope_id: sessionId, betas: FILE_BETAS });
    const match = files.data.find((f) => f.filename.endsWith(name));
    if (match) {
      const blob = await client.beta.files.download(match.id, { betas: FILE_BETAS });
      return JSON.parse(await blob.text());
    }
    await sleep(1000); // wait for indexing, then re-list
  }
  throw new Error(`Output ${name} never indexed`);
}
</code></pre>
<p>I isolated every line that touches the beta API behind one module. When the beta header or the completion-signal shape changes — and on a public beta, it will — there is exactly one file to re-verify.</p>
<h2>The Model-Routing Decision I Reversed</h2>
<p>My first design routed by model tier: Sonnet for the cheap stages, Opus for Optimize, the stage that does the hardest reasoning. It read well on paper. In practice, Optimize on Opus ran six to nine minutes per stage, with high variance. That was close enough to my per-stage timeout to be a production risk, and slow enough that a live run felt broken.</p>
<p>I moved all four agents to <code>claude-sonnet-4-6</code>. Optimize stayed strong and dropped to a predictable runtime. The lesson: model tier is a latency decision as much as a quality one, and a slower top-tier stage that risks a timeout is worse than a faster stage that ships.</p>
<p>Cost lands where caching puts it. Each agent's system prompt is frozen at creation and never overridden per session, so repeated runs read it from cache at a tenth of the input price. A full six-stage run costs roughly $0.50 to $1.50, dominated by tokens — Sonnet runs $3 per million input and $15 per million output. A small managed-compute charge applies only while a session is actively running.</p>
<h2>The Safety Gate: Validate, Then Review</h2>
<p>The output of this pipeline is an installable Claude Code plugin. Plugins carry hooks and MCP configuration — code that runs on other people's machines. So the pipeline <strong>never auto-ships</strong>. It ends at a validated bundle behind a human gate, and two stages enforce that.</p>
<p>Stage 4, Validate, runs inside the Scaffolder's own session container and asserts the bundle is structurally correct. The plugin manifest must parse, every skill needs valid frontmatter, names must be kebab-case, and nothing nests where it shouldn't. A failure sets the bundle status to <code>failed</code>, surfaces the reason, and the pipeline does not advance. Reusing the Scaffolder's session here matters — the validator checks the exact files the agent wrote, in the same container.</p>
<p>Stage 5, Review, is a fresh agent reading the finished tree with no stake in having built it. It returns a typed verdict:</p>
<pre><code class="language-typescript">type ReviewVerdict = 'ship' | 'ship-with-fixes' | 'do-not-ship';

interface Review {
  verdict: ReviewVerdict;
  findings: { area: string; severity: 'blocker' | 'major' | 'minor'; issue: string; fix: string }[];
  risk_flags: string[]; // e.g. "hook runs a shell command", "MCP reads credentials"
}
</code></pre>
<p>A deterministic security scan runs before the Reviewer and is independent of it — plain pattern matching for hardcoded secrets, hooks that shell out, and MCP servers touching credentials. The Reviewer must triage every flag the scan raises rather than silently dropping it. That keeps a security floor even if the model misses something, because regex does not get tired or talked out of a finding.</p>
<p>I deliberately cut the stage that would have opened a pull request automatically. Unreviewed agent-generated code that runs on other machines is exactly the thing a human should approve. The gate is the product, not an obstacle to it.</p>
<h2>Tradeoffs and When Not To Do This</h2>
<p>Durable-step orchestration is not free, and it is not always right.</p>
<p><strong>The complexity tax is real.</strong> You take on a durable workflow runtime, a Postgres schema for runs, jobs, and artifacts, and a streaming layer to show progress. I also built a mock mode (<code>MOCK_AGENTS=1</code>) that returns fixture artifacts with realistic pacing, so I could test the agent orchestration end to end without spending tokens. That is another surface to maintain. A coordinator agent needs none of it — you configure agents and let one of them drive.</p>
<p><strong>Use a coordinator agent instead when</strong> the routing needs judgment: dynamic branching, an unknown number of steps, or a next-step that depends on what the last agent found. My graph was fixed, so code won. A research agent that decides what to investigate next does not have that luxury.</p>
<p><strong>Use a single Messages API call instead when</strong> the task is a one-shot transform or needs sub-second latency. My Intake stage proves the point inside the same system — not every box in the diagram deserves a session.</p>
<p><strong>Account for beta fragility.</strong> Managed Agents and the Files API both ship behind beta headers, and behaviors shift between releases. The completion-signal shape, the indexing lag, and the header strings are all things I expect to re-verify. Containing them in one module is what makes that survivable rather than a rewrite.</p>
<h2>Conclusion</h2>
<p>The portable lesson is about where agent orchestration logic belongs. If your routing is fixed, keep it in durable steps you can read, test, and resume — and treat each Managed Agent as a stateless worker that takes input, writes a file, and stops. If your routing needs judgment, give a coordinator agent the wheel and pay for the flexibility. Most real systems, like this one, are a mix: a Messages call where text becomes JSON, durable steps for the assembly line, and a human at the gate where the output runs on someone else's machine.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li>Put fixed routing in durable workflow steps, not a coordinator agent — you get determinism, resumability, and orchestration you can unit-test</li>
<li>Detect a Managed Agent's <em>true</em> completion (idle-after-work or terminated), because sessions start idle and a naive check downloads an empty artifact</li>
<li>Reserve Managed Agents for stages that need a sandbox, tools, and file output; a structured-output Messages call is faster and cheaper for parsing</li>
<li>Model tier is a latency decision too — I reversed an Opus stage to Sonnet after six-to-nine-minute runs threatened timeouts</li>
<li>When the output runs on other machines, end the pipeline at a human-reviewed gate with an independent verdict and a deterministic security scan</li>
</ul>
<p>This is the first of two posts. The next one goes a layer down — the Managed Agents fundamentals behind these stages and how the same building blocks power a <code>deep-research</code> command. If you want the architecture primer first, start with <a href="https://dak-dev.vercel.app/blog/claude-managed-agents-end-of-diy-infrastructure">why Managed Agents ends DIY agent infrastructure</a>, then <a href="https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio">the orchestration systems I built before this one</a>.</p>]]></content:encoded>
      <category>ai</category>
      <category>claude</category>
      <category>agents</category>
      <category>orchestration</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/durable-agent-orchestration-claude-managed-agents/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/durable-agent-orchestration-claude-managed-agents/thumbnail.jpg" />
    </item>
    <item>
      <title>Preparing for Mythos: Enterprise CMS Security Checklist</title>
      <link>https://dak-dev.vercel.app/blog/preparing-for-mythos-ai-security-checklist</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/preparing-for-mythos-ai-security-checklist</guid>
      <pubDate>Wed, 15 Apr 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Protect your enterprise CMS stack against the vulnerabilities Mythos exposed with this platform-specific checklist for Sitecore, Umbraco, and Optimizely.</description>
      <content:encoded><![CDATA[<p>An AI model found thousands of zero-day vulnerabilities across every major browser and operating system — some hiding for over two decades. On April 8, 2026, Anthropic announced Claude Mythos Preview alongside Project Glasswing, a $100M cybersecurity initiative. The Mythos AI security findings hit enterprise CMS stacks hard: TLS library flaws affect every .NET application handling HTTPS, kernel-level privilege escalations compromise the Windows and Linux servers running Sitecore, Umbraco, and Optimizely, and browser sandbox escapes put every authenticated CMS backoffice session at risk.</p>
<p>I manage CMS implementations for enterprise clients across all three platforms. Here's the platform-specific checklist I'm running right now, and what every CMS team should prioritize before the 90-day public disclosure window opens in July 2026.</p>
<h2>What Mythos Found and Why CMS Teams Should Care</h2>
<p>Mythos is Anthropic's most capable AI model. It wasn't built for security — but its code reasoning capabilities made it extraordinarily effective at chaining exploitable vulnerabilities. The findings relevant to enterprise CMS stacks:</p>
<table>
<thead>
<tr>
<th>Finding</th>
<th>CMS Impact</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Browser sandbox escapes</strong></td>
<td>Chained four vulnerabilities to escape both renderer and OS sandboxes. Every CMS backoffice session (Sitecore <code>/sitecore/admin/</code>, Umbraco <code>/umbraco/</code>, Optimizely <code>/episerver/</code>) becomes an attack vector if the editor's browser is unpatched.</td>
</tr>
<tr>
<td><strong>TLS/AES-GCM flaws</strong></td>
<td>.NET apps on Linux/Kestrel use OpenSSL directly. Self-hosted CMS instances with Kestrel reverse proxies are exposed. Windows IIS uses SChannel (not OpenSSL), but <code>HttpClient</code> calls to external APIs may route through vulnerable TLS stacks.</td>
</tr>
<tr>
<td><strong>Linux kernel privilege escalation</strong></td>
<td>Multiple chains affecting production servers. Any self-hosted CMS on Linux (common for Umbraco 10+ on Kestrel, containerized Sitecore XM Cloud builds) needs kernel patches.</td>
</tr>
<tr>
<td><strong>Windows Server vulnerabilities</strong></td>
<td>Kernel-level and HTTP.sys flaws affect IIS-hosted Sitecore 9-10, Umbraco, and Optimizely CMS 11-12.</td>
</tr>
<tr>
<td><strong>16-year-old FFmpeg bug</strong></td>
<td>CMS media pipelines using FFmpeg for video transcoding or thumbnail generation are exposed. Crafted file uploads are the attack vector.</td>
</tr>
</tbody>
</table>
<p>The 90x improvement in exploit success rate between Opus 4.6 and Mythos (2 successes vs. 181 on Firefox exploit development) signals that AI-assisted vulnerability discovery now outpaces manual security research. Enterprise CMS platforms carry large dependency trees and legacy code — exactly the type of surface area Mythos excels at analyzing.</p>
<h2>Sitecore: What to Patch and Harden Now</h2>
<p>Sitecore's attack surface depends heavily on which generation you're running.</p>
<h3>Sitecore 9.x–10.x (.NET Framework 4.8 / IIS)</h3>
<p><strong>Telerik UI is your top priority.</strong> Sitecore historically bundled Telerik UI for ASP.NET AJAX, which has a well-documented deserialization RCE history (CVE-2017-9248, CVE-2019-18935). If your <code>Telerik.Web.UI.DialogParametersEncryptionKey</code> is weak or default, an attacker with the capabilities Mythos demonstrates could chain this with the newly-discovered IIS/HTTP.sys vulnerabilities for full server compromise.</p>
<pre><code class="language-xml">&lt;!-- web.config — verify Telerik keys are rotated and strong -->
&lt;appSettings>
  &lt;!-- ROTATE these keys. Default or weak values are exploitable -->
  &lt;add key="Telerik.Web.UI.DialogParametersEncryptionKey" value="YOUR-STRONG-KEY-HERE" />
  &lt;add key="Telerik.Upload.ConfigurationHashKey" value="YOUR-STRONG-KEY-HERE" />
&lt;/appSettings>
</code></pre>
<p><strong>Additional hardening:</strong></p>
<ul>
<li>Block public access to <code>/sitecore/admin/</code> and <code>/sitecore/login/</code> via IP allowlisting or VPN</li>
<li>Audit <code>Newtonsoft.Json</code> usage — any <code>TypeNameHandling</code> setting other than <code>None</code> enables deserialization attacks</li>
<li>Patch Windows Server and IIS immediately against the disclosed HTTP.sys vulnerabilities</li>
<li>Review <code>Sitecore.config</code> for hardcoded <code>HashAlgorithm</code> keys and rotate them</li>
<li>Restrict media library upload extensions — Sitecore's default allows types that can trigger server-side processing vulnerabilities</li>
</ul>
<h3>Sitecore XM Cloud</h3>
<p>XM Cloud shifts the server-side risk to Sitecore's managed infrastructure, but your rendering host (Next.js on Vercel or self-hosted) still needs attention:</p>
<ul>
<li>Update your Next.js rendering host dependencies</li>
<li>Audit any middleware that processes media from the Sitecore CDN</li>
<li>Review Experience Edge API keys and scope permissions</li>
</ul>
<h2>Umbraco: Backoffice and Media Pipeline Risks</h2>
<p>Umbraco 10-14 runs on .NET 6/7/8, which means Kestrel is the default web server — and OpenSSL TLS vulnerabilities apply directly when hosted on Linux.</p>
<h3>Critical Items</h3>
<p><strong>ImageSharp is your FFmpeg equivalent.</strong> Umbraco uses ImageSharp for server-side image processing. Pre-3.x versions had memory exhaustion vulnerabilities (CVE-2022-24795) triggered by crafted image uploads. With Mythos demonstrating the ability to find similar media processing bugs at scale, update ImageSharp to the latest version and validate that your upload validation rejects malformed images before they hit the processing pipeline.</p>
<pre><code class="language-csharp">// Startup.cs — restrict upload file types and sizes
services.AddUmbraco(_env, _config)
    .AddBackOffice()
    .AddWebsite()
    .Build();

// In appsettings.json — tighten allowed upload extensions
// Remove any media types you don't need
{
  "Umbraco": {
    "CMS": {
      "Content": {
        "AllowedUploadedFileExtensions": ["jpg", "jpeg", "png", "gif", "webp", "svg", "pdf"]
      }
    }
  }
}
</code></pre>
<p><strong>Backoffice hardening:</strong></p>
<ul>
<li>Umbraco's backoffice at <code>/umbraco/</code> has no built-in rate limiting by default — add brute-force protection via middleware or a WAF</li>
<li>TinyMCE (the rich text editor) has had XSS vectors in older versions (CVE-2024-38356). Update to the version bundled with your Umbraco LTS release</li>
<li>If running on Linux/Kestrel: patch the kernel against Mythos-discovered privilege escalation chains</li>
<li>If running on Windows/IIS: patch HTTP.sys and the Windows kernel</li>
</ul>
<h3>Umbraco Cloud vs Self-Hosted</h3>
<p>Umbraco Cloud (Azure-managed) handles OS patching and TLS termination. Self-hosted instances inherit every OS and runtime vulnerability. If you're self-hosted, the Mythos findings add urgency to evaluating managed hosting — or at minimum, automating your patch pipeline.</p>
<h2>Optimizely: DXP Cloud vs Self-Hosted Exposure</h2>
<p>The security gap between Optimizely's DXP Cloud and self-hosted CMS 11/12 has never been wider.</p>
<h3>Self-Hosted CMS 11 (.NET Framework 4.8)</h3>
<p>CMS 11 is the legacy surface. It runs on .NET Framework 4.8, typically IIS on Windows Server. Every Windows kernel and HTTP.sys vulnerability Mythos found applies here.</p>
<p><strong>Priority actions:</strong></p>
<ul>
<li>Patch Windows Server immediately — the privilege escalation chains Mythos discovered grant kernel-level access</li>
<li>Audit <code>Newtonsoft.Json</code> with <code>TypeNameHandling</code> — same deserialization risk as Sitecore</li>
<li>Review <code>/episerver/</code> admin UI exposure. Block public access via network rules</li>
<li>Audit scheduled jobs endpoints — these accept remote execution triggers if misconfigured</li>
<li>Check <code>Microsoft.Data.SqlClient</code> version (pre-5.1.4 has known vulnerabilities)</li>
</ul>
<h3>Self-Hosted CMS 12 (.NET 6+)</h3>
<p>CMS 12 on .NET 6+ is more modern but still self-managed:</p>
<pre><code class="language-csharp">// Program.cs — add security headers middleware
app.Use(async (context, next) =>
{
    context.Response.Headers.Append("X-Content-Type-Options", "nosniff");
    context.Response.Headers.Append("X-Frame-Options", "DENY");
    context.Response.Headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");
    context.Response.Headers.Append("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
    context.Response.Headers.Append(
        "Content-Security-Policy",
        "default-src 'self'; script-src 'self'; frame-ancestors 'none'");
    await next();
});
</code></pre>
<ul>
<li>Audit the Optimizely add-on marketplace packages you've installed — these are community-contributed and not security-audited by Optimizely</li>
<li>Review Content Delivery API authorization scopes. The default configuration is often more permissive than needed</li>
<li>Check visitor group criteria for injection vectors</li>
</ul>
<h3>DXP Cloud</h3>
<p>DXP Cloud manages OS patching, TLS termination, and includes a WAF. The Mythos findings are largely handled by Optimizely's infrastructure team. Your responsibility: audit application-level code, add-on packages, and Content Delivery API configurations.</p>
<h2>Cross-Platform: The Shared .NET Attack Surface</h2>
<p>Regardless of which CMS you run, these .NET-specific concerns apply to all three:</p>
<h3>NuGet Packages to Audit Now</h3>
<table>
<thead>
<tr>
<th>Package</th>
<th>Risk</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Newtonsoft.Json</code></td>
<td>Deserialization RCE when <code>TypeNameHandling != None</code></td>
<td>Audit all usages, set to <code>None</code> where possible</td>
</tr>
<tr>
<td><code>System.Text.Json</code></td>
<td>Pre-8.0.5 has known vulnerabilities</td>
<td>Update to latest</td>
</tr>
<tr>
<td><code>Microsoft.Data.SqlClient</code></td>
<td>Pre-5.1.4 has SQL injection vectors</td>
<td>Update immediately</td>
</tr>
<tr>
<td><code>Microsoft.IdentityModel.*</code></td>
<td>Pre-7.x had token validation bypasses</td>
<td>Update all identity packages</td>
</tr>
<tr>
<td><code>System.Security.Cryptography.Xml</code></td>
<td>XML signature wrapping attacks</td>
<td>Update and audit XML processing</td>
</tr>
</tbody>
</table>
<h3>Automate Vulnerability Scanning</h3>
<p>Running <code>dotnet list package --vulnerable</code> across 15 client solutions manually won't scale. Automate it.</p>
<pre><code class="language-bash"># Audit all .NET projects in a client directory
for sln in ~/clients/*/*.sln; do
  echo "=== $(basename "$(dirname "$sln")") ==="
  dotnet list "$sln" package --vulnerable --include-transitive 2>/dev/null | grep -E "(Critical|High)"
done
</code></pre>
<p><strong>Tooling for .NET CMS stacks:</strong></p>
<ul>
<li><strong>GitHub Dependabot</strong> — Enable NuGet source scanning on all repos</li>
<li><strong>Snyk</strong> — Supports .NET and NuGet with transitive dependency analysis</li>
<li><strong><code>dotnet-outdated</code></strong> — CLI tool for checking outdated NuGet packages across solutions</li>
<li><strong>OWASP Dependency-Check</strong> — Integrates with Azure DevOps and GitHub Actions</li>
</ul>
<h2>How to Prioritize: A Risk-Based Decision Matrix</h2>
<p>Not every CMS instance carries the same risk. Use this matrix to triage which systems to patch first.</p>
<table>
<thead>
<tr>
<th>Factor</th>
<th>Higher Risk</th>
<th>Lower Risk</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Hosting model</strong></td>
<td>Self-hosted on bare metal or unmanaged VMs</td>
<td>Cloud-managed (XM Cloud, Umbraco Cloud, DXP Cloud)</td>
</tr>
<tr>
<td><strong>Runtime</strong></td>
<td>.NET Framework 4.8 (Sitecore 9-10, Optimizely CMS 11)</td>
<td>.NET 6+ (Umbraco 10-14, Optimizely CMS 12)</td>
</tr>
<tr>
<td><strong>Admin panel exposure</strong></td>
<td><code>/sitecore/admin/</code>, <code>/umbraco/</code>, <code>/episerver/</code> publicly accessible</td>
<td>Admin restricted via VPN or IP allowlist</td>
</tr>
<tr>
<td><strong>Dependency age</strong></td>
<td>Telerik UI, ImageSharp pre-3.x, <code>Newtonsoft.Json</code> with <code>TypeNameHandling</code></td>
<td>Current LTS packages, no known vulnerable transitive deps</td>
</tr>
<tr>
<td><strong>OS patching cadence</strong></td>
<td>Monthly or slower</td>
<td>Automated weekly with rollback capability</td>
</tr>
<tr>
<td><strong>Media processing</strong></td>
<td>FFmpeg or ImageSharp processing user uploads</td>
<td>No server-side media processing or uploads restricted to trusted editors</td>
</tr>
</tbody>
</table>
<h3>Patch Order</h3>
<p><strong>Tier 1 — Patch this week:</strong> Self-hosted .NET Framework 4.8 instances with publicly exposed admin panels. These combine the oldest runtime, the widest OS attack surface, and the most exploitable entry points (Telerik deserialization, HTTP.sys). Sitecore 9.x and Optimizely CMS 11 fall here.</p>
<p><strong>Tier 2 — Patch within two weeks:</strong> Self-hosted .NET 6+ instances on Linux/Kestrel. The runtime is modern, but the Mythos kernel privilege escalation chains and OpenSSL TLS flaws apply directly. Umbraco 10-14 on Linux and Optimizely CMS 12 on Kestrel fall here.</p>
<p><strong>Tier 3 — Patch within 30 days:</strong> Self-hosted .NET 6+ on Windows/IIS with admin panels behind VPN. The attack surface is smaller — Windows SChannel handles TLS (not OpenSSL), and the admin panel isn't publicly reachable. Still patch Windows Server and audit NuGet dependencies.</p>
<p><strong>Tier 4 — Audit application code only:</strong> Cloud-managed platforms (XM Cloud, Umbraco Cloud, DXP Cloud). The provider handles OS, TLS, and infrastructure patching. Your responsibility is application-level: third-party packages, API authorization scopes, and upload validation.</p>
<h2>When This Doesn't Apply</h2>
<p><strong>Managed cloud platforms absorb most of the risk.</strong> If you're on Sitecore XM Cloud, Umbraco Cloud, or Optimizely DXP Cloud, the OS-level and TLS-level vulnerabilities Mythos discovered are patched by the platform provider. Your responsibility narrows to application-level code, third-party packages, and API configurations.</p>
<p><strong>Static/headless rendering hosts are lower risk.</strong> If your CMS uses a headless architecture with a static frontend (Next.js on Vercel, for example), the server-side CMS attack surface is isolated from the public-facing site. The CMS backoffice still needs hardening, but the blast radius of a compromise is contained.</p>
<p><strong>This applies to everyone else.</strong> Self-hosted CMS instances on unpatched Windows Server or Linux, legacy .NET Framework 4.8 applications with known vulnerable dependencies, exposed admin panels without IP restrictions — the Mythos findings make this posture untenable. The window between disclosure and exploitation is shrinking from months to days.</p>
<h2>Conclusion</h2>
<p>Mythos demonstrated that AI can find and chain exploits across operating systems, browsers, TLS libraries, and server software at a rate 90x faster than the previous generation. For enterprise CMS teams running Sitecore, Umbraco, or Optimizely, the attack surface is broad: admin panels, media processing pipelines, deserialization endpoints, and the OS underneath it all.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li><strong>Sitecore teams</strong>: Rotate Telerik encryption keys, block <code>/sitecore/admin/</code> publicly, audit <code>Newtonsoft.Json</code> <code>TypeNameHandling</code>, and patch Windows Server</li>
<li><strong>Umbraco teams</strong>: Update ImageSharp, add backoffice brute-force protection, patch TinyMCE, and address Linux kernel vulnerabilities if on Kestrel</li>
<li><strong>Optimizely teams</strong>: Audit add-on packages, restrict Content Delivery API scopes, and patch self-hosted Windows/IIS instances immediately</li>
<li><strong>All .NET CMS teams</strong>: Run <code>dotnet list package --vulnerable --include-transitive</code> across every solution. Automate it with Dependabot or Snyk. Set a hard patch deadline of June 30, 2026 — before the 90-day Glasswing disclosures go public</li>
<li><strong>Evaluate managed hosting</strong>: The security gap between self-hosted and cloud-managed CMS has never been wider. If you're still self-hosting, the operational cost of staying patched post-Mythos may exceed the cost of migration</li>
</ul>
<p>The Glasswing partner list — AWS, Apple, Google, Microsoft, CrowdStrike — tells you how seriously the industry is taking this. Match that energy across your CMS portfolio.</p>
<p>If you're exploring how AI capabilities are reshaping development workflows beyond security, check out <a href="https://dak-dev.vercel.app/blog/claude-managed-agents-end-of-diy-infrastructure">how Claude Managed Agents replaces DIY agent infrastructure</a> and <a href="https://dak-dev.vercel.app/blog/agent-operating-system-multi-agent-pipelines">multi-agent pipeline architectures</a>. The same AI capability curve driving Mythos is transforming how we build software — understanding both sides matters.</p>]]></content:encoded>
      <category>security</category>
      <category>cms</category>
      <category>web-development</category>
      <category>dotnet</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/preparing-for-mythos-ai-security-checklist/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/preparing-for-mythos-ai-security-checklist/thumbnail.jpg" />
    </item>
    <item>
      <title>The Agent Operating System: Multi-Agent Pipelines with Claude</title>
      <link>https://dak-dev.vercel.app/blog/agent-operating-system-multi-agent-pipelines</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/agent-operating-system-multi-agent-pipelines</guid>
      <pubDate>Tue, 14 Apr 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Map OS abstractions to Claude Managed Agents architecture and build a three-agent auto-PR pipeline that plans, codes, and reviews autonomously.</description>
      <content:encoded><![CDATA[<p>Claude Managed Agents is an operating system for AI agents. Not metaphorically — the Claude Managed Agents architecture maps directly to OS primitives. Sessions are processes. Harnesses are schedulers. Sandboxes are device drivers. Understanding this mapping explains why the platform works, where it breaks down, and how to build multi-agent systems on top of it.</p>
<p>I've built <a href="https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio">four generations of agent orchestration systems</a>, each one teaching me something about coordination, drift, and crash recovery. Managed Agents solves many of the infrastructure problems I solved by hand in STUDIO — and introduces tradeoffs I didn't have to make. This post walks through both sides using a concrete example: a three-agent pipeline that takes a GitHub issue and produces a reviewed pull request.</p>
<h2>Claude Managed Agents as an Operating System</h2>
<p>Operating systems virtualize hardware so applications don't manage memory, disk I/O, or CPU scheduling directly. Managed Agents virtualizes agent infrastructure so developers don't manage execution loops, state persistence, or sandbox lifecycle directly.</p>
<p>The mapping is specific:</p>
<table>
<thead>
<tr>
<th>OS Concept</th>
<th>Managed Agents Equivalent</th>
<th>What It Abstracts Away</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Process</strong></td>
<td>Session (append-only event log)</td>
<td>State management, conversation history</td>
</tr>
<tr>
<td><strong>Scheduler</strong></td>
<td>Harness (stateless orchestration)</td>
<td>Agent loop, tool routing, retry logic</td>
</tr>
<tr>
<td><strong>Device driver</strong></td>
<td>Sandbox (interchangeable containers)</td>
<td>Code execution, file I/O, network access</td>
</tr>
<tr>
<td><strong>IPC</strong></td>
<td>Events (SSE between threads)</td>
<td>Inter-agent communication and handoffs</td>
</tr>
<tr>
<td><strong>Filesystem</strong></td>
<td>Persistent container storage</td>
<td>File state across tool calls</td>
</tr>
</tbody>
</table>
<p>When I built STUDIO, I implemented my own versions of all five. The Planner-Builder-ContentWriter pipeline needed a custom event loop, crash recovery logic, and a preference persistence system. STUDIO's supervision model — confidence scoring, mandatory questioning, validation commands per step — was my "scheduler." The codebase itself was my "filesystem."</p>
<p>Claude Managed Agents standardizes these primitives. The question is whether the standard abstractions fit your workload.</p>
<h2>Building the Pipeline: Three Agents, Three Roles</h2>
<p>Here's the auto-PR pipeline: a <strong>Planner</strong> agent that breaks down a GitHub issue into implementation steps, a <strong>Coder</strong> agent that writes the code, and a <strong>Reviewer</strong> agent that validates the output before opening a PR. This maps to STUDIO's Planner-Builder pattern, but with Anthropic managing the orchestration.</p>
<h3>Defining the Agents</h3>
<p>Each agent gets its own model, system prompt, and tool configuration:</p>
<pre><code class="language-typescript">const planner = await client.beta.agents.create({
  name: "PR Planner",
  model: "claude-sonnet-4-6",
  system: `You are an implementation planner. Given a GitHub issue:
    1. Analyze the requirements
    2. Identify affected files
    3. Break the work into ordered implementation steps
    4. Specify a validation command for each step
    Output a structured JSON plan.`,
  tools: [
    {
      type: "agent_toolset_20260401",
      configs: [
        { name: "bash", enabled: true },
        { name: "read", enabled: true },
        { name: "glob", enabled: true },
        { name: "grep", enabled: true },
      ],
      default_config: { enabled: false },
    },
  ],
});

const coder = await client.beta.agents.create({
  name: "PR Coder",
  model: "claude-sonnet-4-6",
  system: `You are an implementation agent. Given a plan with ordered steps:
    1. Execute each step in order
    2. Run the validation command after each step
    3. If validation fails, fix and retry (max 3 attempts)
    4. Stop and report if a step cannot pass validation`,
  tools: [{ type: "agent_toolset_20260401" }],
});

const reviewer = await client.beta.agents.create({
  name: "PR Reviewer",
  model: "claude-sonnet-4-6",
  system: `You are a code reviewer. Review the implementation against the plan:
    1. Check that all plan steps were completed
    2. Run the full test suite
    3. Review code quality, patterns, and potential issues
    4. Either APPROVE with a summary or REJECT with specific fixes needed`,
  tools: [
    {
      type: "agent_toolset_20260401",
      configs: [
        { name: "write", enabled: false },
        { name: "edit", enabled: false },
      ],
    },
  ],
});
</code></pre>
<p>Notice the tool scoping. The Planner gets read-only access — it plans but doesn't modify. The Reviewer can read and run commands but can't write files. This is the "principle of least privilege" applied to agents. In STUDIO, I enforced this through agent prompt instructions. Managed Agents enforces it at the infrastructure level, which is more reliable.</p>
<h3>Wiring the Handoffs</h3>
<p>The coordinator agent declares which agents it can call via <code>callable_agents</code>:</p>
<pre><code class="language-typescript">const coordinator = await client.beta.agents.create({
  name: "PR Coordinator",
  model: "claude-sonnet-4-6",
  system: `You coordinate the auto-PR pipeline:
    1. Send the issue to the Planner for analysis
    2. Send the plan to the Coder for implementation
    3. Send the result to the Reviewer for validation
    4. If rejected, send fixes back to the Coder
    5. On approval, create the PR via bash`,
  tools: [{ type: "agent_toolset_20260401" }],
  callable_agents: [
    { type: "agent", id: planner.id, version: planner.version },
    { type: "agent", id: coder.id, version: coder.version },
    { type: "agent", id: reviewer.id, version: reviewer.version },
  ],
});
</code></pre>
<p>Each agent runs in its own <strong>thread</strong> — an isolated context with its own conversation history. The coordinator sees condensed summaries of thread activity on the primary session stream. To inspect what the Coder is doing in detail, you stream the thread directly:</p>
<pre><code class="language-typescript">// Stream the coordinator's primary session
const stream = await client.beta.sessions.events.stream(session.id);

// Drill into a specific thread for full traces
for await (const thread of client.beta.sessions.threads.list(session.id)) {
  if (thread.agent_name === "PR Coder") {
    const threadStream = await client.beta.sessions.threads.stream(
      thread.id, { session_id: session.id }
    );
  }
}
</code></pre>
<p>This is the "multiple brains" model from the <a href="https://dak-dev.vercel.app/blog/claude-managed-agents-end-of-diy-infrastructure">Managed Agents architecture</a>. Each brain has its own context, its own tools, and its own thread — but they share a filesystem inside the same container.</p>
<h2>Session Durability and Crash Recovery</h2>
<p>The most underappreciated feature of this architecture: sessions survive infrastructure failures.</p>
<p>In STUDIO, if the Builder crashed mid-execution, I had to implement recovery myself. The supervision system tracked which steps had completed, and the retry logic knew how to resume from the last successful validation. That recovery code accounted for roughly 20% of STUDIO's complexity.</p>
<p>Managed Agents handles this through the append-only session log. Because sessions live outside the harness, a crashed harness doesn't lose history:</p>
<pre><code class="language-typescript">// After a harness crash, recovery is three calls:
const session = await getSession(sessionId);     // Full history intact
const harness = await wake(sessionId);           // New harness instance
await emitEvent(sessionId, resumeEvent);         // Resume from last event
</code></pre>
<p>The Coder agent's thread retains its full conversation — every file it read, every command it ran, every validation result. A new harness picks up exactly where the old one stopped. No checkpoint files, no recovery protocols, no state reconciliation.</p>
<p>This matters for the auto-PR pipeline because implementation sessions can run for 30+ minutes with dozens of tool calls. A single infrastructure hiccup shouldn't invalidate all that work.</p>
<h2>The Scaling Model: Multiple Brains, Multiple Hands</h2>
<p>The pipeline described above uses one brain (harness) per agent. But the architecture supports scaling both axes independently.</p>
<p><strong>Horizontal harness scaling</strong>: Because harnesses are stateless, you can run multiple coordinator sessions in parallel — each processing a different GitHub issue. No shared state means no coordination overhead between sessions.</p>
<p><strong>Multiple sandboxes per session</strong>: A single harness can route tool calls to different execution environments. The Coder agent could theoretically fan out to parallel sandboxes — one for frontend changes, one for backend, one for tests — and merge results.</p>
<p>This is where the multi-agent research preview becomes interesting. The <code>callable_agents</code> API already supports one level of delegation (coordinator → specialists). The Coder and Reviewer can run in parallel on independent parts of the codebase. The event types tell the story:</p>
<table>
<thead>
<tr>
<th>Event</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>session.thread_created</code></td>
<td>Coordinator spawned a new agent thread</td>
</tr>
<tr>
<td><code>agent.thread_message_sent</code></td>
<td>An agent sent work to another thread</td>
</tr>
<tr>
<td><code>agent.thread_message_received</code></td>
<td>An agent received delegated work</td>
</tr>
<tr>
<td><code>session.thread_idle</code></td>
<td>An agent thread finished its current task</td>
</tr>
</tbody>
</table>
<p>The coordinator receives these events and decides when to proceed. If the Reviewer rejects, the coordinator routes the rejection reasons back to the Coder's thread — and that thread retains its full history from the first attempt.</p>
<h2>Tradeoffs: Managed vs. Self-Built</h2>
<p>I've run STUDIO for three months in production. Here's an honest comparison:</p>
<table>
<thead>
<tr>
<th>Factor</th>
<th>STUDIO (Self-Built)</th>
<th>Managed Agents</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Infrastructure setup</strong></td>
<td>2 weeks of building harness, recovery, supervision</td>
<td>Hours of API configuration</td>
</tr>
<tr>
<td><strong>Crash recovery</strong></td>
<td>Custom checkpoint + retry logic (~20% of codebase)</td>
<td>Built-in via session durability</td>
</tr>
<tr>
<td><strong>Tool permissions</strong></td>
<td>Prompt-based enforcement (agent can ignore)</td>
<td>Infrastructure-level enforcement</td>
</tr>
<tr>
<td><strong>Custom orchestration</strong></td>
<td>Full control — confidence scoring, preference learning, mandatory questioning</td>
<td>Limited to system prompts and tool configuration</td>
</tr>
<tr>
<td><strong>Agent delegation depth</strong></td>
<td>Unlimited nesting (Planner → Builder → Sub-builder)</td>
<td>One level only (coordinator → agents, agents cannot delegate further)</td>
</tr>
<tr>
<td><strong>Credential security</strong></td>
<td>Application-level isolation</td>
<td>Sandbox-level isolation with vault storage</td>
</tr>
<tr>
<td><strong>Debugging</strong></td>
<td>Full local logs and traces</td>
<td>Thread-level streaming + Console analytics</td>
</tr>
<tr>
<td><strong>Cost visibility</strong></td>
<td>Direct token counting</td>
<td>Token costs + managed compute</td>
</tr>
</tbody>
</table>
<p><strong>STUDIO wins when</strong> you need custom supervision logic. Confidence scoring, preference learning, mandatory questioning before execution — these require control over the agent loop that Managed Agents doesn't expose. If your agent's value comes from <em>how</em> it orchestrates rather than <em>what</em> it executes, self-built gives you the knobs.</p>
<p><strong>Managed Agents wins when</strong> the orchestration is standard but the infrastructure is complex. Sandboxing, credential isolation, crash recovery, horizontal scaling — these are solved problems that shouldn't be solved again per-project. The auto-PR pipeline above would take weeks to build with proper infrastructure. With Managed Agents, the infrastructure is configuration.</p>
<p><strong>When NOT to use either for this pattern:</strong></p>
<ul>
<li>Single-turn interactions where a PR can be generated in one Messages API call</li>
<li>Codebases requiring custom security scanning that can't run inside a managed container</li>
<li>Environments where agent-generated code must be reviewed by humans before any file writes (Managed Agents writes files inside the sandbox — you review the output, not individual writes)</li>
</ul>
<h2>Conclusion</h2>
<p>The OS metaphor holds because it predicts behavior. Sessions persist like processes. Harnesses restart like schedulers. Sandboxes swap like device drivers. When you understand the abstraction, you can predict what the platform handles and what you need to build yourself.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li>The OS mapping (session=process, harness=scheduler, sandbox=device) is structural, not cosmetic — it predicts crash recovery, scaling, and isolation behaviors</li>
<li>Multi-agent pipelines use <code>callable_agents</code> and threads to isolate context while sharing a filesystem — each agent sees only its own conversation history</li>
<li>Session durability eliminates custom crash recovery code — the append-only event log survives harness failures without checkpointing</li>
<li>Self-built systems like STUDIO retain advantages in custom orchestration logic (confidence scoring, preference learning, supervision rules)</li>
<li>The one-level delegation limit means complex agent hierarchies still need custom coordination — Managed Agents handles the leaf nodes, not the full tree</li>
</ul>
<p>The direction is clear: Claude Managed Agents signals that agent infrastructure is becoming a platform concern, not an application concern. The teams that benefit most are the ones spending more time on plumbing than on the agent behavior they shipped the plumbing to enable.</p>]]></content:encoded>
      <category>ai</category>
      <category>claude</category>
      <category>agents</category>
      <category>architecture</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/agent-operating-system-multi-agent-pipelines/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/agent-operating-system-multi-agent-pipelines/thumbnail.jpg" />
    </item>
    <item>
      <title>Claude Managed Agents: The End of DIY Agent Infrastructure</title>
      <link>https://dak-dev.vercel.app/blog/claude-managed-agents-end-of-diy-infrastructure</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/claude-managed-agents-end-of-diy-infrastructure</guid>
      <pubDate>Tue, 14 Apr 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Discover how Claude Managed Agents replaces months of custom agent infrastructure with a decoupled architecture that cuts time-to-first-token 60%.</description>
      <content:encoded><![CDATA[<p>Claude Managed Agents launched on April 8, 2026, and it solves the hardest part of building AI agents: everything that isn't the model itself. Sandboxing, state management, credential handling, crash recovery, context engineering — the managed platform handles all of it. Internal benchmarks show a 60% reduction in p50 time-to-first-token and up to 10-point improvements in task success rates compared to self-hosted agent loops.</p>
<p>If you've spent weeks building agent infrastructure — wiring up container orchestration, implementing retry logic, managing session state — this is the platform that makes most of that code unnecessary.</p>
<p>Here's what the architecture looks like, when it makes sense to adopt, and where the boundaries are.</p>
<h2>How Claude Managed Agents Decouples Session, Harness, and Sandbox</h2>
<p>The core design decision behind Managed Agents is a three-way separation of concerns that treats each component as independently swappable:</p>
<table>
<thead>
<tr>
<th>Component</th>
<th>Responsibility</th>
<th>Key Property</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Session</strong></td>
<td>Append-only event log storing all interactions</td>
<td>Lives outside the harness — survives crashes</td>
</tr>
<tr>
<td><strong>Harness</strong></td>
<td>Orchestration loop that calls Claude and routes tool outputs</td>
<td>Stateless — scales horizontally</td>
</tr>
<tr>
<td><strong>Sandbox</strong></td>
<td>Container for code execution and file operations</td>
<td>Interchangeable — one brain, many hands</td>
</tr>
</tbody>
</table>
<p>This decoupling exists because Anthropic's earlier architecture coupled the harness directly inside containers. When containers failed, entire sessions were lost. The new design treats the harness as stateless. It calls sandboxes via a standard <code>execute(name, input) → string</code> interface. If a container dies, a new one initializes via <code>provision({resources})</code> without losing session history.</p>
<p>The performance gains are significant. By decoupling containers from harnesses, sessions no longer wait for container provisioning before inference begins. The p95 time-to-first-token dropped by more than 90%.</p>
<h3>Session Durability in Practice</h3>
<p>Because session logs live outside the harness, crash recovery becomes straightforward:</p>
<pre><code class="language-typescript">// Harness recovery after failure
const session = await getSession(sessionId);  // Retrieve full history
const harness = await wake(sessionId);        // Reboot harness
await emitEvent(sessionId, resumeEvent);      // Resume from last event
</code></pre>
<p>No complex recovery protocols. No lost context. The session is the source of truth, and harnesses are disposable workers that read from it.</p>
<h3>Security Boundaries</h3>
<p>Credentials never exist inside sandboxes where untrusted code executes. Managed Agents enforces this through two authentication patterns:</p>
<ul>
<li><strong>Resource-bundled auth</strong>: Git tokens initialize repos during provisioning, then wire into local remotes — the token never appears in the execution environment</li>
<li><strong>Vault-stored credentials</strong>: OAuth tokens stored externally; a proxy fetches them for outbound service calls</li>
</ul>
<p>This matters because agent sandboxes run arbitrary code. Any credential placed inside a sandbox is a credential that user-generated code can exfiltrate.</p>
<h2>What You Get Out of the Box</h2>
<p>Managed Agents provides a complete agent runtime with built-in tools:</p>
<ul>
<li><strong>Bash</strong>: Run shell commands in the container</li>
<li><strong>File operations</strong>: Read, write, edit, glob, and grep files</li>
<li><strong>Web search and fetch</strong>: Search the web and retrieve URL content</li>
<li><strong>MCP servers</strong>: Connect to external tool providers</li>
<li><strong>Prompt caching and compaction</strong>: Built-in context management optimizations</li>
</ul>
<p>The API surface centers on four concepts — <strong>Agent</strong> (model + system prompt + tools), <strong>Environment</strong> (container template with packages and network rules), <strong>Session</strong> (a running agent instance), and <strong>Events</strong> (messages exchanged via server-sent events).</p>
<p>Here's the minimal flow to get a session running:</p>
<pre><code class="language-typescript">import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

// 1. Create an agent
const agent = await client.beta.agents.create({
  model: "claude-sonnet-4-6-20260414",
  system: "You are a code review assistant.",
  tools: [{ type: "bash" }, { type: "file_editor" }],
});

// 2. Create an environment
const env = await client.beta.environments.create({
  packages: ["python3", "nodejs"],
  network_access: { allowed_domains: ["github.com"] },
});

// 3. Start a session and stream events
const session = await client.beta.sessions.create({
  agent_id: agent.id,
  environment_id: env.id,
});

await client.beta.sessions.events.create(session.id, {
  type: "user",
  content: "Review the PR at github.com/org/repo/pull/42",
});
</code></pre>
<p>The SDK sets the required <code>managed-agents-2026-04-01</code> beta header automatically. Rate limits apply: 60 create requests/minute and 600 read requests/minute per organization.</p>
<h2>Messages API vs. Managed Agents: When to Use Which</h2>
<p>This isn't a replacement for the Messages API. It's a higher-level abstraction for a specific class of workloads.</p>
<table>
<thead>
<tr>
<th>Factor</th>
<th>Messages API</th>
<th>Managed Agents</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Control</strong></td>
<td>Full control over agent loop, tool execution, retries</td>
<td>Anthropic manages the loop</td>
</tr>
<tr>
<td><strong>Infrastructure</strong></td>
<td>You build and maintain sandboxes, state, auth</td>
<td>Managed containers, persistent sessions</td>
</tr>
<tr>
<td><strong>Latency</strong></td>
<td>Direct API calls, minimal overhead</td>
<td>Container provisioning adds startup time</td>
</tr>
<tr>
<td><strong>Session duration</strong></td>
<td>Stateless (you manage context)</td>
<td>Hours-long stateful sessions with persistence</td>
</tr>
<tr>
<td><strong>Tool execution</strong></td>
<td>You implement tool handlers</td>
<td>Built-in bash, file ops, web, MCP</td>
</tr>
<tr>
<td><strong>Cost structure</strong></td>
<td>Pay per token</td>
<td>Pay per token + compute time</td>
</tr>
</tbody>
</table>
<p><strong>Use Messages API when:</strong></p>
<ul>
<li>You need sub-second response times for synchronous interactions</li>
<li>Your agent loop has custom logic that doesn't fit the managed model</li>
<li>You need fine-grained control over every tool call and retry</li>
</ul>
<p><strong>Use Managed Agents when:</strong></p>
<ul>
<li>Tasks run for minutes or hours with dozens of tool calls</li>
<li>You need secure code execution without building your own sandbox</li>
<li>You want session persistence across disconnections</li>
<li>You'd rather configure than build infrastructure</li>
</ul>
<h2>Who's Building With It</h2>
<p>Several companies are already in production or late-stage integration:</p>
<ul>
<li><strong>Notion</strong>: Agents handle parallel tasks — coding, content creation — with team collaboration features layered on top</li>
<li><strong>Rakuten</strong>: Enterprise agents deployed across product, sales, marketing, and finance departments, integrated with Slack and Teams for task delegation</li>
<li><strong>Asana</strong>: "AI Teammates" work alongside humans, picking up tasks and drafting deliverables within existing project workflows</li>
<li><strong>Sentry</strong>: A debugging agent pairs with a patch-writing agent, automating the bug-report-to-pull-request pipeline</li>
<li><strong>Vibecode</strong>: Uses managed sessions for rapid app deployment, reporting 10x faster infrastructure spin-up</li>
</ul>
<p>The pattern across these deployments: teams that were spending months building agent infrastructure — sandboxing, credential management, crash recovery — redirected that effort to product features. If you've followed <a href="https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio">my work building autonomous coding agents with STUDIO</a>, the appeal is obvious: Claude Managed Agents provides the infrastructure layer that every agent builder ends up reinventing.</p>
<h2>The Multi-Brain, Multi-Hands Model</h2>
<p>The decoupled architecture enables a scaling model worth understanding. Because harnesses are stateless and sandboxes are interchangeable, you can scale both axes independently:</p>
<p><strong>Multiple brains</strong>: Spin up stateless harnesses horizontally. Each connects to sandboxes only when needed, then releases them.</p>
<p><strong>Multiple hands</strong>: Each sandbox becomes an interchangeable tool. A single harness can reason about multiple execution environments and route work accordingly — containers, custom tools, <a href="https://dak-dev.vercel.app/blog/mcp-apps-interactive-ui-inside-ai-chat">MCP servers</a>, or any system behind the <code>execute()</code> interface.</p>
<p>Multi-agent coordination (multiple harnesses collaborating on a task) is available as a research preview. So is persistent memory across sessions and outcome-based evaluation. These features require a <a href="https://claude.com/form/claude-managed-agents">separate access request</a>.</p>
<h2>Tradeoffs and Limitations</h2>
<p>Managed Agents trades flexibility for operational convenience. Here's what you give up:</p>
<p><strong>Less control over the agent loop.</strong> You can steer mid-execution and interrupt, but you can't customize the core orchestration logic. If your agent needs non-standard retry strategies, custom tool routing, or model-switching mid-conversation, the Messages API gives you that control.</p>
<p><strong>Beta stability risks.</strong> The <code>managed-agents-2026-04-01</code> beta header signals that APIs and behaviors may change between releases. Production workloads need to account for breaking changes.</p>
<p><strong>Container startup overhead.</strong> While the decoupled architecture eliminated most provisioning delays (the 60% p50 improvement), the first interaction in a session still involves container initialization. For latency-sensitive, single-turn interactions, the Messages API is faster.</p>
<p><strong>Vendor lock-in.</strong> Your agent logic lives inside Anthropic's infrastructure. Migrating to self-hosted or another provider means rebuilding the harness, sandbox management, and session persistence you didn't have to build initially.</p>
<p><strong>Research preview features are gated.</strong> Multi-agent coordination, memory, and outcomes — three of the most compelling capabilities — require separate access approval and carry additional stability caveats.</p>
<p><strong>When NOT to use Managed Agents:</strong></p>
<ul>
<li>Single-turn Q&amp;A or chatbot interfaces (overkill for the use case)</li>
<li>Latency-critical applications under 500ms response time requirements</li>
<li>Workloads requiring custom model routing or non-Claude models</li>
<li>Environments where data residency prevents cloud-hosted execution</li>
</ul>
<h2>Conclusion</h2>
<p>Claude Managed Agents represents a clear shift: Anthropic is moving up the stack from model provider to agent platform. The decoupled session-harness-sandbox architecture solves real infrastructure problems that every team building agents has encountered.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li>The three-way decoupling (session, harness, sandbox) is the key architectural insight — it enables crash recovery, horizontal scaling, and secure credential isolation in a single design</li>
<li>Performance gains are concrete: 60% p50 and 90%+ p95 time-to-first-token reductions from eliminating container-inference coupling</li>
<li>The Messages API remains the right choice for low-latency, high-control use cases — Managed Agents targets long-running, infrastructure-heavy workloads</li>
<li>Multi-agent coordination, memory, and outcomes are in research preview — compelling features that aren't production-ready yet</li>
<li>Five major companies (Notion, Rakuten, Asana, Sentry, Vibecode) are already building on the platform, validating the "managed over DIY" approach</li>
</ul>
<p>The decision framework is straightforward: if you're spending more engineering time on agent infrastructure than on agent behavior, Managed Agents eliminates that overhead. If you need full control over every inference call, stick with the Messages API and build the infrastructure yourself.</p>]]></content:encoded>
      <category>ai</category>
      <category>claude</category>
      <category>agents</category>
      <category>developer-tools</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/claude-managed-agents-end-of-diy-infrastructure/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/claude-managed-agents-end-of-diy-infrastructure/thumbnail.jpg" />
    </item>
    <item>
      <title>WebMCP: How Chrome Turns Websites Into AI Agent APIs</title>
      <link>https://dak-dev.vercel.app/blog/webmcp-chrome-ai-agent-protocol</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/webmcp-chrome-ai-agent-protocol</guid>
      <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Explore Chrome&apos;s WebMCP protocol that lets websites expose structured tools to AI agents, replacing brittle scraping with stable, typed APIs.</description>
      <content:encoded><![CDATA[<p>Chrome 145 shipped WebMCP — a browser-native protocol that lets websites expose structured tools to AI agents through typed APIs instead of DOM scraping. Released as an early preview on February 10, 2026, and backed by Google and Microsoft, WebMCP replaces the brittle screenshot-and-scrape pattern with schema-validated tool interfaces that agents call directly.</p>
<p>This matters because AI agents are already the majority of web traffic. Bots account for 51% of all web requests, and most interact with sites through pixel analysis and HTML parsing — approaches that break whenever a CSS class changes or a button moves. WebMCP proposes a structured alternative.</p>
<p>This post covers how WebMCP works, its two API approaches, where it fits within the 17,000+ server MCP ecosystem, and the significant gaps you need to understand before building on it.</p>
<h2>The Problem: Agents Are Scraping Like It's 2005</h2>
<p>Current AI agents interact with websites the same way early screen readers did — by parsing visual layouts. Tools like Playwright MCP take screenshots, analyze DOM trees, and simulate clicks. This works, but it's fragile.</p>
<p>A website redesign breaks every agent that depends on specific HTML structure. A CSS change makes a button invisible to screenshot analysis. Processing entire DOM trees or full-page screenshots wastes tokens and adds latency to every agent action.</p>
<p>WebMCP addresses this by giving developers a way to declare what their site can do. Instead of agents guessing from visual cues, sites expose named tools with typed parameters and structured responses.</p>
<h2>How WebMCP Works: Two API Approaches</h2>
<p>WebMCP provides two ways to expose tools: a declarative HTML approach for forms, and an imperative JavaScript API for complex interactions. Both register tools through the same underlying <code>navigator.modelContext</code> interface.</p>
<h3>Declarative API: HTML Forms as Tools</h3>
<p>The declarative approach requires zero JavaScript. Standard HTML forms gain three new attributes that make them visible to AI agents:</p>
<pre><code class="language-html">&lt;form toolname="book_table"
      tooldescription="Creates a dining reservation at the restaurant">
  &lt;input name="email"
         toolparamdescription="Customer email for confirmation" />
  &lt;input name="date" type="date"
         toolparamdescription="Reservation date in YYYY-MM-DD format" />
  &lt;input name="party_size" type="number"
         toolparamdescription="Number of guests, 1-12" />
  &lt;button type="submit">Reserve&lt;/button>
&lt;/form>
</code></pre>
<p>The <code>toolname</code> attribute declares the tool identifier. The <code>tooldescription</code> gives agents natural language context. And <code>toolparamdescription</code> on each input documents the expected parameter. An agent encountering this form knows it can call <code>book_table</code> with typed parameters — no screenshot parsing required.</p>
<h3>Imperative API: JavaScript Tool Registration</h3>
<p>For single-page applications and dynamic interactions, the imperative API provides programmatic tool registration:</p>
<pre><code class="language-javascript">navigator.modelContext.registerTool({
  name: "search_flights",
  description: "Search available flights between two airports",
  inputSchema: {
    type: "object",
    properties: {
      origin: { type: "string", description: "IATA airport code" },
      destination: { type: "string", description: "IATA airport code" },
      departure_date: { type: "string", format: "date" },
      passengers: { type: "integer", minimum: 1, maximum: 9 }
    },
    required: ["origin", "destination", "departure_date"]
  },
  outputSchema: {
    type: "string",
    description: "JSON array of matching flights with prices"
  },
  execute: async (params) => {
    const results = await flightAPI.search(params);
    return JSON.stringify(results);
  }
});
</code></pre>
<p>This gives developers full control over schemas, validation, and execution logic. Tools registered this way should follow component lifecycle patterns — register on mount, unregister on cleanup:</p>
<pre><code class="language-javascript">useEffect(() => {
  navigator.modelContext.registerTool(flightSearchTool);
  return () => navigator.modelContext.unregisterTool("search_flights");
}, []);
</code></pre>
<h3>Which API to Use</h3>
<table>
<thead>
<tr>
<th>Scenario</th>
<th>Approach</th>
<th>Why</th>
</tr>
</thead>
<tbody>
<tr>
<td>Contact forms, search bars</td>
<td>Declarative</td>
<td>Static HTML, no JS needed</td>
</tr>
<tr>
<td>Multi-step checkout flows</td>
<td>Imperative</td>
<td>Dynamic state, conditional logic</td>
</tr>
<tr>
<td>Content filtering</td>
<td>Declarative</td>
<td>Standard form behavior</td>
</tr>
<tr>
<td>Real-time data queries</td>
<td>Imperative</td>
<td>API integration, async execution</td>
</tr>
</tbody>
</table>
<p>The declarative API covers the 80% case — most web interactions are form submissions. The imperative API handles the remaining 20% where JavaScript execution is unavoidable.</p>
<h2>Where WebMCP Fits Today</h2>
<p>WebMCP targets three use cases in its early preview:</p>
<p><strong>E-commerce.</strong> Agents call <code>search_products</code>, <code>add_to_cart</code>, and <code>checkout</code> with structured parameters instead of navigating product pages visually. This eliminates the brittle dependency on specific button placements and page layouts.</p>
<p><strong>Travel booking.</strong> An agent parsing "round-trip flight for two from London to NYC, March 15-22" calls <code>search_flights()</code> with typed parameters. No form filling, no calendar widget navigation, no screenshot interpretation.</p>
<p><strong>Customer support.</strong> Support agents auto-fill technical details into structured tools rather than copying text between windows and parsing unstructured responses.</p>
<p>If you've worked with <a href="https://dak-dev.vercel.app/blog/mcp-apps-interactive-ui-inside-ai-chat">MCP (Model Context Protocol)</a> in desktop AI tools, the mental model translates directly. WebMCP brings the same tool-registration pattern to browser-based agents — websites become MCP servers, and in-browser AI becomes the client.</p>
<h2>The MCP Ecosystem WebMCP Is Entering</h2>
<p>WebMCP doesn't exist in a vacuum. It lands in an MCP ecosystem that exploded from roughly 100 servers at Anthropic's November 2024 launch to over 17,000 across all directories by January 2026 — a 16,000% increase. Monthly SDK downloads crossed 97 million. Every major AI company now backs the protocol.</p>
<p>In December 2025, Anthropic donated MCP to the Linux Foundation's newly formed <a href="https://www.linuxfoundation.org/press/linux-foundation-announces-the-formation-of-the-agentic-ai-foundation">Agentic AI Foundation</a>, co-founded by Anthropic, Block, and OpenAI. Platinum members include AWS, Cloudflare, Google, and Microsoft. MCP is no longer one company's project — it's an industry standard with formal governance.</p>
<p>That context matters for WebMCP because the browser is the last major surface area without native MCP support. Desktop IDEs, CLI tools, and cloud platforms all have it. The web doesn't — yet.</p>
<h3>First-Party MCPs That Define the Ecosystem</h3>
<p>The shift from community-built servers to official, company-hosted integrations marks 2025-2026 as MCP's enterprise inflection point. These are the servers shaping how developers interact with MCP daily.</p>
<p><strong>Figma MCP</strong> is the one developers talk about most. Figma's <a href="https://www.figma.com/blog/introducing-figma-mcp-server/">official MCP server</a> — launched in beta June 2025 and generally available by October — lets AI coding agents pull design context directly from Figma into development workflows. Select a frame, and your AI agent generates React/Tailwind code with real design tokens, layout constraints, and component metadata. It works with Cursor, VS Code Copilot, Claude Code, and Windsurf. In February 2026, Figma expanded further with <a href="https://www.cmswire.com/digital-experience/figma-make-adds-custom-model-context-protocol-6-new-connectors/">custom MCP connectors</a> for Figma Make, plus certified integrations with Amplitude, Dovetail, and four other services.</p>
<p><strong>Stripe MCP</strong> exposes full payment operations — manage customers, products, pricing, invoices, refunds, and subscriptions through AI agents. The remote server at <code>mcp.stripe.com</code> uses OAuth authentication with parallel tool execution for batch operations. The practical impact: developers query billing data, create test subscriptions, and debug payment flows without leaving their AI coding environment.</p>
<p><strong>Notion MCP</strong> provides full CRUD on pages, databases, blocks, and comments. Enterprise features include MCP activity tracking in audit logs and multi-database queries. In February 2026, Notion launched <a href="https://www.notion.com/releases/2026-02-24">Custom Agents</a> — autonomous AI that works across Notion, Slack, Figma, Linear, and custom MCP servers.</p>
<p><strong>GitHub MCP</strong> goes beyond basic repo access. It covers issue management, PR workflows, Actions monitoring, security findings, and code search — with content sanitization enabled by default for prompt injection protection. GitHub's <a href="https://github.blog/changelog/2025-12-10-the-github-mcp-server-adds-support-for-tool-specific-configuration-and-more/">December 2025 update</a> added tool-specific configuration and lockdown mode.</p>
<p><strong>Cloudflare</strong> plays a dual role: infrastructure provider for hosting remote MCP servers (used by Atlassian, Stripe, Linear, PayPal, Sentry, and others) and publisher of 13+ first-party servers for Workers, R2, KV, and D1. Their <a href="https://blog.cloudflare.com/mcp-demo-day/">MCP Demo Day</a> showcased 10 companies building production MCP servers on Cloudflare's edge network.</p>
<p>Other official servers worth tracking: <strong>Linear</strong> for issue tracking with OAuth 2.1, <strong>Supabase</strong> with 20+ tools for database management and migrations, <strong>Slack</strong> for channel search and messaging, <strong>Vercel</strong> for deployment management, <strong>Atlassian</strong> for Jira and Confluence, and <strong>Google Cloud</strong> for Maps, BigQuery, and Kubernetes Engine.</p>
<h3>Where WebMCP Fills the Gap</h3>
<p>Every server listed above operates outside the browser. They connect through local stdio processes, remote HTTP endpoints, or IDE extensions. When an AI agent needs to interact with a website — not an API, but an actual web interface — it falls back to Playwright screenshots and DOM scraping.</p>
<p>WebMCP closes this gap. A website that implements <code>navigator.modelContext.registerTool()</code> becomes a first-class MCP server, discoverable by in-browser AI the same way Stripe's MCP server is discoverable by Claude Code. The protocol difference: these servers live inside the page itself, exposing tools that reflect the site's actual capabilities rather than an external API's interpretation of them.</p>
<p>The 17,000+ existing MCP servers handle the API layer. WebMCP handles the presentation layer. Together, they cover the full stack of agent-to-service communication.</p>
<h2>Tradeoffs and Limitations</h2>
<p>WebMCP is an early preview with significant gaps. Understanding them before building on this protocol is essential.</p>
<p><strong>No security model.</strong> The specification defines no authentication, permission, or sandboxing mechanisms. Malicious websites can create "poisoned" tools with misleading descriptions — a tool named <code>confirm_order</code> could execute a different action entirely. No CORS-like policies exist for tool access. Until the security model matures, treat every WebMCP tool as untrusted input.</p>
<p><strong>No headless mode.</strong> WebMCP requires a visible browser window with UI synchronization. This blocks server-side agent architectures and automated testing pipelines that run headless Chrome. If your agents operate without a display, WebMCP doesn't work.</p>
<p><strong>Tool discoverability is unsolved.</strong> There's no standard for agents to discover which tools a site exposes before loading the page. No registry, no manifest file, no <code>robots.txt</code> equivalent for tool declarations. Agents must visit each page to learn what's available.</p>
<p><strong>No error handling standards.</strong> The protocol doesn't define how tools should report failures, validation errors, or rate limits. Each implementation invents its own error format, which defeats the standardization goal.</p>
<p><strong>Early preview access only.</strong> Chrome 145+ with feature flags enabled, or Canary 146+. Chrome's early preview program signup is required for documentation access. Production deployment is not viable yet.</p>
<h3>When NOT to Use WebMCP</h3>
<ul>
<li><strong>Production applications.</strong> The API surface is unstable and the security model is undefined. Building production features on this protocol is premature.</li>
<li><strong>Sites without agent use cases.</strong> A personal blog or portfolio has no meaningful tools to expose. WebMCP adds complexity without benefit for read-only content.</li>
<li><strong>Security-sensitive workflows.</strong> Payment processing, authentication flows, and data access should wait for sandboxing and permission models.</li>
<li><strong>Server-side agents.</strong> The headless mode limitation eliminates backend agent architectures entirely.</li>
</ul>
<h2>What This Means for Developers</h2>
<p>WebMCP signals a directional shift in how the web handles AI agent traffic. Google and Microsoft back the proposal, which moves it beyond research experiment territory.</p>
<p>The practical impact depends on your timeline:</p>
<p><strong>Right now:</strong> Experiment with the declarative API on non-critical forms. Adding <code>toolname</code> and <code>tooldescription</code> attributes to existing HTML is low-risk and reversible. It builds familiarity with the mental model before the protocol stabilizes.</p>
<p><strong>Next 6 months:</strong> Watch the security model development. The permission and sandboxing specifications will determine whether WebMCP is viable for anything beyond demos.</p>
<p><strong>Next 12 months:</strong> If the security model materializes, the imperative API becomes the primary integration point for SPAs and complex web applications. Start identifying which user flows would benefit from structured agent access. Companies like Figma, Stripe, and Notion already committed to MCP for their APIs — expect them to adopt WebMCP for their web interfaces once the protocol stabilizes.</p>
<h2>Conclusion</h2>
<p>WebMCP turns websites from opaque visual interfaces into structured tool providers for AI agents. Chrome 145's early preview delivers two APIs — declarative HTML attributes for forms and an imperative JavaScript interface for complex interactions — and it arrives at the right time: the MCP ecosystem has 17,000+ servers, 97 million monthly SDK downloads, and backing from every major AI company through the Linux Foundation's Agentic AI Foundation.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li>WebMCP replaces brittle DOM scraping with typed, schema-validated tool interfaces that AI agents call directly</li>
<li>The declarative API (<code>toolname</code>, <code>tooldescription</code> attributes) requires zero JavaScript and works on any HTML form</li>
<li>The imperative API (<code>navigator.modelContext.registerTool()</code>) handles stateful interactions with full JSON Schema validation</li>
<li>The MCP ecosystem exploded to 17,000+ servers — Figma, Stripe, Notion, GitHub, and Cloudflare all ship official first-party integrations</li>
<li>WebMCP fills the browser gap: existing MCPs handle APIs, WebMCP handles web interfaces</li>
<li>The security model is undefined — no authentication, sandboxing, or permission mechanisms exist yet</li>
<li>This is an early preview in Chrome 145+, not production-ready — experiment on non-critical surfaces only</li>
</ul>
<p>The protocol addresses a real problem: 51% of web traffic comes from bots, and most interact through brittle scraping. The ecosystem infrastructure is already in place — first-party MCPs from Figma, Stripe, and GitHub prove that companies will invest in structured agent access. Whether WebMCP becomes the browser-native standard depends on how fast the security and discoverability gaps close. For now, understand the API surface, track the specification, and keep your forms ready.</p>]]></content:encoded>
      <category>ai</category>
      <category>web-standards</category>
      <category>chrome</category>
      <category>developer-tools</category>
      <category>mcp</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/webmcp-chrome-ai-agent-protocol/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/webmcp-chrome-ai-agent-protocol/thumbnail.jpg" />
    </item>
    <item>
      <title>Building Plugin Architect: A Zero-Code Claude Code Plugin</title>
      <link>https://dak-dev.vercel.app/blog/building-plugin-architect-zero-code-claude-plugin</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/building-plugin-architect-zero-code-claude-plugin</guid>
      <pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Discover how 30KB of prompt engineering replaced a SQLite-backed codebase to become a complete plugin design system for Claude Code&apos;s 6 extension points.</description>
      <content:encoded><![CDATA[<p>I shipped a Claude Code plugin with zero runtime code. No TypeScript. No build step. No dependencies. The entire product is 30KB of Markdown across three files — and it turns Claude into an expert architect for the full Claude Code plugin ecosystem. This is the story of building that plugin.</p>
<p>Plugin Architect guides you through designing and building Claude Code plugins from scratch, covering all 6 extension points: Skills, MCP Servers, Hooks, Agents, LSP Servers, and Plugins. It follows a structured workflow — Discover, Classify, Design, Confirm, Build, Register — and writes complete, production-ready code. No TODOs. No placeholders.</p>
<p>This post covers why I pivoted from a code-heavy approach to pure prompt engineering, how the architecture works, and what the tradeoffs are.</p>
<h2>Project Overview</h2>
<h3>The Challenge</h3>
<p>Claude Code's plugin system supports 6 extension points, each with different file structures, configuration patterns, and use cases. A developer wanting to build a plugin faces scattered documentation, unclear component selection, and no scaffolding tools.</p>
<p>The questions stack up fast: Should this be a Skill or an MCP Server? Do I need Hooks? What goes in <code>plugin.json</code> vs <code>.mcp.json</code>? Where do agents live? The cognitive overhead of these decisions delays the actual building.</p>
<h3>The Solution</h3>
<p>Plugin Architect encodes all of that knowledge into a single skill. When you run <code>/plugin-architect</code>, Claude receives a comprehensive instruction set — a component selection matrix, complete file structure templates, 5 worked examples, and 8 integration patterns — then walks you through the design and build process step by step.</p>
<pre><code class="language-bash"># Install and use
/plugin install plugin-architect@twofoldtech-dakota-plugin-architect

# Design and build a plugin
/plugin-architect Build a plugin that enforces code style rules
</code></pre>
<h2>Tech Stack</h2>
<table>
<thead>
<tr>
<th>Category</th>
<th>Technology</th>
<th>Why</th>
</tr>
</thead>
<tbody>
<tr>
<td>Knowledge Base</td>
<td>Markdown (SKILL.md)</td>
<td>Native Claude Code skill format, zero compilation</td>
</tr>
<tr>
<td>Supporting Docs</td>
<td>Markdown (examples.md, integrations.md)</td>
<td>Context-injectable reference material</td>
</tr>
<tr>
<td>Configuration</td>
<td>JSON (plugin.json, marketplace.json)</td>
<td>Required plugin manifest format</td>
</tr>
<tr>
<td>Distribution</td>
<td>GitHub + Claude Marketplace</td>
<td>Direct install from repository URL</td>
</tr>
</tbody>
</table>
<h2>Architecture</h2>
<p>The architecture is intentionally minimal. Three Markdown files carry the entire product:</p>
<pre><code class="language-text">plugin-architect/                     (~35KB total)
├── .claude-plugin/
│   ├── plugin.json                   # Plugin manifest
│   └── marketplace.json              # Distribution config
├── skills/
│   └── plugin-architect/
│       ├── SKILL.md                  # Core instruction set (13KB)
│       ├── examples.md               # 5 complete plugin examples (11KB)
│       └── integrations.md           # 8 integration patterns (6KB)
└── README.md                         # User documentation
</code></pre>
<p><code>SKILL.md</code> is the engine. At 13KB (~380 lines), it stays under the recommended 500-line limit for Claude Code skills while encoding decision logic, component templates, and workflow instructions. The two supporting files — <code>examples.md</code> and <code>integrations.md</code> — provide reference material that Claude pulls from when building specific plugin types.</p>
<h3>The Component Selection Matrix</h3>
<p>The core design decision is a classification system. Instead of asking developers to read docs for all 6 extension points, SKILL.md contains a mapping from intent to component:</p>
<pre><code class="language-text">"I want Claude to know about X"          → Skill
"I want a /command that does X"           → Skill (user-invocable)
"I want Claude to call X API"            → MCP Server
"I want to enforce X on every edit"      → Hook (PreToolUse)
"I want to auto-run tests after changes" → Hook (PostToolUse)
"I want to bundle all of this for team"  → Plugin
</code></pre>
<p>This matrix eliminates the most common point of confusion. Users describe what they want in natural language, and the skill maps it to the correct extension point with the right file structure.</p>
<h3>The Confirm-Before-Build Gate</h3>
<p>The 6-step workflow includes an explicit confirmation gate at step 4. After Discover, Classify, and Design, the skill presents the proposed architecture to the user and waits for approval before generating any files. This prevents unwanted code generation — a real risk when a skill has broad tool access.</p>
<h2>Key Features</h2>
<h3>Complete Template Coverage</h3>
<p>Every extension point has a production-ready template. MCP Servers get a full TypeScript setup with the <code>@modelcontextprotocol/sdk</code>, Zod validation, and stdio transport:</p>
<pre><code class="language-typescript">import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
  name: "server-name",
  version: "1.0.0",
  capabilities: { tools: { listChanged: true } },
});

server.registerTool("tool-name", {
  description: "What it does, what it returns, when to use it",
  inputSchema: {
    param: z.string().describe("What this param means"),
  },
}, async ({ param }) => {
  return { content: [{ type: "text", text: "result" }] };
});

const transport = new StdioServerTransport();
await server.connect(transport);
</code></pre>
<p>Hook configurations include complete bash scripts for common patterns like secret detection:</p>
<pre><code class="language-json">{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "./hooks/scripts/check-secrets.sh",
        "timeout": 10
      }]
    }]
  }
}
</code></pre>
<h3>Context Injection at Load Time</h3>
<p>Skills can execute shell commands dynamically when loaded. Plugin Architect uses this pattern in its examples to show how skills inject runtime context into their prompts:</p>
<pre><code class="language-markdown">Current branch: !`git branch --show-current`
Recent commits: !`git log --oneline -5`
</code></pre>
<p>This turns static Markdown into dynamic, context-aware instructions without writing runtime code.</p>
<h3>5 Worked Examples and 8 Integration Patterns</h3>
<p>The <code>examples.md</code> file contains 5 complete plugin implementations covering different component combinations. The <code>integrations.md</code> file provides patterns for connecting plugins to external services — SQLite, PostgreSQL, GitHub, Slack, Stripe, OAuth, Docker, and Cloudflare Workers.</p>
<p>These aren't abstract descriptions. Each example includes every file needed to ship: <code>plugin.json</code>, skill definitions, MCP server code, hook scripts, and configuration. Copy the structure, change the names, and you have a working plugin.</p>
<h2>The Pivot: How This Claude Code Plugin Shed Its Codebase</h2>
<p>Plugin Architect didn't start as a Markdown-only project. The commit history tells the story.</p>
<p>From February 10-13, the repository housed <strong>Hive</strong> — a code-heavy system with SQLite storage, configurable tool categories, workflow support, migrations, and a CI pipeline. Eight commits built out this architecture.</p>
<p>On February 15, I deleted all of it.</p>
<pre><code class="language-text">b9d0fca: Remove Hive source, docs, and templates
</code></pre>
<p>Nine commits followed in a single day, restructuring the entire repo as a lightweight prompt-only Claude Code plugin. The Hive codebase — with its database layer, migration system, and TypeScript runtime — was replaced by three Markdown files.</p>
<h3>Why the Pivot</h3>
<p>The code-heavy approach solved the wrong problem. Plugin Architect doesn't need to <em>run</em> anything. It needs to <em>know</em> things and <em>guide</em> decisions. Those are prompt engineering problems, not software engineering problems.</p>
<p>SQLite added complexity without value. Tool categories and filtering required configuration that slowed down the user. The CI pipeline tested infrastructure that wasn't the product — the product was the knowledge encoded in the prompts.</p>
<p>The pivot cut repository size from hundreds of files to 8. Build time went from "install dependencies, compile TypeScript, run tests" to zero. The install path went from "clone, install, build, configure" to a single command.</p>
<h3>The Tradeoff</h3>
<p>Pure prompt engineering trades validation for simplicity. The Hive approach could programmatically verify that generated plugins had correct file structures, valid JSON manifests, and matching tool registrations. The Markdown approach relies on Claude following the instructions accurately.</p>
<p>In practice, Claude follows well-structured instructions reliably. The cases where it deviates are edge cases — unusual component combinations or ambiguous user requests — and the Confirm-Before-Build gate catches most of those by showing the proposed architecture before generating code.</p>
<h2>Lessons Learned</h2>
<h3>What Worked Well</h3>
<p><strong>Single-skill architecture.</strong> Keeping everything in one skill (<code>/plugin-architect</code>) with supporting reference files made the product discoverable. Users learn one command. Claude loads the full context on every invocation, ensuring it always has the complete picture regardless of which extension point the user needs.</p>
<p><strong>No-placeholder policy.</strong> The instruction to write complete, production-ready code in every generated file eliminated the most frustrating failure mode: scaffolding that requires significant manual completion. Users get working plugins, not starter templates.</p>
<p><strong>Intent-based classification.</strong> The component selection matrix is the most-used part of the skill. Mapping natural language descriptions to extension points removes a decision that blocks most first-time plugin developers.</p>
<h3>What I'd Do Differently</h3>
<p><strong>Add more language examples.</strong> All MCP Server templates use TypeScript. The MCP protocol is language-agnostic, and Python developers are a large segment of the Claude Code user base. Adding Python SDK examples would broaden the audience.</p>
<p><strong>Split the knowledge base.</strong> Loading the full 30KB context on every invocation wastes tokens when a user only needs help with one component type. A multi-skill architecture — <code>/plugin-architect hooks</code>, <code>/plugin-architect mcp</code> — would load targeted context and reduce token consumption.</p>
<p><strong>Add a health check mechanism.</strong> There is no way to verify that a plugin generated by Plugin Architect is correctly structured after the fact. A companion validation tool — which I later built as plugin-ops — fills this gap.</p>
<h2>Conclusion</h2>
<p>Plugin Architect demonstrates that prompt engineering is a valid product architecture. A well-structured 30KB knowledge base, encoded in three Markdown files, replaces what would otherwise require a runtime, database, and build pipeline.</p>
<p>The key insight: <strong>match the solution to the problem type.</strong> Plugin Architect solves a knowledge and guidance problem, not a computation problem. Markdown and prompt engineering are the right tools for that job. Runtime code would have been over-engineering.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li>Zero-code plugins are viable products when the problem is knowledge transfer, not computation</li>
<li>Intent-based classification (natural language → component type) removes the biggest friction point for new plugin developers</li>
<li>Pivoting from a code-heavy architecture to pure prompts cut complexity by an order of magnitude with no loss in capability</li>
<li>The Confirm-Before-Build gate prevents the most common failure mode of generative tools: unwanted output</li>
<li>Supporting reference files (examples, integration patterns) scale the skill's knowledge without bloating the core instruction set</li>
</ul>
<p><strong>Source Code:</strong> <a href="https://github.com/twofoldtech-dakota/plugin-architect">GitHub</a></p>]]></content:encoded>
      <category>claude-code</category>
      <category>ai-tools</category>
      <category>open-source</category>
      <category>prompt-engineering</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/building-plugin-architect-zero-code-claude-plugin/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/building-plugin-architect-zero-code-claude-plugin/thumbnail.jpg" />
    </item>
    <item>
      <title>Building Plugin GTM: A Go-To-Market Engine Inside Claude Code</title>
      <link>https://dak-dev.vercel.app/blog/building-plugin-gtm-go-to-market-engine</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/building-plugin-gtm-go-to-market-engine</guid>
      <pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Learn how I built a 29-tool MCP server that handles product analysis, GTM strategy, content generation, and launch tracking without leaving the terminal.</description>
      <content:encoded><![CDATA[<p>I built a go-to-market engine as a Claude Code plugin. It scans a codebase, builds positioning and messaging, generates launch content, and tracks execution — all from the terminal. 29 MCP tools. 7 skills. 106 tests. Zero context-switching to marketing tools.</p>
<p>Plugin GTM exists because the gap between "I built something" and "people know about it" is where most developer projects die. The Claude Code plugin system turned out to be the right platform to close that gap.</p>
<h2>Project Overview</h2>
<h3>The Challenge</h3>
<p>Developers ship code, then stall on go-to-market. Positioning requires thinking about audiences. Messaging requires distilling technical capability into benefits. Content requires writing landing pages, README files, social posts, and launch emails.</p>
<p>The typical workflow: finish coding, open a Google Doc, stare at a blank page, context-switch between 5 tools, and spend a weekend on launch prep. The mechanical work of GTM — not the strategy — consumes the time.</p>
<h3>The Solution</h3>
<p>Plugin GTM keeps the entire GTM workflow inside Claude Code. Seven slash commands cover the full lifecycle:</p>
<table>
<thead>
<tr>
<th>Command</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/gtm-analyze</code></td>
<td>Scan a codebase or describe an idea to build a product profile</td>
</tr>
<tr>
<td><code>/gtm-plan</code></td>
<td>Create positioning, messaging, ICP, channels, pricing, timeline</td>
</tr>
<tr>
<td><code>/gtm-content</code></td>
<td>Generate launch content across 9 content types</td>
</tr>
<tr>
<td><code>/gtm-research</code></td>
<td>Competitive analysis, market sizing, channel research</td>
</tr>
<tr>
<td><code>/gtm-publish</code></td>
<td>Export content from database to project files</td>
</tr>
<tr>
<td><code>/gtm-refine</code></td>
<td>Iterate on content with feedback and version tracking</td>
</tr>
<tr>
<td><code>/gtm</code></td>
<td>Dashboard, status, project list</td>
</tr>
</tbody>
</table>
<h2>Tech Stack</h2>
<table>
<thead>
<tr>
<th>Category</th>
<th>Technology</th>
<th>Why</th>
</tr>
</thead>
<tbody>
<tr>
<td>Runtime</td>
<td>Node.js 22+</td>
<td>Native <code>node:sqlite</code> — zero external database dependencies</td>
</tr>
<tr>
<td>Protocol</td>
<td>MCP SDK (stdio)</td>
<td>Direct integration with Claude Code's tool system</td>
</tr>
<tr>
<td>Validation</td>
<td>Zod</td>
<td>Runtime type checking for all 29 tool parameters</td>
</tr>
<tr>
<td>Build</td>
<td>tsup (esbuild)</td>
<td>ESM output with sourcemaps and declaration files</td>
</tr>
<tr>
<td>Testing</td>
<td>Vitest</td>
<td>106 tests with process isolation for SQLite</td>
</tr>
<tr>
<td>Persistence</td>
<td>SQLite (WAL mode)</td>
<td>Structured data with relational integrity</td>
</tr>
</tbody>
</table>
<h2>Architecture</h2>
<p>The plugin follows a three-layer design:</p>
<pre><code class="language-text">┌─────────────────────────────────────────────┐
│           Skills Layer (7 SKILL.md)          │
│  /gtm  /gtm-analyze  /gtm-plan  /gtm-content│
│  /gtm-research  /gtm-publish  /gtm-refine   │
├─────────────────────────────────────────────┤
│        MCP Server (29 tools, 2 resources)    │
│   Product CRUD │ Plan CRUD │ Content CRUD    │
│   Launch Items │ Versions  │ Export/Diff     │
├─────────────────────────────────────────────┤
│           SQLite Persistence (WAL)           │
│   products │ plans │ content │ versions      │
│                launch_items                   │
└─────────────────────────────────────────────┘
</code></pre>
<p>The skills layer handles user interaction through prompt engineering that guides Claude through GTM workflows. The MCP server handles data: 29 tools for CRUD operations, content versioning, and file export. SQLite provides persistence with foreign key constraints and cascading deletes.</p>
<h3>The Data Model</h3>
<p>Five tables form the core, with a clear hierarchy:</p>
<pre><code class="language-text">Product (1) ──&lt; Plan (N)
                  │
           ┌──────┴──────┐
           │              │
    Content (N)    LaunchItem (N)
       │
ContentVersion (N)
</code></pre>
<p>A product has plans. Plans have content and launch items. Content has automatic version snapshots. Deleting a product cascades through all associated data. This is a deliberate choice for clean project management, though it carries the risk of accidental data loss.</p>
<h2>Key Features</h2>
<h3>Content Versioning with Automatic Snapshots</h3>
<p>Every content update triggers an automatic snapshot of the previous version before overwriting. This happens at the data layer, not the skill layer. It works regardless of which skill or tool initiates the change.</p>
<pre><code class="language-typescript">export function updateContent(id: string, updates: Partial&lt;Content>) {
  const existing = getContent(id);
  if (!existing) throw new Error("Content not found");

  // Auto-snapshot before change
  if (updates.body !== undefined &amp;&amp; updates.body !== existing.body) {
    snapshotVersion(id);
  }

  // Proceed with update...
}
</code></pre>
<p>The version history is append-only. Restoring a previous version creates a new snapshot of the current state, then overwrites with the restored content. No data is lost at any step.</p>
<h3>Content Export with Drift Detection</h3>
<p>Generated content lives in the SQLite database until exported to files. The export system detects drift between the database and filesystem:</p>
<pre><code class="language-typescript">export type DiffStatus =
  | "not_exported"    // Never exported
  | "in_sync"         // File matches database
  | "file_modified"   // Someone edited the file
  | "db_modified"     // Content updated in database
  | "both_modified";  // Both changed independently
</code></pre>
<p>This prevents a common problem: generating content, editing it manually, then overwriting with a stale database version. The <code>/gtm-publish</code> skill surfaces conflicts and lets you choose which version to keep.</p>
<h3>GTM Templates by Category</h3>
<p>Five category-specific templates provide starting points with pre-configured positioning, messaging, ICP profiles, and launch checklists:</p>
<table>
<thead>
<tr>
<th>Template</th>
<th>Target</th>
<th>Key Channels</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>developer-tool</code></td>
<td>Developers building tools</td>
<td>GitHub, HN, Twitter, Dev.to</td>
</tr>
<tr>
<td><code>saas</code></td>
<td>SaaS products</td>
<td>ProductHunt, blogs, email, SEO</td>
</tr>
<tr>
<td><code>open-source</code></td>
<td>OSS projects</td>
<td>GitHub, Reddit, Discord, conferences</td>
</tr>
<tr>
<td><code>cli-tool</code></td>
<td>CLI applications</td>
<td>GitHub, package registries, tutorials</td>
</tr>
<tr>
<td><code>api-service</code></td>
<td>API products</td>
<td>Docs site, integrations, developer relations</td>
</tr>
</tbody>
</table>
<p>Each template is a ~6KB TypeScript object with real positioning frameworks, not generic placeholder text. The <code>developer-tool</code> template includes positioning for both individual developers and team leads — different audiences with different buying criteria.</p>
<h2>Performance Results</h2>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Manual GTM</th>
<th>With plugin-gtm</th>
<th>Improvement</th>
</tr>
</thead>
<tbody>
<tr>
<td>Time from code-complete to launch content</td>
<td>2-3 days</td>
<td>30-60 minutes</td>
<td>3-6x faster</td>
</tr>
<tr>
<td>Content types generated per session</td>
<td>1-2</td>
<td>5-9</td>
<td>4x coverage</td>
</tr>
<tr>
<td>Context switches to external tools</td>
<td>5-8</td>
<td>0</td>
<td>Eliminated</td>
</tr>
<tr>
<td>Version tracking of content iterations</td>
<td>Manual/none</td>
<td>Automatic</td>
<td>Full history</td>
</tr>
</tbody>
</table>
<h2>The Tradeoffs</h2>
<h3>What This Costs</h3>
<p><strong>SQLite is synchronous and single-threaded.</strong> The <code>DatabaseSync</code> API from Node 22's native <code>node:sqlite</code> blocks the event loop during queries. For a single-user tool, queries complete in microseconds. For concurrent access from multiple Claude Code sessions, contention becomes real.</p>
<p><strong>The MCP server is monolithic.</strong> All 29 tools live in a single 21KB <code>index.ts</code> file (~600 lines). Readable today, but adding 20 more tools would make a single file unwieldy. A tool registry pattern would scale better.</p>
<p><strong>Templates are hardcoded.</strong> The 5 GTM templates are TypeScript objects compiled into the server. Adding a custom template requires modifying source code and rebuilding. A user-facing template system would be more flexible.</p>
<p><strong>Content generation quality depends on the LLM.</strong> The MCP tools store and version content, but the writing happens in the skills layer through Claude. The quality of generated landing pages and social posts varies with how well the product was analyzed in step one.</p>
<h3>When Not to Use This</h3>
<p>Plugin GTM works for developer-focused products where the builder is also the marketer. It breaks down when:</p>
<ul>
<li>GTM requires cross-functional team coordination (no collaboration features)</li>
<li>Distribution channels need API integrations (no automated posting)</li>
<li>Content needs visual design (generates text only, no images or layouts)</li>
<li>Market research needs quantitative data beyond what web search provides</li>
</ul>
<h2>Lessons Learned</h2>
<h3>What Worked Well</h3>
<p><strong>Codebase analysis as the entry point.</strong> Starting with <code>/gtm-analyze</code> — which reads README, <code>package.json</code>, source files, and git history — produces strong product profiles. Technical capability extraction maps directly to feature-benefit messaging. This approach works because the codebase <em>is</em> the product.</p>
<p><strong>Separation of storage and generation.</strong> Keeping the MCP server as a pure CRUD layer and the skills as the intelligence layer made both easier to build and test. The 106 tests cover the data layer exhaustively without needing to test LLM output.</p>
<p><strong>Content versioning by default.</strong> Making snapshots automatic (not opt-in) eliminated the "I liked the previous version better" problem. Users iterate freely knowing every version is preserved.</p>
<h3>What I'd Do Differently</h3>
<p><strong>Add batch operations from the start.</strong> The initial 20 tools required individual calls for each operation. Version 0.2.0 added batch export and publish, but retrofitting batch semantics onto a per-item API required new tools rather than extending existing ones.</p>
<p><strong>Integrate with at least one distribution channel.</strong> Even a single GitHub Releases integration would demonstrate the full pipeline: analyze → plan → generate → publish. Without automated distribution, the last mile is still manual.</p>
<p><strong>Design the content model for collaboration.</strong> The single-user SQLite approach was fast to build but locks out the most valuable GTM pattern: getting feedback from others before launch.</p>
<h2>Conclusion</h2>
<p>Plugin GTM proves that developer marketing doesn't need to be a context-switching marathon. Persistent storage, structured workflows, and content versioning handle the mechanical work. Product analysis, positioning frameworks, content generation, and launch checklists stay in the environment where you built the product.</p>
<p>The real value isn't the content generation. It's the structured thinking that <code>/gtm-plan</code> forces: define your ICP before writing copy, establish positioning before creating content, track launch items with deadlines.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li>Codebase analysis is an effective starting point for product positioning — the code reveals technical capability that maps to messaging</li>
<li>Content versioning should be automatic, not opt-in — iteration happens constantly, and users need to restore previous versions</li>
<li>Drift detection between database and filesystem prevents the most common content management failure: accidental overwrites</li>
<li>Category-specific GTM templates provide 80% of the strategy framework, letting you focus on the 20% that's unique to your product</li>
<li>MCP server architecture separates data persistence from LLM-driven generation, making both independently testable</li>
</ul>
<p><strong>Source Code:</strong> <a href="https://github.com/twofoldtech-dakota/plugin-gtm">GitHub</a></p>]]></content:encoded>
      <category>claude-code</category>
      <category>ai-tools</category>
      <category>open-source</category>
      <category>developer-tools</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/building-plugin-gtm-go-to-market-engine/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/building-plugin-gtm-go-to-market-engine/thumbnail.jpg" />
    </item>
    <item>
      <title>Building Plugin Ops: A Claude Code Plugin for Plugin Maintenance</title>
      <link>https://dak-dev.vercel.app/blog/building-plugin-ops-maintenance-engine</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/building-plugin-ops-maintenance-engine</guid>
      <pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Explore how I built a 32-tool MCP server with health scanning, issue tracking, release management, and operational runbooks for Claude Code plugins.</description>
      <content:encoded><![CDATA[<p>I built a Claude Code plugin that maintains other Claude Code plugins. It runs health scans across ~25 checks, tracks issues with priority-based triage, and automates semver releases with changelog generation. 32 MCP tools. 5 skills. All backed by native Node.js SQLite.</p>
<p>Plugin Ops completes a three-plugin lifecycle toolkit. <a href="https://dak-dev.vercel.app/blog/building-plugin-architect-zero-code-claude-plugin">Plugin Architect</a> designs and builds plugins. <a href="https://dak-dev.vercel.app/blog/building-plugin-gtm-go-to-market-engine">Plugin GTM</a> takes them to market. Plugin Ops keeps them healthy after launch.</p>
<h2>Project Overview</h2>
<h3>The Challenge</h3>
<p>Claude Code plugins ship fast. The ecosystem is new, documentation is evolving, and most plugins launch without health checks, issue tracking, or release processes. A plugin that works today might break tomorrow when APIs change, dependencies drift, or the Claude Code plugin spec updates.</p>
<p>Manual maintenance doesn't scale. Checking file structure validity, scanning for missing manifests, verifying skill frontmatter, auditing dependencies — these are repetitive tasks. Without automation, they get skipped until something breaks.</p>
<h3>The Solution</h3>
<p>Plugin Ops provides five operational commands that cover the maintenance lifecycle:</p>
<table>
<thead>
<tr>
<th>Command</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/ops</code></td>
<td>Dashboard, project registration, routing</td>
</tr>
<tr>
<td><code>/ops-health</code></td>
<td>Run ~25 health checks, export reports</td>
</tr>
<tr>
<td><code>/ops-issues</code></td>
<td>File, triage, and track issues</td>
</tr>
<tr>
<td><code>/ops-release</code></td>
<td>Semver bumps, changelog generation, git tags</td>
</tr>
<tr>
<td><code>/ops-runbook</code></td>
<td>Execute guided operational procedures</td>
</tr>
</tbody>
</table>
<p>Register a plugin project once, then run health scans on demand. Issues discovered during scans feed directly into the tracker. Releases follow semver with auto-generated changelogs.</p>
<h2>Tech Stack</h2>
<table>
<thead>
<tr>
<th>Category</th>
<th>Technology</th>
<th>Why</th>
</tr>
</thead>
<tbody>
<tr>
<td>Runtime</td>
<td>Node.js 22+</td>
<td>Native <code>node:sqlite</code> (DatabaseSync) — zero external deps</td>
</tr>
<tr>
<td>Protocol</td>
<td>MCP SDK (stdio)</td>
<td>32 tools + 3 resources over Claude Code's tool system</td>
</tr>
<tr>
<td>Validation</td>
<td>Zod</td>
<td>Runtime schema validation for all tool parameters</td>
</tr>
<tr>
<td>Build</td>
<td>tsup (esbuild)</td>
<td>ESM output, <code>bundle: false</code> preserves file structure</td>
</tr>
<tr>
<td>Persistence</td>
<td>SQLite (WAL mode)</td>
<td>5 tables with foreign keys and cascading deletes</td>
</tr>
<tr>
<td>CI</td>
<td>GitHub Actions</td>
<td>Parallel typecheck + build on every push</td>
</tr>
</tbody>
</table>
<h2>Architecture</h2>
<p>Plugin Ops mirrors the architecture established by Plugin GTM: a skills layer for user interaction, an MCP server for data operations, and SQLite for persistence.</p>
<pre><code class="language-text">┌──────────────────────────────────────────────┐
│           Skills Layer (5 SKILL.md)           │
│  /ops  /ops-health  /ops-issues               │
│  /ops-release  /ops-runbook                    │
├──────────────────────────────────────────────┤
│      MCP Server (32 tools, 3 resources)       │
│  Project CRUD │ Health CRUD │ Issue CRUD      │
│  Release CRUD │ Runbook Exec │ Templates      │
├──────────────────────────────────────────────┤
│          SQLite Persistence (WAL)             │
│  projects │ health_checks │ issues            │
│  releases │ runbook_executions                │
└──────────────────────────────────────────────┘
</code></pre>
<h3>Project Auto-Detection</h3>
<p>When you run <code>/ops init</code> in a plugin directory, the system scans the filesystem to classify the project:</p>
<pre><code class="language-typescript">export function detectProject(projectPath: string): {
  has_skills: number;
  has_mcp: number;
  has_hooks: number;
  has_agents: number;
  type: ProjectType;
  version: string | null;
  name: string | null;
} {
  // Check for skills/ directory
  if (existsSync(join(projectPath, "skills"))) has_skills = 1;
  // Check for .mcp.json or src/index.ts
  if (existsSync(join(projectPath, ".mcp.json"))) has_mcp = 1;
  // Check for hooks in .claude/settings.json
  // Check for agents/ directory

  // Classify type
  if (has_mcp &amp;&amp; has_skills) type = "full";
  else if (has_mcp) type = "mcp";
  else type = "skill-only";

  return { has_skills, has_mcp, has_hooks, has_agents, type, version, name };
}
</code></pre>
<p>This detection maps directly to health check templates. A skill-only plugin gets 8 checks. An MCP plugin gets 10. A full plugin gets 15.</p>
<h2>Key Features</h2>
<h3>Health Check Templates</h3>
<p>Three templates scale checks based on project complexity:</p>
<table>
<thead>
<tr>
<th>Template</th>
<th>Checks</th>
<th>For</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>skill-only</code></td>
<td>8</td>
<td>Skills-only plugins (Markdown files)</td>
</tr>
<tr>
<td><code>mcp-plugin</code></td>
<td>10</td>
<td>MCP server plugins (TypeScript runtime)</td>
</tr>
<tr>
<td><code>full-plugin</code></td>
<td>15</td>
<td>Full plugins with skills, MCP, hooks, and agents</td>
</tr>
</tbody>
</table>
<p>Checks cover structure (directory layout, manifest validity), skills (frontmatter schema, file sizes), MCP (tool registration, transport config), and quality (README completeness, license presence).</p>
<p>The health check definitions exist in templates, but evaluation happens through Claude. The MCP tools record results — they don't perform the scanning. This delegates intelligence to the LLM while the data layer handles persistence and trend tracking.</p>
<h3>Issue Tracking with Health Scan Integration</h3>
<p>Issues flow from health scans into a structured tracker with priority, category, and lifecycle management:</p>
<pre><code class="language-typescript">server.tool(
  "ops_issue_create",
  "File a new issue for a project",
  {
    project_id: z.string(),
    title: z.string(),
    priority: z.enum(["critical", "high", "medium", "low"]).optional(),
    category: z.enum([
      "bug", "dependency", "quality",
      "structure", "feature", "tech-debt"
    ]).optional(),
    health_check_id: z.string().optional(),
  },
  async (params) => {
    const issue = createIssue(params);
    return { content: [{ type: "text", text: JSON.stringify(issue, null, 2) }] };
  },
);
</code></pre>
<p>The <code>health_check_id</code> foreign key links issues to the scan that discovered them. This creates traceability: which scan found the problem, when it was filed, and when it was resolved. Issue stats aggregate by status, priority, and category.</p>
<h3>Release Management with Changelog Export</h3>
<p>The release workflow handles semver versioning and generates changelogs from the issue history:</p>
<pre><code class="language-typescript">// Changelog export renders Markdown from release + issue data
export function exportChangelog(projectId: string): string {
  const releases = listReleases(projectId);
  return releases.map(release => {
    const issues = listIssuesByRelease(release.id);
    return `## ${release.version} (${release.released_at})\n\n` +
      issues.map(i => `- ${i.title}`).join("\n");
  }).join("\n\n");
}
</code></pre>
<p>Each release records the version, release date, notes, and associated file changes. The export produces a <code>CHANGELOG.md</code> with diff detection — the same drift detection pattern from Plugin GTM.</p>
<h2>Performance Results</h2>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Manual Maintenance</th>
<th>With plugin-ops</th>
<th>Improvement</th>
</tr>
</thead>
<tbody>
<tr>
<td>Time to audit plugin health</td>
<td>30-60 min</td>
<td>2-5 min</td>
<td>10x faster</td>
</tr>
<tr>
<td>Issue tracking for plugins</td>
<td>Ad-hoc/none</td>
<td>Structured with triage</td>
<td>Full lifecycle</td>
</tr>
<tr>
<td>Release changelog generation</td>
<td>Manual</td>
<td>Automatic from issues</td>
<td>Time saved</td>
</tr>
<tr>
<td>Ops procedure consistency</td>
<td>Memory-dependent</td>
<td>Runbook-guided</td>
<td>Reproducible</td>
</tr>
</tbody>
</table>
<h2>The Tradeoffs</h2>
<h3>What This Costs</h3>
<p><strong>Health scanning is LLM-driven, not deterministic.</strong> The check templates define what to look for, but Claude performs the evaluation. Results can vary between sessions. A deterministic linter would produce consistent output but couldn't evaluate subjective criteria like "README completeness."</p>
<p><strong>No test suite.</strong> Plugin Ops ships without tests. For a tool that audits the health of other plugins — including checking for test coverage — this is an ironic gap. The architecture mirrors Plugin GTM, which has 106 tests, so retrofitting tests is straightforward.</p>
<p><strong>Migrations run on every connection.</strong> The 5-second TTL on database connections means <code>migrate()</code> executes on every reconnection. The migrations are idempotent (<code>CREATE TABLE IF NOT EXISTS</code> and <code>PRAGMA table_info</code> checks), but the overhead is unnecessary for a stable schema.</p>
<p><strong>Cascade deletes risk data loss.</strong> Deleting a project removes all health checks, issues, releases, and runbook executions. There's no soft-delete mechanism at the data layer. The skill layer asks for confirmation, but a direct MCP tool call bypasses that guardrail.</p>
<h3>When Not to Use This</h3>
<p>Plugin Ops works for solo plugin developers managing 1-10 projects. It breaks down when:</p>
<ul>
<li>Multiple developers need concurrent access to the same database</li>
<li>You need deterministic, reproducible health scans (use a linter instead)</li>
<li>Plugin maintenance requires integration with external issue trackers (GitHub Issues, Linear)</li>
<li>You're managing non-plugin projects (the health templates are plugin-specific)</li>
</ul>
<h2>Lessons Learned</h2>
<h3>What Worked Well</h3>
<p><strong>Shared architectural patterns.</strong> Building Plugin Ops after Plugin GTM meant reusing the same patterns: TTL connection pool, Zod validation, SKILL.md conventions, WAL mode SQLite. The commit history shows 3 commits to reach feature completeness. Shared patterns eliminated most architectural decisions.</p>
<p><strong>Template-based health checks.</strong> Scaling checks by project type avoids overwhelming simple plugins with irrelevant checks. A skill-only plugin doesn't need MCP transport validation.</p>
<p><strong>Runbooks as first-class operations.</strong> Recording runbook executions — which steps were completed, how long they took, what failed — turns tribal knowledge into auditable procedures.</p>
<h3>What I'd Do Differently</h3>
<p><strong>Add deterministic checks alongside LLM evaluation.</strong> Programmatic validation for objective criteria (JSON validity, file existence, semver format) would make health scans reproducible. Reserve LLM evaluation for subjective criteria (documentation quality, API design).</p>
<p><strong>Implement soft deletes.</strong> Cascade deletion is aggressive for a maintenance tool. Archiving projects instead of deleting them would preserve historical data.</p>
<p><strong>Write tests from the start.</strong> Plugin GTM's test suite caught edge cases in content versioning and export. Plugin Ops would benefit from the same coverage, especially for migration code.</p>
<h2>Conclusion</h2>
<p>Plugin Ops closes the lifecycle loop for Claude Code plugins. Design with <a href="https://dak-dev.vercel.app/blog/building-plugin-architect-zero-code-claude-plugin">Plugin Architect</a>, launch with <a href="https://dak-dev.vercel.app/blog/building-plugin-gtm-go-to-market-engine">Plugin GTM</a>, maintain with Plugin Ops.</p>
<p>The three plugins share architectural DNA: MCP servers with SQLite persistence, Zod-validated tools, and SKILL.md-driven user interaction. Building them in sequence — architect first, then GTM, then ops — created compounding velocity. Each plugin took less time than the last because the patterns were established.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li>Project auto-detection maps plugin structure to the right health check template, avoiding irrelevant checks for simpler projects</li>
<li>Linking issues to health scans creates traceability from discovery to resolution</li>
<li>LLM-driven evaluation handles subjective quality criteria that deterministic linters cannot assess</li>
<li>Shared architectural patterns between plugins reduce time-to-ship for each subsequent project</li>
<li>The lifecycle toolkit pattern (build → launch → maintain) covers gaps that individual tools leave open</li>
</ul>
<p><strong>Source Code:</strong> <a href="https://github.com/twofoldtech-dakota/plugin-ops">GitHub</a></p>]]></content:encoded>
      <category>claude-code</category>
      <category>ai-tools</category>
      <category>open-source</category>
      <category>developer-tools</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/building-plugin-ops-maintenance-engine/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/building-plugin-ops-maintenance-engine/thumbnail.jpg" />
    </item>
    <item>
      <title>Claude Code Skills and the Agent Skills Open Standard</title>
      <link>https://dak-dev.vercel.app/blog/claude-code-skills-agent-skills-standard</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/claude-code-skills-agent-skills-standard</guid>
      <pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Build portable AI agent capabilities with Claude Code&apos;s SKILL.md format. The Agent Skills open standard works across 10+ platforms including GitHub Copilot.</description>
      <content:encoded><![CDATA[<p>Agent Skills is an open standard supported by GitHub Copilot, Cursor, Gemini CLI, and 7+ other platforms. Write a <code>SKILL.md</code> once and it works across all of them. Anthropic published the specification in December 2025 at <a href="https://agentskills.io/home">agentskills.io</a>, and adoption moved fast — the reference repository has 67,000+ stars on GitHub.</p>
<p>This post covers Claude Code Skills in detail: the <code>SKILL.md</code> format, invocation control, subagents, hooks, and the open standard that makes Skills portable across platforms. <a href="https://dak-dev.vercel.app/blog/ai-isnt-just-for-coders-claude-skills">Part 1</a> covered Skills for non-technical users. <a href="https://dak-dev.vercel.app/blog/claude-skills-power-user-guide">Part 2</a> covered the architecture and advanced patterns.</p>
<h2>Claude Code Skills: The SKILL.md Format</h2>
<p>Every Claude Code Skill lives in a directory with a <code>SKILL.md</code> file at its root. The file has two sections: YAML frontmatter for configuration and a markdown body for instructions.</p>
<h3>Complete Frontmatter Reference</h3>
<pre><code class="language-yaml">---
name: pr-review                    # Max 64 chars, lowercase + hyphens
description: Reviews pull requests against team coding standards
argument-hint: "[PR number]"       # Shown in autocomplete
disable-model-invocation: false    # true = manual /pr-review only
user-invocable: true               # false = Claude-only, hidden from / menu
allowed-tools: Bash(gh *), Read    # Tools Claude can use without asking
model: sonnet                      # Model override when active
context: fork                      # Run in isolated subagent
agent: Explore                     # Subagent type (with context: fork)
---
</code></pre>
<p>The <code>name</code> field has two restrictions: no "anthropic" or "claude" (reserved words), and no XML tags in any frontmatter value. Names must use lowercase letters, numbers, and hyphens only.</p>
<h3>Directory Structure</h3>
<pre><code class="language-text">pr-review/
├── SKILL.md              # Required — config + instructions
├── checklist.md          # Reference doc (loaded on demand)
├── scripts/
│   └── diff-stats.sh     # Executable (output enters context, not source)
└── examples/
    └── good-review.md    # Example output for Claude to follow
</code></pre>
<h3>Storage Locations</h3>
<p>Claude Code discovers Skills from four locations, in priority order:</p>
<table>
<thead>
<tr>
<th>Priority</th>
<th>Location</th>
<th>Scope</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Enterprise managed settings</td>
<td>All org users</td>
</tr>
<tr>
<td>2</td>
<td><code>~/.claude/skills/{name}/SKILL.md</code></td>
<td>All your projects</td>
</tr>
<tr>
<td>3</td>
<td><code>.claude/skills/{name}/SKILL.md</code></td>
<td>Current project</td>
</tr>
<tr>
<td>4</td>
<td>Plugin marketplace installs</td>
<td>Where plugin is enabled</td>
</tr>
</tbody>
</table>
<p>In monorepos, Claude also discovers Skills from nested directories. Editing a file in <code>packages/frontend/</code> triggers discovery of Skills in <code>packages/frontend/.claude/skills/</code>.</p>
<p><strong>Backward compatibility:</strong> As of Claude Code v2.1.3 (January 2026), <code>.claude/commands/</code> files and <code>.claude/skills/</code> directories both work. A file at <code>.claude/commands/review.md</code> and a directory at <code>.claude/skills/review/SKILL.md</code> both create the <code>/review</code> command. Existing commands continue working with no migration required.</p>
<h3>Dynamic Context Injection</h3>
<p>The <code>!`command`</code> syntax runs shell commands before Skill content reaches Claude:</p>
<pre><code class="language-yaml">---
name: pr-summary
description: Summarizes the current pull request
context: fork
agent: Explore
allowed-tools: Bash(gh *)
---

## Context
- PR diff: !`gh pr diff`
- PR comments: !`gh pr view --comments`
- Changed files: !`gh pr diff --name-only`

## Task
Summarize this pull request. Focus on:
1. What changed and why
2. Potential risks or breaking changes
3. Test coverage gaps
</code></pre>
<p>The shell commands execute immediately. Their output replaces the <code>!`command`</code> placeholder before Claude sees the prompt. This loads real-time data into the Skill without Claude spending turns on tool calls.</p>
<p>The tradeoff: dynamic context runs on every invocation. If <code>gh pr diff</code> returns 50KB of output, that consumes 50KB of context window each time. Keep commands focused and pipe through filters when dealing with large output.</p>
<h2>Invocation Control</h2>
<h3>The Control Matrix</h3>
<p>Two frontmatter fields determine who can trigger a Skill:</p>
<table>
<thead>
<tr>
<th>Configuration</th>
<th>User types <code>/name</code></th>
<th>Claude auto-invokes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Default (both true)</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td><code>disable-model-invocation: true</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>user-invocable: false</code></td>
<td>No</td>
<td>Yes</td>
</tr>
</tbody>
</table>
<p>Use <code>disable-model-invocation: true</code> for destructive operations (database migrations, deployments) where you want explicit user control. Use <code>user-invocable: false</code> for background knowledge that Claude should apply automatically — coding standards, project conventions, error handling patterns.</p>
<h3>String Substitution</h3>
<p>Skills accept arguments through substitution variables:</p>
<pre><code class="language-yaml">---
name: review-file
description: Reviews a specific file for code quality
argument-hint: "[file-path]"
---

Review the file at $ARGUMENTS for:
1. Code quality and readability
2. Security vulnerabilities
3. Performance issues
</code></pre>
<p>Invoking <code>/review-file src/auth.ts</code> replaces <code>$ARGUMENTS</code> with <code>src/auth.ts</code>. Use <code>$0</code>, <code>$1</code>, <code>$2</code> for positional arguments when a Skill accepts multiple inputs.</p>
<h3>Context Window Budget</h3>
<p>Skill descriptions consume 2% of the context window — approximately 16,000 characters as a fallback limit. If you install many Skills, some descriptions get excluded from the system prompt.</p>
<p>Run <code>/context</code> to check which Skills loaded and which were excluded. Override the budget with the <code>SLASH_COMMAND_TOOL_CHAR_BUDGET</code> environment variable if the default is too restrictive.</p>
<p>The tradeoff: more Skills means more competition for the description budget. Skills with <code>disable-model-invocation: true</code> don't consume description budget because they're excluded from auto-invocation. Use this flag on rarely-needed Skills to free up space.</p>
<h2>Subagents and Hooks</h2>
<h3>Forked Execution</h3>
<p>Adding <code>context: fork</code> runs the Skill in an isolated subagent. The Skill content becomes the subagent's system prompt. The parent conversation continues after the subagent completes.</p>
<pre><code class="language-yaml">---
name: security-audit
description: Runs a security audit on the codebase
context: fork
agent: general-purpose
allowed-tools: Bash(npm audit *), Read, Grep, Glob
---

Audit this codebase for security vulnerabilities:

1. Run `npm audit` and analyze results
2. Search for hardcoded secrets using patterns: API keys, tokens, passwords
3. Check dependency versions against known CVEs
4. Report findings with severity levels
</code></pre>
<p>Available agent types: <code>Explore</code> (fast, read-only codebase analysis), <code>Plan</code> (architecture design), <code>general-purpose</code> (full capabilities), or custom agents defined in <code>.claude/agents/</code>.</p>
<p>The tradeoff: forked Skills lose conversation history. The subagent starts with only the Skill content and the user's invocation arguments. Design forked Skills to be self-contained — include all necessary context in the Skill itself or load it via dynamic context injection.</p>
<h3>Skill Preloading in Subagents</h3>
<p>Custom subagents can preload Skills so the full Skill content is injected at startup:</p>
<pre><code class="language-yaml"># .claude/agents/api-developer.md
---
name: api-developer
description: Implements API endpoints following team conventions
skills:
  - api-conventions
  - error-handling-patterns
  - database-patterns
---

Build API endpoints using the preloaded team patterns.
Always follow the conventions in the loaded Skills.
</code></pre>
<p>This differs from normal Skill discovery. Preloaded Skills inject their full content immediately rather than waiting for activation. Use this for domain-specific agents where certain conventions always apply.</p>
<h3>Lifecycle Hooks</h3>
<p>Skills support hooks that run at specific events:</p>
<pre><code class="language-yaml">---
name: safe-deploy
description: Deploys to staging with safety checks
hooks:
  PreToolUse:
    - matcher: Bash(rm *|git push --force*)
      type: prompt
      prompt: "Block this command. Explain why it's unsafe in a deployment context."
  Stop:
    - type: command
      command: "echo 'Deploy skill completed at $(date)' >> /tmp/deploy.log"
---
</code></pre>
<p>Hook events include <code>PreToolUse</code>, <code>PostToolUse</code>, <code>Stop</code>, <code>SubagentStart</code>, <code>SubagentStop</code>, <code>Notification</code>, <code>UserPromptSubmit</code>, <code>SessionStart</code>, and <code>SessionEnd</code>. Hooks can be shell commands (<code>type: command</code>), single-turn model prompts (<code>type: prompt</code>), or multi-turn agents (<code>type: agent</code>).</p>
<p>The <code>async: true</code> option (added January 2026) runs hooks in the background without blocking Skill execution — useful for logging, notifications, or non-critical validation.</p>
<h2>The Agent Skills Open Standard</h2>
<h3>Specification</h3>
<p>Anthropic published the Agent Skills specification at <a href="https://agentskills.io/home">agentskills.io</a> in December 2025. The core format matches what Claude Code uses: a directory with a <code>SKILL.md</code> file containing YAML frontmatter and markdown instructions.</p>
<p>The open standard defines a minimal required schema:</p>
<pre><code class="language-yaml">---
name: my-skill          # Required: max 64 chars
description: What it does and when to use it  # Required: max 1024 chars
license: MIT            # Optional
compatibility: "Requires git, node >= 18"     # Optional: max 500 chars
metadata:               # Optional: arbitrary key-value pairs
  author: Dakota Smith
  version: 1.0.0
---
</code></pre>
<p>The specification mandates progressive disclosure: metadata (~100 tokens) loads at startup, core content (under 5,000 tokens recommended) loads on activation, supplementary files load on demand.</p>
<h3>Platform Adoption</h3>
<p>As of early 2026, these platforms read the Agent Skills format:</p>
<table>
<thead>
<tr>
<th>Platform</th>
<th>Skill Location</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Claude Code</td>
<td><code>.claude/skills/</code></td>
<td>Full spec + extensions (hooks, subagents, dynamic context)</td>
</tr>
<tr>
<td>Claude.ai</td>
<td>Upload via Settings</td>
<td>ZIP package format</td>
</tr>
<tr>
<td>GitHub Copilot</td>
<td><code>.github/skills/</code> or <code>.claude/skills/</code></td>
<td>Personal skills at <code>~/.copilot/skills/</code></td>
</tr>
<tr>
<td>Cursor</td>
<td><code>.claude/skills/</code></td>
<td>Standard format</td>
</tr>
<tr>
<td>Gemini CLI</td>
<td><code>.claude/skills/</code></td>
<td>Standard format</td>
</tr>
<tr>
<td>OpenAI Codex CLI</td>
<td><code>.claude/skills/</code></td>
<td>Standard format</td>
</tr>
<tr>
<td>Goose (Block)</td>
<td><code>.claude/skills/</code></td>
<td>Standard format</td>
</tr>
<tr>
<td>Windsurf</td>
<td><code>.claude/skills/</code></td>
<td>Standard format</td>
</tr>
<tr>
<td>Roo Code</td>
<td><code>.claude/skills/</code></td>
<td>Standard format</td>
</tr>
<tr>
<td>Amp</td>
<td><code>.claude/skills/</code></td>
<td>Standard format</td>
</tr>
</tbody>
</table>
<p>The key distinction: Claude Code extends the standard with platform-specific features. These extensions work only in Claude Code and degrade gracefully elsewhere — other platforms ignore unknown frontmatter fields.</p>
<h3>What's Portable vs. What's Not</h3>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Open Standard</th>
<th>Claude Code Only</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>name</code>, <code>description</code></td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Markdown body instructions</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Supporting files (scripts, references)</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td><code>license</code>, <code>compatibility</code>, <code>metadata</code></td>
<td>Yes</td>
<td>Ignored by Claude Code</td>
</tr>
<tr>
<td><code>disable-model-invocation</code></td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td><code>user-invocable</code></td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td><code>context: fork</code>, <code>agent</code></td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td><code>hooks</code></td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td><code>allowed-tools</code></td>
<td>Experimental</td>
<td>Yes</td>
</tr>
<tr>
<td><code>!`command`</code> dynamic context</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td><code>$ARGUMENTS</code> substitution</td>
<td>No</td>
<td>Yes</td>
</tr>
</tbody>
</table>
<p>Write the core Skill (name, description, instructions, supporting files) for maximum portability. Add Claude Code extensions knowing they won't break anything on other platforms — unknown fields are ignored, not rejected.</p>
<h3>Validation</h3>
<p>The reference library provides validation:</p>
<pre><code class="language-bash">npx skills-ref validate ./my-skill
</code></pre>
<p>This checks frontmatter requirements, directory naming conventions, and file size recommendations against the open standard specification.</p>
<h2>Practical Migration: Commands to Skills</h2>
<p>If you have existing <code>.claude/commands/</code> files, they keep working. But the Skills format offers more capability. Here's the conversion pattern:</p>
<p><strong>Before</strong> (<code>.claude/commands/deploy.md</code>):</p>
<pre><code class="language-markdown">Deploy the current branch to staging.
Run tests first, then build, then deploy.
</code></pre>
<p><strong>After</strong> (<code>.claude/skills/deploy/SKILL.md</code>):</p>
<pre><code class="language-yaml">---
name: deploy
description: Deploys the current branch to staging after running tests and build
argument-hint: "[environment]"
disable-model-invocation: true
allowed-tools: Bash(npm run *), Bash(git *)
hooks:
  PreToolUse:
    - matcher: Bash(git push --force*)
      type: prompt
      prompt: "Block force pushes during deployment."
---

Deploy the current branch to $ARGUMENTS (default: staging).

1. Run the test suite: `npm run test`
2. Build the project: `npm run build`
3. Deploy: `npm run deploy:$ARGUMENTS`

If any step fails, stop and report the error. Do not proceed to deployment.
</code></pre>
<p>The Skills version adds: argument support, invocation control (manual-only for safety), tool permissions, and a hook to prevent force pushes. The commands version has none of these.</p>
<h2>Limitations and Tradeoffs</h2>
<p><strong>Context budget is real.</strong> With 2% of the context window allocated to Skill descriptions, a project with 30+ Skills hits the limit. Prioritize: use <code>disable-model-invocation: true</code> on rarely-needed Skills to remove them from the description budget.</p>
<p><strong>Subagents cannot nest.</strong> A forked Skill cannot spawn another subagent. Design your agent architecture as a flat hierarchy — one level of delegation, not a tree.</p>
<p><strong>MCP tools are unavailable in background subagents.</strong> If your Skill relies on MCP servers (database connections, external APIs), it cannot run with <code>context: fork</code>. Run it in the main conversation context instead.</p>
<p><strong>Platform behavior varies.</strong> The <code>allowed-tools</code> field is marked experimental in the open standard. Each platform interprets it differently or ignores it. Test Skills on every target platform before distributing.</p>
<p><strong>Hot-reload has limits.</strong> Skills auto-reload on save within a running session. Subagent definitions in <code>.claude/agents/</code> require a session restart or <code>/agents</code> reload to pick up changes.</p>
<p><strong>When NOT to use Skills:</strong> One-off scripts that you'll run once and discard. Aliases shorter than their frontmatter (if the Skill body is shorter than the config, use a shell alias). Tasks requiring real-time bidirectional connections — Skills don't maintain open sockets or streaming API sessions.</p>
<h2>Conclusion</h2>
<p>The Agent Skills standard solved a real problem: AI capabilities locked inside individual platforms. A Skill written for Claude Code now works in GitHub Copilot, Cursor, and Gemini CLI without modification. Claude Code's extensions (hooks, subagents, dynamic context) add power for teams that need it, while the portable core ensures the investment transfers across tools.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li><code>SKILL.md</code> is the universal format: YAML frontmatter for config, markdown body for instructions, supporting files for resources</li>
<li>Claude Code extends the open standard with <code>context: fork</code>, hooks, dynamic context (<code>!`command`</code>), and subagent integration — powerful but not portable to other platforms</li>
<li>The core Skill format (name, description, instructions, supporting files) works across 10+ platforms including GitHub Copilot, Cursor, and Gemini CLI</li>
<li>Use <code>disable-model-invocation: true</code> for destructive operations and <code>user-invocable: false</code> for background conventions</li>
<li>Skill descriptions consume 2% of the context window — monitor with <code>/context</code> and keep descriptions specific to avoid budget overflow</li>
</ul>
<p><em>This is Part 3 of a series on Claude Skills. <a href="https://dak-dev.vercel.app/blog/ai-isnt-just-for-coders-claude-skills">Part 1</a> covers what Skills are and why they matter for non-technical teams. <a href="https://dak-dev.vercel.app/blog/claude-skills-power-user-guide">Part 2</a> covers the architecture and advanced patterns for power users.</em></p>]]></content:encoded>
      <category>ai-tools</category>
      <category>claude-code</category>
      <category>skills</category>
      <category>developer-tools</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/claude-code-skills-agent-skills-standard/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/claude-code-skills-agent-skills-standard/thumbnail.jpg" />
    </item>
    <item>
      <title>Claude Skills for Power Users: Scripts, Teams, and Architecture</title>
      <link>https://dak-dev.vercel.app/blog/claude-skills-power-user-guide</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/claude-skills-power-user-guide</guid>
      <pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Explore Claude Skills&apos; three-tier progressive disclosure architecture and learn to build advanced workflows using executable scripts and team deployment.</description>
      <content:encoded><![CDATA[<p>A well-built Claude Skill costs 100 tokens when idle — roughly one cent per thousand conversations. Load 10 Claude Skills at once and the overhead stays negligible. That efficiency comes from an architecture most users never see: a three-tier progressive disclosure system that loads information only when Claude needs it.</p>
<p><a href="https://dak-dev.vercel.app/blog/ai-isnt-just-for-coders-claude-skills">Part 1 of this series</a> covered what Skills are and why they matter for non-technical teams. This guide goes deeper. You'll learn the architecture behind Skills, how to build advanced multi-step workflows with validation, and how to deploy Skills across an organization.</p>
<h2>The Three-Tier Architecture</h2>
<p>Every Skill loads in three stages. Understanding these stages is the difference between a Skill that wastes context and one that scales.</p>
<p><strong>Tier 1 — Metadata (always loaded).</strong> Claude reads the Skill's name and description at the start of every conversation. Cost: ~100 tokens per Skill. This is how Claude decides whether your Skill is relevant to the current task.</p>
<p><strong>Tier 2 — Instructions (loaded when triggered).</strong> When Claude determines a Skill applies, it loads the full instruction file. Cost: under 5,000 tokens. This contains the step-by-step playbook for the workflow.</p>
<p><strong>Tier 3 — Resources (loaded as needed).</strong> Supporting files — templates, reference docs, scripts — load only when a specific step requires them. Cost: effectively unlimited because they enter context one piece at a time.</p>
<p>The result: Anthropic reports a 98% token reduction when Skills are present but not triggered. Install 20 Skills and pay the context cost of fewer than 2,000 tokens total until one activates.</p>
<p>This architecture also means <strong>the structure of your Skill matters more than its length.</strong> A 200-line instruction file that loads 5 reference files on demand outperforms a 1,000-line monolith that loads everything upfront.</p>
<h2>Building Advanced Claude Skills</h2>
<h3>The Skill File Format</h3>
<p>Every Skill is a directory containing a <code>SKILL.md</code> file. The file has two parts: YAML frontmatter (metadata) and markdown body (instructions).</p>
<pre><code class="language-yaml">---
name: weekly-report
description: Generates weekly status reports from raw notes, following the team's standard format with executive summary, risk flags, and metric tables.
---

## Instructions

When the user provides weekly notes, meeting summaries, or ticket updates:

1. Extract key metrics and progress items
2. Format using the team template in REPORT_TEMPLATE.md
3. Flag any items marked "blocked" or "at risk"
4. Generate executive summary (3 sentences max)
</code></pre>
<p>Two rules for the <code>description</code> field: write it in third person ("Generates weekly reports" not "I generate weekly reports"), and be specific about when the Skill applies. Vague descriptions like "helps with reports" cause poor activation accuracy. Specific descriptions like "generates weekly status reports from raw notes" trigger reliably.</p>
<h3>Supporting Files</h3>
<p>A Skill directory can contain anything Claude needs:</p>
<pre><code class="language-text">weekly-report/
  SKILL.md              # Main instructions (Tier 2)
  REPORT_TEMPLATE.md    # Team's report format (Tier 3)
  METRIC_DEFINITIONS.md # What each KPI means (Tier 3)
  examples/
    good-report.md      # Example of excellent output (Tier 3)
</code></pre>
<p>Claude loads <code>REPORT_TEMPLATE.md</code> when it reaches the "format using the team template" step — not before. This keeps the context window lean until the information is needed.</p>
<h3>Executable Scripts</h3>
<p>This is where Skills get powerful. A Skill can include Python or JavaScript scripts that Claude runs during execution. The script source code never enters the context window. Only the script's output does.</p>
<p>A PDF analysis Skill might include:</p>
<pre><code class="language-text">pdf-analyzer/
  SKILL.md
  scripts/
    extract_text.py     # Extracts text from PDF
    extract_tables.py   # Extracts tabular data
    validate_output.py  # Checks extraction quality
</code></pre>
<p>Claude runs <code>extract_text.py</code> on the uploaded PDF, receives the extracted text as output, and works with that text — without the script source code consuming context tokens. This makes scripts far more token-efficient than having Claude generate equivalent code from scratch each session.</p>
<p>The tradeoff: script availability depends on the platform. On claude.ai, Claude can install packages from npm and PyPI. On the API, only pre-installed packages are available. Know your deployment target before building script-heavy Skills.</p>
<h3>The Validation Pattern</h3>
<p>The most reliable advanced pattern is plan-validate-execute:</p>
<ol>
<li>Claude creates an intermediate output (a draft, a data structure, a plan)</li>
<li>A validation script checks the output for errors</li>
<li>Claude fixes any issues before proceeding</li>
<li>Final execution only happens after validation passes</li>
</ol>
<p>This catches errors before they compound. For a form-filling Skill, the sequence looks like: analyze form → generate field mapping → validate mapping against constraints → fill the form → verify output. Each step has a checkpoint. If validation fails at step 3, Claude returns to step 2 instead of producing a broken final result.</p>
<h2>Patterns That Separate Good Skills From Great Ones</h2>
<h3>Chunk Over Monolith</h3>
<p>A single 800-line Skill that handles voice consistency, audience targeting, format selection, and quality review will underperform four focused Skills that each handle one concern.</p>
<p>Rhonda Britten, a business coach, tested this directly: a master voice Skill combined with separate audience-specific Skills (public-facing vs. coaching clients) outperformed a monolithic voice profile. Each audience Skill activates independently based on context.</p>
<p>The principle: one Skill, one job. Composition happens through Claude's judgment, not through complex branching inside a single Skill.</p>
<h3>Workflow Sequencing</h3>
<p>Skills compose naturally when their descriptions are specific. A four-Skill content pipeline:</p>
<ol>
<li><strong>Business Case Builder</strong> — Analyzes opportunity and generates projections</li>
<li><strong>Sales Page Writer</strong> — Takes the business case and creates conversion copy</li>
<li><strong>Email Conversion Tester</strong> — Reviews the sales page for conversion optimization</li>
<li><strong>Social Amplifier</strong> — Generates platform-specific posts from the sales page</li>
</ol>
<p>Each Skill's description references the output of the previous step. Claude chains them automatically when you say "take this business case through the full content pipeline." No explicit chaining mechanism exists — composition happens through Claude's semantic understanding of each Skill's description.</p>
<h3>Calibrate Freedom</h3>
<p>Match prescriptiveness to risk:</p>
<ul>
<li><strong>High freedom</strong> (text guidance only): Content analysis, brainstorming, code reviews. Claude uses judgment within guardrails.</li>
<li><strong>Medium freedom</strong> (templates and pseudocode): Reports with preferred structure, emails with required sections. Claude fills a framework.</li>
<li><strong>Low freedom</strong> (exact scripts): Data migrations, compliance documents, financial calculations. Claude executes precisely specified steps.</li>
</ul>
<p>The higher the cost of error, the lower the freedom. A creative brainstorm Skill and a payroll calculation Skill need fundamentally different levels of prescriptiveness.</p>
<h2>Real-World Results</h2>
<p>These results come from published case studies, not synthetic benchmarks.</p>
<table>
<thead>
<tr>
<th>Skill</th>
<th>Creator</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr>
<td>SEO Content Optimizer</td>
<td>Wyndo</td>
<td>3,500 monthly Google clicks using Skills to analyze top-ranking pages and generate optimized content</td>
</tr>
<tr>
<td>MCP Execution Debugger</td>
<td>Jenny Ouyang</td>
<td>Converted 20-minute debugging sessions into 2-minute structured diagnostic reports</td>
</tr>
<tr>
<td>Learning Capture (Blue Fish)</td>
<td>mark</td>
<td>Auto-extracts insights from conversations into a categorized Notion database using scan + capture sub-skills</td>
</tr>
<tr>
<td>Inventory Analyst</td>
<td>Alex Willen</td>
<td>Projects 12-month sales using velocity, manufacturing time, shipping delays, and seasonal patterns</td>
</tr>
<tr>
<td>Brand Onboarding Package</td>
<td>Patrick Schaber</td>
<td>Packages brand guidelines into a shareable Skill so new contractors produce on-brand work from day one</td>
</tr>
</tbody>
</table>
<p>The common thread: each Skill encodes domain expertise that would otherwise require re-explanation every session. The Blue Fish Skill uses a two-word trigger ("PIN" to capture, "APPROVE" to confirm) to minimize friction during normal conversations.</p>
<h2>Team Deployment</h2>
<p>Skills distribution varies by plan:</p>
<p><strong>Individual (Pro/Max):</strong> Skills are private to your account. No peer-to-peer sharing mechanism exists on claude.ai.</p>
<p><strong>Team/Enterprise:</strong> Organization Owners upload Skills through admin settings. Provisioned Skills appear for all org members immediately. Owners choose whether Skills are enabled or disabled by default. Individual users can toggle provisioned Skills off but cannot delete org-provisioned ones.</p>
<p><strong>Skills Directory:</strong> Pre-built partner Skills from Notion, Figma, Atlassian (Jira/Confluence), Canva, and Cloudflare. Admins provision these across the org in one click from <a href="https://claude.com/connectors">claude.com/connectors</a>.</p>
<p>The tradeoff: Skills do not sync across surfaces. A Skill uploaded to claude.ai must be separately uploaded to the API and separately configured for Claude Code. If your team works across multiple Anthropic surfaces, plan for maintaining Skills in each environment.</p>
<h2>When Skills Break Down</h2>
<p>Skills are not the right tool for every situation.</p>
<p><strong>Vague descriptions cause misfires.</strong> Skills activate based on semantic matching between the conversation and the Skill description. If your description is generic ("helps with writing"), the Skill triggers when it shouldn't and stays silent when it should activate. Test activation with 10 different prompt phrasings before deploying to your team.</p>
<p><strong>Session state resets.</strong> Skills don't persist data between conversations. Each session starts fresh. If your workflow requires memory across sessions, you need an external system (Notion, a database, a shared file) as the persistence layer.</p>
<p><strong>500 lines is the practical limit.</strong> Anthropic recommends keeping <code>SKILL.md</code> under 500 lines. Beyond that, move content into supporting reference files that load on demand. A 1,200-line <code>SKILL.md</code> wastes context on instructions Claude doesn't need for the current step.</p>
<p><strong>Security matters for shared Skills.</strong> A Skill can direct Claude to execute arbitrary code through bundled scripts. Only install Skills from trusted sources. For organizations, the admin provisioning path provides centralized control. For individuals, review any community Skill's scripts before installing.</p>
<p><strong>One-off tasks don't need Skills.</strong> If you'll do something once, a normal prompt is faster than building a Skill. The return on investment starts at the second use and compounds with every use after that. Budget 15-30 minutes to build and test a first working Skill.</p>
<h2>Conclusion</h2>
<p>Skills are infrastructure, not features. The three-tier architecture makes them lightweight to install and powerful to execute — but only when built with that architecture in mind.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li>Skills use progressive disclosure: ~100 tokens at rest, under 5,000 when active, unlimited resources on demand — a 98% context reduction when idle</li>
<li>Structure Skills as focused, single-purpose units; composition through multiple Skills outperforms monolithic mega-Skills</li>
<li>Use the plan-validate-execute pattern for any Skill where errors are costly</li>
<li>Match prescriptiveness to risk: high freedom for creative tasks, low freedom for precision tasks</li>
<li>Team deployment requires admin provisioning; Skills do not sync across claude.ai, the API, and Claude Code</li>
</ul>
<p><em>This is Part 2 of a series on Claude Skills. <a href="https://dak-dev.vercel.app/blog/ai-isnt-just-for-coders-claude-skills">Part 1</a> covers what Skills are and why they matter for non-technical teams. <a href="https://dak-dev.vercel.app/blog/claude-code-skills-agent-skills-standard">Part 3</a> dives into Claude Code Skills and the Agent Skills open standard for developers.</em></p>]]></content:encoded>
      <category>ai-tools</category>
      <category>productivity</category>
      <category>claude</category>
      <category>skills</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/claude-skills-power-user-guide/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/claude-skills-power-user-guide/thumbnail.jpg" />
    </item>
    <item>
      <title>MCP Apps: Interactive UI Has Entered the Chat</title>
      <link>https://dak-dev.vercel.app/blog/mcp-apps-interactive-ui-inside-ai-chat</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/mcp-apps-interactive-ui-inside-ai-chat</guid>
      <pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Explore how MCP Apps turn AI chat into an interactive canvas with embedded dashboards, forms, and 3D visualizations—no client-specific code required.</description>
      <content:encoded><![CDATA[<p>Two weeks ago, MCP tools returned text. Today, with MCP Apps, they return entire applications.</p>
<p><a href="https://modelcontextprotocol.io/extensions/apps/overview">MCP Apps</a> launched on January 26, 2026, as the first official extension to the Model Context Protocol. The concept: tools no longer limit themselves to text responses. They ship interactive HTML interfaces—dashboards, forms, 3D visualizations, PDF viewers—that render directly inside the conversation. Six clients support MCP Apps at launch. Ten companies shipped integrations on day one. The <a href="https://github.com/modelcontextprotocol/ext-apps">ext-apps repository</a> hit 1.4k GitHub stars in its first two weeks.</p>
<p>This post covers what MCP Apps are, how the architecture works, and why it matters for developers building on MCP.</p>
<h2>What Changes With Interactive Tools</h2>
<p>Traditional MCP tools accept input and return structured data. The host renders it as text, images, or resource links. That works for most tasks. But some interactions demand more than a text response.</p>
<p>Ask an AI "show me sales by region" and you get a list of numbers. With this extension, the same tool returns an interactive map. Users click regions to drill down, hover for details, and toggle metrics—all without additional prompts. The interaction stays inside the conversation, right alongside the discussion that prompted it.</p>
<p>Here's what interactive tool UIs enable that text responses cannot:</p>
<ul>
<li><strong>Data exploration</strong> — Interactive dashboards with filtering, sorting, and export</li>
<li><strong>Configuration wizards</strong> — Forms with dependent fields, validation, and defaults</li>
<li><strong>Rich media</strong> — PDF viewers, 3D model renderers, sheet music displays</li>
<li><strong>Real-time monitoring</strong> — Live-updating metrics without repeated prompts</li>
<li><strong>Multi-step workflows</strong> — Approval flows, code review, issue triage with persistent state</li>
</ul>
<p>The ext-apps repo ships 12+ working examples covering these exact use cases: Three.js 3D scenes, CesiumJS globe maps, cohort heatmaps, budget allocators, PDF viewers, system monitors, and more.</p>
<h2>How the Architecture Works</h2>
<p>MCP Apps combine two existing MCP primitives in a new way: tools and resources.</p>
<p>A tool declares a UI resource in its description using a <code>_meta.ui.resourceUri</code> field. That URI uses the <code>ui://</code> scheme and points to an HTML page served by the MCP server. When the host calls the tool, four things happen:</p>
<ol>
<li><strong>UI preloading</strong> — The host fetches the <code>ui://</code> resource before the tool completes, enabling streamed inputs</li>
<li><strong>Resource fetch</strong> — The server returns bundled HTML (with CSS/JS inlined via tools like <code>vite-plugin-singlefile</code>)</li>
<li><strong>Sandboxed rendering</strong> — The host renders the HTML inside a sandboxed iframe with restricted permissions</li>
<li><strong>Bidirectional communication</strong> — The app and host exchange messages via JSON-RPC over <code>postMessage</code></li>
</ol>
<p>The app stays isolated from the host. It cannot access the parent DOM, read cookies, or escape its container. All communication flows through a structured, auditable message protocol.</p>
<pre><code class="language-typescript">// Server: register a tool with UI metadata
const resourceUri = "ui://dashboard/app.html";

registerAppTool(
  server,
  "show-dashboard",
  {
    title: "Dashboard",
    description: "Displays an interactive analytics dashboard.",
    inputSchema: { type: "object", properties: { region: { type: "string" } } },
    _meta: { ui: { resourceUri } },
  },
  async ({ region }) => ({
    content: [{ type: "text", text: JSON.stringify(await getAnalytics(region)) }],
  }),
);
</code></pre>
<pre><code class="language-typescript">// Client: the App class handles host communication
import { App } from "@modelcontextprotocol/ext-apps";

const app = new App({ name: "Dashboard", version: "1.0.0" });
app.connect();

// Receive the initial tool result
app.ontoolresult = (result) => {
  const data = JSON.parse(result.content?.find(c => c.type === "text")?.text);
  renderChart(data);
};

// Call server tools from the UI when users interact
document.getElementById("refresh").addEventListener("click", async () => {
  const result = await app.callServerTool({ name: "show-dashboard", arguments: { region: "us-west" } });
  renderChart(JSON.parse(result.content?.find(c => c.type === "text")?.text));
});
</code></pre>
<p>The <code>App</code> class from <code>@modelcontextprotocol/ext-apps</code> abstracts the postMessage protocol. It provides methods for receiving tool results, calling server tools, updating model context, logging events, and opening browser links. You can also skip the SDK entirely and implement the <a href="https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx">JSON-RPC protocol</a> directly.</p>
<h2>Why This Matters for Developers</h2>
<p>Before this extension, building interactive experiences for AI chat required client-specific code. A Slack integration needed Slack Block Kit. A Claude integration needed Claude's custom format. Every platform had its own UI contract.</p>
<p>The new standard defines a single contract: HTML in a sandboxed iframe with JSON-RPC messaging. Write your app once, and it renders in Claude, VS Code Insiders, Goose, Postman, MCPJam, and ChatGPT (support rolling out now). JetBrains, AWS, and Google DeepMind have all signaled interest.</p>
<p>The practical impact: a tool developer ships one interactive experience that works across every compliant host. No client-specific code. No platform-locked UI. If you've followed the <a href="https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio">evolution of AI dev tools</a>, this represents a similar shift—from fragmented, platform-specific approaches to a shared standard.</p>
<p>The SDK supports this portability with framework starter templates for React, Vue, Svelte, Preact, Solid, and vanilla JavaScript. Each template demonstrates the same patterns adapted to the framework's conventions.</p>
<p>Ten companies shipped launch-day integrations: Amplitude, Asana, Box, Canva, Clay, Figma, Hex, monday.com, Slack, and Salesforce. These aren't demos—they're production servers that return interactive UIs in any supporting client.</p>
<h2>Building Your First MCP App</h2>
<p>The fastest path uses the <code>create-mcp-app</code> skill with an AI coding agent:</p>
<pre><code class="language-bash"># Install the skill in Claude Code
/plugin marketplace add modelcontextprotocol/ext-apps
/plugin install mcp-apps@modelcontextprotocol-ext-apps

# Then ask your agent:
# "Create an MCP App that displays a color picker"
</code></pre>
<p>For manual setup, the dependencies are minimal:</p>
<pre><code class="language-bash">npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/sdk
npm install -D typescript vite vite-plugin-singlefile express cors tsx
</code></pre>
<p>A typical project structure separates server from UI:</p>
<pre><code class="language-text">my-mcp-app/
├── server.ts          # MCP server with tool + resource registration
├── mcp-app.html       # UI entry point
├── src/
│   └── mcp-app.ts     # UI logic using the App class
├── vite.config.ts     # Bundles HTML into single file
└── package.json
</code></pre>
<p>Build, serve, and test:</p>
<pre><code class="language-bash">npm run build &amp;&amp; npm run serve
# Server runs at http://localhost:3001/mcp
</code></pre>
<p>To test locally with Claude, tunnel your server with <code>cloudflared</code>:</p>
<pre><code class="language-bash">npx cloudflared tunnel --url http://localhost:3001
</code></pre>
<p>Then add the generated URL as a custom connector in Claude's settings.</p>
<p>The repo also includes a <code>basic-host</code> test interface at <code>localhost:8080</code> that renders your app without needing a full AI client. Useful for rapid iteration during development.</p>
<h2>What's Next</h2>
<p>The extension went from proposal (November 2025) to production (January 2026) in about two months. The spec has a stable <code>2026-01-26</code> version and an active draft for the next iteration.</p>
<p>The ecosystem is moving fast. Microsoft 365 Copilot Chat plans to support interactive tool UIs with rich widgets starting late February 2026. ChatGPT support is rolling out. The collaboration between Anthropic, OpenAI, and the MCP-UI community on a shared standard signals that this isn't a vendor-locked feature—it's infrastructure. That <a href="https://dak-dev.vercel.app/blog/my-2026-dev-setup">cross-platform AI tooling convergence</a> will reshape how developers build integrations.</p>
<p>For developers building MCP servers, the question shifts from "what data does my tool return?" to "what experience does my tool deliver?" The answer no longer has to be text.</p>
<h2>Conclusion</h2>
<p>MCP Apps represent the biggest expansion of the Model Context Protocol since its launch. Interactive HTML rendered inside AI conversations, secured by iframe sandboxing, portable across every major AI client—all from a single codebase. Two weeks in, the adoption signals are strong: 1.4k GitHub stars, 10 launch partners, 6+ supporting clients, and major platforms lining up.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li>MCP Apps are the first official MCP extension, enabling interactive HTML UIs inside AI conversations</li>
<li>The architecture uses sandboxed iframes with JSON-RPC over postMessage for security and portability</li>
<li>One codebase runs across 6+ AI clients with zero platform-specific UI code</li>
<li>10 companies shipped production integrations at launch; more adopting weekly</li>
<li>The <code>@modelcontextprotocol/ext-apps</code> SDK supports React, Vue, Svelte, Preact, Solid, and vanilla JS</li>
</ul>
<p>Start with the <a href="https://modelcontextprotocol.io/extensions/apps/overview">official docs</a>, clone the <a href="https://github.com/modelcontextprotocol/ext-apps">ext-apps repo</a>, and run any of the 12+ examples to see interactive tool UIs in action.</p>]]></content:encoded>
      <category>mcp</category>
      <category>ai-tools</category>
      <category>developer-tools</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/mcp-apps-interactive-ui-inside-ai-chat/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/mcp-apps-interactive-ui-inside-ai-chat/thumbnail.jpg" />
    </item>
    <item>
      <title>AI Isn&apos;t Just for Coders: How Claude Skills Bridge the Gap</title>
      <link>https://dak-dev.vercel.app/blog/ai-isnt-just-for-coders-claude-skills</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/ai-isnt-just-for-coders-claude-skills</guid>
      <pubDate>Thu, 05 Feb 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Discover why half of all workers avoid AI — and how Claude Skills turn any workflow into a repeatable, quality-controlled playbook. No coding required.</description>
      <content:encoded><![CDATA[<p>Half your team isn't using AI. That's not speculation — Gallup reports that 49% of U.S. workers never touch AI tools at work. Among those who do, confidence is dropping: ManpowerGroup measured an 18% decline in AI confidence even as usage climbed 13% over the past year. Meanwhile, a feature called Claude Skills is solving the exact problem that drives this resistance — and most people have never heard of it.</p>
<p>The conventional response to low adoption: "Those employees need training." But 87% of workers have received zero AI training, and the answer isn't another workshop with generic prompts. The answer is giving people structured tools that match how they already work.</p>
<h2>The Blank Prompt Problem</h2>
<p>Most people's first AI experience follows the same pattern. Open a chatbot. Stare at a blank text box. Type something vague. Get a vague response. Walk away unimpressed.</p>
<p>This isn't a user problem. It's a design problem.</p>
<p>A blank prompt box is the AI equivalent of handing someone an empty spreadsheet and saying "do finance." Without context about your role, your standards, and your workflow, AI produces generic output that requires so much editing it feels faster to do the work yourself.</p>
<p>The data confirms this: 45% of employees doubt AI's accuracy, according to SurveyMonkey's 2026 workplace report. A growing number of workers experience what psychologists now call FOBO — Fear of Becoming Obsolete. 73% worry about losing their professional skills to AI, so they avoid it entirely.</p>
<p>The irony: the people most skeptical of AI stand to benefit the most from structured AI workflows.</p>
<h2>What Are Claude Skills?</h2>
<p>Skills are Claude's answer to the blank prompt problem. Instead of starting every conversation from scratch, a Skill teaches Claude how you work — once — and applies that knowledge automatically going forward.</p>
<p>Think of a Skill as a playbook. You define:</p>
<ul>
<li><strong>What</strong> Claude should produce (a weekly status report, a content brief, an onboarding checklist)</li>
<li><strong>How</strong> it should be structured (your team's format, your company's tone, your manager's preferred level of detail)</li>
<li><strong>What standards</strong> to maintain (word count, required sections, data points to include)</li>
</ul>
<p>Once created, a Skill activates whenever the task is relevant. No re-explaining context. No copy-pasting previous prompts. The institutional knowledge is built in.</p>
<p>Here's the important part: <strong>creating a Skill requires zero coding.</strong> You build one by describing your workflow to Claude in a normal conversation. Claude generates the Skill structure for you. If you can describe how you do your job, you can create a Skill.</p>
<p>This isn't a developer tool repurposed for business users. Anthropic designed Skills for everyone — pre-built Skills for document creation (Excel, Word, PowerPoint, PDF) ship with every Claude account, including the free tier. Custom Skills require a Pro subscription, but the creation process stays the same: describe your process, let Claude build it.</p>
<h2>Skills in Action: Four Business Workflows</h2>
<p>Here's what Skills look like across four non-technical roles.</p>
<h3>Project Manager: Weekly Status Reports</h3>
<p><strong>Before</strong>: Copy last week's report. Update each section manually. Chase down teammates for numbers. Spend 45 minutes formatting.</p>
<p><strong>With a Status Report Skill</strong>: Feed Claude your raw notes, meeting summaries, and ticket updates. The Skill enforces your report template — executive summary first, risk items flagged, metrics in a consistent format every time. A polished status report in 3 minutes instead of 45.</p>
<p>The Skill doesn't do the thinking for you. You decide what's important. But the formatting, structure, and consistency happen without effort.</p>
<h3>Marketing Manager: Content Repurposing</h3>
<p><strong>Before</strong>: Write a blog post. Manually adapt it for LinkedIn, the newsletter, social media, and an internal summary. Each version takes 15-20 minutes.</p>
<p><strong>With a Repurposing Skill</strong>: Feed Claude the original post. The Skill produces all four versions — each adapted for the platform's format, character limits, and tone — while maintaining your brand voice. One input, four outputs, 60+ minutes saved per piece of content.</p>
<h3>HR Professional: Onboarding Checklists</h3>
<p><strong>Before</strong>: Copy the template for each new hire. Customize by role. Miss the same items every third hire because the template drifted from the actual process.</p>
<p><strong>With an Onboarding Skill</strong>: The Skill contains your complete onboarding process — role-specific requirements, equipment lists, access permissions, training schedules. Feed it the new hire details. It generates a customized, complete checklist every time. Zero items forgotten because the Skill is the single source of truth.</p>
<h3>Sales Lead: Call Preparation</h3>
<p><strong>Before</strong>: Scan the CRM. Skim recent emails. Wing the opening pitch.</p>
<p><strong>With a Call Prep Skill</strong>: Paste the prospect's information and recent communications. The Skill generates a briefing document: company context, previous touchpoints, suggested talking points, and three discovery questions. Preparation that took 20 minutes now takes 2.</p>
<h2>Why Consistency Matters More Than Speed</h2>
<p>Enterprise AI users report saving 40-60 minutes per day, according to OpenAI's 2025 Enterprise Report. Those time savings are real. But speed isn't the primary value of Skills.</p>
<p><strong>Consistency is.</strong></p>
<p>Without a Skill, Claude's output varies based on how you phrase the prompt. Ask the same question three different ways, get three different quality levels. Teams working without Skills produce work that depends entirely on who wrote the prompt and how much time they had.</p>
<p>With a Skill, the quality floor rises. Every output follows the same structure, meets the same standards, and includes the same required elements. The worst output your team produces with a Skill is better than the average output without one.</p>
<p>This matters most for teams where consistency is the goal: compliance documents, client deliverables, internal reporting, brand communications. One Skill that enforces your standard eliminates the variance.</p>
<p>OpenAI's enterprise research reinforces this: 75% of enterprise AI users report completing tasks they couldn't complete before. The gap isn't about doing things faster. It's about reaching a quality bar that previously required specialized expertise.</p>
<h2>Getting Started in Five Minutes</h2>
<p>No technical setup required. Four steps:</p>
<p><strong>1. Identify your most repetitive workflow.</strong> Not the most complex — the most frequent. The report you write every Monday. The email structure you recreate weekly. The analysis format your stakeholders expect.</p>
<p><strong>2. Describe it to Claude.</strong> Open Claude and say: "I want to create a Skill for [your workflow]. Here's how I do it today..." Walk Claude through your process, your format, and your quality standards. Be specific about what a good output looks like.</p>
<p><strong>3. Let Claude build the Skill.</strong> Claude generates a structured Skill based on your description. Review it. Adjust any details. Save it.</p>
<p><strong>4. Use it.</strong> Next time you need that workflow, the Skill handles the structure. You focus on the substance.</p>
<p>The entire process takes five minutes for a straightforward Skill. Every use after that compounds the return.</p>
<p>For teams, the math is compelling. A team of 10 people using 3-4 Skills each, saving 30 minutes per day — that's 25 hours of recovered capacity per week. At a loaded cost of $50/hour, that's over $65,000 per year in productivity gains.</p>
<h2>Conclusion</h2>
<p>The divide between AI adopters and AI skeptics isn't about technical ability. It's about whether people have structured tools that match their actual work.</p>
<p>The teams pulling ahead in 2026 aren't more technical. They're more systematic. They encode their workflows, their standards, and their institutional knowledge into Skills — and Claude works the way they work instead of the other way around.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li>49% of workers avoid AI because the blank prompt produces inconsistent results — Skills solve this with built-in structure</li>
<li>Creating a Skill requires zero coding: describe your workflow to Claude and let it build the Skill for you</li>
<li>The biggest value isn't speed — it's consistency across every output, every team member, every time</li>
<li>Start with your most repetitive workflow, not your most complex one</li>
<li>Skills compound across teams: 10 people using 4 Skills each can recover 25+ hours per week</li>
</ul>
<p>The question for your team isn't "should we use AI?" It's "have we given AI enough structure to produce useful output?" Skills are that structure.</p>
<p><em>This is Part 1 of a series on Claude Skills. <a href="https://dak-dev.vercel.app/blog/claude-skills-power-user-guide">Part 2</a> covers power-user techniques for building advanced Skills. <a href="https://dak-dev.vercel.app/blog/claude-code-skills-agent-skills-standard">Part 3</a> dives into Claude Code Skills and the Agent Skills open standard for developers.</em></p>]]></content:encoded>
      <category>ai-tools</category>
      <category>productivity</category>
      <category>claude</category>
      <category>skills</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/ai-isnt-just-for-coders-claude-skills/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/ai-isnt-just-for-coders-claude-skills/thumbnail.jpg" />
    </item>
    <item>
      <title>Why I Built STUDIO: Four Generations of AI Code Supervision</title>
      <link>https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio</guid>
      <pubDate>Sun, 01 Feb 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Four AI orchestration systems taught me that 19 agents produce more drift than 3 supervised ones. STUDIO adds confidence scoring and preference learning.</description>
      <content:encoded><![CDATA[<p>19 agents produced worse code than 3.</p>
<p>That counterintuitive result—discovered after building four generations of AI orchestration systems—drives the thesis behind STUDIO. The problem with AI coding tools isn't speed. It's drift. Ask Claude to build a feature—you get working code. Ask for another—more working code. After ten features, your codebase has three different patterns for the same problem, duplicate utilities scattered across files, and state management that contradicts itself. Each change looked correct in isolation. The aggregate is a mess.</p>
<p>I spent four iterations trying to fix this. Here's the path from reactive review to proactive supervision.</p>
<h2>The Drift Problem</h2>
<p>AI optimizes for task completion, not system coherence. It solves the immediate problem without considering how that solution fits existing patterns. Junior developers do this too—but juniors learn from code review. AI accepts the review, then makes the same mistake in a different file.</p>
<p>After 14 years in enterprise .NET and Sitecore—the same platform-specific complexity that drove the <a href="https://dak-dev.vercel.app/blog/building-claude-marketplace-cms-analyzers">CMS analysis marketplace</a>—I've seen what drift looks like at scale. Codebases that started clean but accumulated "quick fixes" until the original architecture disappeared. AI accelerates this. It writes code faster than you can review it, and each generation of code is internally consistent but externally disconnected from what came before.</p>
<p>The core insight: <strong>prevention beats detection.</strong> Catching drift after it happens is cleanup work. Stopping it before execution is architecture.</p>
<h2>Generation 1: APL — Reactive Review</h2>
<p><a href="https://dak-dev.vercel.app/blog/building-apl-autonomous-coding-agent">APL—the Autonomous Phased Looper</a>—was my first attempt. Three phases: Plan, Execute, Review. The reviewer used Reflexion to self-critique and catch mistakes after execution. The learner agent persisted patterns to disk for future sessions.</p>
<p>APL worked. It <a href="https://dak-dev.vercel.app/blog/how-apl-built-this-blog">built this blog</a> with 47 stories across 6 epics, hitting Lighthouse 99. But the review phase was reactive—it caught problems after they existed in the codebase. The self-learning system helped patterns compound over time, and the ReAct execution loops caught individual task failures. Cross-task drift, though, slipped through. The reviewer could find inconsistent import paths. It couldn't prevent the architectural decisions that led to them.</p>
<p>APL proved that phased execution with self-learning produces working software. It didn't prove that working software stays coherent at scale.</p>
<h2>Generation 2: ORC — 19 Agents, 19 Opinions</h2>
<p>If three agents couldn't prevent drift, nineteen might.</p>
<p><a href="https://github.com/twofoldtech-dakota/ORC">ORC</a> decomposed development into specialists: Architect, Security Engineer, Database Engineer, Frontend Specialist, QA, Technical Writer, and more. It added codebase analysis, Epic→Feature→Story planning, anti-slop detection, and pattern learning.</p>
<p>The system was powerful. One prompt could generate complete features with tests, docs, and security review. But 19 agents meant 19 opinions. The coordination overhead ate tokens—each specialist wanted to weigh in on every decision. Debugging required figuring out which agent introduced a problem. Specialists sometimes disagreed (the Architect wanted one pattern, the Security Engineer wanted another), and resolving conflicts took longer than building the feature manually.</p>
<p>More agents didn't mean better code. It meant more complexity and more coordination surface area. ORC taught me that capability without accountability produces chaos.</p>
<h2>Generation 3: ALLOY — The Hybrid That Couldn't Decide</h2>
<p>ALLOY tried to split the difference—three core agents that could summon specialists when needed. Hybrid approach. Less overhead than ORC, more capability than APL.</p>
<p>The problem moved: deciding <em>when</em> to summon specialists became its own source of drift. The system would skip consultation to move faster, then produce work that needed specialist review anyway. When it did consult, the specialist's recommendation sometimes conflicted with what the core agent had already started building.</p>
<p>ALLOY proved something important: the problem wasn't capability. It was accountability. No amount of agent architecture fixes drift if the system can bypass its own quality gates. The moment an agent can skip a check to "move faster," it will—and the drift compounds from there.</p>
<h2>Generation 4: STUDIO — Supervision Over Scale</h2>
<p><a href="https://github.com/twofoldtech-dakota/studio">STUDIO</a> returns to three agents: Planner, Builder, Content Writer. The difference is supervision.</p>
<p>Before any plan executes, STUDIO runs a mandatory questioning phase. It consults domain expert personas, challenges its own plan against five criteria (requirements coverage, edge cases, simplicity, integration fit, failure modes), and presents a confidence score. Low confidence triggers more questions. High confidence proceeds to execution.</p>
<pre><code class="language-text">╔══════════════════════════════════════════════════════════════╗
║  PLAN CONFIDENCE: 85%                                        ║
╠══════════════════════════════════════════════════════════════╣
║  Requirements:    [████████░░] 80%                           ║
║  Step Quality:    [██████████] 100%                          ║
║  Context:         [████████░░] 80%                           ║
║  Risk:            [████████░░] 80%                           ║
╚══════════════════════════════════════════════════════════════╝
</code></pre>
<p>The Builder executes exactly what the plan specifies. Each step has a validation command. If validation fails, it retries with hints from the failure output. If retries exhaust, it blocks and asks for help. Work doesn't silently fail—every step either passes validation or stops the pipeline.</p>
<p>When you correct something, STUDIO asks if it should remember the preference. Say yes, and it persists to a rules file that applies to future builds. Corrections compound instead of disappearing between sessions. This is the same persistence principle from APL's <code>.apl/</code> directory, but applied to supervision rules rather than coding patterns.</p>
<p>The preference file grows over time:</p>
<pre><code class="language-json">{
  "preferences": [
    {
      "rule": "Use named exports, never default exports",
      "learned_from": "session_2026-01-28",
      "applied_count": 47
    },
    {
      "rule": "All API routes return typed response objects",
      "learned_from": "session_2026-01-30",
      "applied_count": 12
    }
  ]
}
</code></pre>
<p>After 10 corrections, STUDIO's plans already reflect your preferences. After 50, it rarely needs correction at all. The supervision tightens automatically.</p>
<h2>The Pattern: What Four Generations Taught Me</h2>
<p><strong>Supervision beats autonomy.</strong> AI writes code fine. AI can't judge if that code fits your architecture without explicit checks. Validation at each step prevents drift better than review after the fact. APL detected problems reactively. STUDIO prevents them proactively.</p>
<p><strong>Constraints beat capabilities.</strong> ORC could do more than STUDIO. STUDIO's constraints—mandatory questioning, quality gates, five challenges before execution—produce more consistent results. Limiting what AI can skip forces thoroughness.</p>
<p><strong>Memory compounds value.</strong> Ephemeral sessions waste corrections. Persisting preferences means projects get smarter over time. This applies to both <a href="https://dak-dev.vercel.app/blog/building-apl-autonomous-coding-agent">APL's pattern learning</a> and STUDIO's preference rules.</p>
<p><strong>Simplicity enables debugging.</strong> When ORC failed, finding which of 19 agents broke took longer than fixing the problem. Three agents means three places to look. <a href="https://dak-dev.vercel.app/blog/my-2026-dev-setup">My dev setup</a> evolved toward this same principle—subtraction matters as much as addition.</p>
<p><strong>The agent count doesn't correlate with output quality.</strong> Three supervised agents outperform 19 unsupervised ones. The supervision architecture—confidence scoring, mandatory challenges, persistent preferences—matters more than the number of specialists. This insight applies beyond coding tools to any <a href="https://dak-dev.vercel.app/blog/claude-skills-power-user-guide">multi-agent system architecture</a>.</p>
<h2>The Tradeoffs</h2>
<p>STUDIO's supervision model has costs:</p>
<p><strong>Supervision adds 30-60 seconds of latency before execution.</strong> The mandatory questioning phase, confidence scoring, and five-criteria challenge run before any code is written. For a 5-minute feature, that's 10-20% overhead. For quick fixes or single-line changes, the supervision pipeline costs more than the work itself.</p>
<p><strong>Rapid prototyping doesn't fit the supervised model.</strong> When the goal is "try three approaches and see which feels right," mandatory validation gates slow exploration. Use vanilla Claude Code or APL for exploratory work. STUDIO is for execution against known requirements.</p>
<p><strong>The confidence threshold (default 85%) needs per-team tuning.</strong> At 85%, STUDIO asks additional questions on roughly 40% of plans. Some teams find this too cautious; others want it higher. Tuning the threshold requires 5-10 sessions of observation to find the right balance for your codebase and risk tolerance.</p>
<p><strong>The preference file grows and needs periodic pruning.</strong> After 50+ sessions, accumulated preferences can conflict—an early rule about naming conventions might contradict a later architectural decision. Quarterly review of the preferences file prevents stale rules from degrading output. The same <a href="https://dak-dev.vercel.app/blog/building-apl-autonomous-coding-agent">maintenance principle applies to APL's pattern directory</a>.</p>
<h2>Key Takeaways</h2>
<ul>
<li><strong>19 agents produce more drift than 3 supervised ones.</strong> Coordination overhead and conflicting opinions outweigh the benefits of specialization.</li>
<li><strong>Prevention beats detection.</strong> Catching drift reactively (APL) works. Preventing it proactively (STUDIO) works better.</li>
<li><strong>Confidence scoring makes uncertainty visible.</strong> You see doubt before it becomes a problem in your codebase.</li>
<li><strong>Persistent preferences create compounding quality.</strong> Each correction makes future builds more accurate. After 50 corrections, the system rarely needs intervention.</li>
<li><strong>Constraints produce better output than capabilities.</strong> Mandatory quality gates force thoroughness. Optional checks get skipped.</li>
</ul>
<p>Install STUDIO:</p>
<pre><code class="language-bash">claude
/plugin marketplace add https://github.com/twofoldtech-dakota/studio.git
/plugin install studio@twofoldtech-dakota
/build "your goal here"
</code></pre>
<p>Watch the questioning phase. See the confidence score before execution begins. That visibility—knowing the system's uncertainty before it writes code—is the difference between supervised and autonomous development.</p>
<p>GitHub: <a href="https://github.com/twofoldtech-dakota/studio">twofoldtech-dakota/studio</a></p>]]></content:encoded>
      <category>ai</category>
      <category>architecture</category>
      <category>automation</category>
      <category>claude-code</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/supervisor-in-the-machine-why-i-built-studio/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/supervisor-in-the-machine-why-i-built-studio/thumbnail.jpg" />
    </item>
    <item>
      <title>Building APL: An Autonomous Coding Agent for Claude Code</title>
      <link>https://dak-dev.vercel.app/blog/building-apl-autonomous-coding-agent</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/building-apl-autonomous-coding-agent</guid>
      <pubDate>Sun, 25 Jan 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Build an autonomous coding agent that cuts context switches from 20 to 3 per feature using phased planning, ReAct execution, and persistent self-learning.</description>
      <content:encoded><![CDATA[<p>Context switches dropped from 15-20 to 2-3 per feature. Rework from missed requirements fell from 30% to 8%. Time to first working version collapsed from hours to minutes.</p>
<p>Those numbers come from APL—the Autonomous Phased Looper—a Claude Code plugin I built to handle entire features autonomously. APL plans work using Tree-of-Thoughts decomposition, executes tasks through ReAct loops, reviews its own output with Reflexion, and persists what it learns to disk. It has since shipped several production projects, <a href="https://dak-dev.vercel.app/blog/how-apl-built-this-blog">including this blog</a>.</p>
<p>This post covers why vanilla Claude Code stalls on complex features, how the three-phase architecture solves it, and what APL learned from building real software.</p>
<h2>Why Vanilla Claude Code Stalls on Complex Features</h2>
<p>Claude Code excels at individual tasks. Write a function, refactor a component, debug an error—it delivers. But complex features require coordination: understanding requirements, breaking down work, executing in sequence, and verifying results.</p>
<p>Running Claude Code manually for each subtask introduces friction:</p>
<ul>
<li>Context gets lost between sessions</li>
<li>No systematic verification of completed work</li>
<li>Repeated mistakes without learning</li>
<li>Human bottleneck for every decision</li>
</ul>
<p>A new feature with 15 subtasks means 15 context switches, 15 opportunities for misalignment, and no guarantee the pieces fit together. I needed a system that could operate autonomously while maintaining quality. That system also needed to <a href="https://dak-dev.vercel.app/blog/building-claude-marketplace-cms-analyzers">integrate with specialized plugins</a> for domain-specific tasks.</p>
<h2>The Three-Phase Architecture</h2>
<p>APL structures autonomous work into three distinct phases: Plan, Execute, and Review. Each phase has a specialized agent optimized for its task.</p>
<pre><code class="language-text">┌─────────────────────────────────────────────────────────┐
│                    APL ORCHESTRATOR                      │
└─────────────────────────┬───────────────────────────────┘
                          │
        ┌─────────────────┼─────────────────┐
        ▼                 ▼                 ▼
   ┌─────────┐      ┌──────────┐      ┌─────────┐
   │  PLAN   │ ───▶ │ EXECUTE  │ ───▶ │ REVIEW  │
   │  PHASE  │      │  PHASE   │      │  PHASE  │
   └─────────┘      └──────────┘      └─────────┘
        │                 │                 │
   Tree-of-Thoughts  ReAct Loops     Reflexion
   Task Breakdown    Parallel Exec   Self-Critique
</code></pre>
<h3>Phase 1: Planning with Tree-of-Thoughts</h3>
<p>The planner agent receives a goal and decomposes it into a structured task list. This isn't bullet points—it uses Tree-of-Thoughts reasoning to explore multiple approaches before committing to one.</p>
<pre><code class="language-typescript">// Example task decomposition output
{
  "goal": "Add user authentication to the API",
  "tasks": [
    {
      "id": "task_001",
      "subject": "Create User model with password hashing",
      "success_criteria": [
        "User schema includes email, passwordHash, createdAt",
        "Password hashing uses bcrypt with cost factor 12",
        "Model exports TypeScript types"
      ],
      "dependencies": [],
      "parallel_safe": true
    },
    {
      "id": "task_002",
      "subject": "Implement JWT token generation",
      "success_criteria": [
        "Tokens include userId and expiration",
        "Secret loaded from environment variable",
        "Expiration set to 24 hours"
      ],
      "dependencies": ["task_001"],
      "parallel_safe": false
    }
  ]
}
</code></pre>
<p>The key insight: <strong>success criteria are defined upfront</strong>. The coder agent knows exactly what "done" looks like before writing a single line. This same principle—explicit completion criteria before execution—later became central to how <a href="https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio">STUDIO validates every build step</a>.</p>
<h3>Phase 2: Execution with ReAct Loops</h3>
<p>The coder agent implements each task using the ReAct pattern: Reason, Act, Observe, Verify.</p>
<pre><code class="language-text">┌──────────────────────────────────────────────────────┐
│                    ReAct LOOP                         │
│                                                      │
│  ┌─────────┐    ┌─────────┐    ┌─────────┐         │
│  │ REASON  │───▶│   ACT   │───▶│ OBSERVE │         │
│  │         │    │         │    │         │         │
│  │ "What   │    │ Write   │    │ Check   │         │
│  │ approach│    │ code,   │    │ output, │         │
│  │ solves  │    │ run     │    │ errors, │         │
│  │ this?"  │    │ tests   │    │ results │         │
│  └─────────┘    └─────────┘    └────┬────┘         │
│                                      │              │
│                      ┌───────────────┘              │
│                      ▼                              │
│                 ┌─────────┐                         │
│                 │ VERIFY  │──── Success? ───▶ Next  │
│                 │         │                   Task  │
│                 │ Check   │                         │
│                 │ success │──── Failure? ───▶ Retry │
│                 │ criteria│                         │
│                 └─────────┘                         │
└──────────────────────────────────────────────────────┘
</code></pre>
<p>When independent tasks exist, APL executes them in parallel. A task graph ensures dependencies are respected while maximizing throughput.</p>
<h3>Phase 3: Review with Reflexion</h3>
<p>After execution completes, the reviewer agent performs self-critique using the Reflexion pattern. It examines all changes holistically:</p>
<ul>
<li>Do the changes satisfy the original goal?</li>
<li>Are there cross-task issues (inconsistent naming, conflicting patterns)?</li>
<li>Did any task introduce regressions?</li>
<li>What patterns worked well? What failed?</li>
</ul>
<p>The reviewer outputs both fixes and learning insights. Fixes trigger another execution cycle. Insights persist to the learning system.</p>
<h2>The Self-Learning System</h2>
<p>APL maintains a <code>.apl/</code> directory in each project with accumulated knowledge:</p>
<pre><code class="language-text">.apl/
├── patterns/
│   ├── success/           # Approaches that worked
│   └── anti-patterns/     # Approaches that failed
├── preferences/           # User coding style preferences
├── project-knowledge/     # Project-specific context
└── session-logs/          # Execution history
</code></pre>
<p>Before planning, the planner agent consults this knowledge base. Before coding, the coder agent reviews relevant patterns. The learner agent extracts insights after each session.</p>
<pre><code class="language-typescript">// Example learned pattern
{
  "id": "pattern_auth_001",
  "category": "authentication",
  "title": "JWT refresh token rotation",
  "context": "When implementing JWT auth with refresh tokens",
  "pattern": "Store refresh tokens in httpOnly cookies, rotate on each use, maintain a token family for revocation",
  "why": "Prevents token theft and enables immediate revocation of compromised sessions",
  "learned_from": "session_2026-01-15_auth_impl",
  "success_rate": 0.95
}
</code></pre>
<p>Over time, APL becomes more effective on your specific codebase. A project with 20 sessions of accumulated patterns produces measurably better output than a fresh project—fewer retries, fewer style mismatches, faster planning. This persistence model is what separates APL from running Claude Code repeatedly. <a href="https://dak-dev.vercel.app/blog/my-2026-dev-setup">My dev setup</a> includes tools that make these learning loops visible across sessions.</p>
<h2>Error Handling and Recovery</h2>
<p>Autonomous systems fail. APL handles this through three mechanisms:</p>
<p><strong>Graduated Retry Logic</strong>: Simple errors (syntax, imports) retry immediately. Complex errors trigger reasoning about the failure before retry. Repeated failures escalate to the user.</p>
<p><strong>Checkpointing</strong>: APL saves state after each completed task. If a session crashes, it resumes from the last checkpoint rather than starting over.</p>
<p><strong>Error Categorization</strong>: Errors are classified (transient, logic, environment, unknown) to select appropriate recovery strategies.</p>
<pre><code class="language-typescript">// Error handling configuration
{
  "retry_policy": {
    "max_retries_per_task": 3,
    "backoff_strategy": "exponential",
    "escalation_threshold": 2,
    "checkpoint_frequency": "per_task"
  },
  "error_categories": {
    "syntax": { "retry": true, "backoff": false },
    "test_failure": { "retry": true, "backoff": true },
    "environment": { "retry": false, "escalate": true }
  }
}
</code></pre>
<h2>The Plugin Architecture</h2>
<p>APL is implemented as a Claude Code plugin—a collection of markdown files defining agents, commands, and hooks. This architecture follows patterns from the <a href="https://dak-dev.vercel.app/blog/claude-code-skills-agent-skills-standard">Agent Skills Standard</a>, where specialized agents provide domain expertise through a consistent interface.</p>
<pre><code class="language-text">apl-autonomous-phased-looper/
├── .claude-plugin/
│   └── plugin.json
├── agents/
│   ├── apl-orchestrator.md
│   ├── planner-agent.md
│   ├── coder-agent.md
│   ├── tester-agent.md
│   ├── reviewer-agent.md
│   └── learner-agent.md
├── commands/
│   └── apl.md
└── hooks/
    └── session-end.md
</code></pre>
<p>Each agent is a markdown file with a system prompt defining its role, available tools, and behavior. The orchestrator coordinates the phases, delegating to specialized agents.</p>
<pre><code class="language-markdown"># Planner Agent (excerpt)

You are the APL Planning specialist. Your role is to decompose
goals into structured task lists using Tree-of-Thoughts reasoning.

## Process

1. Analyze the goal and identify key requirements
2. Generate 2-3 possible decomposition approaches
3. Evaluate each approach for completeness and parallelism
4. Select the optimal approach and output structured tasks
5. Define success criteria for each task

## Output Format

Return a JSON task list with: id, subject, description,
success_criteria[], dependencies[], parallel_safe
</code></pre>
<h2>Results</h2>
<p>APL has handled dozens of features across multiple projects. The measured results:</p>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Before APL</th>
<th>With APL</th>
</tr>
</thead>
<tbody>
<tr>
<td>Context switches per feature</td>
<td>15-20</td>
<td>2-3</td>
</tr>
<tr>
<td>Time to first working version</td>
<td>Hours</td>
<td>Minutes</td>
</tr>
<tr>
<td>Rework due to missed requirements</td>
<td>30%</td>
<td>8%</td>
</tr>
<tr>
<td>Consistent code style</td>
<td>Manual review</td>
<td>Automatic</td>
</tr>
</tbody>
</table>
<p>The self-learning compounds over time. APL on a mature project (20+ sessions) outperforms APL on a new one because it has internalized the patterns—which frameworks to use, how to structure tests, what naming conventions the project follows.</p>
<h2>The Tradeoffs</h2>
<p>APL isn't free. Here's what it costs:</p>
<p><strong>Token consumption runs 3-5x higher than manual Claude Code usage.</strong> The planning phase alone generates thousands of tokens exploring approaches. For a feature that costs $0.50 in manual prompts, APL runs $1.50-$2.50. The ROI is positive for features with 5+ subtasks, but negative for small changes.</p>
<p><strong>Exploratory coding doesn't fit the phased model.</strong> APL needs clear goals with definable success criteria. If you're experimenting—"try this approach, see if it feels right"—the rigid Plan-Execute-Review cycle adds overhead without value. Use vanilla Claude Code for exploration, APL for execution.</p>
<p><strong>Cold starts on new projects are slow.</strong> With no <code>.apl/</code> knowledge base, the first session relies entirely on the planner's general knowledge. Patterns that APL would catch on a mature project (naming conventions, test structure, import paths) require manual correction on a fresh project.</p>
<p><strong>The <code>.apl/</code> directory requires periodic maintenance.</strong> Learned patterns accumulate without pruning. After 30+ sessions, outdated patterns can conflict with newer ones. A quarterly review of <code>.apl/patterns/</code> prevents stale knowledge from degrading output quality.</p>
<h2>Key Takeaways</h2>
<ul>
<li><strong>Structure beats prompting.</strong> A well-designed workflow with clear phases outperforms a single clever prompt. Each agent does one thing well.</li>
<li><strong>Success criteria are everything.</strong> Defining "done" upfront eliminates ambiguity and enables automated verification.</li>
<li><strong>Learning requires persistence.</strong> Ephemeral sessions waste insights. Persisting patterns to disk creates compounding value.</li>
<li><strong>Humans remain in the loop.</strong> APL escalates uncertainty rather than guessing. Autonomy doesn't mean unsupervised.</li>
<li><strong>Token cost is the price of autonomy.</strong> The 3-5x token increase buys structured execution. For complex features, it's worth it. For quick fixes, it isn't.</li>
</ul>
<p>APL is open source. Install it:</p>
<pre><code class="language-bash">/plugin install apl-autonomous-phased-looper@apl-marketplace
</code></pre>
<p>Then run:</p>
<pre><code class="language-bash">/apl Build a REST API with user authentication
</code></pre>
<p>Watch the phases unfold. Check the <code>.apl/</code> directory to see what it learns. The code is on GitHub: <a href="https://github.com/twofoldtech-dakota/apl">twofoldtech-dakota/apl</a></p>
<p>Autonomous coding removes the friction between intent and implementation. APL handles the mechanical work—planning subtasks, writing boilerplate, running tests, fixing lint errors—so I focus on architecture and product decisions. Four generations of iteration later, this foundation became <a href="https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio">STUDIO</a>, which adds supervision and confidence scoring on top.</p>]]></content:encoded>
      <category>ai</category>
      <category>claude-code</category>
      <category>automation</category>
      <category>open-source</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/building-apl-autonomous-coding-agent/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/building-apl-autonomous-coding-agent/thumbnail.jpg" />
    </item>
    <item>
      <title>My 2026 Dev Setup: Custom Claude Code Workflows</title>
      <link>https://dak-dev.vercel.app/blog/my-2026-dev-setup</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/my-2026-dev-setup</guid>
      <pubDate>Sun, 25 Jan 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Triple-monitor hardware, 5 MCP servers, and custom Claude Code skills that cut feature delivery time from days to hours. The full 2026 developer setup.</description>
      <content:encoded><![CDATA[<p>Build a custom skill: 30 minutes. Time saved per use: 5-10 minutes. Uses per week: 10+. Breakeven: one week.</p>
<p>That's the ROI math behind every Claude Code customization in this setup. Boris Cherny, the creator of Claude Code, describes his setup as "surprisingly vanilla." Mine is the opposite: multi-machine hardware, 5 MCP servers, and custom skills that turn Claude Code into an autonomous development partner. I built <a href="https://dak-dev.vercel.app/blog/building-apl-autonomous-coding-agent">APL</a>, <a href="https://dak-dev.vercel.app/blog/building-claude-marketplace-cms-analyzers">a CMS analysis marketplace</a>, and <a href="https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio">STUDIO</a>. Claude Code now handles entire features while I review the output.</p>
<h2>The Multi-Machine Setup</h2>
<table>
<thead>
<tr>
<th>Machine</th>
<th>Role</th>
<th>Primary Use</th>
</tr>
</thead>
<tbody>
<tr>
<td>Desktop PC</td>
<td>Primary workstation</td>
<td>Triple-monitor focused development</td>
</tr>
<tr>
<td>Work Laptop + VM</td>
<td>Remote-capable</td>
<td>Environment isolation, client work</td>
</tr>
<tr>
<td>M1 MacBook Pro</td>
<td>Mobile</td>
<td>Away-from-desk development</td>
</tr>
</tbody>
</table>
<p>The common thread: <strong>Cursor runs on all three.</strong> Having a consistent editor across machines reduces friction when switching contexts. Cursor handles inline completions while Claude Code tackles larger tasks—complementary tools, not competing ones.</p>
<h2>Terminal and Shell</h2>
<p><strong>iTerm2 + Zsh + Oh My Zsh</strong></p>
<pre><code class="language-bash"># Key Oh My Zsh plugins
plugins=(
  git
  zsh-autosuggestions
  zsh-syntax-highlighting
)
</code></pre>
<p>The autosuggestions plugin alone saves hours per week. Type a few characters, hit right arrow, command complete. Syntax highlighting catches typos before execution.</p>
<p>I haven't switched to Warp, Ghostty, or other modern terminals. iTerm2 handles everything I need: split panes, search, profiles per project. New tools need to offer substantial improvement to justify switching costs—a principle that applies to <a href="https://dak-dev.vercel.app/blog/mcp-apps-interactive-ui-inside-ai-chat">choosing any tool in the AI dev ecosystem</a>.</p>
<h2>Editor: Cursor + Claude Code</h2>
<p>Cursor started as a VS Code fork with AI features. It's matured into an editor designed around AI-assisted development. Key advantages over vanilla VS Code:</p>
<ul>
<li><strong>Tab completion that understands context</strong>: Cursor's completions consider your entire codebase, not isolated files</li>
<li><strong>Inline edits with Cmd+K</strong>: Describe a change, see the diff, accept or reject</li>
<li><strong>Composer for multi-file changes</strong>: When a task touches several files, Composer handles the coordination</li>
</ul>
<p>Cursor and Claude Code complement rather than compete:</p>
<table>
<thead>
<tr>
<th>Task</th>
<th>Tool</th>
</tr>
</thead>
<tbody>
<tr>
<td>Line-level completions</td>
<td>Cursor</td>
</tr>
<tr>
<td>Small refactors (single file)</td>
<td>Cursor Cmd+K</td>
</tr>
<tr>
<td>Multi-file features</td>
<td>Claude Code</td>
</tr>
<tr>
<td>Autonomous development</td>
<td>APL via Claude Code</td>
</tr>
</tbody>
</table>
<p>The boundary isn't rigid. Match the tool to the task.</p>
<h2>Claude Code Configuration</h2>
<p>Here's where the setup diverges from vanilla.</p>
<h3>MCP Servers</h3>
<p>Five MCP servers extend Claude Code's capabilities:</p>
<table>
<thead>
<tr>
<th>MCP Server</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>GitHub</strong></td>
<td>PRs, issues, repo management without leaving Claude Code</td>
</tr>
<tr>
<td><strong>Filesystem/Memory</strong></td>
<td>Persistent context between sessions, project-specific memory</td>
</tr>
<tr>
<td><strong>Database</strong></td>
<td>Direct query access during development, schema introspection</td>
</tr>
<tr>
<td><strong>Context7</strong></td>
<td>Enhanced context management for large codebases</td>
</tr>
<tr>
<td><strong>Pencil.dev</strong></td>
<td>Design-to-code workflow, visual verification of UI implementations</td>
</tr>
</tbody>
</table>
<p>Each server eliminates a context switch. Without GitHub MCP, every PR review requires switching to a browser. Without Database MCP, every schema question requires a separate terminal. Five servers, five fewer reasons to leave Claude Code.</p>
<h3>Custom Skills and Hooks</h3>
<p>Beyond MCPs, custom skills and hooks transform the workflow:</p>
<p><strong>Skills (slash commands)</strong></p>
<table>
<thead>
<tr>
<th>Skill</th>
<th>Purpose</th>
<th>Time Saved</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/meta</code></td>
<td>APL orchestrator—plan, execute, review</td>
<td>Hours per feature</td>
</tr>
<tr>
<td><code>/write-post</code></td>
<td>Blog content creation with brand validation</td>
<td>30 min per post</td>
</tr>
<tr>
<td><code>/review-post</code></td>
<td>Content quality checks against <a href="https://dak-dev.vercel.app/blog/claude-code-skills-agent-skills-standard">brand guidelines</a></td>
<td>20 min per review</td>
</tr>
<tr>
<td><code>/content-strategist</code></td>
<td>SEO and content planning</td>
<td>45 min per analysis</td>
</tr>
</tbody>
</table>
<p>The <code>/meta</code> command alone transformed my workflow. Instead of manually orchestrating Claude Code through 15+ subtasks, I describe the goal and watch the phases unfold:</p>
<pre><code class="language-bash"># Before APL: 15-20 manual prompts per feature
> "Create the user model"
> "Now add the authentication middleware"
> "Now write tests for the auth flow"
> "Now fix that import error"
> ...repeat 15 times...

# After APL: one command
> /meta Add user authentication with JWT tokens
# APL handles: planning, coding, testing, review, learning
</code></pre>
<p><strong>Hooks</strong> automate session boundaries:</p>
<ul>
<li>Session end hooks trigger learning extraction to <code>.apl/patterns/</code></li>
<li>Pre-commit hooks run validation</li>
<li>Context-gathering hooks populate project state on session start</li>
</ul>
<p>Building skills follows the <a href="https://dak-dev.vercel.app/blog/claude-code-skills-agent-skills-standard">Agent Skills Standard</a>, which defines a consistent interface for composable, shareable automation. The <a href="https://dak-dev.vercel.app/blog/claude-skills-power-user-guide">power user guide</a> covers the architecture in depth.</p>
<h2>The APL Workflow in Practice</h2>
<p><a href="https://dak-dev.vercel.app/blog/building-apl-autonomous-coding-agent">APL</a> is the centerpiece of my Claude Code customization. Here's how it fits daily work:</p>
<p><strong>Morning</strong>: Review overnight changes, check APL session logs in <code>.apl/session-logs/</code>
<strong>Feature work</strong>: <code>/meta</code> with goal description, monitor progress, answer escalation questions
<strong>Code review</strong>: APL's reviewer catches issues before I see the PR
<strong>Learning</strong>: Insights persist to <code>.apl/</code> for future sessions</p>
<p>The workflow isn't "fire and forget." I monitor active sessions, answer escalation questions, and review decisions. The mechanical work—boilerplate, tests, lint fixes—happens autonomously. <a href="https://dak-dev.vercel.app/blog/how-apl-built-this-blog">APL built this entire blog</a> using that workflow: 47 stories, 6 sessions, 2 hours of human input.</p>
<table>
<thead>
<tr>
<th>Scenario</th>
<th>Approach</th>
</tr>
</thead>
<tbody>
<tr>
<td>Quick bug fix</td>
<td>Vanilla Claude Code</td>
</tr>
<tr>
<td>Single function</td>
<td>Cursor inline edit</td>
</tr>
<tr>
<td>New feature with multiple files</td>
<td>APL</td>
</tr>
<tr>
<td>Refactoring across codebase</td>
<td>APL</td>
</tr>
<tr>
<td>Exploring unfamiliar code</td>
<td>Vanilla with questions</td>
</tr>
<tr>
<td>Production deployment</td>
<td>Manual (never autonomous)</td>
</tr>
</tbody>
</table>
<h2>Design Workflow with Pencil.dev</h2>
<p>Pencil.dev closes the design-to-code loop:</p>
<ol>
<li><strong>Design first</strong>: Create the component in Pencil's canvas</li>
<li><strong>Generate code</strong>: Claude Code reads the design via MCP, generates React/Tailwind</li>
<li><strong>Verify visually</strong>: Compare implementation to design in Pencil</li>
</ol>
<p>No more "it looks different than the mockup" conversations. The mockup and the code stay synchronized. For this blog, Pencil handles component design before implementation, visual regression checking, and design system consistency verification.</p>
<h2>What I Removed</h2>
<p>The setup evolved through subtraction:</p>
<table>
<thead>
<tr>
<th>Removed</th>
<th>Reason</th>
</tr>
</thead>
<tbody>
<tr>
<td>Complex terminal prompt (Starship, Powerlevel10k)</td>
<td>Distracting. A prompt with git status suffices.</td>
</tr>
<tr>
<td>Multiple browser profiles</td>
<td>One profile with containers for isolation.</td>
</tr>
<tr>
<td>Elaborate git aliases</td>
<td><code>gh</code> CLI handles most workflows better.</td>
</tr>
<tr>
<td>Docker Desktop</td>
<td>CLI docker commands work. The GUI adds overhead.</td>
</tr>
<tr>
<td>Note-taking apps for dev notes</td>
<td>Code comments and markdown files in the repo.</td>
</tr>
</tbody>
</table>
<p>Each removal reduced cognitive load. The best tools are invisible—they don't demand attention.</p>
<h2>The Tradeoffs</h2>
<p>Heavy customization carries specific costs:</p>
<p><strong>Customization creates friction in shared environments.</strong> My config includes 5 MCP servers, custom skills, and APL-specific hooks. Pairing on another developer's machine means working without these tools—or spending 20 minutes installing them. For teams, the customization tax is real. Shared skills need documentation; personal ones don't.</p>
<p><strong>Multi-machine sync is manual and that's a deliberate choice.</strong> I don't use a dotfiles repo. Settings sync is ad-hoc: copy what I need, when I need it. The friction of maintaining sync scripts outweighs occasional manual copies when switching machines daily at most. If you switch machines hourly, invest in proper dotfiles.</p>
<p><strong>APL creates platform lock-in.</strong> The <code>.apl/</code> directory, learned patterns, and phased workflow are specific to Claude Code. Switching to a different AI coding tool means abandoning accumulated project knowledge. For projects with 20+ APL sessions of learned patterns, that's a significant switching cost.</p>
<p><strong>5+ MCP servers require documentation for onboarding.</strong> Each server has configuration requirements, authentication setup, and interaction patterns. New team members need a guide explaining what each MCP provides and how they compose. Without documentation, the setup is opaque.</p>
<h2>Key Takeaways</h2>
<ul>
<li><strong>Customize Claude Code aggressively.</strong> The "vanilla is fine" approach works for basic tasks. Skills, hooks, agents, and MCPs enable workflows that weren't possible before.</li>
<li><strong>ROI math justifies every customization.</strong> 30 minutes to build, 5-10 minutes saved per use, 10+ uses per week = one-week breakeven. Track it.</li>
<li><strong>Multi-machine setups work without elaborate sync.</strong> Match the tool to the task, accept manual sync, and move on.</li>
<li><strong>Cursor and Claude Code complement each other.</strong> Cursor for inline completions and small edits. Claude Code for multi-file features and autonomous development.</li>
<li><strong>Subtraction matters as much as addition.</strong> Every removed tool reduces cognitive load. The best tools are invisible.</li>
</ul>
<p>The trend is clear: AI tooling rewards customization. Build the workflow that matches how you think, not the workflow the defaults provide. Start with <a href="https://dak-dev.vercel.app/blog/ai-isnt-just-for-coders-claude-skills">Skills</a> if you haven't explored them—they're the lowest-friction entry point to reshaping Claude Code around your workflow.</p>]]></content:encoded>
      <category>productivity</category>
      <category>claude-code</category>
      <category>tools</category>
      <category>setup</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/my-2026-dev-setup/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/my-2026-dev-setup/thumbnail.jpg" />
    </item>
    <item>
      <title>Building a Claude Code Plugin Marketplace for CMS Analysis</title>
      <link>https://dak-dev.vercel.app/blog/building-claude-marketplace-cms-analyzers</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/building-claude-marketplace-cms-analyzers</guid>
      <pubDate>Sat, 24 Jan 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>Replace generic linters with 50 platform-specific rules per CMS. Specialized Claude Code plugins outperform general agents for Sitecore and Umbraco analysis.</description>
      <content:encoded><![CDATA[<p>A specialized agent with 50 platform-specific rules outperforms a general agent with 500 generic rules. That's the core lesson from building a marketplace of Claude Code plugins for enterprise CMS analysis.</p>
<p>Enterprise CMS platforms—Sitecore, Umbraco, Optimizely—have steep learning curves and platform-specific patterns. Running a general-purpose linter on a Sitecore codebase produces noise: valid Helix architecture patterns flagged as issues, hardcoded GUIDs missed entirely, pipeline processor ordering problems invisible to generic tools, and XM Cloud migration blockers undetected. Enterprise teams need analysis that speaks their platform's language.</p>
<p>So I built a curated marketplace of specialized Claude Code plugins, each loaded with platform-specific expertise. The plugin architecture enables specialized agents to operate autonomously, following the same phased patterns used in <a href="https://dak-dev.vercel.app/blog/building-apl-autonomous-coding-agent">APL's multi-agent orchestration</a>.</p>
<h2>Why Generic Linters Fail on Enterprise CMS Platforms</h2>
<p>Generic code analysis tools optimize for language-level patterns—unused variables, potential null references, formatting violations. CMS platforms operate at a higher abstraction layer:</p>
<ul>
<li><strong>Architecture violations</strong> require platform knowledge. Sitecore's Helix architecture enforces strict layer separation (Foundation → Feature → Project). A generic linter sees a valid C# reference. A Sitecore specialist sees a cross-layer dependency that breaks the entire module boundary.</li>
<li><strong>Configuration patterns</strong> are platform-specific. Hardcoded GUIDs, pipeline processor ordering, serialization configurations—these have meaning only within the CMS context.</li>
<li><strong>Migration blockers</strong> need version-aware detection. Moving from Sitecore Classic to XM Cloud requires identifying on-premise-only APIs, server-side rendering dependencies, and incompatible pipeline configurations.</li>
</ul>
<p>A general agent can't know that <code>Glass Mapper over-fetching</code> is a Sitecore-specific anti-pattern, or that <code>Umbraco content apps</code> have specific registration requirements. Platform depth beats breadth.</p>
<h2>The Marketplace Architecture</h2>
<p>Rather than one monolithic tool, the marketplace offers platform-specific analyzers as standalone plugins:</p>
<pre><code class="language-text">claude-marketplace/
├── analyzers/
│   ├── sitecore-classic/     # Sitecore 10.x on-prem
│   ├── xm-cloud/             # Sitecore XM Cloud
│   ├── umbraco/              # Umbraco 14-16
│   ├── optimizely-cms/       # Optimizely CMS 12
│   └── optimizely-exp/       # Optimizely Experimentation
└── shared/
    ├── security-rules/       # Cross-platform security checks
    └── performance-rules/    # Common performance patterns
</code></pre>
<p>Teams install only what they need. This follows the same principle behind the <a href="https://dak-dev.vercel.app/blog/claude-code-skills-agent-skills-standard">Agent Skills Standard</a>—composable, specialized capabilities instead of monolithic tooling.</p>
<h3>Plugin Anatomy</h3>
<p>Each analyzer plugin follows a consistent structure:</p>
<pre><code class="language-text">sitecore-classic/
├── .claude-plugin/
│   └── plugin.json
├── commands/
│   ├── analyze.md            # Full codebase analysis
│   ├── security-scan.md      # Security-focused scan
│   └── setup.md              # Initial configuration
├── agents/
│   └── sitecore-expert.md    # Platform-specialized agent
├── skills/
│   ├── helix-patterns.md     # Helix architecture knowledge
│   ├── pipeline-analysis.md  # Pipeline processor expertise
│   └── template-review.md    # Template/rendering analysis
└── rules/
    ├── architecture.json     # Helix compliance rules
    ├── security.json         # Security vulnerability patterns
    └── performance.json      # Performance anti-patterns
</code></pre>
<h3>The Expert Agent</h3>
<p>Each analyzer includes a specialized agent with deep platform knowledge. The Sitecore expert agent, for example, knows Helix layer separation, dependency direction enforcement, serialization patterns (Unicorn, TDS, SCS), and common anti-patterns like cross-layer dependencies and Glass Mapper over-fetching.</p>
<pre><code class="language-markdown"># Sitecore Expert Agent (excerpt)

You are a Sitecore 10.x architecture specialist with expertise in:

## Helix Principles
- Foundation, Feature, Project layer separation
- Dependency direction (Project → Feature → Foundation)
- Module boundary enforcement
- Serialization patterns (Unicorn, TDS, SCS)

## Common Anti-Patterns
- Cross-layer dependencies (Feature referencing Project)
- Business logic in renderings
- Hardcoded item paths instead of queries
- Missing null checks on Sitecore.Context
- Glass Mapper over-fetching
</code></pre>
<h3>Rule Definitions</h3>
<p>Rules are defined in JSON with severity, detection patterns, and remediation guidance:</p>
<pre><code class="language-json">{
  "rules": [
    {
      "id": "SC001",
      "name": "Cross-Layer Dependency",
      "severity": "error",
      "category": "architecture",
      "description": "Feature layer must not reference Project layer",
      "detection": {
        "type": "reference_analysis",
        "pattern": "Feature.*/.*references.*Project.*"
      },
      "remediation": "Move shared functionality to Foundation layer or refactor the dependency direction",
      "documentation": "https://helix.sitecore.com/principles/architecture-principles/layers.html"
    },
    {
      "id": "SC002",
      "name": "Hardcoded Item GUID",
      "severity": "warning",
      "category": "maintainability",
      "description": "Item GUIDs should be centralized in constants",
      "detection": {
        "type": "pattern",
        "regex": "new ID\\([\"'](\\{?[0-9a-fA-F-]{36}\\}?)[\"']\\)"
      },
      "remediation": "Extract GUID to a constants class in the appropriate Foundation module"
    }
  ]
}
</code></pre>
<h2>The Analysis Workflow</h2>
<p>Running an analysis produces a structured markdown report:</p>
<pre><code class="language-bash">/sitecore-classic:analyze
</code></pre>
<p>The report includes severity breakdown, critical issues with exact file locations, remediation guidance with links to documentation, and a full architecture dependency graph. Here's a representative output:</p>
<pre><code class="language-markdown"># Sitecore Classic Analysis Report

**Project:** Acme.Website
**Analyzed:** 2026-01-24 14:32 UTC
**Files Scanned:** 847
**Issues Found:** 23

## Summary

| Severity | Count |
|----------|-------|
| Critical | 2     |
| Error    | 7     |
| Warning  | 14    |

## Critical Issues

### SC-SEC-001: Hardcoded Connection String
**Location:** src/Foundation/Database/App_Config/ConnectionStrings.config:12
**Details:** Production database credentials in source control
**Remediation:** Move to environment variables or Azure Key Vault

### SC-SEC-003: Exposed Admin Endpoint
**Location:** src/Project/Website/Controllers/AdminController.cs:1
**Details:** /api/admin/* endpoints lack authorization attributes
**Remediation:** Add [Authorize(Roles = "sitecore\\Admin")] attribute
</code></pre>
<h2>Safe Mode for Sensitive Codebases</h2>
<p>Enterprise teams worry about sending proprietary code to AI systems. Safe mode addresses this:</p>
<pre><code class="language-bash">/sitecore-classic:analyze --safe-mode
</code></pre>
<p>In safe mode, the analyzer:</p>
<ol>
<li>Reads file paths and structure only (not file contents)</li>
<li>Analyzes project references and dependencies</li>
<li>Checks configuration file names (not values)</li>
<li>Reports structural issues without exposing code</li>
</ol>
<pre><code class="language-markdown">## Safe Mode Analysis

**Note:** Content analysis disabled. Structural findings only.

### Project Structure
- 3 Project layer modules detected
- 12 Feature layer modules detected
- 4 Foundation layer modules detected

### Dependency Graph Issues
- Feature.Navigation references Project.Website (Helix violation)
- Missing Foundation.DependencyInjection reference in 3 Features

### Configuration Concerns
- ConnectionStrings.config present in source (verify secrets handling)
- 2 modules missing Unicorn serialization configuration
</code></pre>
<p>Safe mode catches approximately 40% of the issues that a full analysis finds. The remaining 60% require content inspection—code patterns, hardcoded values, logic anti-patterns. For security-conscious teams, safe mode serves as a first pass. Full analysis can follow in a controlled environment.</p>
<h2>CI/CD Integration</h2>
<p>The analyzers integrate into build pipelines for automated enforcement:</p>
<pre><code class="language-yaml"># Azure DevOps example
- task: Bash@3
  displayName: 'Run Sitecore Analysis'
  inputs:
    targetType: 'inline'
    script: |
      claude-code /sitecore-classic:analyze --output ./analysis-report.md

      # Fail build on critical issues
      if grep -q "Critical" ./analysis-report.md; then
        echo "##vso[task.logissue type=error]Critical issues found"
        exit 1
      fi
</code></pre>
<p>Pull requests get automated analysis comments. Critical issues block merges. This mirrors the same CI/CD philosophy used in <a href="https://dak-dev.vercel.app/blog/how-apl-built-this-blog">this blog's content validation pipeline</a>—automated gates that catch problems before they reach production.</p>
<h2>Platform Coverage</h2>
<p>The marketplace currently includes five analyzers:</p>
<table>
<thead>
<tr>
<th>Platform</th>
<th>Version</th>
<th>Status</th>
<th>Focus Areas</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sitecore Classic</td>
<td>10.x</td>
<td>Stable</td>
<td>Helix, pipelines, serialization</td>
</tr>
<tr>
<td>XM Cloud</td>
<td>Current</td>
<td>Stable</td>
<td>Headless patterns, Edge, JSS</td>
</tr>
<tr>
<td>Umbraco</td>
<td>14-16</td>
<td>Stable</td>
<td>Composition, content apps, packages</td>
</tr>
<tr>
<td>Optimizely CMS</td>
<td>12</td>
<td>Stable</td>
<td>Content areas, blocks, scheduling</td>
</tr>
<tr>
<td>Optimizely Experimentation</td>
<td>Current</td>
<td>Beta</td>
<td>A/B tests, feature flags, metrics</td>
</tr>
</tbody>
</table>
<p>Each analyzer averages 50 platform-specific rules across architecture, security, performance, and maintainability categories. The shared rule sets add cross-platform security checks and common performance patterns.</p>
<h2>The Tradeoffs</h2>
<p>Specialized plugins carry specific costs:</p>
<p><strong>Rule maintenance scales per platform version.</strong> Each major CMS release requires rule review and updates. Sitecore's XM Cloud evolution alone generated 12 rule changes in three months. For teams tracking multiple platforms, the maintenance burden compounds. Budget 2-4 hours per platform per major release for rule updates.</p>
<p><strong>Small projects don't justify the overhead.</strong> For codebases under 10K lines of code or greenfield projects without established patterns, the marketplace adds complexity without proportional value. A general-purpose linter suffices until the codebase grows enough to accumulate platform-specific patterns.</p>
<p><strong>False negatives are the hidden risk.</strong> Missing a rule is worse than a false positive. If the analyzer doesn't flag a cross-layer dependency, the team assumes the architecture is clean. Regular rule audits against the latest platform documentation mitigate this, but gaps exist—especially for newer platform features.</p>
<p><strong>Safe mode provides a fraction of full analysis.</strong> The ~40% detection rate means teams relying exclusively on safe mode miss the majority of issues. Safe mode works as a gate, not a replacement. <a href="https://dak-dev.vercel.app/blog/my-2026-dev-setup">My dev setup</a> includes both modes in a staged pipeline—safe mode in CI, full analysis in local development.</p>
<h2>Key Takeaways</h2>
<ul>
<li><strong>Domain expertise compounds.</strong> A specialized agent with 50 platform-specific rules outperforms a general agent with 500 generic rules. Depth beats breadth for CMS analysis.</li>
<li><strong>Safety enables enterprise adoption.</strong> Safe mode removed the primary objection from security teams. Address their concerns first, and capability conversations follow.</li>
<li><strong>Plugin architecture enables composition.</strong> Teams install only what they need. Adding a new CMS platform follows the same structure—no monolith, no bloat.</li>
<li><strong>CI/CD integration is table stakes.</strong> Analysis that runs only on-demand gets skipped. Automated pipeline integration ensures every change gets reviewed.</li>
<li><strong>Markdown is infrastructure.</strong> The entire plugin—agents, commands, rules—is markdown and JSON. No build process, no compilation. Edit and reload. This simplicity enabled <a href="https://dak-dev.vercel.app/blog/how-apl-built-this-blog">APL to build complex projects</a> using the same plugin patterns.</li>
</ul>
<p>The marketplace is open source: <a href="https://github.com/twofoldtech-dakota/claude-marketplace">twofoldtech-dakota/claude-marketplace</a></p>
<p>Install it:</p>
<pre><code class="language-bash">/plugin marketplace add https://github.com/twofoldtech-dakota/claude-marketplace
/plugin install sitecore-classic@claude-marketplace
/sitecore-classic:setup
</code></pre>
<p>Contributions welcome. Each analyzer follows the same structure, so adding a new platform (Kentico, Contentful, Sanity) is straightforward. CMS development doesn't have to mean fighting the platform—specialized analysis turns Claude Code into a team member who understands your architecture, powered by the same <a href="https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio">supervision principles</a> that keep autonomous agents aligned.</p>]]></content:encoded>
      <category>ai</category>
      <category>claude-code</category>
      <category>cms</category>
      <category>enterprise</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/building-claude-marketplace-cms-analyzers/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/building-claude-marketplace-cms-analyzers/thumbnail.jpg" />
    </item>
    <item>
      <title>How APL Built a 99-Lighthouse Blog in 6 Sessions</title>
      <link>https://dak-dev.vercel.app/blog/how-apl-built-this-blog</link>
      <guid isPermaLink="true">https://dak-dev.vercel.app/blog/how-apl-built-this-blog</guid>
      <pubDate>Fri, 23 Jan 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dakota Smith</dc:creator>
      <author>dakota@twofold.tech (Dakota Smith)</author>
      <description>An autonomous coding agent executed 47 stories across 6 epics, producing 4,200 lines of code and Lighthouse 99 performance with two hours of human input.</description>
      <content:encoded><![CDATA[<p>47 stories. 6 epics. 4,200 lines of code. Lighthouse 99 performance. Two hours of human input.</p>
<p>The blog you're reading was built by <a href="https://dak-dev.vercel.app/blog/building-apl-autonomous-coding-agent">APL—the Autonomous Phased Looper</a>. I wrote a spec document defining the architecture, design system, and performance targets. APL planned the work, executed it across six sessions, and reviewed its own output. Here's the full breakdown of what that looked like, where APL needed help, and what the numbers reveal about autonomous development.</p>
<h2>The Spec: What APL Received</h2>
<p>APL started with a <code>CLAUDE.md</code> file containing:</p>
<ul>
<li>Next.js 16 with App Router and SSG</li>
<li>Neo-brutalist dark design (thick borders, hard shadows, no rounded corners)</li>
<li>MDX content with advanced code highlighting via Shiki</li>
<li>Lighthouse scores of 98+ across all categories</li>
<li>WCAG 2.1 AA accessibility compliance</li>
<li>Giscus comments, Vercel Analytics, Schema.org structured data</li>
</ul>
<p>The spec included color values (<code>#0A0A0A</code> background, <code>#F5F5F5</code> text, <code>#333333</code> surface), typography rules (Space Grotesk, 400/600/700 weights), performance targets (LCP &lt; 2.0s, CLS &lt; 0.05), and content structure (MDX files in <code>/content/posts/</code> with specific frontmatter schema). Everything APL needed to make decisions without asking.</p>
<p>Spec quality determines output quality. Vague specs produce vague code. The <code>CLAUDE.md</code> ran 400+ lines because every ambiguous decision was resolved upfront.</p>
<h2>Planning: 6 Epics, 47 Stories</h2>
<p>Using <a href="https://dak-dev.vercel.app/blog/building-apl-autonomous-coding-agent">APL's Tree-of-Thoughts planning</a>, I ran:</p>
<pre><code class="language-bash">/apl Build the complete blog according to CLAUDE.md
</code></pre>
<p>The planner decomposed the project into six epics with dependency analysis:</p>
<pre><code class="language-text">Epic 1: Foundation &amp; Project Setup         (5 stories)
Epic 2: Advanced Code Highlighting System   (4 stories)
Epic 3: Core UI Components &amp; Design System  (8 stories)
Epic 4: Blog Pages &amp; Content Display        (7 stories)
Epic 5: SEO, Analytics &amp; Comments           (7 stories)
Epic 6: Performance Optimization            (11 stories)  ← 5 more stories than any other epic
</code></pre>
<p>The task graph identified parallelization opportunities:</p>
<pre><code class="language-text">Epic 1 ────────────────────────────────────────┐
   │                                            │
   ├── Epic 2 (parallel) ─────────────────────┐│
   │                                           ││
   └── Epic 3 ──── Epic 4 ──── Epic 5 ──── Epic 6
</code></pre>
<p>Epic 2 (code highlighting) had no dependencies on Epic 3 (UI components) and could run in parallel. Each story had explicit success criteria—the same pattern that <a href="https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio">STUDIO later formalized</a> with mandatory validation commands per step.</p>
<pre><code class="language-json">{
  "id": "story_3_04",
  "subject": "Build BlogCard component with neo-brutalist styling",
  "success_criteria": [
    "Component renders title, excerpt, date, tags",
    "4px solid border with #333333 color",
    "Hard shadow offset (4px, 4px) with no blur",
    "Hover state with color transition",
    "Keyboard focusable with visible focus ring",
    "Passes axe accessibility audit"
  ]
}
</code></pre>
<h2>Execution: Epic by Epic</h2>
<h3>Epics 1-2: Foundation and Code Highlighting</h3>
<p>The coder agent initialized the Next.js project, configured TypeScript strict mode, set up Tailwind with custom design tokens, and installed the MDX pipeline. The Tailwind config encoded the spec's design system:</p>
<pre><code class="language-typescript">// Generated by APL - tailwind.config.ts
const config: Config = {
  theme: {
    extend: {
      colors: {
        background: '#0A0A0A',
        surface: '#333333',
        text: '#F5F5F5',
        muted: '#A9A9A9',
      },
      fontFamily: {
        sans: ['Space Grotesk', 'sans-serif'],
      },
      boxShadow: {
        'brutal': '4px 4px 0px 0px #333333',
        'brutal-hover': '6px 6px 0px 0px #333333',
      },
    },
  },
};
</code></pre>
<p>The Shiki integration required the ReAct loop to self-correct. APL's first attempt used <code>rehype-pretty-code</code>, but the line highlighting syntax conflicted with MDX processing:</p>
<pre><code class="language-text">REASON: rehype-pretty-code throws "Unexpected token" on line highlights
ACT: Switch to direct Shiki integration with custom rehype plugin
OBSERVE: Syntax highlighting works, line numbers render correctly
VERIFY: ✓ Code blocks highlight, ✓ Line numbers visible, ✓ Diff syntax works
</code></pre>
<p>The fix took one retry cycle. APL switched to direct Shiki integration and validated all three success criteria before moving on.</p>
<h3>Epics 3-4: UI Components and Pages</h3>
<p>Epic 3 produced 12 components with neo-brutalist constraints. Every component included focus states because the spec mentioned WCAG compliance and the success criteria included "keyboard focusable with visible focus ring":</p>
<pre><code class="language-typescript">// Generated by APL - components/ui/Button.tsx
export function Button({ children, variant = 'primary', onClick }: ButtonProps) {
  return (
    &lt;button
      onClick={onClick}
      className={cn(
        'px-6 py-3 font-semibold border-4 border-surface',
        'shadow-brutal hover:shadow-brutal-hover',
        'transition-shadow duration-150',
        'focus:outline-none focus:ring-2 focus:ring-text focus:ring-offset-2 focus:ring-offset-background',
        variant === 'primary' &amp;&amp; 'bg-text text-background',
        variant === 'secondary' &amp;&amp; 'bg-background text-text'
      )}
    >
      {children}
    &lt;/button>
  );
}
</code></pre>
<p>Epic 4 wired the components into pages. The blog listing and individual post pages connected through the MDX pipeline with static generation:</p>
<pre><code class="language-typescript">// Generated by APL - app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await getAllPosts();
  return posts.map((post) => ({ slug: post.slug }));
}
</code></pre>
<h3>Epics 5-6: SEO, Analytics, and Performance</h3>
<p>APL generated Schema.org JSON-LD for BlogPosting, BreadcrumbList, and Person types. Giscus integration used IntersectionObserver for lazy loading—exactly as the spec prescribed.</p>
<p>The performance epic contained 11 stories, the largest epic. APL ran Lighthouse audits after each optimization:</p>
<pre><code class="language-text">Lighthouse (pre-optimization):     Lighthouse (post-optimization):
- Performance: 89                  - Performance: 99
- Accessibility: 100               - Accessibility: 100
- Best Practices: 100              - Best Practices: 100
- SEO: 100                         - SEO: 100

Issues identified and resolved:
- LCP 2.4s → 1.2s (hero image priority prop)
- 12KB unused CSS → 0 (Tailwind purge)
- Font render delay → 0 (next/font preloading)
- Layout shift → 0.02 CLS (blur placeholders)
</code></pre>
<h2>The Review Phase</h2>
<p>After execution, the reviewer agent examined all changes holistically:</p>
<pre><code class="language-markdown">## Review Summary

### Cross-Task Issues Found: 2
1. Inconsistent import paths (some relative, some alias)
   - Fixed: Standardized to @/ alias throughout

2. Missing error boundary on Comments component
   - Fixed: Added ErrorBoundary wrapper

### Patterns Learned
- Neo-brutalist focus rings: ring-2 ring-text ring-offset-2 ring-offset-background
- Lazy loading threshold: rootMargin 100px works well for comments
- Image priority: Always set priority={true} on above-fold hero images

### Regressions: None detected
</code></pre>
<p>The learner agent persisted these insights to <code>.apl/patterns/</code> for future projects. The neo-brutalist focus ring pattern alone saved time on every subsequent component built with APL.</p>
<h2>Where APL Needed a Human</h2>
<p>APL isn't fully autonomous. I intervened for:</p>
<p><strong>Design decisions the spec left open.</strong> The spec said "accent color TBD." I picked the specific neon green after seeing the dark theme in context. APL can't make aesthetic judgments—it needs concrete values.</p>
<p><strong>Content creation.</strong> APL scaffolded the MDX files with correct frontmatter, but I wrote the actual posts. Content requires judgment about what to say and why it matters.</p>
<p><strong>API keys and deployment config.</strong> Giscus repo ID, Vercel project settings, domain configuration—APL prompted me to provide these at the right moments.</p>
<p><strong>Image assets.</strong> Thumbnails and hero images required human creation. APL sized the placeholders correctly but couldn't produce the visual content.</p>
<p>Total human time: approximately two hours across the entire build. Most of that was content, images, and design decisions—not code.</p>
<h2>The Numbers</h2>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Total stories executed</td>
<td>47</td>
</tr>
<tr>
<td>Lines of code generated</td>
<td>~4,200</td>
</tr>
<tr>
<td>Components created</td>
<td>18</td>
</tr>
<tr>
<td>APL sessions</td>
<td>6 (one per epic)</td>
</tr>
<tr>
<td>Errors requiring retry</td>
<td>8</td>
</tr>
<tr>
<td>Human interventions</td>
<td>12</td>
</tr>
<tr>
<td>Final Lighthouse Performance</td>
<td>99</td>
</tr>
<tr>
<td>Human time</td>
<td>~2 hours</td>
</tr>
</tbody>
</table>
<p>Eight errors across 47 stories is a 17% retry rate. All eight were resolved within APL's retry budget (3 attempts per task). No story required human debugging.</p>
<h2>The Tradeoffs</h2>
<p>This project demonstrates both the strengths and costs of autonomous development:</p>
<p><strong>Token cost for 6 sessions adds up.</strong> Each epic-length APL session consumes 3-5x the tokens of manual Claude Code usage. Six sessions for the full blog build cost meaningfully more than a skilled developer prompting Claude Code interactively. The ROI works because APL handles coordination—47 stories with dependency tracking—not because it's cheaper per token.</p>
<p><strong>Spec quality is the bottleneck, not agent capability.</strong> The 400-line <code>CLAUDE.md</code> took significant upfront effort. APL's output quality tracked the spec's specificity. Sections with precise values (color codes, shadow offsets, font weights) produced correct output on the first pass. Sections with vague guidance ("accent color TBD") required human intervention. The two-hour figure excludes spec-writing time.</p>
<p><strong>Experimental UIs don't fit the autonomous model.</strong> APL works when success criteria are measurable: "4px border," "Lighthouse 99," "keyboard focusable." For design-first projects where the goal is "try this layout, see if it feels right," the phased model adds overhead without value. <a href="https://dak-dev.vercel.app/blog/my-2026-dev-setup">My dev setup</a> separates these workflows—APL for execution, <a href="https://dak-dev.vercel.app/blog/my-2026-dev-setup">Pencil.dev for design exploration</a>.</p>
<p><strong>Review phase catches integration issues, not architectural problems.</strong> APL's reviewer found inconsistent imports and a missing error boundary. It did not question whether the overall architecture was optimal. Architectural decisions were locked in at spec time. For projects where the architecture is uncertain, the autonomous model is the wrong tool. <a href="https://dak-dev.vercel.app/blog/supervisor-in-the-machine-why-i-built-studio">STUDIO addresses this gap</a> with its mandatory questioning phase before execution begins.</p>
<h2>Key Takeaways</h2>
<ul>
<li><strong>Autonomous coding works for spec-driven projects.</strong> A detailed spec with measurable success criteria produces working software with minimal human intervention.</li>
<li><strong>47 stories, 6 sessions, 2 hours human time.</strong> The ratio demonstrates that coordination—not individual task execution—is where autonomous agents add the most value.</li>
<li><strong>Lighthouse 99 without manual optimization.</strong> Performance targets in the spec translated directly to optimization stories with verifiable criteria.</li>
<li><strong>Spec investment pays for itself.</strong> The upfront cost of a thorough spec is repaid by reduced iteration cycles. Garbage in, garbage out applies to autonomous agents more than it does to manual development.</li>
<li><strong>Humans remain essential for judgment.</strong> Design aesthetics, content strategy, and architectural tradeoffs require human input. APL handles the mechanical translation from spec to code.</li>
</ul>
<p>Try APL yourself: <a href="https://github.com/twofoldtech-dakota/apl">twofoldtech-dakota/apl</a></p>
<p>The blog is proof that autonomous development works—not for everything, but for translating clear specs into working software. The same <a href="https://dak-dev.vercel.app/blog/claude-skills-power-user-guide">Skills architecture</a> that powers APL's commands can automate any repeatable workflow, from <a href="https://dak-dev.vercel.app/blog/building-claude-marketplace-cms-analyzers">CMS analysis</a> to content validation pipelines.</p>]]></content:encoded>
      <category>ai</category>
      <category>automation</category>
      <category>nextjs</category>
      <category>project-showcase</category>
      <media:content url="https://dak-dev.vercel.app/images/posts/how-apl-built-this-blog/hero.jpg" medium="image" type="image/jpeg" />
      <media:thumbnail url="https://dak-dev.vercel.app/images/posts/how-apl-built-this-blog/thumbnail.jpg" />
    </item>
  </channel>
</rss>