<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: lleqsnoom</title>
    <description>The latest articles on DEV Community by lleqsnoom (@mielony).</description>
    <link>https://dev.to/mielony</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3892225%2Fe9071ef4-8334-4d42-8e9a-9d8ed1853f4b.png</url>
      <title>DEV Community: lleqsnoom</title>
      <link>https://dev.to/mielony</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mielony"/>
    <language>en</language>
    <item>
      <title>Every Agent Session Is a Test Run</title>
      <dc:creator>lleqsnoom</dc:creator>
      <pubDate>Wed, 16 Sep 2026 17:56:14 +0000</pubDate>
      <link>https://dev.to/mielony/every-agent-session-is-a-test-run-21o</link>
      <guid>https://dev.to/mielony/every-agent-session-is-a-test-run-21o</guid>
      <description>&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Every morning at 05:00, a scheduled job opens the transcripts of everything my AI coding agent did in the last 24 hours. It leaves me a list of proposed edits to the skills it used. Not a summary of what I did — a list, each item citing the exact line of the transcript and the exact line of the file that caused the problem.&lt;/p&gt;

&lt;p&gt;I built it on top of &lt;a href="https://github.com/lleqsnoom/xskills" rel="noopener noreferrer"&gt;xskills&lt;/a&gt;, my collection of agent skills. It is called &lt;code&gt;x-skills-daily-reflection&lt;/code&gt;. It turned my skill set from "a folder of instructions I wrote once" into "a tool that gets measurably less wrong every week."&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: skills rot silently
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://mielony.com/blog/build-your-own-agent-skillset/" rel="noopener noreferrer"&gt;an earlier post of mine&lt;/a&gt; I argued for building your own agent skillset. That argument has a hidden bill, and I named it there: maintenance is on you, forever.&lt;/p&gt;

&lt;p&gt;Here is what maintenance looks like. A skill is a markdown file of instructions. When it is wrong, nothing crashes: no stack trace, no failed test, no red build. What happens instead is worse: the agent reads a stale instruction, stumbles, improvises, and &lt;em&gt;succeeds anyway&lt;/em&gt;. The work gets done. The only trace is a slightly longer session, a repeated tool call, a correction you typed mid-flow and forgot about two minutes later.&lt;/p&gt;

&lt;p&gt;That trace lives in a place nobody looks: the session transcript. Every conversation your agent has is a test run of the skills it used, and every transcript is a test report that gets thrown away.&lt;/p&gt;

&lt;p&gt;People solved this for code decades ago. CI runs your tests on every push. What is missing is the equivalent for &lt;em&gt;instructions&lt;/em&gt;: a job that treats your own agent sessions as the test suite. Your skill files are the code under test.&lt;/p&gt;

&lt;h2&gt;
  
  
  The loop in one picture
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The diagram is a five-step loop; you can see it rendered in &lt;a href="https://mielony.com/blog/self-improvement-by-cron/" rel="noopener noreferrer"&gt;the original post&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Three pieces make that loop run, and none of them are clever:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;automation/daily-reflection/
├── collect-sessions.mjs   # gather last 24h of sessions, scan for friction
├── precheck.sh            # fail closed: skip the run when there is nothing honest to do
└── runbook.md             # the agent's instructions for the headless run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The collector&lt;/strong&gt; walks every project directory my agent CLI (Crush) has touched recently. It exports the sessions modified in the last 24 hours and runs the &lt;code&gt;x-autoreflection&lt;/code&gt; scanner over each one. The scanner extracts mechanical signals from each session: failed commands, repeated tool calls, moments I corrected the agent, skills loaded but never used, questions asked in prose instead of a structured prompt. Each signal keeps a severity, a suspect skill, and quoted evidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The precheck&lt;/strong&gt; runs before the agent is invoked and fails closed. It skips the day when a binary is missing, when &lt;code&gt;skills/&lt;/code&gt; has uncommitted edits, or when no session in the window touched a skill. That git check is the whole philosophy in four lines: every proposal cites a skill by &lt;code&gt;file:line&lt;/code&gt;, and uncommitted edits move those lines. A reflection that runs against a moving target produces plausible garbage. Plausible garbage is the one output you cannot afford from a system whose entire job is to be trustworthy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The runbook&lt;/strong&gt; is what the headless agent follows. It is plain markdown, but written for an agent that cannot ask questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;At most 4 sessions, at most 10 proposals.&lt;/strong&gt; Caps, not targets. Without a human in the loop, an agent optimizing for "good retro" will find &lt;em&gt;something&lt;/em&gt; to say about everything. A quiet day produces a three-line digest. The runbook says: do not invent findings to fill it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify every signal against the real file.&lt;/strong&gt; A signal is a lead, not a finding. The agent opens the actual &lt;code&gt;SKILL.md&lt;/code&gt; and decides. &lt;em&gt;Keep&lt;/em&gt;: the file is wrong. &lt;em&gt;Re-grade&lt;/em&gt;: real friction, but not that skill's fault. &lt;em&gt;Drop&lt;/em&gt;: the transcript misled the scanner. A &lt;code&gt;grep&lt;/code&gt; exiting 1 because it found nothing is the answer, not a failure. Dropping is recorded, so tomorrow's run does not re-litigate it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blame the instruction, not the agent.&lt;/strong&gt; "The &lt;code&gt;SKILL.md&lt;/code&gt; did not say" is a gap. "I forgot" is not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every proposal has Signal, Target, Change, and Check.&lt;/strong&gt; The Check must be a command that runs: a test, a lint rule, a script that exits 0 once the fix is in. A proposal you cannot check is a wish.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And then the rule that defines the whole system, printed twice in the runbook:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Never edit anything under &lt;code&gt;skills/&lt;/code&gt;.&lt;/strong&gt; Propose, then stop. The review decides.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why the loop does not close itself
&lt;/h2&gt;

&lt;p&gt;The obvious design is a fully closed loop: cron fires, agent reflects, agent edits the skill, agent commits. It would take an afternoon to build, and it would be the wrong system.&lt;/p&gt;

&lt;p&gt;Not because agents edit files badly — they are fine at it. Because a self-editing instruction set has no audit trail and no stopping condition. If today's run misreads a signal and "fixes" a skill into uselessness, tomorrow's run reflects on sessions shaped by that bad edit. The drift compounds. The precheck already knows this, which is why it refuses to run against a dirty tree. Skip the review, and you are not editing a file; you are editing the audit trail.&lt;/p&gt;

&lt;p&gt;So the output is a &lt;code&gt;DIGEST.md&lt;/code&gt; with proposals, and the output of my morning coffee is five minutes of checkboxes: accept, defer, drop. Accepted proposals route by size. A one-line edit goes in directly, a cluster goes through &lt;code&gt;x-fix&lt;/code&gt;, and a design decision goes to &lt;code&gt;x-plan&lt;/code&gt; with the reflection attached. The automation read 40 sessions. It handed me three verified, checkable changes instead of a vague feeling that something was off.&lt;/p&gt;

&lt;p&gt;This is the same shape as a deploy pipeline. The pipeline builds, tests, and stages everything automatically — but something with judgement presses the button.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it found, honestly
&lt;/h2&gt;

&lt;p&gt;The loop is honest about its limits. Mechanical scanning only sees friction that leaves a trace. A wrong-but-successful instruction produces no failed command to flag, which is why the runbook lets the agent log &lt;code&gt;manual&lt;/code&gt; findings it noticed by reading. And it costs one small agent run per day — on a quiet day, the precheck skips even that.&lt;/p&gt;

&lt;p&gt;Most days are the three-line digest. But the pattern of what surfaces is what you cannot see from inside:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The same gap twice is a defect.&lt;/strong&gt; A missing flag in one session is a hypothesis. The same command failing in three sessions is a bug with a patch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loaded but unused skills are a smell.&lt;/strong&gt; If the agent keeps loading a skill and abandoning it, the description promises the wrong thing or the body answers the wrong question.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation drift is catchable.&lt;/strong&gt; A documented command that no longer runs leaves one trace: the agent tries it, fails, and improvises. Hours later, that trace is in a transcript. Without the loop, you find it months later, when you run the command yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Build the minimal version
&lt;/h2&gt;

&lt;p&gt;You do not need Orca, a skill framework, or any of my code. You need a place where your agent's conversations are stored, a scheduler, and the agent's headless mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# crontab: 5 5 * * *  ~/reflection/run.sh&lt;/span&gt;

agent sessions &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nt"&gt;--since&lt;/span&gt; 24h &lt;span class="nt"&gt;--out&lt;/span&gt; /tmp/reflection/sessions/   &lt;span class="c"&gt;# collect&lt;/span&gt;
agent run &lt;span class="nt"&gt;--headless&lt;/span&gt; &lt;span class="nt"&gt;--runbook&lt;/span&gt; ~/reflection/runbook.md &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--context&lt;/span&gt; /tmp/reflection/sessions/                               &lt;span class="c"&gt;# reflect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a first runbook can be five sentences:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read every transcript in the folder.&lt;/li&gt;
&lt;li&gt;List every moment the user corrected you, retried a command, or worked around a missing capability.&lt;/li&gt;
&lt;li&gt;For each, check whether an instruction file could have prevented it.&lt;/li&gt;
&lt;li&gt;For each that could, write one proposal: which file, what change, what command proves it.&lt;/li&gt;
&lt;li&gt;Output the list to &lt;code&gt;DIGEST.md&lt;/code&gt;. Edit nothing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first week it will mostly produce noise, and the noise is informative — it shows you which signals to filter. Mine learned to stop flagging &lt;code&gt;grep&lt;/code&gt;'s exit codes after I made "drop the signal, record why" part of the procedure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part people get wrong
&lt;/h2&gt;

&lt;p&gt;Two failure modes, both of which I built first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The loop that must find something.&lt;/strong&gt; You schedule a daily reflection. For three days it says "nothing to report." The temptation is to loosen the criteria until something appears. Do not. A reflection that never comes back empty is not reflecting. It is generating content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Closing the loop to save five minutes.&lt;/strong&gt; The human review feels like the weakest link, so it is the part everyone automates away first. It is the load-bearing part. Five minutes of checkboxes a day is the price of an instruction set that improves in one direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version, again
&lt;/h2&gt;

&lt;p&gt;Your agent's conversations are already a test suite for your workflows — the only one that runs on real work instead of synthetic benchmarks. A cron job, a collector script, and a runbook are enough to stop throwing that test suite away.&lt;/p&gt;

&lt;p&gt;The system does not improve itself. It improves &lt;em&gt;your&lt;/em&gt; half-hour a week into a targeted, evidenced, checkable five minutes. Every accepted proposal makes the next week a little smoother, and the next digest a little shorter. Most mornings it is three lines. That is the system telling you it worked.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://mielony.com/blog/self-improvement-by-cron/" rel="noopener noreferrer"&gt;mielony.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Sampling Parameters as Substances: An Honest Analogy</title>
      <dc:creator>lleqsnoom</dc:creator>
      <pubDate>Mon, 14 Sep 2026 06:11:00 +0000</pubDate>
      <link>https://dev.to/mielony/sampling-parameters-as-substances-an-honest-analogy-4ep6</link>
      <guid>https://dev.to/mielony/sampling-parameters-as-substances-an-honest-analogy-4ep6</guid>
      <description>&lt;h1&gt;
  
  
  Sampling Parameters as Substances: An Honest Analogy
&lt;/h1&gt;

&lt;p&gt;A strange question that works: &lt;em&gt;why does cannabis seem to make people more creative?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It doesn't make anyone smarter — it changes &lt;strong&gt;filtering&lt;/strong&gt;. The mind lets through associations it would normally reject. Distant ideas reach awareness more easily. That feels like creativity from the inside.&lt;/p&gt;

&lt;p&gt;Then someone asked a better question: &lt;em&gt;so it's like turning up a model's temperature?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yes. And that opens a door. Every sampling parameter in a language model sits on the same trade-off — &lt;strong&gt;how boldly the model picks its next word&lt;/strong&gt; — and each one has a rough equivalent in how a mind works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one trade-off behind everything
&lt;/h2&gt;

&lt;p&gt;A language model doesn't "know" what to say. At every step it produces a probability for every token it could write next, then picks one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pick the most likely word every time&lt;/strong&gt; and the text is safe, correct, boring. It loops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick something unlikely often enough&lt;/strong&gt; and the text is surprising — sometimes brilliant, sometimes nonsense.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every parameter below just moves the needle between those two poles.&lt;/p&gt;

&lt;h2&gt;
  
  
  The LLM pharmacopoeia
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnk0wxyt5cer3r5ndktqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnk0wxyt5cer3r5ndktqt.png" alt="Sampling parameters mapped to mental states — temperature, top-p, context window, repetition penalty, max tokens" width="799" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Max tokens is the odd one out — it's a budget, not a mood. It never touches &lt;em&gt;which&lt;/em&gt; token gets picked, only how many are allowed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters now
&lt;/h2&gt;

&lt;p&gt;One caveat, because it's the most interesting part: &lt;strong&gt;the dial is disappearing.&lt;/strong&gt; The newest reasoning models expose no temperature at all. The industry stopped turning the knob up and started spending the compute on thinking instead.&lt;/p&gt;

&lt;p&gt;The full article develops the analogy parameter by parameter, with a careful caveat up front: these are analogies, not neuroscience. No substance has a &lt;code&gt;top_p&lt;/code&gt; value, and a model is not a mind with loose filters. The comparison earns its place because a person and a model both face a version of the same decision — choosing among thousands of possible next steps, and deciding how much to trust the obvious one.&lt;/p&gt;

&lt;p&gt;→ Read the full post on mielony.com.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>ai</category>
      <category>explainers</category>
      <category>sampling</category>
    </item>
    <item>
      <title>Path-Tracing Doom on macOS: Metal Ray Tracing on Apple Silicon</title>
      <dc:creator>lleqsnoom</dc:creator>
      <pubDate>Sun, 13 Sep 2026 14:30:45 +0000</pubDate>
      <link>https://dev.to/mielony/path-tracing-doom-on-macos-metal-ray-tracing-on-apple-silicon-4dkb</link>
      <guid>https://dev.to/mielony/path-tracing-doom-on-macos-metal-ray-tracing-on-apple-silicon-4dkb</guid>
      <description>&lt;p&gt;&lt;strong&gt;There is no Vulkan ray tracing on macOS.&lt;/strong&gt; Apple ships Metal, so a Vulkan RT app runs only through &lt;strong&gt;MoltenVK&lt;/strong&gt; — and MoltenVK's ray tracing is an experimental, unmerged pull request, not an installable driver. On that missing layer, the 1993 game's path tracer runs: every pixel traced per frame, direct and bounced light, reflections, soft shadows — at ~44 FPS at 800p on an M4 Max.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fddmlww8xypyg7ad66sea.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fddmlww8xypyg7ad66sea.jpg" alt="Path-traced Doom 2 on Apple Silicon" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;I ported path-traced Doom 2 to Apple Silicon on a patched MoltenVK with Metal RT. It translates SPIR-V to Metal Shading Language and runs the same RTGL1 path tracer and Doom port as the Intel Arc article. The port ships as a self-contained zip (game + path tracer + patched MoltenVK + SDL); you supply &lt;code&gt;Doom2.wad&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download + every patch:&lt;/strong&gt; &lt;a href="https://mielony.com/blog/path-tracing-doom-on-macos/" rel="noopener noreferrer"&gt;https://mielony.com/blog/path-tracing-doom-on-macos/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why macOS is different
&lt;/h2&gt;

&lt;p&gt;On Intel Arc the bug class was "assumptions about the device." macOS goes further — there is no Vulkan loader at all. The game links MoltenVK (Vulkan-on-Metal), which stops at Vulkan 1.2 graphics/compute. Ray tracing (&lt;code&gt;VK_KHR_acceleration_structure&lt;/code&gt;, &lt;code&gt;VK_KHR_ray_tracing_pipeline&lt;/code&gt;) exists only on an unmerged MoltenVK PR (#2771), which maps the Vulkan RT entry points onto Metal behind &lt;code&gt;MVK_CONFIG_ENABLE_EXPERIMENTAL_RAY_TRACING=1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What broke, layer by layer
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Driver.&lt;/strong&gt; MoltenVK fails &lt;code&gt;vkCreateDevice&lt;/code&gt; if &lt;em&gt;any&lt;/em&gt; requested feature is unsupported, and the path tracer asks for its full set up front — the patch clears every feature bit the device does not report. SPIRV-Cross's MSL backend lacked Metal types for ray-tracing built-ins like &lt;code&gt;gl_LaunchIDEXT&lt;/code&gt;, so every ray-generation shader failed to compile until a +21-line patch added them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Renderer.&lt;/strong&gt; An sRGB swapchain double-encoded the already display-ready image; a missing barrier loaded stale tiles — 8×8 and 16×16 artifacts on a tile-based Apple GPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Game.&lt;/strong&gt; Metal surface from &lt;code&gt;SDL_Metal_CreateView&lt;/code&gt;, true fullscreen, HighDPI matching the panel backing store (3456×2234), and a green &lt;code&gt;FPS: n&lt;/code&gt; HUD counter.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Doom 2 &lt;code&gt;demo1&lt;/code&gt; on the M4 Max: &lt;strong&gt;43.8 FPS at 800p&lt;/strong&gt;, &lt;strong&gt;51.7 FPS at 450p internal&lt;/strong&gt;. &lt;code&gt;rt_renderscale&lt;/code&gt; sets internal render height, and RT cost scales with it — not the window. For comparison, the Intel Arc A770 reaches 90 FPS at 450p internal on the same renderer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you bother?
&lt;/h2&gt;

&lt;p&gt;Only if the Mac is the point. It runs 44–52 FPS at low internal resolutions, has no music, stands on an open unmerged PR, and needs a commercial Doom 2 IWAD plus a ModDB lighting addon. If nothing ties you to macOS, Arc/Linux or an RTX machine is smoother — same renderer either way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full write-up with benchmarks, build scripts and every patch:&lt;/strong&gt; &lt;a href="https://mielony.com/blog/path-tracing-doom-on-macos/" rel="noopener noreferrer"&gt;https://mielony.com/blog/path-tracing-doom-on-macos/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>doom</category>
      <category>rtx</category>
      <category>mac</category>
      <category>macos</category>
    </item>
  </channel>
</rss>
