<?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: Sergio Farfan Cardenete</title>
    <description>The latest articles on DEV Community by Sergio Farfan Cardenete (@sergio_farfn_b071cafc7ed).</description>
    <link>https://dev.to/sergio_farfn_b071cafc7ed</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3828298%2F93ba3193-a163-43de-b5a5-88d654bffd3d.jpg</url>
      <title>DEV Community: Sergio Farfan Cardenete</title>
      <link>https://dev.to/sergio_farfn_b071cafc7ed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sergio_farfn_b071cafc7ed"/>
    <language>en</language>
    <item>
      <title>NoSleep: Prevent your Mac to go sleep. Period.</title>
      <dc:creator>Sergio Farfan Cardenete</dc:creator>
      <pubDate>Sun, 22 Mar 2026 05:09:02 +0000</pubDate>
      <link>https://dev.to/sergio_farfn_b071cafc7ed/nosleep-a-lightweight-macos-menu-bar-app-with-swiftui-5fap</link>
      <guid>https://dev.to/sergio_farfn_b071cafc7ed/nosleep-a-lightweight-macos-menu-bar-app-with-swiftui-5fap</guid>
      <description>&lt;p&gt;Have you ever been mid-presentation, watching a long build compile, or waiting for a large file to download — only for your Mac to decide it's nap time? macOS ships a built-in tool for exactly this: &lt;code&gt;caffeinate&lt;/code&gt;. But running it from the terminal every time is clunky.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;NoSleep&lt;/strong&gt; — a tiny macOS menu bar utility that wraps &lt;code&gt;caffeinate&lt;/code&gt; in a one-click toggle. No Dock icon. No main window. Just a cup icon in your menu bar.&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.amazonaws.com%2Fuploads%2Farticles%2Fomv4ih7hgxuyfhb1xkuo.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%2Fomv4ih7hgxuyfhb1xkuo.png" alt="NoSleep menu bar dropdown" width="466" height="754"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-click toggle&lt;/strong&gt; — start/stop caffeinate from the menu bar&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duration presets&lt;/strong&gt; — 15 min, 30 min, 1 hr, 2 hr, 4 hr, 8 hr, 10 hr, or Indefinite&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live countdown&lt;/strong&gt; — shows remaining time while active (e.g. &lt;code&gt;2h 34m&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start at Login&lt;/strong&gt; — optional LaunchAgent so it auto-starts on boot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prevents display + idle sleep&lt;/strong&gt; — uses &lt;code&gt;caffeinate -d -i&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Swift 6.0&lt;/strong&gt; with strict concurrency&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SwiftUI&lt;/strong&gt; + &lt;code&gt;MenuBarExtra&lt;/code&gt; (macOS 13+)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swift Package Manager&lt;/strong&gt; — no Xcode project file required&lt;/li&gt;
&lt;li&gt;Minimum target: &lt;strong&gt;macOS 14 (Sonoma)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  App Entry Point: MenuBarExtra
&lt;/h2&gt;

&lt;p&gt;The entire app lives in the menu bar, which SwiftUI makes surprisingly clean with &lt;code&gt;MenuBarExtra&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="kd"&gt;@main&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;NoSleepApp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;@StateObject&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;caffeinateManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CaffeinateManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;@StateObject&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;loginManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;LoginItemManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Scene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;MenuBarExtra&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;MenuBarView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;caffeinateManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;loginManager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;loginManager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;systemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;caffeinateManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isActive&lt;/span&gt;
                  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"cup.and.saucer.fill"&lt;/span&gt;
                  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"cup.and.saucer"&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole entry point. &lt;code&gt;MenuBarExtra&lt;/code&gt; handles all the menu bar plumbing — no &lt;code&gt;NSStatusItem&lt;/code&gt;, no AppKit boilerplate. The icon toggles between a filled and outlined cup based on whether caffeinate is running.&lt;/p&gt;

&lt;p&gt;Setting &lt;code&gt;LSUIElement: true&lt;/code&gt; in &lt;code&gt;Info.plist&lt;/code&gt; hides the Dock icon and removes the main window entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Core Logic: CaffeinateManager
&lt;/h2&gt;

&lt;p&gt;The heart of the app is &lt;code&gt;CaffeinateManager&lt;/code&gt; — an &lt;code&gt;@MainActor&lt;/code&gt; &lt;code&gt;ObservableObject&lt;/code&gt; that manages the &lt;code&gt;caffeinate&lt;/code&gt; child process and a countdown timer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Spawning the Process
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;stop&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;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executableURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fileURLWithPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"/usr/bin/caffeinate"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"-d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-i"&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;selectedDuration&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indefinite&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"-t"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;selectedDuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rawValue&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;remainingSeconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selectedDuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rawValue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;

    &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;terminationHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;@MainActor&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleTermination&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;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;
    &lt;span class="n"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;selectedDuration&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indefinite&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scheduledTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;withTimeInterval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;repeats&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;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;@MainActor&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tick&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;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;A few things worth noting:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;-d -i&lt;/code&gt; flags&lt;/strong&gt; — &lt;code&gt;-d&lt;/code&gt; prevents the display from sleeping, &lt;code&gt;-i&lt;/code&gt; prevents idle sleep. Together they cover the common use cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;-t &amp;lt;seconds&amp;gt;&lt;/code&gt;&lt;/strong&gt; — when a duration is selected, caffeinate self-terminates after that many seconds. The app also runs a &lt;code&gt;Timer&lt;/code&gt; in parallel to track remaining time for the UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;terminationHandler&lt;/code&gt;&lt;/strong&gt; — if caffeinate exits on its own (duration expired, or the system killed it), this handler fires and cleans up app state. The &lt;code&gt;Task { @MainActor in ... }&lt;/code&gt; pattern bridges from the background callback thread into the main actor, which Swift 6 strict concurrency requires.&lt;/p&gt;

&lt;h3&gt;
  
  
  Duration Options
&lt;/h3&gt;

&lt;p&gt;Durations are a typed enum with raw values in 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;enum&lt;/span&gt; &lt;span class="kt"&gt;SleepDuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;CaseIterable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Identifiable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;fifteenMin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;thirtyMin&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1800&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;oneHour&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;twoHours&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7200&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;fourHours&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;14400&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;eightHours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;28800&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;tenHours&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;36000&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;indefinite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The selected duration is persisted in &lt;code&gt;UserDefaults&lt;/code&gt; so the preference survives app restarts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Login Item: LaunchAgent Plist
&lt;/h2&gt;

&lt;p&gt;Rather than using &lt;code&gt;SMAppService&lt;/code&gt; (which requires a sandboxed app), NoSleep writes a &lt;code&gt;LaunchAgent&lt;/code&gt; plist directly to &lt;code&gt;~/Library/LaunchAgents/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;plist&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Label&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;com.nosleep.app&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;ProgramArguments&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/Users/you/Applications/NoSleep.app/Contents/MacOS/NoSleep&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;RunAtLoad&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach works without sandboxing and gives full control over the plist.&lt;/p&gt;




&lt;h2&gt;
  
  
  Build &amp;amp; Install
&lt;/h2&gt;

&lt;p&gt;The project uses Swift Package Manager — no &lt;code&gt;.xcodeproj&lt;/code&gt; needed.&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;# Build (compiles, bundles, ad-hoc code signs)&lt;/span&gt;
./build.sh

&lt;span class="c"&gt;# Run&lt;/span&gt;
open NoSleep.app

&lt;span class="c"&gt;# Install to ~/Applications (optional)&lt;/span&gt;
./install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Requirements: Swift 6.0+, Xcode Command Line Tools, macOS 14+.&lt;/p&gt;




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

&lt;p&gt;NoSleep is open source under the GPLv3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/sergio-farfan/nosleep" rel="noopener noreferrer"&gt;github.com/sergio-farfan/nosleep&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contributions, issues, and stars are all welcome. If you run into any macOS quirks with &lt;code&gt;caffeinate&lt;/code&gt; or &lt;code&gt;MenuBarExtra&lt;/code&gt;, feel free to open an issue.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Swift 6 and SwiftUI on macOS Sonoma.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>macos</category>
      <category>swift</category>
      <category>swiftui</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Built a Windows-Style Alt+Tab Window Switcher for macOS in Pure Swift</title>
      <dc:creator>Sergio Farfan Cardenete</dc:creator>
      <pubDate>Sun, 22 Mar 2026 04:16:11 +0000</pubDate>
      <link>https://dev.to/sergio_farfn_b071cafc7ed/i-built-a-windows-style-alttab-window-switcher-for-macos-in-pure-swift-4pp7</link>
      <guid>https://dev.to/sergio_farfn_b071cafc7ed/i-built-a-windows-style-alttab-window-switcher-for-macos-in-pure-swift-4pp7</guid>
      <description>&lt;p&gt;One of my biggest frustrations after spending years on Windows was losing a proper window switcher when I moved to macOS. &lt;code&gt;Cmd-Tab&lt;/code&gt; switches between &lt;em&gt;applications&lt;/em&gt;, not &lt;em&gt;windows&lt;/em&gt;. If you have four Terminal windows open, you cannot directly jump to a specific one — you have to &lt;code&gt;Cmd-Tab&lt;/code&gt; to Terminal, then use &lt;code&gt;Cmd-`&lt;/code&gt; to cycle through its windows. It is a two-step dance every single time.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;AltTab&lt;/strong&gt; — a lightweight, zero-dependency macOS utility that brings back the Windows &lt;code&gt;Alt-Tab&lt;/code&gt; experience using &lt;code&gt;Option-Tab&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What It Does
&lt;/h2&gt;

&lt;p&gt;Hold &lt;code&gt;Option&lt;/code&gt; and tap &lt;code&gt;Tab&lt;/code&gt; — a panel appears showing thumbnails of every open window across all your apps. Cycle through them with &lt;code&gt;Tab&lt;/code&gt; / &lt;code&gt;Shift-Tab&lt;/code&gt; or the arrow keys, then release &lt;code&gt;Option&lt;/code&gt; to jump straight to the selected window. Click any thumbnail to switch instantly.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Shortcut&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Option-Tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open switcher / next window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cycle forward&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Shift-Tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cycle backward&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;← / →&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Navigate left / right&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Escape&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cancel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Enter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Confirm and switch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Click&lt;/td&gt;
&lt;td&gt;Select and switch immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Minimized windows are included and will automatically unminimize when selected. No Dock icon, no clutter — just a clean menu bar icon.&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.amazonaws.com%2Fuploads%2Farticles%2F7k2pmmc2l7i9brmph21e.jpeg" 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%2F7k2pmmc2l7i9brmph21e.jpeg" alt="AltTab menu bar menu showing Launch at Login, About AltTab, and Quit AltTab options" width="432" height="284"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt; macOS 13 Ventura or later · Full Xcode installation&lt;/p&gt;

&lt;h3&gt;
  
  
  One-liner install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/sergio-farfan/alttab-macos.git &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;alttab-macos &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./build.sh &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; open ~/Applications/AltTab.app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;strong&gt;System Settings → Privacy &amp;amp; Security → Accessibility&lt;/strong&gt; and grant permission to AltTab. That is all — press &lt;code&gt;Option-Tab&lt;/code&gt; and it just works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build options
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./build.sh build          &lt;span class="c"&gt;# Build Release binary only&lt;/span&gt;
./build.sh &lt;span class="nb"&gt;install&lt;/span&gt;        &lt;span class="c"&gt;# Build and install to ~/Applications&lt;/span&gt;
./build.sh &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--system&lt;/span&gt;  &lt;span class="c"&gt;# Build and install to /Applications (requires sudo)&lt;/span&gt;
./build.sh run            &lt;span class="c"&gt;# Build and launch immediately&lt;/span&gt;
./build.sh uninstall      &lt;span class="c"&gt;# Remove the installed app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Permissions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt; (required) — needed to intercept the &lt;code&gt;Option-Tab&lt;/code&gt; hotkey and raise windows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screen Recording&lt;/strong&gt; (optional) — enables live window thumbnails; gracefully falls back to app icons if denied&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Global hotkey interception&lt;/strong&gt; — A CGEvent tap installed at the session level intercepts &lt;code&gt;Option-Tab&lt;/code&gt; system-wide before it reaches any app, without stealing keyboard focus.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complete window discovery&lt;/strong&gt; — On-screen windows come from &lt;code&gt;CGWindowList&lt;/code&gt;. Minimized windows require a separate AXUIElement query per app — no single API covers both. Results are deduplicated and merged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MRU ordering&lt;/strong&gt; — Windows are sorted most-recently-used first. App-level focus is tracked via NSWorkspace notifications; intra-app window switches (like &lt;code&gt;Cmd-`&lt;/code&gt;) are caught by per-app AXObserver callbacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-activating overlay&lt;/strong&gt; — The switcher is an &lt;code&gt;NSPanel&lt;/code&gt; with &lt;code&gt;.nonactivatingPanel&lt;/code&gt;, so it appears on screen without stealing focus. Releasing &lt;code&gt;Option&lt;/code&gt; activates the target window, not AltTab.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live thumbnails&lt;/strong&gt; — macOS 14+ uses ScreenCaptureKit for async, high-quality captures. macOS 13 falls back to &lt;code&gt;CGWindowListCreateImage&lt;/code&gt;. If Screen Recording permission is denied, app icons are shown instead — no crash, no prompt.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Stats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;~2,000 lines&lt;/strong&gt; of Swift across 9 source files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero external dependencies&lt;/strong&gt; — pure Swift + AppKit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MIT licensed&lt;/strong&gt; — fork it, modify it, ship it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS 13+&lt;/strong&gt; (Ventura, Sonoma, Sequoia)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;The code is on GitHub: &lt;strong&gt;&lt;a href="https://github.com/sergio-farfan/alttab-macos" rel="noopener noreferrer"&gt;github.com/sergio-farfan/alttab-macos&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have been frustrated by macOS window switching, give it a try. And if you are curious about the low-level macOS APIs — CGEvent taps, AXUIElement, ScreenCaptureKit — the codebase is small enough to read in an afternoon.&lt;/p&gt;

&lt;p&gt;Feedback, issues, and PRs are welcome!&lt;/p&gt;

</description>
      <category>swift</category>
      <category>macos</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Generate OCI Architecture Diagrams from Terraform with One Claude Code Command</title>
      <dc:creator>Sergio Farfan Cardenete</dc:creator>
      <pubDate>Tue, 17 Mar 2026 01:16:57 +0000</pubDate>
      <link>https://dev.to/sergio_farfn_b071cafc7ed/generate-oci-architecture-diagrams-from-terraform-with-one-claude-code-command-1f4b</link>
      <guid>https://dev.to/sergio_farfn_b071cafc7ed/generate-oci-architecture-diagrams-from-terraform-with-one-claude-code-command-1f4b</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Manually drawing OCI diagrams in draw.io is tedious...&lt;br&gt;
If you have ever had to document an OCI architecture, the process is familiar. You open draw.io, locate the correct Oracle icon set, drag shapes onto the canvas, manually wire up VCNs and subnets, nudge elements into alignment — then spend another 30 minutes reconciling colors against Oracle's official template, only to discover that the Terraform configuration changed the previous week and the diagram is already out of date.&lt;/p&gt;

&lt;p&gt;For cloud architects working with OCI, this is a recurring overhead on every project:&lt;/p&gt;
&lt;h2&gt;
  
  
  Diagrams drift from reality
&lt;/h2&gt;

&lt;p&gt;Terraform is the source of truth, but draw.io has no awareness of it. Every infrastructure change requires a manual diagram update — one that typically does not occur until someone requests it during a review.&lt;/p&gt;
&lt;h2&gt;
  
  
  The OCI icon set is not native to draw.io
&lt;/h2&gt;

&lt;p&gt;It must be located, imported, and mapped to the correct services across 15 categories and 220+ icons — a non-trivial exercise before any actual diagramming begins.&lt;/p&gt;
&lt;h2&gt;
  
  
  Layout is time-consuming
&lt;/h2&gt;

&lt;p&gt;Correctly representing the &lt;code&gt;Region → VCN → Subnet → Service&lt;/code&gt; hierarchy, with proper spacing, non-overlapping containers, and Oracle's color scheme, requires significant effort even for experienced practitioners.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hub-and-spoke topologies are especially difficult
&lt;/h2&gt;

&lt;p&gt;Arranging 10–15 spoke VCNs connected through a DRG in a clean, readable layout is an hour-long exercise in manual positioning.&lt;/p&gt;
&lt;h2&gt;
  
  
  Diagrams are created once and abandoned
&lt;/h2&gt;

&lt;p&gt;Because updates are costly, teams stop maintaining them. By the time a new team member onboards or an audit is conducted, the diagram reflects an architecture from two sprints prior.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;The root cause is that architecture diagrams are treated as design artifacts — something produced manually — rather than something derived directly from the infrastructure definition.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;


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

&lt;p&gt;&lt;a href="https://github.com/sergio-farfan/OCI-draw.io-Architect" rel="noopener noreferrer"&gt;https://github.com/sergio-farfan/OCI-draw.io-Architect&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Claude Code plugin — type /drawio-architect in any project...&lt;/p&gt;
&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The plugin accepts three input types: a Terraform directory path — parsed to extract VCNs, subnets, gateways, and DRG attachments — a VCN name resolved against existing &lt;code&gt;.tfvars&lt;/code&gt; files, or a plain-text description of the target architecture.&lt;/p&gt;

&lt;p&gt;From any of these inputs, it computes a pixel-precise grid layout, calculating container bounding boxes to eliminate element overlap, and generates a Python script leveraging a custom &lt;code&gt;DrawioBuilder&lt;/code&gt; class &lt;strong&gt;backed by 220 bundled OCI SVG icons&lt;/strong&gt;. Executing the script produces a &lt;code&gt;.drawio&lt;/code&gt; file fully styled with Oracle's official color palette.&lt;/p&gt;

&lt;p&gt;The entire workflow is invoked within Claude Code via a single &lt;code&gt;/drawio-architect&lt;/code&gt; command.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step by Step Installation
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code&lt;/strong&gt; (CLI) installed and working&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python 3.8+&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;draw.io desktop&lt;/strong&gt; for viewing generated &lt;code&gt;.drawio&lt;/code&gt; files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The plugin bundles 220 OCI SVG icons and auto-installs Pillow (Python imaging library) if missing.&lt;/p&gt;
&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Step 1 - Download, Extract and Install
&lt;/h4&gt;

&lt;p&gt;One command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://github.com/sergio-farfan/OCI-draw.io-Architect/releases/download/v1.0.0/oci-drawio-architect-v1.0.0.tar.gz | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xz&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./oci-drawio-architect/install.sh

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download, extract and execute the Installer script&lt;/li&gt;
&lt;li&gt;Check prerequisites (Python 3, Pillow)&lt;/li&gt;
&lt;li&gt;Install Pillow automatically if missing&lt;/li&gt;
&lt;li&gt;Create a local marketplace at &lt;code&gt;~/.claude/plugins/marketplaces/local/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copy the plugin files into the marketplace&lt;/li&gt;
&lt;li&gt;Verify all components (5 checks)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 2 - Register in Claude Code
&lt;/h4&gt;

&lt;p&gt;Open Claude Code and run these two commands:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/plugin marketplace add ~/.claude/plugins/marketplaces/local&lt;/code&gt;&lt;br&gt;
&lt;code&gt;/plugin install oci-drawio-architect@local&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Exit Claude Code and reopen it for the plugin to load.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 3 - Verify
&lt;/h4&gt;

&lt;p&gt;Run inside Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/drawio-architect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command should prompt you for what to diagram.&lt;/p&gt;

&lt;p&gt;Example Snippet:&lt;br&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%2Fpdqpe2sucr46xr68jp8g.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%2Fpdqpe2sucr46xr68jp8g.png" alt=" " width="559" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>oci</category>
      <category>terraform</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
