<?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: fanioz</title>
    <description>The latest articles on DEV Community by fanioz (@fanioz).</description>
    <link>https://dev.to/fanioz</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%2F79058%2Fb6eb34b9-d790-4cd1-a1cc-b914d99e6f15.jpeg</url>
      <title>DEV Community: fanioz</title>
      <link>https://dev.to/fanioz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fanioz"/>
    <language>en</language>
    <item>
      <title>Solstice Cipher: Routing Light to Crack Codes — A Puzzle Game for the June Solstice Game Jam</title>
      <dc:creator>fanioz</dc:creator>
      <pubDate>Sat, 20 Jun 2026 04:48:53 +0000</pubDate>
      <link>https://dev.to/fanioz/solstice-cipher-routing-light-to-crack-codes-a-puzzle-game-for-the-june-solstice-game-jam-lcc</link>
      <guid>https://dev.to/fanioz/solstice-cipher-routing-light-to-crack-codes-a-puzzle-game-for-the-june-solstice-game-jam-lcc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Furec534dbcexm32n9zkx.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%2Furec534dbcexm32n9zkx.png" alt="Solstice Chiper" width="800" height="654"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/june-game-jam-2026-06-03"&gt;June Solstice Game Jam&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;The June solstice is the moment the sun reaches its peak — the longest day, the shortest shadow. I wanted to build a game where you &lt;em&gt;become&lt;/em&gt; the sun.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solstice Cipher&lt;/strong&gt; is an optical puzzle game where you manipulate light beams to decrypt hidden words. Each level gives you a sun emitter, a set of cipher glyphs hiding the letters of a secret word, and a briefcase full of optical tools. Your job: route the light beam through the correct sequence of glyphs to illuminate every letter and reveal the cipher.&lt;/p&gt;

&lt;p&gt;The game progresses through 15 hand-crafted levels that track the arc of the solstice day. Early levels teach you the basics with a single mirror; by the end, you're juggling prisms that split beams, color filters that tint white light into red, green, or blue, combiners that additively blend two colored beams back together, portals that teleport light across the board, and benders that deflect beams at fixed 45° angles. Every tool snaps to 15-degree increments, turning freeform placement into a satisfying logic constraint.&lt;/p&gt;

&lt;p&gt;The solstice connection isn't just thematic window dressing — it's the core mechanic. You literally control light, casting it through shadow to reveal hidden knowledge. The deeper you progress, the more tools you need, mirroring how the sun's journey across the sky grows more complex as the day unfolds.&lt;/p&gt;

&lt;p&gt;You can play it right now — no downloads required:&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://solstice-cipher-game.vercel.app/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;solstice-cipher-game.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Video Demo
&lt;/h2&gt;


&lt;div&gt;
    &lt;iframe src="https://www.youtube.com/embed/9bnl6GyHAv0"&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;


&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/fanioz" rel="noopener noreferrer"&gt;
        fanioz
      &lt;/a&gt; / &lt;a href="https://github.com/fanioz/solstice-cipher" rel="noopener noreferrer"&gt;
        solstice-cipher
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Solstice Cipher&lt;/h1&gt;
&lt;/div&gt;
  &lt;p&gt;
    &lt;i&gt;A neon-lit optical puzzle game about manipulating light beams to decrypt hidden codes.&lt;/i&gt;
    &lt;br&gt;
    Built for the &lt;b&gt;June Solstice Game Jam&lt;/b&gt;
  &lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://solstice-cipher-game.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/88d3a824b0ec998c833e046b669e21b5730cc55be1da7c3db6a9435440049e83/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506c61795f6f6e5f5765622d736f6c73746963652d2d6369706865722d2d67616d652e76657263656c2e6170702d3030303030303f7374796c653d666f722d7468652d6261646765266c6f676f3d76657263656c" alt="Play on Vercel"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/c78003e8be8add393d686aedf873c9142d917a55ad2bed2998bcae4b2cb4a366/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f476f646f745f342e362d2532334646464646462e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d676f646f742d656e67696e65"&gt;&lt;img src="https://camo.githubusercontent.com/c78003e8be8add393d686aedf873c9142d917a55ad2bed2998bcae4b2cb4a366/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f476f646f745f342e362d2532334646464646462e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d676f646f742d656e67696e65" alt="Godot 4.6"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/e9c645b4f75fb6ee2166f95974252f40881834a0de450fbd754d4ffc9c98750b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506c6174666f726d2d576562253230253743253230416e64726f69642d626c75653f7374796c653d666f722d7468652d6261646765"&gt;&lt;img src="https://camo.githubusercontent.com/e9c645b4f75fb6ee2166f95974252f40881834a0de450fbd754d4ffc9c98750b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506c6174666f726d2d576562253230253743253230416e64726f69642d626c75653f7374796c653d666f722d7468652d6261646765" alt="Platforms"&gt;&lt;/a&gt;
&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;About the Game&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Solstice Cipher&lt;/strong&gt; is a sci-fi optical puzzle game where you manipulate light beams to decrypt hidden codes. You are given a grid and a briefcase full of optical tools like mirrors and beam splitters. Your goal is to route a single light emitter through the correct sequence of receiver glyphs to reveal the hidden cipher.&lt;/p&gt;

&lt;p&gt;It features a sleek, high-contrast neon aesthetic with strict orthogonal grids, capturing the feeling of classic "laser reflecting" games with modern polish and smooth animations.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Optical Puzzles:&lt;/strong&gt; Drag and drop tools like mirrors and splitters to direct light beams around obstacles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contextual Learning:&lt;/strong&gt; Learn the mechanics naturally as you play, thanks to a contextual UI tutorial system that guides you without breaking immersion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neon Aesthetic:&lt;/strong&gt; A sleek, high-contrast visual…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/fanioz/solstice-cipher" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;I didn't write a single line of GDScript by hand. Instead, I took on the role of &lt;strong&gt;Game Director&lt;/strong&gt;, using &lt;strong&gt;Google Antigravity&lt;/strong&gt; — a Gemini-powered autonomous coding agent — as my lead programmer and Godot engine specialist.&lt;/p&gt;

&lt;p&gt;I chose &lt;strong&gt;Godot 4.6&lt;/strong&gt; with the &lt;strong&gt;GL Compatibility renderer (WebGL 2)&lt;/strong&gt; to target both web browsers and Android. My process was entirely prompt-driven: I described architectural constraints and game mechanics in plain English, and Antigravity generated the implementation.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. A Multi-Pass 2D Raycasting Engine
&lt;/h3&gt;

&lt;p&gt;The heart of the game is a custom raycasting system built on Godot's &lt;code&gt;PhysicsDirectSpaceState2D&lt;/code&gt;. Every time a tool is moved or rotated, the engine recalculates the entire light path from scratch:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;space_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_world_2d&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direct_space_state&lt;/span&gt;

&lt;span class="n"&gt;active_rays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="s2"&gt;"origin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sun&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;global_position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Vector2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RIGHT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rotated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sun&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s2"&gt;"color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"white"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"bounces_left"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MAX_BOUNCES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"exclude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="s2"&gt;"current_dist"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each ray segment is cast using &lt;code&gt;PhysicsRayQueryParameters2D&lt;/code&gt;, and when the beam hits a tool, the tool's &lt;code&gt;process_beam()&lt;/code&gt; method returns zero, one, or two new rays depending on its type. Mirrors use &lt;code&gt;Vector2.bounce()&lt;/code&gt; for physically accurate reflections. Prisms split a single beam into two — one straight-through and one at a right angle. The whole system runs in a propagation queue that resolves in multiple passes (up to 10) to handle combiners that need to accumulate inputs from separate beam branches before emitting their blended output:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;active_rays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;pass_count&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;propagation_queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;active_rays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;duplicate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;active_rays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;propagation_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;propagation_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop_front&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;_cast_ray_segment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;space_state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;propagation_queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Seven Optical Tools, One Unified Interface
&lt;/h3&gt;

&lt;p&gt;Every tool implements a single polymorphic &lt;code&gt;process_beam()&lt;/code&gt; method. The raycaster doesn't care &lt;em&gt;what&lt;/em&gt; it hit — it just calls &lt;code&gt;process_beam()&lt;/code&gt; and follows the output. This made it trivial to add new tool types without touching the core engine:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mirror&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reflects the beam (&lt;code&gt;Vector2.bounce()&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Prism&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Splits into straight-through + right-angle beams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Filter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Passes beam through, tinting it red/green/blue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Combiner&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Collects two colored beams, additively blends RGB, emits one output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Portal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Teleports beam to a linked portal with local-space direction inversion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bender&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deflects beam at a fixed 45° angle relative to its normal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shade&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Blocks the beam entirely&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  3. Color-Matched Cipher Glyphs
&lt;/h3&gt;

&lt;p&gt;The real "aha!" moment in puzzle design came from coupling color to the cipher. Each glyph has a &lt;code&gt;required_color&lt;/code&gt; property — if the beam hitting it doesn't match, it stays dark:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;set_illuminated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hit_color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"white"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;hit_color&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;required_color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This means later levels aren't just about routing light to the right &lt;em&gt;place&lt;/em&gt; — you need the right &lt;em&gt;color&lt;/em&gt; of light to arrive there. You might need to split a white beam through a prism, filter one branch to red and the other to blue, then recombine them downstream for a magenta glyph. It transforms each puzzle into a logic circuit.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Contextual Tutorial Without Breaking Flow
&lt;/h3&gt;

&lt;p&gt;With the jam clock ticking, I couldn't afford to build scripted tutorial levels. Instead, I implemented a lightweight contextual UI system that teaches mechanics &lt;em&gt;as&lt;/em&gt; the player discovers them:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_on_item_dropped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drop_position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_slot_ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;instruction_1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;instruction_1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tool_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"mirror"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;instruction_3&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;instruction_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;instruction_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;instruction_3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;drop_position&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="kt"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The instructions only appear &lt;em&gt;after&lt;/em&gt; the player successfully performs an action. Drop your first mirror? Now the rotation hint appears — positioned right above where you dropped it. It's reactive, not prescriptive.&lt;/p&gt;
&lt;h3&gt;
  
  
  5. Procedural Puzzle Verification with a BFS Backwards Solver
&lt;/h3&gt;

&lt;p&gt;To validate that generated puzzle layouts are actually solvable, I tasked Antigravity with building a &lt;code&gt;BackwardsSolver&lt;/code&gt;. It uses BFS pathfinding on the grid to find routes from the light source to each glyph, then analyzes turns and intersections to determine exactly which tools (mirrors, prisms, filters) need to be placed and where. If the required tool count exceeds the tier's budget, the layout is rejected:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Budget check&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;get_piece_budget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;# Over budget — reject and regenerate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This guarantees every procedurally generated level is mathematically solvable before the player ever sees it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prize Category
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Best Ode to Alan Turing
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Solstice Cipher&lt;/em&gt; is, at its core, a game about mechanical decryption.&lt;/p&gt;

&lt;p&gt;Just as Turing's Bombe machine required operators to wire together rotors in precise configurations to complete an electrical circuit and crack Enigma, players in &lt;em&gt;Solstice Cipher&lt;/em&gt; must wire together optical tools in precise configurations to complete a &lt;em&gt;light&lt;/em&gt; circuit and crack a hidden word. The parallel is structural, not superficial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Turing's rotor → the Mirror.&lt;/strong&gt; Both redirect a signal (electrical/optical) along a new path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The plugboard → the Filter and Combiner.&lt;/strong&gt; Both transform the signal's &lt;em&gt;properties&lt;/em&gt; (letter substitution / color transformation) as it passes through.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Enigma ciphertext → the darkened glyphs.&lt;/strong&gt; Both are meaningless until the correct circuit configuration illuminates the answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The game's multi-pass raycasting engine effectively makes each puzzle chamber a programmable optical computer. The player doesn't just &lt;em&gt;solve&lt;/em&gt; puzzles — they physically &lt;em&gt;program&lt;/em&gt; a decryption machine out of light and glass, one mirror at a time. Every valid solution is a working program; every incorrect configuration is a bug.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Google AI Usage
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Solstice Cipher&lt;/em&gt; was built from the ground up using &lt;strong&gt;Google Antigravity&lt;/strong&gt;, a Gemini-powered autonomous coding agent, acting as my lead programmer and Godot 4.6 specialist. My role was pure game direction — defining architecture constraints, reviewing generated code, and steering design decisions.&lt;/p&gt;

&lt;p&gt;Antigravity co-developed every technical system in the project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;multi-pass 2D raycasting engine&lt;/strong&gt; with &lt;code&gt;PhysicsDirectSpaceState2D&lt;/code&gt;, including the propagation queue and combiner resolution loop&lt;/li&gt;
&lt;li&gt;All &lt;strong&gt;seven optical tool implementations&lt;/strong&gt; with their polymorphic &lt;code&gt;process_beam()&lt;/code&gt; interfaces&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;BFS backwards solver&lt;/strong&gt; for procedural puzzle validation with tier-based budget constraints&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;contextual tutorial system&lt;/strong&gt; with tween-driven breathing animations&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;CipherUI&lt;/strong&gt; system that connects glyph illumination signals to the win condition checker&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;SaveManager&lt;/strong&gt;, &lt;strong&gt;AudioManager&lt;/strong&gt; (with SFX pooling), and &lt;strong&gt;TransitionManager&lt;/strong&gt; autoloads&lt;/li&gt;
&lt;li&gt;A complete &lt;strong&gt;GUT test suite&lt;/strong&gt; validating the scaffolder's determinism and the solver's correctness&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This project demonstrates Google AI not as an embedded runtime feature, but as a full-spectrum game development partner — from architecture to implementation to testing.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Discussion:&lt;/strong&gt; What's your approach to teaching players new mechanics during a jam? Scripted tutorials, contextual hints, or something else entirely? Let me know below!&lt;/p&gt;

</description>
      <category>godot</category>
      <category>gamedev</category>
      <category>webdev</category>
      <category>hackathon</category>
    </item>
    <item>
      <title>Building a Native macOS Menu Bar Widget with SwiftUI and Glassmorphism</title>
      <dc:creator>fanioz</dc:creator>
      <pubDate>Sat, 06 Jun 2026 01:52:38 +0000</pubDate>
      <link>https://dev.to/fanioz/building-a-native-macos-menu-bar-widget-with-swiftui-and-glassmorphism-52fl</link>
      <guid>https://dev.to/fanioz/building-a-native-macos-menu-bar-widget-with-swiftui-and-glassmorphism-52fl</guid>
      <description>&lt;p&gt;I recently open-sourced SysMonitor, a native macOS menu bar app for tracking system resources like CPU, RAM, Disk I/O, and Network speeds.&lt;/p&gt;

&lt;p&gt;I built it because I was tired of the two extremes in the macOS monitoring ecosystem: tools that give you just a tiny text readout in the menu bar with no details, or massive&lt;br&gt;
dashboards that look like an airplane cockpit. I wanted a clean menu bar readout that drops down into a gorgeous, translucent widget only when I need it.&lt;/p&gt;

&lt;p&gt;Here's how I put it together using 100% Swift and SwiftUI, and the workarounds I used to make it feel truly native.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ditching &lt;code&gt;NSPopover&lt;/code&gt; for Custom Glassmorphism
&lt;/h2&gt;

&lt;p&gt;When you build a menu bar app, the standard Apple way to show a dropdown is using &lt;code&gt;NSPopover&lt;/code&gt;. It handles the positioning and the little arrow pointing to the menu bar icon&lt;br&gt;
automatically.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;NSPopover&lt;/code&gt; has strict visual constraints. It wraps your content in a border and doesn't easily let you achieve edge-to-edge transparency or custom glassmorphism.&lt;/p&gt;

&lt;p&gt;Instead, I opted to build a custom, borderless &lt;code&gt;NSWindow&lt;/code&gt; backed by an &lt;code&gt;NSVisualEffectView&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create a borderless, transparent window&lt;/span&gt;
&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titlebarAppearsTransparent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titleVisibility&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hidden&lt;/span&gt;
&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isOpaque&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;

&lt;span class="c1"&gt;// Add the glassmorphism backdrop&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;visualEffect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NSVisualEffectView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;visualEffect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blendingMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;behindWindow&lt;/span&gt;
&lt;span class="n"&gt;visualEffect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;material&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hudWindow&lt;/span&gt;
&lt;span class="n"&gt;visualEffect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;
&lt;span class="n"&gt;visualEffect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;autoresizingMask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This gave me the exact visual style I wanted—a frosted glass panel floating over the desktop—but it meant I had to manually calculate exactly where the window should appear on the&lt;br&gt;
screen.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Math Behind Menu Bar Positioning
&lt;/h2&gt;

&lt;p&gt;Because I wasn't using &lt;code&gt;NSPopover&lt;/code&gt;, the widget window had no idea where the menu bar icon was. To make it feel like a dropdown, I had to grab the coordinates of the &lt;code&gt;NSStatusItem&lt;/code&gt;&lt;br&gt;
button and position the window relative to it.&lt;/p&gt;

&lt;p&gt;Here's the logic inside the &lt;code&gt;AppDelegate&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;statusItem&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Get the button's bounds and convert to global screen coordinates&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;buttonFrameInWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;buttonFrameInScreen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="nf"&gt;convertToScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buttonFrameInWindow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;windowWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;windowHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Center the window horizontally under the button&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;xPos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buttonFrameInScreen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;midX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;windowWidth&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Place it just below the menu bar&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;yPos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buttonFrameInScreen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;windowHeight&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. Update the frame&lt;/span&gt;
    &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;NSRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;xPos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;yPos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;windowWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;windowHeight&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This guarantees the window snaps perfectly underneath the icon, regardless of whether the user has a notch, an external monitor, or moves the icon around in their menu bar.&lt;/p&gt;
&lt;h2&gt;
  
  
  Smart Battery Management &amp;amp; Auto-Hide
&lt;/h2&gt;

&lt;p&gt;One of the biggest issues with system monitors is that polling &lt;code&gt;sysctl&lt;/code&gt; and calculating CPU ticks in the background can actually consume a lot of CPU, draining your MacBook&lt;br&gt;
battery just to tell you your battery is draining.&lt;/p&gt;

&lt;p&gt;To fix this, SysMonitor throttles itself. When the glass widget is visible, it polls every 2 seconds for a smooth UI. But when you click away, the window listens for&lt;br&gt;
&lt;code&gt;windowDidResignKey&lt;/code&gt;, auto-hides with a quick fade-out animation, and dials the polling back to every 5 seconds.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;AppDelegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSWindowDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Hide the widget window automatically when the user clicks elsewhere&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;windowDidResignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;widgetWindow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isVisible&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;hideWidgetWindow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Fades out and drops polling rate to 5s&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  The Final Result
&lt;/h2&gt;

&lt;p&gt;The end result is exactly what I wanted: a fast, native tool that tells me what I need to know and then gets out of my way.&lt;/p&gt;

&lt;p&gt;You can check out the full source code (and grab the build) over on GitHub:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/fanioz" rel="noopener noreferrer"&gt;
        fanioz
      &lt;/a&gt; / &lt;a href="https://github.com/fanioz/sysmonitor" rel="noopener noreferrer"&gt;
        sysmonitor
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;SysMonitor &lt;em&gt;(sysmonitor)&lt;/em&gt;
&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/fanioz/sysmonitor/assets/SysMonitor.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Ffanioz%2Fsysmonitor%2FHEAD%2Fassets%2FSysMonitor.png" alt="SysMonitor Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A native macOS system resource widget with menu bar integration and a beautiful glassmorphic UI.&lt;/p&gt;

&lt;p&gt;SysMonitor provides an elegant, unobtrusive way to track critical macOS system metrics. It combines a persistent menu bar item for glanceable CPU and RAM usage with a highly detailed, translucent widget window for per-core stats, disk I/O, network throughput, and memory breakdown.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Menu Bar Integration:&lt;/strong&gt; Live, compact system stats right in your macOS menu bar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Glassmorphic Widget:&lt;/strong&gt; A beautifully designed translucent window that pops down directly from the menu bar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low Overhead:&lt;/strong&gt; Self-regulates its polling interval when hidden to minimize CPU footprint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart Alerts:&lt;/strong&gt; Native macOS notifications when metrics exceed safe thresholds.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;To install and build SysMonitor from source, you need Xcode installed on your Mac (macOS 13 or later).&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/fanioz/sysmonitor.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; sysmonitor
xcodebuild -scheme sysmonitor -configuration Release build
open build/Release/sysmonitor.app&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Once launched, SysMonitor will appear in your…&lt;/p&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/fanioz/sysmonitor" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;&lt;strong&gt;Discussion Question:&lt;/strong&gt; When you build background utilities for macOS or Windows, how do you balance the polling frequency with battery life constraints? Do you stick to fixed&lt;br&gt;
intervals or dynamically throttle based on app visibility? Let me know below!&lt;/p&gt;

</description>
      <category>macos</category>
      <category>swiftui</category>
      <category>swift</category>
      <category>productivity</category>
    </item>
    <item>
      <title>System Restore - The Portfolio</title>
      <dc:creator>fanioz</dc:creator>
      <pubDate>Tue, 27 Jan 2026 12:22:15 +0000</pubDate>
      <link>https://dev.to/fanioz/system-restore-the-portfolio-2d1</link>
      <guid>https://dev.to/fanioz/system-restore-the-portfolio-2d1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjl0on1uvujwpew5rnwst.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.amazonaws.com%2Fuploads%2Farticles%2Fjl0on1uvujwpew5rnwst.png" alt="system restore - the portfolio"&gt;&lt;/a&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31"&gt;New Year, New You Portfolio Challenge Presented by Google AI&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;I'm &lt;strong&gt;Rifani Arsyad&lt;/strong&gt;, a Full Stack Developer from Indonesia 🇮🇩 coding in cross-platform application development. With this portfolio, I wanted to showcase my technical ability across Windows desktop (WinUI 3, .NET), cross-platform (Tauri, Flutter), web development (React, Laravel), and AI/LLM integration, through an interactive, gamified experience that I hope you actually enjoy exploring it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Portfolio
&lt;/h2&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://portfolio-app-516262214479.us-west1.run.app"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;




&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;This project was my first real attempt at using an all in Google AI tools throughout the development journey, from brainstorming to deployment, to the image cover of this post 😂&lt;/p&gt;

&lt;p&gt;Here is my process with Google AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Brainstorming: I started with Gemini Chat to explore the "system restore" concept and refine the narrative flow&lt;/li&gt;
&lt;li&gt;Initial Code: Google AI Studio helped generate early boilerplate for the Gemini API integration and React components&lt;/li&gt;
&lt;li&gt;Refinement: I iterated on the generated code in Antigravity, adding TypeScript types, error handling, and polish&lt;/li&gt;
&lt;li&gt;Deployment: Finally deployed to Google Cloud Run with Cloud Build handling CI/CD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tech Stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend: React 18, TypeScript, Vite, Tailwind CSS v4&lt;/li&gt;
&lt;li&gt;AI: Google Gemini API via Express.js BFF&lt;/li&gt;
&lt;li&gt;Deployment: Docker + Cloud Run + Cloud Build CI/CD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Light Interactivity, I included three small moments to gently guide exploration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A letter-swap puzzle to reveal the About section&lt;/li&gt;
&lt;li&gt;Floating bubbles that respond to cursor movement&lt;/li&gt;
&lt;li&gt;A simulated file browser for navigating projects&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I'm Most Proud Of
&lt;/h2&gt;

&lt;p&gt;The combination of a visually appealing design with a functional AI assistant that actually helps users navigate the portfolio. These are all while maintaining a sense of nostalgia for the 90s.&lt;br&gt;
More than any technical detail, I'm quietly proud that I actually finished and shipped this. Like many other developers, I've started plenty of side projects that never saw the light of day. This time,thanks to the structure of the challenge and the gentle guidance of Gemini, so I can pushed through to completion. It's a small thing, but for me, shipping something complete (even imperfect) feels like real progress.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Configure CrewAI with Groq: Alternative LLM Setup Guide</title>
      <dc:creator>fanioz</dc:creator>
      <pubDate>Fri, 05 Dec 2025 22:11:00 +0000</pubDate>
      <link>https://dev.to/fanioz/configure-crewai-with-groq-alternative-llm-setup-guide-4gc9</link>
      <guid>https://dev.to/fanioz/configure-crewai-with-groq-alternative-llm-setup-guide-4gc9</guid>
      <description>&lt;h2&gt;
  
  
  I Replaced OpenAI with Groq in My CrewAI Project – Here's What Actually Happened
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Problem: OpenAI Costs Add Up
&lt;/h2&gt;

&lt;p&gt;Running multiple agents inside CrewAI can produce high token usage fast. Proprietary models like GPT-4 become expensive when scaling production workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: OpenAI-Compatible APIs
&lt;/h2&gt;

&lt;p&gt;CrewAI supports any OpenAI-compatible API endpoint through its native &lt;code&gt;LLM&lt;/code&gt; class. This allows you to switch to alternative providers like &lt;strong&gt;Groq&lt;/strong&gt;, &lt;strong&gt;Moonshot (Kimi)&lt;/strong&gt;, or &lt;strong&gt;local models&lt;/strong&gt; (Ollama) without rewriting agent code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verified Pricing Comparison (Updated Late 2025)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input / 1M tokens&lt;/th&gt;
&lt;th&gt;Output / 1M tokens&lt;/th&gt;
&lt;th&gt;API Base URL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Groq&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Llama-3.3-70B Versatile&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.59&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.79&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.groq.com/openai/v1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OpenAI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GPT-5.1&lt;/td&gt;
&lt;td&gt;$1.25&lt;/td&gt;
&lt;td&gt;$10.00&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.openai.com/v1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Pricing sourced from Groq Model Cards and independent LLM pricing aggregators as of November–December 2025.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost difference example:&lt;/strong&gt; For high-volume processing, Groq Llama-3.3-70B can be &lt;strong&gt;dramatically cheaper&lt;/strong&gt; depending on usage scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Configure CrewAI with Alternative LLMs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Environment Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPENAI_API_KEY="your-api-key"
OPENAI_API_BASE="https://api.groq.com/openai/v1"
OPENAI_MODEL="llama-3.3-70b-versatile"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Configure Custom LLM in &lt;code&gt;agents.py&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;`&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;crewai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LLM&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decouple&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomAgents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;api_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OPENAI_API_BASE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OPENAI_API_BASE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OPENAI_MODEL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-3.5-turbo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;api_base&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;api_base&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Agent Definition (No Changes Required)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;research_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Senior Research Analyst&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;backstory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Expert in market analysis with 10+ years experience&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Provide comprehensive research and insights&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing Your Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Verify API Connectivity
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python test_api.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Supported Providers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Groq
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPENAI_API_BASE="https://api.groq.com/openai/v1"
OPENAI_MODEL="llama-3.3-70b-versatile"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Moonshot / Kimi
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPENAI_API_BASE="https://api.moonshot.cn/v1"
OPENAI_MODEL="moonshot-v1-8k"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Local Models (Ollama Example)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_ollama&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OllamaLLM&lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ollama&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OllamaLLM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openhermes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt;: Groq reports &lt;strong&gt;~276 tokens/sec throughput&lt;/strong&gt; for Llama-3.3-70B Versatile under typical inference conditions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency&lt;/strong&gt;: Typical 0.5–1.5s end-to-end response for standard workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Length&lt;/strong&gt;: Large context support (model-card dependent, e.g. up to ~128K tokens).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limits&lt;/strong&gt;: See Groq account dashboard for up-to-date tier limits.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Invalid API Key
&lt;/h3&gt;

&lt;p&gt;Check formatting &amp;amp; run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python test_api.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Model Not Found
&lt;/h3&gt;

&lt;p&gt;Verify with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python test_api.py &lt;span class="nt"&gt;--list-models&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connection Timeout
&lt;/h3&gt;

&lt;p&gt;Verify base URL formatting and internet connectivity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quality Differences
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;  &lt;span class="c1"&gt;# range 0.1–0.9 recommended
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When to Use Alternative LLMs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use alternatives when&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need lower cost &amp;amp; high throughput&lt;/li&gt;
&lt;li&gt;Running many agents or parallel processes&lt;/li&gt;
&lt;li&gt;Reducing vendor lock-in is important&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use proprietary models when&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You require specialized features or alignment&lt;/li&gt;
&lt;li&gt;Your workload is small (&amp;lt;$20/month usage)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Complete Example Setup
&lt;/h2&gt;

&lt;p&gt;test_api.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decouple&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_api_key&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Test if the API key is valid&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;api_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OPENAI_API_BASE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OPENAI_MODEL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Testing API key: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API Base: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Model: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Test the API key with a simple request
&lt;/span&gt;    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Make a simple API call to test authentication
&lt;/span&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/models&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Status Code: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SUCCESS: API Key is VALID&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; available models&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;First few models:&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ERROR: API Key is INVALID&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Response:&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ERROR: Error testing API: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;test_api_key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;crewai langchain-openai python-decouple

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"OPENAI_API_KEY='your-key'"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"OPENAI_API_BASE='https://api.groq.com/openai/v1'"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .env
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"OPENAI_MODEL='llama-3.3-70b-versatile'"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .env

python test_api.py
python main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;CrewAI supports OpenAI-compatible APIs directly via environment configs.&lt;/li&gt;
&lt;li&gt;Switching providers requires no rewrite of agent logic.&lt;/li&gt;
&lt;li&gt;Groq provides high performance and significantly lower token cost for scale workloads.&lt;/li&gt;
&lt;li&gt;Swapping between providers is reversible by modifying &lt;code&gt;.env&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.crewai.com/concepts/agents" rel="noopener noreferrer"&gt;https://docs.crewai.com/concepts/agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://console.groq.com/docs/model/llama-3.3-70b-versatile" rel="noopener noreferrer"&gt;https://console.groq.com/docs/model/llama-3.3-70b-versatile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://groq.com" rel="noopener noreferrer"&gt;https://groq.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.moonshot.cn/docs" rel="noopener noreferrer"&gt;https://platform.moonshot.cn/docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>crewai</category>
      <category>groq</category>
      <category>llm</category>
      <category>openai</category>
    </item>
  </channel>
</rss>
