<?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: twistedtransistor</title>
    <description>The latest articles on DEV Community by twistedtransistor (@twistedtransistor).</description>
    <link>https://dev.to/twistedtransistor</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%2F2716514%2F6a3b5b1a-e5db-4509-90cb-993d697e5905.png</url>
      <title>DEV Community: twistedtransistor</title>
      <link>https://dev.to/twistedtransistor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/twistedtransistor"/>
    <language>en</language>
    <item>
      <title>Meet my simple CLI Tool That Makes Oh My Posh Theme-Hopping Effortless</title>
      <dc:creator>twistedtransistor</dc:creator>
      <pubDate>Wed, 20 Aug 2025 04:40:46 +0000</pubDate>
      <link>https://dev.to/twistedtransistor/meet-my-simple-cli-tool-that-makes-oh-my-posh-theme-hopping-effortless-31aj</link>
      <guid>https://dev.to/twistedtransistor/meet-my-simple-cli-tool-that-makes-oh-my-posh-theme-hopping-effortless-31aj</guid>
      <description>&lt;p&gt;Theme manager for &lt;a href="https://ohmyposh.dev/" rel="noopener noreferrer"&gt;Oh My Posh&lt;/a&gt; that lets you browse, preview, install, activate, add custom and tweak themes directly inside your terminal.&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%2Fx0fnnvfmsukgff0d44oe.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%2Fx0fnnvfmsukgff0d44oe.png" alt=" " width="800" height="430"&gt;&lt;/a&gt;&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%2F4a3oxzt7b96du1k1cwyr.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%2F4a3oxzt7b96du1k1cwyr.png" alt=" " width="800" height="688"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;💻 &lt;strong&gt;Fast and simple&lt;/strong&gt;: runs from terminal. Simple interface.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Real-time Search&lt;/strong&gt;: Filter local and remote theme repo&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;Fast Installation&lt;/strong&gt;: Single or multiple theme download&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Easy Theme Switching&lt;/strong&gt;: Theme activation (Bash/Zsh/Fish) &lt;/li&gt;
&lt;li&gt;🗂️ &lt;strong&gt;Dual Panel Interface&lt;/strong&gt;: Local and remote theme management&lt;/li&gt;
&lt;li&gt;🎯 &lt;strong&gt;Custom Repositories&lt;/strong&gt;: Add themes from Git repository (json has to be in root)&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;Theme Customization&lt;/strong&gt;: Built-in color editor&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;Basic Previews&lt;/strong&gt;: Sample prompt structure with basic metadata (Name, Version, Source, Color variation)&lt;/li&gt;
&lt;li&gt;🚀 &lt;strong&gt;Performance Optimized&lt;/strong&gt;: Smart caching and modular architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before using this tool, you need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Oh My Posh installed&lt;/strong&gt; - Visit &lt;a href="https://ohmyposh.dev/" rel="noopener noreferrer"&gt;ohmyposh.dev&lt;/a&gt; for installation instructions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatible shell&lt;/strong&gt;: Bash, Zsh, or Fish&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.6+&lt;/strong&gt; with standard libraries&lt;/li&gt;
&lt;/ol&gt;

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

&lt;h3&gt;
  
  
  Method 1: PyPI (Recommended)
&lt;/h3&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;oh-my-theme
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Method 2: AUR (Arch Linux)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yay &lt;span class="nt"&gt;-S&lt;/span&gt; oh-my-theme
&lt;span class="c"&gt;# or&lt;/span&gt;
paru &lt;span class="nt"&gt;-S&lt;/span&gt; oh-my-theme
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Method 3: Git Clone
&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/mikeisfree/oh-my-theme.git
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage After Installation
&lt;/h2&gt;

&lt;p&gt;Once installed run with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;omt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Shell Config
&lt;/h2&gt;

&lt;p&gt;The tool automatically updates your shell configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bash&lt;/strong&gt;: &lt;code&gt;~/.bashrc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zsh&lt;/strong&gt;: &lt;code&gt;~/.zshrc&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fish&lt;/strong&gt;: &lt;code&gt;~/.config/fish/config.fish&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Clean Theme Management:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Removes&lt;/strong&gt; all existing Oh My Posh theme lines when activating a new theme - If You want to keep existing oh-my-posh configuration commenting it out will not be enough - back it up to a separate file! &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adds&lt;/strong&gt; only the new active theme command&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preserves&lt;/strong&gt; all other shell configuration! (aliases, exports, functions)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After activating a theme, reload your shell:&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="nb"&gt;source&lt;/span&gt; ~/.bashrc    &lt;span class="c"&gt;# For Bash&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc     &lt;span class="c"&gt;# For Zsh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F5790bavopnp8q6wujcak.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%2F5790bavopnp8q6wujcak.png" alt=" " width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage Details
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Interface Overview
&lt;/h3&gt;

&lt;p&gt;The tool displays two panels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Left Panel&lt;/strong&gt;: installed themes (local)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Right Panel&lt;/strong&gt;: Available themes from Oh My Posh main repository + custom repos added by user (remote)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Keyboard Shortcuts
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&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;TAB&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Switch between panels&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 theme list&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;Activate/Remove/Customize local theme or Select remote theme&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SPACE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle selection for remote themes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview selected theme&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install selected remote themes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;NEW&lt;/strong&gt;: Enter search mode for real-time theme filtering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;NEW&lt;/strong&gt;: Add custom Git repository&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ESC&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exit search mode &amp;amp; cancel dialogs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;q&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Quit application&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Local Theme Actions (ENTER)
&lt;/h3&gt;

&lt;p&gt;When you press ENTER on a local theme, you'll see these options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;A&lt;/code&gt; - &lt;strong&gt;Activate&lt;/strong&gt; theme in shell&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;R&lt;/code&gt; - &lt;strong&gt;Remove&lt;/strong&gt; theme
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;C&lt;/code&gt; - &lt;strong&gt;Customize&lt;/strong&gt; theme colors&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Browse Remote Themes&lt;/strong&gt;: Use &lt;code&gt;TAB&lt;/code&gt; to switch to the right panel and browse available themes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search Themes&lt;/strong&gt;: Press &lt;code&gt;/&lt;/code&gt; to search and filter themes in real-time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preview Themes&lt;/strong&gt;: Press &lt;code&gt;p&lt;/code&gt; to see previews with sample prompts and metadata&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select Themes&lt;/strong&gt;: Use &lt;code&gt;SPACE&lt;/code&gt; to select multiple themes for installation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install Themes&lt;/strong&gt;: Press &lt;code&gt;i&lt;/code&gt; to download selected themes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Activate Theme&lt;/strong&gt;: Switch to local panel (&lt;code&gt;TAB&lt;/code&gt;) and press &lt;code&gt;ENTER&lt;/code&gt; → &lt;code&gt;A&lt;/code&gt; on your desired theme&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customize Theme&lt;/strong&gt;: Press &lt;code&gt;ENTER&lt;/code&gt; → &lt;code&gt;C&lt;/code&gt; on local themes to edit colors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add Custom Repos&lt;/strong&gt;: Press &lt;code&gt;+&lt;/code&gt; to add themes from custom Git repositories&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Theme Previews
&lt;/h3&gt;

&lt;p&gt;Preview feature shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sample prompt structure&lt;/strong&gt; git status, paths, segments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Essential metadata&lt;/strong&gt;: Name, Version, Source (git repository), Color variation&lt;/li&gt;
&lt;/ul&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%2Fvjjwtyzjqm7jff8w32ep.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%2Fvjjwtyzjqm7jff8w32ep.png" alt=" " width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Filter
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Press &lt;code&gt;/&lt;/code&gt; to enter search mode&lt;/li&gt;
&lt;li&gt;Type to filter themes in real-time across both local and remote panels&lt;/li&gt;
&lt;li&gt;Search results highlight matching text&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;ESC&lt;/code&gt; to exit search and process filtered items &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Custom Repository Support
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Press &lt;code&gt;+&lt;/code&gt; to add themes from custom Git repository&lt;/li&gt;
&lt;li&gt;Enter the Git repository URL when prompted&lt;/li&gt;
&lt;li&gt;The tool will fetch all &lt;code&gt;.omp.json&lt;/code&gt; files from the repository root&lt;/li&gt;
&lt;li&gt;Custom themes are downloaded to your local themes directory&lt;/li&gt;
&lt;li&gt;repository address will be added to filter array &lt;/li&gt;
&lt;/ul&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%2F202qqf25tah8au7jaloc.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%2F202qqf25tah8au7jaloc.png" alt=" " width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Theme Customization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Select any local theme and press &lt;code&gt;ENTER&lt;/code&gt; → &lt;code&gt;C&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Visual color editor shows current segment colors&lt;/li&gt;
&lt;li&gt;Simple color picker interface for modifications&lt;/li&gt;
&lt;li&gt;Save as new theme (new json file) or overwrite original&lt;/li&gt;
&lt;li&gt;Preserve customizations across updates&lt;/li&gt;
&lt;/ul&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%2Fmpy1xf1lxk0k37t8dli5.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%2Fmpy1xf1lxk0k37t8dli5.png" alt=" " width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Theme Storage
&lt;/h2&gt;

&lt;p&gt;Downloaded themes are stored in &lt;code&gt;~/.poshthemes/&lt;/code&gt; directory. The tool manages this directory automatically.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  "Unsupported shell" Error
&lt;/h3&gt;

&lt;p&gt;Make sure your &lt;code&gt;SHELL&lt;/code&gt; environment variable is set correctly:&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="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$SHELL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Safety measures:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Backup-friendly: Uses a clean replacement strategy that preserves non-Oh My Posh configurations
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Atomic updates: Reads entire file, modifies in memory, then writes back
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Error handling: Returns success/failure status
&lt;/h3&gt;

&lt;h3&gt;
  
  
  uses regex pattern to identify Oh My Posh lines:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;init_pattern &lt;span class="o"&gt;=&lt;/span&gt; re.compile&lt;span class="o"&gt;(&lt;/span&gt;r&lt;span class="s2"&gt;"^&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="s2"&gt;*(eval.*oh-my-posh init.*|oh-my-posh init.*fish.*)"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  User confirmation: Always asks for confirmation before activating themes
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Theme Not Activating
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Ensure Oh My Posh is properly installed and in your PATH&lt;/li&gt;
&lt;li&gt;Check that your shell configuration file exists and is writable&lt;/li&gt;
&lt;li&gt;Reload your shell after theme activation&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Preview Not Working
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;For remote themes: The tool will offer to download the theme for preview&lt;/li&gt;
&lt;li&gt;For local themes: Ensure the theme file exists in &lt;code&gt;~/.poshthemes/&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Search Not Responding
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you're in search mode (press &lt;code&gt;/&lt;/code&gt; first)&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;ESC&lt;/code&gt; to exit search mode if stuck&lt;/li&gt;
&lt;li&gt;Search works across both local and remote theme panels&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Custom Repository Issues
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ensure the Git repository URL is valid and accessible&lt;/li&gt;
&lt;li&gt;Repository must contain &lt;code&gt;.omp.json&lt;/code&gt; files in the root directory&lt;/li&gt;
&lt;li&gt;Check your internet connection for repository access&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Theme Customization Problems
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Only local themes can be customized&lt;/li&gt;
&lt;li&gt;Ensure you have write permissions to the themes directory&lt;/li&gt;
&lt;li&gt;Invalid JSON themes cannot be edited safely&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smart Caching&lt;/strong&gt;: Theme metadata is cached to speed up repeated previews&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File Reuse&lt;/strong&gt;: Existing downloaded themes are reused for previews&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Management&lt;/strong&gt;: Cache size is limited to prevent memory bloat&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy Loading&lt;/strong&gt;: Theme parsing only when needed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's New in v2.0
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🔍 &lt;strong&gt;Search&lt;/strong&gt;: Filter themes instantly with &lt;code&gt;/&lt;/code&gt; keybind&lt;/li&gt;
&lt;li&gt;🎯 &lt;strong&gt;Custom Repositories&lt;/strong&gt;: Add themes from Git repository with &lt;code&gt;+&lt;/code&gt; keybind
&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;Theme Customization&lt;/strong&gt;: Built-in color editor for personalizing themes&lt;/li&gt;
&lt;li&gt;✨ &lt;strong&gt;Enhanced Previews&lt;/strong&gt;: sample prompts with essential metadata&lt;/li&gt;
&lt;li&gt;🏗️ &lt;strong&gt;Modular Architecture&lt;/strong&gt;: Improved code organization and maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;p&gt;⭐ Star on GitHub if you like it!&lt;br&gt;&lt;br&gt;
📦 Review the package on PyPI or AUR&lt;br&gt;&lt;br&gt;
🐛 Report issues on GitHub&lt;br&gt;&lt;br&gt;
🔧 Submit pull requests with updates/upgrades&lt;/p&gt;

&lt;h2&gt;
  
  
  License
&lt;/h2&gt;

&lt;p&gt;This project is open source. Please check the license file for details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;Oh My Theme v2.0 features a modular architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;oh_my_theme/main.py&lt;/code&gt;&lt;/strong&gt;: Core UI and application logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;oh_my_theme/preview.py&lt;/code&gt;&lt;/strong&gt;: Enhanced theme previews and sample generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;oh_my_theme/search.py&lt;/code&gt;&lt;/strong&gt;: Real-time search and filtering functionality&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;oh_my_theme/repositories.py&lt;/code&gt;&lt;/strong&gt;: Custom Git repository management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;oh_my_theme/editor.py&lt;/code&gt;&lt;/strong&gt;: Theme color customization interface&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;oh_my_theme/config.py&lt;/code&gt;&lt;/strong&gt;: Configuration and settings management&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.6+&lt;/strong&gt;: Core runtime requirement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standard libraries only&lt;/strong&gt;: curses, json, os, subprocess, urllib&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No external dependencies required&lt;/strong&gt;: Pure Python implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ohmyposh.dev/" rel="noopener noreferrer"&gt;Oh My Posh Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ohmyposh.dev/docs/" rel="noopener noreferrer"&gt;Oh My Posh Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes" rel="noopener noreferrer"&gt;Oh My Posh Themes Repository (main)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mikeisfree/ohmytheme" rel="noopener noreferrer"&gt;Project Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pypi.org/project/oh-my-theme/" rel="noopener noreferrer"&gt;PyPI Package&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This tool modifies your shell configuration files. It's recommended to backup your configuration before first use.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Google's Hand &amp; Gesture Recognition + my playground</title>
      <dc:creator>twistedtransistor</dc:creator>
      <pubDate>Thu, 14 Aug 2025 22:33:37 +0000</pubDate>
      <link>https://dev.to/twistedtransistor/googles-hand-gesture-recognition-my-playground-4707</link>
      <guid>https://dev.to/twistedtransistor/googles-hand-gesture-recognition-my-playground-4707</guid>
      <description>&lt;p&gt;Playground Git &lt;a href="https://github.com/mikeisfree/hand_gesture_recognition_nextj_playground" rel="noopener noreferrer"&gt;repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google &lt;a href="https://mediapipe-studio.webapps.google.com/demo/hand_landmarker?hl=en" rel="noopener noreferrer"&gt;product page&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Hand &amp;amp; Gesture
&lt;/h3&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%2Fng0njauzzxy9hfdm2apn.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%2Fng0njauzzxy9hfdm2apn.png" alt="live view" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I just learned about this project's existence, I knew I had to try it out. If you are a kid of the 80s/90s like me and still haven't received a functioning Power Glove for which your parents paid ~35 years ago... you might be thinking... that's about time!&lt;/p&gt;

&lt;p&gt;Were there other attempts over time? Sure! Quite a lot, especially since modern VR headsets are on the market. Even though it had far superior successors, something was still lacking. The promise of a unified controller and seamless interaction using just the human hand had never been fulfilled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Nextjs viewTransitions
&lt;/h3&gt;

&lt;p&gt;When I think of UIs that could benefit from hand tracking solutions, what first comes to my mind is a multi-layered control panel where the user who interacts with it should not experience typical HTTP loading screens between pages, but rather be served with a consistent and continuous environment that can grow and grow while keeping reasonable efficiency at low resource consumption.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the status
&lt;/h3&gt;

&lt;p&gt;Well... I should probably end this simple test right after I implemented MediaPipe to a Next.js example project from GitHub and added camera controls. But then I started to think about how it will work with this or that kind of slider.&lt;br&gt;
How can I improve my own ease of interaction? How can I scale it to work with every machine I run it on?&lt;/p&gt;

&lt;p&gt;This is why it is what it is now: a playground that can be easily adjusted by tilting tracking confidence or gesture threshold and also calibrated for every screen and resolution.&lt;/p&gt;

&lt;p&gt;The project currently also contains some components that can be reused, like an image slider, horizontal page slider, articles to scroll through, music player with volume rocker...&lt;/p&gt;
&lt;h3&gt;
  
  
  What do i think
&lt;/h3&gt;

&lt;p&gt;I think it is worth giving it a shot. It most probably will not be something that will resonate with everyone, but if you are willing to spend a bit of time to get used to it and also tweak the settings, then I believe it could be an enjoyable experience and also maybe the start of a new idea for a smart TV control app or a PC UI HUD, or maybe some gaming experience or lots and lots...&lt;/p&gt;
&lt;h3&gt;
  
  
  Whats the future like
&lt;/h3&gt;

&lt;p&gt;My plan is to add more and more elements and finally build THE control room within a Clear Canvas component from which I will be able to interact with all created tools using two hands, including both preconfigured and custom-made gestures.&lt;/p&gt;
&lt;h2&gt;
  
  
  Tech list
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MediaPipe:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TypeScript:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tailwind CSS:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Building and Running
&lt;/h2&gt;

&lt;p&gt;This is very simple. Just use following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;The application follows a layered architecture with React Context providers managing state and MediaPipe handling computer vision processing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────┐
│           Next.js App Router            │
├─────────────────────────────────────────┤
│        Context Providers Layer         │
│  ┌─────────────────────────────────────┐ │
│  │ MediaPipeOptionsProvider            │ │
│  │ GestureOptionsProvider              │ │
│  │ CalibrationProvider                 │ │
│  │ HandTrackingProvider                │ │
│  └─────────────────────────────────────┘ │
├─────────────────────────────────────────┤
│         Hand Tracking Layer            │
│  ┌─────────────────────────────────────┐ │
│  │ MediaPipe Hands API                 │ │
│  │ Camera Utils                        │ │
│  │ Gesture Recognition                 │ │
│  └─────────────────────────────────────┘ │
├─────────────────────────────────────────┤
│            UI Components               │
│  ┌─────────────────────────────────────┐ │
│  │ GestureCursor                       │ │
│  │ HandTrackingOverlay                 │ │
│  │ MediaPipeControls                   │ │
│  └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Routes Structure
&lt;/h2&gt;

&lt;p&gt;The application uses Next.js App Router with the following route structure:&lt;/p&gt;

&lt;h3&gt;
  
  
  Main Routes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/&lt;/code&gt; (Home Page)&lt;/strong&gt;: Landing page with navigation to all demo routes and MediaPipe controls&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/blog&lt;/code&gt;&lt;/strong&gt;: Floating cards demo with ViewTransition animations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/card&lt;/code&gt;&lt;/strong&gt;: Interactive card gallery with image transitions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/scroll-test&lt;/code&gt;&lt;/strong&gt;: Horizontal slider controlled by hand gestures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/slider&lt;/code&gt;&lt;/strong&gt;: Play around with (add any "further.mp3" to public/sfx first)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/clear-canvas&lt;/code&gt;&lt;/strong&gt;: Canvas drawing application with gesture controls&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/calibration&lt;/code&gt;&lt;/strong&gt;: Hand tracking calibration interface&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Route Functionality
&lt;/h3&gt;

&lt;p&gt;Each route demonstrates different aspects of gesture control:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Blog Route&lt;/strong&gt; (&lt;code&gt;/blog&lt;/code&gt;): Showcases ViewTransition API with floating card layouts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Card Route&lt;/strong&gt; (&lt;code&gt;/card&lt;/code&gt;): Image gallery with smooth transitions between views&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scroll Test&lt;/strong&gt; (&lt;code&gt;/scroll-test&lt;/code&gt;): Horizontal navigation using pinch-and-drag gestures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slider Route&lt;/strong&gt; (&lt;code&gt;/slider&lt;/code&gt;): Volume control using hand position mapping&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear Canvas&lt;/strong&gt; (&lt;code&gt;/clear-canvas&lt;/code&gt;): Drawing interface with gesture-based controls&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calibration&lt;/strong&gt; (&lt;code&gt;/calibration&lt;/code&gt;): Setup interface for hand tracking accuracy&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Context Providers &amp;amp; State Management
&lt;/h2&gt;

&lt;p&gt;The application uses a hierarchical context provider system to manage different aspects of the hand tracking system:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. MediaPipeOptionsProvider
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt;: &lt;code&gt;contexts/MediaPipeOptionsContext.tsx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Manages MediaPipe hand detection configuration options&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Persistent storage via localStorage&lt;/li&gt;
&lt;li&gt;Real-time option updates&lt;/li&gt;
&lt;li&gt;Default configuration management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Configuration Options&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;MediaPipeOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;runningMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;IMAGE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;VIDEO&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Processing mode&lt;/span&gt;
  &lt;span class="nl"&gt;maxNumHands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Max hands to detect (1-4)&lt;/span&gt;
  &lt;span class="nl"&gt;minHandDetectionConfidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Palm detection threshold (0-1)&lt;/span&gt;
  &lt;span class="nl"&gt;minHandPresenceConfidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Hand presence threshold (0-1)&lt;/span&gt;
  &lt;span class="nl"&gt;minTrackingConfidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Tracking confidence (0-1)&lt;/span&gt;
  &lt;span class="nl"&gt;modelComplexity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Model accuracy vs speed&lt;/span&gt;
  &lt;span class="nl"&gt;staticImageMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Static vs video processing&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. GestureOptionsProvider
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt;: &lt;code&gt;contexts/GestureOptionsContext.tsx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Manages gesture detection algorithms and thresholds&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple pinch detection modes&lt;/li&gt;
&lt;li&gt;Configurable sensitivity thresholds&lt;/li&gt;
&lt;li&gt;Algorithm switching capabilities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Detection Modes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Original&lt;/strong&gt;: Simple bone landmark distance calculation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple&lt;/strong&gt;: Flesh-compensated distance with palm width normalization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced&lt;/strong&gt;: Multi-factor detection with confidence scoring&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. CalibrationProvider
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt;: &lt;code&gt;contexts/CalibrationContext.tsx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Handles coordinate transformation between camera space and screen space&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Screen resolution awareness&lt;/li&gt;
&lt;li&gt;Coordinate transformation algorithms&lt;/li&gt;
&lt;li&gt;Persistent calibration storage&lt;/li&gt;
&lt;li&gt;Automatic invalidation on resolution changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Calibration Data Structure&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CalibrationData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;screenWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Current screen width&lt;/span&gt;
  &lt;span class="nl"&gt;screenHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Current screen height&lt;/span&gt;
  &lt;span class="nl"&gt;cameraAspectRatio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Camera feed aspect ratio&lt;/span&gt;
  &lt;span class="nl"&gt;scaleFactorX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// X-axis scaling factor&lt;/span&gt;
  &lt;span class="nl"&gt;scaleFactorY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Y-axis scaling factor&lt;/span&gt;
  &lt;span class="nl"&gt;offsetX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// X-axis offset&lt;/span&gt;
  &lt;span class="nl"&gt;offsetY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Y-axis offset&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. HandTrackingProvider
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt;: &lt;code&gt;components/hand-tracking/HandTrackingProvider.tsx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Core MediaPipe integration and hand detection processing&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynamic MediaPipe script loading&lt;/li&gt;
&lt;li&gt;Camera initialization and management&lt;/li&gt;
&lt;li&gt;Real-time hand landmark processing&lt;/li&gt;
&lt;li&gt;Error handling and recovery&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Options-to-UI Integration
&lt;/h2&gt;

&lt;p&gt;The system provides a comprehensive UI for configuring all hand tracking parameters:&lt;/p&gt;

&lt;h3&gt;
  
  
  MediaPipeControls Component
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt;: &lt;code&gt;components/MediaPipeControls.tsx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integration Pattern&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Context Consumption&lt;/strong&gt;: Uses both MediaPipeOptions and GestureOptions contexts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Updates&lt;/strong&gt;: Changes immediately affect hand tracking behavior&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent Storage&lt;/strong&gt;: All settings automatically saved to localStorage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Import/Export&lt;/strong&gt;: JSON-based configuration sharing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;UI Control Types&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SliderControl&lt;/strong&gt;: Numeric range inputs with visual feedback&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ToggleControl&lt;/strong&gt;: Boolean switches with animated states&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SelectControl&lt;/strong&gt;: Dropdown menus for enumerated options&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Control Categories&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;MediaPipe Core Settings&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Running mode selection&lt;/li&gt;
&lt;li&gt;Hand count limits&lt;/li&gt;
&lt;li&gt;Confidence thresholds&lt;/li&gt;
&lt;li&gt;Model complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Gesture Detection Settings&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Detection algorithm selection&lt;/li&gt;
&lt;li&gt;Sensitivity thresholds per algorithm&lt;/li&gt;
&lt;li&gt;Mode-specific parameter tuning&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Configuration Management&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Settings export/import&lt;/li&gt;
&lt;li&gt;Reset to defaults&lt;/li&gt;
&lt;li&gt;Real-time configuration preview&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Calibration System
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Calibration is Necessary
&lt;/h3&gt;

&lt;p&gt;The calibration system addresses fundamental challenges in hand tracking applications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Coordinate System Mismatch&lt;/strong&gt;: MediaPipe returns normalized coordinates (0-1) from camera space, but UI interactions require pixel-perfect screen coordinates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Camera-Screen Alignment&lt;/strong&gt;: The camera's field of view rarely matches the screen's aspect ratio or position perfectly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Perspective Distortion&lt;/strong&gt;: Hand movements in 3D space need accurate mapping to 2D screen interactions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User Variability&lt;/strong&gt;: Different users have varying hand sizes, camera positions, and interaction preferences&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Calibration Structure
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt;: &lt;code&gt;app/calibration/&lt;/code&gt; route&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Process Flow&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Input → Camera Capture → Coordinate Mapping → Validation → Storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Calibration Steps&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Screen Resolution Detection&lt;/strong&gt;: Captures current viewport dimensions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Camera Aspect Ratio Calculation&lt;/strong&gt;: Determines camera feed proportions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reference Point Mapping&lt;/strong&gt;: User touches screen corners/edges while system records hand positions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transform Matrix Generation&lt;/strong&gt;: Calculates scale factors and offsets for coordinate conversion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation Testing&lt;/strong&gt;: User tests accuracy across screen regions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent Storage&lt;/strong&gt;: Saves calibration data with resolution validation&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Calibration Data Processing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Coordinate Transformation Algorithm&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;applyCalibration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalizedX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;normalizedY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;calibrationData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Fallback: simple mapping&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;normalizedX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;normalizedY&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&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="c1"&gt;// Apply calibration transformation&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;normalizedX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Mirror horizontally&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;normalizedY&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="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;calibrationData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scaleFactorX&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;handX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;calibrationData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;calibrationData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scaleFactorY&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;handY&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;calibrationData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetY&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;&lt;strong&gt;Calibration Persistence&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stored in localStorage as &lt;code&gt;handTrackingCalibration&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Automatically invalidated when screen resolution changes&lt;/li&gt;
&lt;li&gt;Includes timestamp and validation checksums&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Benefits of Calibration
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Accuracy&lt;/strong&gt;: Precise cursor positioning across the entire screen&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: Reliable gesture recognition regardless of camera setup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Experience&lt;/strong&gt;: Reduced frustration from misaligned interactions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptability&lt;/strong&gt;: Works with various camera positions and screen sizes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Optimized coordinate calculations reduce processing overhead&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Gesture Recognition System
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Detection Algorithms
&lt;/h3&gt;

&lt;p&gt;The system implements three distinct gesture detection approaches:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Original Mode
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Method&lt;/strong&gt;: Direct 3D distance calculation between fingertip landmarks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Case&lt;/strong&gt;: High precision applications requiring exact finger positioning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pros&lt;/strong&gt;: Simple, fast, precise for ideal conditions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons&lt;/strong&gt;: Sensitive to hand size variations and camera distance&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Simple Mode
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Method&lt;/strong&gt;: Palm-width normalized distance with flesh compensation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Case&lt;/strong&gt;: General-purpose applications with varied users&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pros&lt;/strong&gt;: Accounts for hand size differences, more forgiving&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons&lt;/strong&gt;: Less precise than original mode&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Advanced Mode
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Method&lt;/strong&gt;: Multi-factor confidence scoring with weighted detection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Case&lt;/strong&gt;: Professional applications requiring robust detection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Factors&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Fingertip distance (40% weight)&lt;/li&gt;
&lt;li&gt;Joint distance (40% weight)&lt;/li&gt;
&lt;li&gt;Finger curl detection (20% weight)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Pros&lt;/strong&gt;: Most robust, handles edge cases, configurable&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Cons&lt;/strong&gt;: Higher computational cost, more complex tuning&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>gesturerecognition</category>
      <category>google</category>
      <category>playground</category>
      <category>ui</category>
    </item>
    <item>
      <title>Seemless Coolify SSL. Self-sign, self-renew with Telegram/Discord status reports. Coolify + Ubuntu + Oracle</title>
      <dc:creator>twistedtransistor</dc:creator>
      <pubDate>Sun, 13 Apr 2025 12:05:15 +0000</pubDate>
      <link>https://dev.to/twistedtransistor/seemless-coolify-ssl-self-sign-self-renew-report-via-telegramdiscord-full-scripts-example-201d</link>
      <guid>https://dev.to/twistedtransistor/seemless-coolify-ssl-self-sign-self-renew-report-via-telegramdiscord-full-scripts-example-201d</guid>
      <description>&lt;ol&gt;
&lt;li&gt;You host apps like the big boys do ? &lt;/li&gt;
&lt;li&gt;You don't afraid to take responsibility for Your own VPS ?&lt;/li&gt;
&lt;li&gt;You say "NO" to those childish domains with fancy letters and words like: "lookatmydomainname.com" but rather prefer highly enjoyable IP numbers sexy as Tom Cruise and old Cadillac ?&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You dont like setting up SSl and refreshing it over and over again ? &lt;/p&gt;
&lt;h2&gt;
  
  
  Youre in a good spot! Follow along and make SSL certs run on IP address of your COOLIFY VPS best way there always been!
&lt;/h2&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  How it works ?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If the cert or key doesn’t exist — it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates &lt;code&gt;/etc/ssl/certs/coolify-selfsigned.crt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Creates &lt;code&gt;/etc/ssl/private/coolify-selfsigned.key&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Uses default values for country/state/org (you can customize them if you like)&lt;/li&gt;
&lt;li&gt;Logs the entire process&lt;/li&gt;
&lt;li&gt;Emails you that it &lt;em&gt;successfully created&lt;/em&gt; the cert&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  🔁 &lt;strong&gt;Renewal (if certs already exist)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backs up current cert and key to a timestamped folder&lt;/li&gt;
&lt;li&gt;Creates a fresh new cert valid for 365 days&lt;/li&gt;
&lt;li&gt;Replaces the old one&lt;/li&gt;
&lt;li&gt;Reloads NGINX to apply it&lt;/li&gt;
&lt;li&gt;Emails you success or failure&lt;/li&gt;
&lt;li&gt;Logs it all&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  🧠 &lt;strong&gt;Smart Logic&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Doesn’t break if files are missing — just regenerates them&lt;/li&gt;
&lt;li&gt;Doesn’t overwrite backups — stores them neatly by date&lt;/li&gt;
&lt;li&gt;Won’t crash silently — will email you even if NGINX fails to reload&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🤖 &lt;strong&gt;Auto Mode (via cron)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can schedule it (e.g., every 6 months)&lt;/li&gt;
&lt;li&gt;run it by cron or manually, -&amp;gt; it &lt;strong&gt;does the same full check + create + backup + renew&lt;/strong&gt; process &lt;/li&gt;
&lt;li&gt;You don’t need to do anything — take Your mama on pizza, smash buttons or do whatever the hell you want&lt;/li&gt;
&lt;/ul&gt;







&lt;h1&gt;
  
  
  🧪SETUP
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;you don't ask...You COMMAND!&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Open with nano:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /usr/local/bin/renew-coolify-cert-auto.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Paste the script and save it:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;CERT_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/etc/ssl/certs/coolify-selfsigned.crt"&lt;/span&gt;
&lt;span class="nv"&gt;KEY_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/etc/ssl/private/coolify-selfsigned.key"&lt;/span&gt;
&lt;span class="nv"&gt;BACKUP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/etc/ssl/backup-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%F_%H-%M-%S&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/coolify-cert-renew.log"&lt;/span&gt;
&lt;span class="nv"&gt;ALERT_EMAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your@email.com"&lt;/span&gt; &lt;span class="c"&gt;# &amp;lt;-- CHANGE THIS&lt;/span&gt;


&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"========== &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="s1"&gt;'+%F %T'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; =========="&lt;/span&gt;

&lt;span class="c"&gt;# Check if cert/key exist&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CERT_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KEY_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[!] Cert or key missing. First-time setup or files deleted."&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[+] Generating new certificate..."&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CERT_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KEY_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[*] Backing up existing certs to &lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CERT_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt;
    &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KEY_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Generate new cert&lt;/span&gt;
openssl req &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 365 &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa:2048 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-keyout&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KEY_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-out&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CERT_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/C=US/ST=None/L=None/O=SelfSigned/CN=coolify.local"&lt;/span&gt;

&lt;span class="c"&gt;# Secure the key file&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KEY_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Reload NGINX&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[*] Reloading NGINX..."&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;systemctl reload nginx&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[✓] SSL cert created or renewed successfully."&lt;/span&gt;
    mail &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"✅ Coolify SSL Cert Created/Renewed"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ALERT_EMAIL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"Success: Coolify self-signed cert created or renewed on &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; at &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[X] NGINX reload failed!"&lt;/span&gt;
    mail &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"❌ Coolify SSL Renewal Failed"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ALERT_EMAIL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"ERROR: Coolify cert was generated but NGINX reload failed on &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; at &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;. Check it manually."&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"====================================="&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Make it executable:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; +x /usr/local/bin/renew-coolify-cert-auto.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Do the test run :
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; /usr/local/bin/renew-coolify-cert-auto.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔁 Add Cron (6-month schedule):
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Paste:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0 0 1 1,7 &lt;span class="k"&gt;*&lt;/span&gt; /usr/local/bin/renew-coolify-cert-auto.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  🔥CONGRATS! You became a LEGEND running hardened, hands-off Coolify cert!
&lt;/h1&gt;

&lt;h2&gt;
  
  
  ...but just in case Your'e ambitions havent been fulfied yet... you need more and being a legend is simply not enough for You...
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Telegram + Discord Alerts Setup (instead of/in addition to Email)&lt;/strong&gt;
&lt;/h3&gt;

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

&lt;p&gt;✅ Message your &lt;strong&gt;Telegram&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ Post to &lt;strong&gt;Discord channel webhook&lt;/strong&gt;  &lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ Still support email if you so choose
&lt;/h2&gt;
&lt;h2&gt;
  
  
  🧪 Step 1: Prepare Telegram Bot
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;In Telegram, search: &lt;code&gt;@BotFather&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;/newbot&lt;/code&gt; and follow the prompts to:&lt;/li&gt;
&lt;li&gt;&lt;ul&gt;
&lt;li&gt;Name your bot&lt;/li&gt;
&lt;li&gt;Get your bot token (save it)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the token (looks like &lt;code&gt;123456789:ABCdefGHI...&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start a chat with your bot (&lt;code&gt;/start&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now find your &lt;strong&gt;Telegram user ID&lt;/strong&gt;:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Visit this bot: https://t.me/userinfobot
- It’ll reply with your user ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  🧪 Step 2: Create Discord Webhook
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to your server settings → &lt;code&gt;Integrations → Webhooks&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;New Webhook&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Choose a channel&lt;/li&gt;
&lt;li&gt;Copy the &lt;strong&gt;Webhook URL&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  🧠 Step 3: Update the Script
&lt;/h2&gt;

&lt;p&gt;Here’s the updated portion of the script with &lt;strong&gt;Telegram + Discord alerts&lt;/strong&gt; (plus optional email)&lt;br&gt;
Paste it at the bottom of script below "} | tee -a "$LOG_FILE"&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;# Send Telegram Alert&lt;/span&gt;
send_telegram&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;MESSAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
  &lt;span class="nv"&gt;TELEGRAM_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_TELEGRAM_BOT_TOKEN"&lt;/span&gt;
  &lt;span class="nv"&gt;TELEGRAM_USER_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_TELEGRAM_USER_ID"&lt;/span&gt;
  curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.telegram.org/bot&lt;/span&gt;&lt;span class="nv"&gt;$TELEGRAM_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;/sendMessage"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;chat_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TELEGRAM_USER_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MESSAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;parse_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Markdown"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Send Discord Alert&lt;/span&gt;
send_discord&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;MESSAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
  &lt;span class="nv"&gt;DISCORD_WEBHOOK_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_DISCORD_WEBHOOK_URL"&lt;/span&gt;
  curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$MESSAGE&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DISCORD_WEBHOOK_URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Alert message text&lt;/span&gt;
&lt;span class="nv"&gt;ALERT_MSG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[*] Coolify SSL Cert was updated on &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; at &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="s1"&gt;'%F %T'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Success alert&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;systemctl reload nginx&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nv"&gt;ALERT_MSG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"✅ *Coolify SSL updated successfully* on &lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt; at &lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="s1"&gt;'%F %T'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nv"&gt;ALERT_MSG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"❌ *Coolify SSL updated but NGINX reload failed!* on &lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt; at &lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="s1"&gt;'%F %T'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Send alerts&lt;/span&gt;
send_telegram &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ALERT_MSG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
send_discord &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ALERT_MSG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Optional Email (still supported)&lt;/span&gt;
mail &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"Coolify SSL Update Status"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ALERT_EMAIL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ALERT_MSG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔧 Replace placeholders:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;YOUR_TELEGRAM_BOT_TOKEN&lt;/code&gt; → Your bot token&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;YOUR_TELEGRAM_USER_ID&lt;/code&gt; → From &lt;code&gt;@userinfobot&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;YOUR_DISCORD_WEBHOOK_URL&lt;/code&gt; → Your webhook URL&lt;/li&gt;
&lt;li&gt;(Optional) Change or remove email alert&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ✅ Done!
&lt;/h3&gt;

&lt;p&gt;Try a manual run:&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="nb"&gt;sudo&lt;/span&gt; /usr/local/bin/renew-coolify-cert-auto.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see messages pop up on both Telegram &lt;em&gt;and&lt;/em&gt; Discord. 🔔💬&lt;/p&gt;




&lt;h1&gt;
  
  
  The world salutes You!
&lt;/h1&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%2Fyrp3vqeltelq6cqc2roq.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%2Fyrp3vqeltelq6cqc2roq.png" alt="Image description" width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>oracle</category>
      <category>coolify</category>
      <category>ssl</category>
    </item>
    <item>
      <title>Oracle Cloud VPS - recover SSH access to your instance with webUI &amp; cloud shell. No user pass or scripts</title>
      <dc:creator>twistedtransistor</dc:creator>
      <pubDate>Wed, 09 Apr 2025 17:00:16 +0000</pubDate>
      <link>https://dev.to/twistedtransistor/oracle-cloud-vps-recover-ssh-access-to-your-instance-with-webui-cloud-shell-no-user-pass-or-244c</link>
      <guid>https://dev.to/twistedtransistor/oracle-cloud-vps-recover-ssh-access-to-your-instance-with-webui-cloud-shell-no-user-pass-or-244c</guid>
      <description>&lt;p&gt;&lt;strong&gt;Tutorial Content&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Intro - time waster &amp;amp; page filler&lt;/li&gt;
&lt;li&gt; Starting point&lt;/li&gt;
&lt;li&gt; Step by step solution&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Intro&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As many of You I host some of evil "world shall know my name" experiments on Oracle infrastructure. Free tier of service gained a lot of traction and with that I stumbled upon more and more reports on the web written by users who accidently blocked SSH access to their instances while mixing "the ultimate weapon" ingredients.&lt;/p&gt;

&lt;p&gt;I haven't paid much attention to those lenghty posts, tips, replies, feedbacks as other people already involved seemed more than capable to provide support.&lt;br&gt;
Plus:  &lt;em&gt;Hey...this does not concern me! - I use CLI &amp;amp; scripts with caution and keep config files clean and always ready for upcoming world domination.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yeah...so Yesterday things got turned as I rushed ports forwarding. &lt;br&gt;
Have any of You ever heard of tool which fits task better than "ufw"?  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;me neither! Damn....&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2 commands and SSH was cooked. Right away i did some tests against the wall emerged in between me and my SSH jar and &lt;strong&gt;few terminals later I can confirm sh...t is solid.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Running scripts against instance was tempting althou "run command" plugin on my Ubuntu instance was inactive. &lt;br&gt;
&lt;em&gt;Why ? - how should I know ? broken or someth...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Connecting to the instance from web CLI directly to instance required user password...and &lt;em&gt;I used my instance with ssh key thus I did what all IT professionals have before me - never chrooted to set the passswdssw..whatever...or maybe just lost the damn thing - YOLO!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If You stuck like i did - follow along.&lt;br&gt;
Fortunately this is Linux. Modular system made of modules and submodules developed with modular modulesss - ok! I shut up! - follow along please&lt;/p&gt;

&lt;p&gt;Finally I found THE solution! - and decided to post it here for fame and money!🤩 &lt;/p&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Starting point - why it had to be me and You?!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSH access is blocked by ufw.&lt;/li&gt;
&lt;li&gt;Run Command is unavailable because the Oracle Cloud Agent isn't communicating.&lt;/li&gt;
&lt;li&gt;Console Connection access is blocked because the ubuntu user has no password.&lt;/li&gt;
&lt;li&gt;people who can't tell CLI Terminal from terminal at the airport laught at You
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;THE PATH Forward: Resetting the User Passswwwr..bla..bla like a champ&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since you cannot log in via any standard means, the primary way to regain control is to modify the instance's boot disk offline to set a password for the ubuntu user (or create a new user with a password). The standard procedure for this in OCI is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method: Attach Boot Volume to a Rescue Instance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This involves detaching the boot disk from your broken instance and temporarily attaching it to another (working) Linux instance to modify it.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Step by step solution&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stop Your Instance:&lt;/strong&gt;&lt;br&gt;
Go to the OCI Console -&amp;gt; Compute -&amp;gt; Instances -&amp;gt; Select &lt;strong&gt;'your-instance'&lt;/strong&gt; -&amp;gt; Click &lt;strong&gt;Stop&lt;/strong&gt;.&lt;br&gt;
Wait for it to fully stop (icon turns red/grey).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Did that made Your'e screen to exploade ? - damn...why the hell mine did!?&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Identify the Boot Volume:&lt;/strong&gt;&lt;br&gt;
On the Instance Details page, scroll down to 'Resources' -&amp;gt; 'Boot Volume'. Click on the boot volume name to go to its details page. Note its name.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detach the Boot Volume:&lt;/strong&gt;&lt;br&gt;
On the Boot Volume Details page, click the &lt;strong&gt;Detach&lt;/strong&gt; button.&lt;br&gt;
Confirm the detachment. Wait for it to complete.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create or Use a "Rescue" Instance:&lt;/strong&gt;&lt;br&gt;
You need another Linux instance in the same Availability Domain (AD) that you can SSH into.&lt;/p&gt;

&lt;p&gt;If you don't have one, create a small, temporary Linux instance (Oracle Linux is fine) in the same AD as your original instance. Make sure you can SSH into this new instance. Let's call this the &lt;strong&gt;'Rescue Instance'&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Attach the Boot Volume to the Rescue Instance:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to the Rescue Instance's details page.&lt;/li&gt;
&lt;li&gt;Go to "Resources" -&amp;gt; "Attached block volumes"&lt;/li&gt;
&lt;li&gt;Click "Attach Block Volume"&lt;/li&gt;
&lt;li&gt;Select "Paravirtualized" as the attachment type.&lt;/li&gt;
&lt;li&gt;Choose detached "your-instance-name" boot volume&lt;/li&gt;
&lt;li&gt;Choose a device path (usually &lt;code&gt;/dev/oracleoci/oraclevdb&lt;/code&gt; or similar is fine, the OS will likely see it as &lt;code&gt;/dev/sdb&lt;/code&gt; or &lt;code&gt;/dev/sdc&lt;/code&gt;, etc.).&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Attach&lt;/strong&gt;. Wait for the attachment to complete.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SSH into the Rescue Instance:&lt;/strong&gt;&lt;br&gt;
Connect to your working Rescue Instance via SSH.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Identify the Attached Disk:&lt;/strong&gt;&lt;br&gt;
Run the following command on the Rescue Instance to identify the newly attached disk (e.g., &lt;code&gt;/dev/sdb&lt;/code&gt;, &lt;code&gt;/dev/sdc&lt;/code&gt;) and its partitions (e.g., &lt;code&gt;/dev/sdb1&lt;/code&gt; which should contain the root filesystem &lt;code&gt;/&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fdisk &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Mount the Filesystem:&lt;/strong&gt;&lt;br&gt;
Create a mount point:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; /mnt/rescue
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Mount the root partition of the attached volume (Replace &lt;code&gt;/dev/sdb1&lt;/code&gt; with the correct partition identified in the previous step):&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mount /dev/sdb1 /mnt/rescue
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Chroot into the Mounted Filesystem:&lt;/strong&gt;&lt;br&gt;
This allows you to run commands as if you were inside the original instance's OS:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chroot&lt;/span&gt; /mnt/rescue
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Set the Password:&lt;/strong&gt;&lt;br&gt;
Now that you are 'inside' the original OS environment, set a password for the &lt;code&gt;ubuntu&lt;/code&gt; user:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;passwd ubuntu
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Enter and confirm a new, strong password when prompted.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Exit Chroot:&lt;/strong&gt;&lt;br&gt;
Type &lt;code&gt;exit&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Unmount the Filesystem:&lt;/strong&gt;&lt;br&gt;
Unmount the volume:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;umount /mnt/rescue
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detach the Volume from Rescue Instance:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Go back to the OCI Console -&amp;gt; Rescue Instance Details -&amp;gt; Attached Block Volumes -&amp;gt; Find the attached boot volume -&amp;gt; Click the Actions menu (...) -&amp;gt; &lt;strong&gt;Detach&lt;/strong&gt;. Wait for detachment.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Re-attach Boot Volume to Original Instance:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Go back to your &lt;em&gt;original&lt;/em&gt; instance details page -&amp;gt; Resources -&amp;gt; Boot Volume -&amp;gt; Click &lt;strong&gt;Attach&lt;/strong&gt;. Select the correct boot volume. Confirm. Wait for attachment.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start Original Instance:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Go back to the original instance's details page and click &lt;strong&gt;Start&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Console Connection:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Once the instance is running, create a new &lt;strong&gt;Console Connection&lt;/strong&gt;, connect to it, and log in as &lt;code&gt;ubuntu&lt;/code&gt; using the password you just set.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Fix the Firewall:&lt;/strong&gt;&lt;br&gt;
Once logged in via the console, allow SSH traffic and reload the firewall:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 22/tcp
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw status &lt;span class="c"&gt;# (to verify)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Test SSH:&lt;/strong&gt;&lt;br&gt;
Disconnect the console connection and try SSHing normally (replace &lt;code&gt;YOUR_INSTANCE_IP&lt;/code&gt; with the actual IP):&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh ubuntu@YOUR_INSTANCE_IP
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enjoy new life. Make plans.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Never allow people to tell You that Apps primarly made to indefinitely shuffle icons on desktop are absurdly useless and do not solve real life problems!&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;obviously they just want to get the license cheaper&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>tutorial</category>
      <category>productivity</category>
      <category>cloud</category>
      <category>oracle</category>
    </item>
  </channel>
</rss>
