<?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>Forem: Brandon Skinner</title>
    <description>The latest articles on Forem by Brandon Skinner (@mentalquill).</description>
    <link>https://forem.com/mentalquill</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%2F259509%2Febbf156a-53e2-405f-94b7-25a82f1cc70a.jpg</url>
      <title>Forem: Brandon Skinner</title>
      <link>https://forem.com/mentalquill</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mentalquill"/>
    <language>en</language>
    <item>
      <title>Upskilling in AI: Unconventional Prompt Use</title>
      <dc:creator>Brandon Skinner</dc:creator>
      <pubDate>Sun, 11 Jan 2026 00:39:55 +0000</pubDate>
      <link>https://forem.com/mentalquill/upskilling-in-ai-unconventional-prompt-use-4p79</link>
      <guid>https://forem.com/mentalquill/upskilling-in-ai-unconventional-prompt-use-4p79</guid>
      <description>&lt;p&gt;AI is all the rage at the moment and is being applied to every facet of life. Everywhere you turn, AI is often staring you in the face. Head down to your favorite cafe, a new AI-generated image of the barista as Thanos snapping the stains off mugs hangs behind the urinal. You search for "Hot Wheels hubcap sizes" on Google and get a four paragraph AI summary.&lt;/p&gt;

&lt;p&gt;A lot of folks are also being asked to dive into AI head-first and become productive at very high levels professionally without a whole lot of preamble. This can be difficult since AI-first workflows are a completely different paradigm and way of work. The mechanics of "doing the thing" became the arena of AI and you are now the conductor. The manager. The editor. The reviewer. For many, these mechanics are part of their professional joy. However, we must adapt to our new normal.&lt;/p&gt;

&lt;p&gt;While I won't be diving into the Brainstorm -&amp;gt; Plan -&amp;gt; Execute -&amp;gt; Review loop (or other synonyms, depending on the article) for effective AI use in the context of software engineering, I'd like to focus on something I've found helpful and effective for wrapping your head around AI and how to get what you want from it.&lt;/p&gt;

&lt;p&gt;Prompt writing and building context is a skill unto itself. And a core one in the context of AI-first approaches and agentic workflows. If you cannot get a desired one-off outcome from AI through prompts and context engineering, you're going to have a hard time layering the additional complexities for doing real work with AI.  &lt;/p&gt;

&lt;p&gt;Just like coding or labbing something for professional development, prompt writing and context engineering is something that requires consistent practice in a variety of situations. While I write &lt;em&gt;a lot&lt;/em&gt; of prompts and do &lt;em&gt;a lot&lt;/em&gt; of context engineering professionally, I also practice and refine these skills frequently. &lt;em&gt;"How?"&lt;/em&gt;, you may be asking.&lt;/p&gt;

&lt;p&gt;Well, AI can be more than just business, serious research, and text overlaying Subway Surfers for social media $$$. It can be more than just practical. It can be fun. It opens up new possibilities for creation and expression that previously just weren't possible. While there are downsides and controversies surrounding AI training and whether AI should be leveraged creatively, let's not throw the baby out with the bath water. When Pandora's Box opens, you can either cower or reach inside. Personally, my feet are kicking the air and I swan dove into the depths of the abyss.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;That's all well and good but how do I get in on the action? Where's the benefit for me?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, dear reader, the sky is the limit and the only restriction is your own imagination and ability to bend AI to your will.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fun with pictures
&lt;/h2&gt;

&lt;p&gt;Have you ever had an idea for a picture or scene that you think would be fun to send to your friend with a dog obsession? Have you ever thought "&lt;em&gt;I would love to use this picture as my profile but I'd prefer to be a Jedi&lt;/em&gt;"? All this and more can be yours.&lt;/p&gt;

&lt;p&gt;Now let's suppose your friend had a dog. A rambunctious little guy who has taken to leaping from the couch so high and so far you'd swear he's gonna hit the moon one of these nights. Don't let your dreams be dreams! Through the power of AI, all things are possible.&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%2Fk7ekqp1sepuazzazkuxx.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%2Fk7ekqp1sepuazzazkuxx.png" alt="A golden retriever jumping from a couch to the moon" width="719" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now suppose you don't like Golden Retrievers. Maybe you like a nice Frenchie.&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%2Fznm0osiarvzrl39jtwwi.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%2Fznm0osiarvzrl39jtwwi.png" alt="A Frenchie jumping from a couch to the moon" width="719" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now isn't that cool. You could swap it for pretty much anything and &lt;a href="https://youtu.be/hKUpAYOLfOs?t=156" rel="noopener noreferrer"&gt;send everything to the moon&lt;/a&gt;. You can also generate any kind of image, convert images between styles (e.g.: comic book style, Disney style), change text on images, generate memes.... Your imagination is your inkwell and AI is your awesome, though sometimes janky, quill. These capabilities are on your phone and this silliness both familiarizes you with AI and can bring joy and color into your and your loved ones' lives.&lt;/p&gt;

&lt;p&gt;But, there's a lot more possible here than strictly goofing around.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI for running
&lt;/h2&gt;

&lt;p&gt;Let's say you've been running for a bit. Your Strava is loaded up and you're following a loose plan. Maybe you're running two easy runs, one speed day, a long run, and a recovery run every week, each with varying intensities. You wake up one day and think to yourself, &lt;em&gt;"I wanna run a 50K in 6 months"&lt;/em&gt;. Ordinarily, you'd need to spend time researching how to go about it. You'd spend time accounting for sick days or missed training days. You'd spend time adjusting with your available routes and situation. You read an article and now you just &lt;em&gt;have&lt;/em&gt; to adjust your training. You realize intervals aren't your jam and you prefer Fartleks. Enter AI.&lt;/p&gt;

&lt;p&gt;With AI, you can generate a structured plan very easily. Once the plan is set, making adjustments through conversations with AI is trivial. Making adjustments for sick days? Trivial. Ran a new PB and wanna adjust your plan? Trivial. Wanna track your workouts in a spreadsheet? AI will create one. Anything you'd wanna do is a brief text conversation away.&lt;/p&gt;

&lt;p&gt;My experience with this has been very positive. Feeding in my recent PBs, average heart rates, normal elevation load, goals, and preferences allowed me to build a plan in minutes. We're talking a focused training plan for a 50k complete with applicable strength training all in a convenient, annotated spreadsheet for tracking. I have had a couple sick days and some time off for Christmas which the AI (Claude in my case) handled perfectly. Tracking my fitness metrics in COROS and Strava shows marked improvements consistent with a quality training plan at my current training age that meets or exceeds previous more generic plans I was running (e.g.: Daniels' Running Formula) as well as my attempts at more targeted training. As long as you keep your thread going (or summarize / pass context into a new one), you essentially have &lt;a href="https://en.wikipedia.org/wiki/K%C3%ADlian_Jornet" rel="noopener noreferrer"&gt;Kilian Jornet&lt;/a&gt; as the butler for your training plan. While the real Killian would probably never do this, AI will (happily).&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%2F8baz1vo2ytzpcpsdn9hv.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%2F8baz1vo2ytzpcpsdn9hv.png" alt="A spreadsheet containing a training plan for a 50K" width="718" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently, a single cycle is all I'm running with. But, I am going to try a multi-year plan once my current one concludes and I get my race results. Needless to say, I'll be guinea-pigging it up in the back half of 2026 and either touting the awesomeness of AI or finding myself a real coach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These are just a couple of the ways I'm using AI personally to improve my life, do some professional development, and annoy / delight my loved ones. I've also had success scaling recipes, creating recipes from what I have on hand, and proofreading my writing. Truly, the sky is the limit here. AI is becoming more and more ubiquitous and learning how to engage with it and get benefits from it is likely to serve you well personally and professionally.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Fennel as Neovim Config</title>
      <dc:creator>Brandon Skinner</dc:creator>
      <pubDate>Sun, 04 Jan 2026 16:44:34 +0000</pubDate>
      <link>https://forem.com/mentalquill/fennel-as-neovim-config-3kin</link>
      <guid>https://forem.com/mentalquill/fennel-as-neovim-config-3kin</guid>
      <description>&lt;p&gt;One of my main goals during my end-of-year break was to update my crusty old Neovim config I copied from Vim ages ago into Lua. However, a random post I saw about &lt;a href="https://github.com/Olical/conjure" rel="noopener noreferrer"&gt;Conjure&lt;/a&gt; piqued my interest. Through a bit of research, I found out the plugin was written in &lt;a href="https://fennel-lang.org/" rel="noopener noreferrer"&gt;Fennel&lt;/a&gt;. Further, there were people both succeeding and failing to use Fennel to write their plugins and Neovim configurations. With curiosity at an all-time high and my love of Lisps thoroughly stoked, I decided to take a crack at moving my Neovim config to Fennel instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fennel?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Fennel is a programming language that brings together the simplicity, speed, and reach of Lua with the flexibility of a &lt;a href="https://en.wikipedia.org/wiki/Lisp_(programming_language)" rel="noopener noreferrer"&gt;Lisp syntax and macro system&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lisps are cool. Lua is cool. So by extension, Fennel is &lt;em&gt;really&lt;/em&gt; cool.&lt;/p&gt;

&lt;p&gt;The value prospect is simple: cross-compile to Lua. That simple idea has a lot of potential, especially since Lua is used in a lot of novel places. Now any Lua integration is a Fennel integration. From Neovim to game frameworks like &lt;a href="https://love2d.org/" rel="noopener noreferrer"&gt;LÖVE&lt;/a&gt;. It's pretty awesome.&lt;/p&gt;

&lt;p&gt;In Lisps, almost everything is an expression that resolves to a value. That simple concept lends itself well to being used for non-trivial configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  But how?
&lt;/h3&gt;

&lt;p&gt;Enter &lt;a href="https://github.com/Olical/nfnl" rel="noopener noreferrer"&gt;nfnl&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enhance your Neovim experience through Fennel with zero overhead. Write Fennel, run Lua, nfnl will not load unless you're actively modifying your Neovim configuration or plugin source code (nfnl-plugin-example, my Neovim configuration).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I won't bore you with all the details of the &lt;a href="https://github.com/Olical/nfnl/blob/main/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;. But two important notes for our purposes are:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Automatically compiles _.fnl files to _.lua when you save your changes.&lt;/li&gt;
&lt;li&gt;Compiles your Fennel code and then steps out of the way leaving you with plain Lua that doesn't require nfnl to load in the future.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;And it's as simple as banging a &lt;code&gt;{ "Olical/nfnl", ft = "fennel" }&lt;/code&gt; into your Lazy config and hitting a:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;shell&lt;/strong&gt;&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="s2"&gt;"{}"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/.config/nvim/.nfnl.fnl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that (and a proper Fennel install) .fnl files in your config directory cross-compile to their equivalent .lua files. One cool convenience is &lt;code&gt;~/.config/nvim/fnl&lt;/code&gt; directory compiles to &lt;code&gt;~/.config/nvim/lua&lt;/code&gt;, which is very handy. Under the hood, you're just running officially supported Lua in Neovim.&lt;/p&gt;

&lt;h3&gt;
  
  
  Okay... I need a bit more than that
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; I'm a Mac user. I will be using my normal commands and I leave finding equivalents as an exercise to the non-Mac-user and non-Homebrew-user readers. &lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;I also assume familiarity with the shell and that you are already rocking Lua in Neovim.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Happy to help!&lt;/p&gt;

&lt;p&gt;It's actually relatively easy and I modeled my approach after Oliver Caldwell's &lt;a href="https://github.com/Olical/dotfiles" rel="noopener noreferrer"&gt;dotfiles&lt;/a&gt;. To make this work as easily as possible, I recommend starting off just getting Lazy and nfnl up and running. To do so, you'll need to back everything up and then get the bootstrap going. Our basic blueprint is essentially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|_.config/
  |_ nvim/
    |_ .nfnl.fnl
    |_ init.lua
    |_ init.fnl
    |_ fnl/
      |_ config/
        |_ macros.fnl
      |_ plugins/
        |_ nfnl.fnl
    |_lua/
      |_ config/
        |_ lazy.lua
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  First things first
&lt;/h4&gt;

&lt;p&gt;To make things simple and avoid issues, we'll need a clean slate. To do so, you should just back up your nvim configuration. If you're already deep into Neovim configuration, you'll be able to bring what you want back later if you want to.&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;mv&lt;/span&gt; ~/.config/nvim ~/.config/nvim.bak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Secondly...
&lt;/h4&gt;

&lt;p&gt;Create the basic directories you need.&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.config/nvim/fnl/config ~/.config/nvim/fnl/plugins ~/.config/nvim/lua/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Third
&lt;/h4&gt;

&lt;p&gt;Create a couple of very similar Lua files:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;~/.config/nvim/init.lua&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Bootstrap lazy.nvim&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lazypath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="s2"&gt;"/lazy/lazy.nvim"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;fs_stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lazypath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lazyrepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://github.com/folke/lazy.nvim.git"&lt;/span&gt;
  &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s2"&gt;"git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"clone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"--filter=blob:none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"--branch=stable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lazyrepo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lazypath&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;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shell_error&lt;/span&gt; &lt;span class="o"&gt;~=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_echo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"Failed to clone lazy.nvim:\n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"ErrorMsg"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"WarningMsg"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Press any key to exit..."&lt;/span&gt; &lt;span class="p"&gt;},&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="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getchar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;os.exit&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="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rtp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;prepend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lazypath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- Setup lazy.nvim&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lazy"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="n"&gt;spec&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="s2"&gt;"Olical/nfnl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"fennel"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;-- automatically check for plugin updates&lt;/span&gt;
  &lt;span class="n"&gt;checker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;~/.config/nvim/lua/config/lazy.lua&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Bootstrap lazy.nvim&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lazypath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="s2"&gt;"/lazy/lazy.nvim"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;fs_stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lazypath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lazyrepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://github.com/folke/lazy.nvim.git"&lt;/span&gt;
  &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s2"&gt;"git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"clone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"--filter=blob:none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"--branch=stable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lazyrepo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lazypath&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;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shell_error&lt;/span&gt; &lt;span class="o"&gt;~=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_echo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"Failed to clone lazy.nvim:\n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"ErrorMsg"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"WarningMsg"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Press any key to exit..."&lt;/span&gt; &lt;span class="p"&gt;},&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="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getchar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;os.exit&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="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rtp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;prepend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lazypath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- Setup lazy.nvim&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lazy"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;-- import your plugins&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"plugins"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;-- automatically check for plugin updates&lt;/span&gt;
  &lt;span class="n"&gt;checker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference between them is subtle and boils down to &lt;code&gt;~/.config/nvim/lua/config/lazy.lua&lt;/code&gt; importing from the plugins directory rather than installing plugins directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;  &lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;-- import your plugins&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"plugins"&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;Which allows us (through the magic of nfnl) to simply create spec files in &lt;code&gt;~/.config/nvim/fnl/plugins&lt;/code&gt; and easily manage plugin installation and configuration in Fennel.&lt;/p&gt;

&lt;h4&gt;
  
  
  Fourth!!
&lt;/h4&gt;

&lt;p&gt;Now, in order to make the cutover smooth, we need to add our first spec. To do so, first we should create a simple macro to make our lives easier:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;~/.config/nvim/fnl/config/macros.fnl&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;;; fennel-ls: macro-file
;; [nfnl-macro]

;; Macros

(fn tx [&amp;amp; args]
  "Mixed sequential and associative tables at compile time. Because the Neovim ecosystem loves them but Fennel has no neat way to express them"
  (let [to-merge (when (table? (. args (length args)))
                   (table.remove args))]
    (if to-merge
      (do
        (each [key value (pairs to-merge)]
          (tset args key value))
        args)
      args)))

{: tx}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then the spec:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;~/.config/nvim/fnl/plugins/nfnl.fnl&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;(import-macros {: tx} :config.macros)

(tx "Olical/nfnl" {:ft "fennel"})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which should also be cross-compiled to &lt;code&gt;~/.config/nvim/lua/plugins/nfnl.lua&lt;/code&gt; if everything is running properly.&lt;/p&gt;

&lt;h4&gt;
  
  
  And finally...
&lt;/h4&gt;

&lt;p&gt;Now it's time to create a simple &lt;code&gt;init.fnl&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;~/.config/nvim/init.fnl&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;(require :config.lazy)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should also have access to &lt;code&gt;:NfnlCompileFile&lt;/code&gt; in Neovim when editing &lt;code&gt;.fnl&lt;/code&gt; files if everything is running properly.&lt;/p&gt;

&lt;p&gt;To complete the cutover, all you need to do is open &lt;code&gt;~/.config/nvim/init.fnl&lt;/code&gt; in Neovim, &lt;code&gt;rm ~/.config/nvim/init.lua&lt;/code&gt;, and then run &lt;code&gt;:NfnlCompileFile&lt;/code&gt;. With that, a new &lt;code&gt;init.lua&lt;/code&gt; cross-compiled from your init.fnl should be generated and your cutover is complete. &lt;code&gt;.fnl&lt;/code&gt; files you create and edit should now get cross-compiled to Lua which are then run directly in Neovim like normal.&lt;/p&gt;

&lt;p&gt;You can now move your old config pieces you want back in or rebuild with Fennel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can you show some examples?
&lt;/h3&gt;

&lt;p&gt;Certainly!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;~/.config/nvim/init.fnl&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;;;; Options
(set vim.g.mapleader " ")
(set vim.g.maplocalleader " ")
(set vim.o.termguicolors true)
(set vim.wo.number true)
(set vim.o.shiftwidth 4)
(set vim.o.softtabstop 4)
(set vim.o.expandtab true)

(require :config.lazy)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;~/.config/nvim/fnl/plugins/nvim-tmux-navigation.fnl&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;(import-macros {: tx} :config.macros)

(tx "alexghergh/nvim-tmux-navigation"
    {:config
    (fn []
      (let [nav (require :nvim-tmux-navigation)]
          (nav.setup
        {:disable_when_zoomed true
         :keybindings { :up :&amp;lt;C-k&amp;gt;
                :down :&amp;lt;C-j&amp;gt;
                :left :&amp;lt;C-h&amp;gt;
                :right :&amp;lt;C-l&amp;gt;
                :last_active :&amp;lt;C-\&amp;gt;
                :next :&amp;lt;C-Space&amp;gt;}})))})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;~/.config/nvim/fnl/plugins/surround.fnl&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;(import-macros {: tx} :config.macros)

(tx "kylechui/nvim-surround"
  {:event "VeryLazy"
   :opts {}
   :config
   (fn []
     (let [ns (require :nvim-surround)]
       (ns.setup {})))})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;~/.config/nvim/fnl/plugins/treesitter.fnl&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;(import-macros {: tx} :config.macros)

(vim.api.nvim_create_autocmd
  "FileType"
  {:pattern ["*"]
   :callback #(vim.schedule #(pcall #(vim.treesitter.start)))})

(tx
  "nvim-treesitter/nvim-treesitter"
  {:main :nvim-treesitter.configs
   :branch "main"
   :build ":TSUpdate"
   :config
   (fn []
     (let [ts (require :nvim-treesitter)
       languages [:query
        :clojure
        :vimdoc
        :gitattributes
        :gitcommit
        :regex
        :bash
        :markdown
        :markdown_inline
        :vim
        :lua
        :fennel]]
       (ts.install languages)))})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Anything else to watch for?
&lt;/h3&gt;

&lt;p&gt;Well, if you install Mason and such (highly recommend looking at &lt;a href="https://github.com/Olical/dotfiles/blob/main/stowed/.config/nvim/fnl/plugins/lsp.fnl" rel="noopener noreferrer"&gt;Olical's dotfiles&lt;/a&gt; for a cool LSP config) and you're using the Fennel language server for development, you're going to want to create a &lt;code&gt;flsproject.fnl&lt;/code&gt; file in order to avoid a lot of red in your editor:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;~/.config/nvim/flsproject.fnl&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;{:macro-path "fnl/config/macros.fnl"
 :library {:nvim true}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On top of that, the &lt;code&gt;vim&lt;/code&gt; global may be unknown. It still works fine but hitting a &lt;code&gt;(global vim vim)&lt;/code&gt; at the top is an easy workaround to get rid of the errors without having a negative effect.&lt;/p&gt;

&lt;p&gt;Another important tidbit worth reiterating is that Lua is still what's being run here. So if you need to use Lua, you can. One example in this article is our Lazy config which is also required from Fennel (and by extension our cross-compiled Lua) and works wonderfully.&lt;/p&gt;

&lt;p&gt;Which leads nicely into the final pitfall. You can only require files that are in Lua. The Fennel code doesn't actually run and if an accompanying Lua file is not generated, that code just doesn't exist and can't be used. Some Fennel constructs like macro files are a little different but by and large this rule runs true.&lt;/p&gt;

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

&lt;p&gt;And that's how you easily get up and running with Fennel for Neovim configurations. Mine still isn't where I'd necessarily like it and I'm iteratively improving it. Long term, I'll be building a simple &lt;a href="https://en.wikipedia.org/wiki/Domain-specific_language" rel="noopener noreferrer"&gt;DSL&lt;/a&gt; for composing my configuration. Information and help is a bit scant with running Fennel for Neovim configurations and plugins, but hopefully this helps other folks avoid the initial pitfalls I ran into.&lt;/p&gt;

&lt;p&gt;It's worth noting that there are a few options besides nfnl, like &lt;a href="https://github.com/Olical/aniseed" rel="noopener noreferrer"&gt;Aniseed&lt;/a&gt; and &lt;a href="https://github.com/udayvir-singh/tangerine.nvim" rel="noopener noreferrer"&gt;Tangerine&lt;/a&gt;. I tried them but didn't end up going with them because the simplicity of nfnl is awesome. After all is said and done, you get all the fun and benefits of Fennel but you're still just running native Lua in Neovim keeping everything nice and simple.&lt;/p&gt;

&lt;p&gt;There's also some configuration options for nfnl that are worth exploring to keep everything clean. Like only compiling from certain directories. I'll leave that to you if you're interested in exploring more.&lt;/p&gt;

</description>
      <category>neovim</category>
      <category>fennel</category>
      <category>vim</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
