<?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: Sebastian Tiedtke</title>
    <description>The latest articles on DEV Community by Sebastian Tiedtke (@sourishkrout).</description>
    <link>https://dev.to/sourishkrout</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%2F423328%2F56c19e86-7171-4336-a412-c963938dc2a7.png</url>
      <title>DEV Community: Sebastian Tiedtke</title>
      <link>https://dev.to/sourishkrout</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sourishkrout"/>
    <language>en</language>
    <item>
      <title>ENV vars are like needles in a haystack, aren't they?</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Wed, 11 Dec 2024 00:53:24 +0000</pubDate>
      <link>https://dev.to/sourishkrout/env-vars-are-like-needles-in-a-haystack-arent-they-4nob</link>
      <guid>https://dev.to/sourishkrout/env-vars-are-like-needles-in-a-haystack-arent-they-4nob</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/sourishkrout" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F423328%2F56c19e86-7171-4336-a412-c963938dc2a7.png" alt="sourishkrout"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/sourishkrout/owl-store-a-type-system-for-environment-variables-to-specify-resolve-and-verify-correctness-2pl" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Owl Store: A Type System for Environment Variables to Specify, Resolve, and Verify Correctness&lt;/h2&gt;
      &lt;h3&gt;Sebastian Tiedtke ・ Dec 10&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#opensource&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#computerscience&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devops&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Owl Store: A Type System for Environment Variables to Specify, Resolve, and Verify Correctness</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Tue, 10 Dec 2024 05:37:35 +0000</pubDate>
      <link>https://dev.to/sourishkrout/owl-store-a-type-system-for-environment-variables-to-specify-resolve-and-verify-correctness-2pl</link>
      <guid>https://dev.to/sourishkrout/owl-store-a-type-system-for-environment-variables-to-specify-resolve-and-verify-correctness-2pl</guid>
      <description>&lt;p&gt;Tired of copying secrets into GitHub/Gitlab every other day? Chasing down correct values for newly introduced ENV vars after git pull? Today, we are making these problems go away. Don't believe me? Read on.&lt;/p&gt;

&lt;p&gt;Introducing the 🦉 Owl Store, a concrete implementation of a Type System for Environment Variables that specifies, resolves, and verifies your environment's correctness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Start With A Demo
&lt;/h2&gt;

&lt;p&gt;The demo is a &lt;strong&gt;Poor Sebastian’s Vercel&lt;/strong&gt; to generate preview URLs for Runme's documentation. Here is what it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Dagger module that leverages the Docusaurus build&lt;/li&gt;
&lt;li&gt;To generate production-ready Nginx container image with the docs&lt;/li&gt;
&lt;li&gt;Pushes the image to GCP’s artifact registry&lt;/li&gt;
&lt;li&gt;Launches a Google Cloud Run instance and returns the Preview URL&lt;/li&gt;
&lt;li&gt;Transparently uses the Owl Store to resolve the services accounts to auth the GCP operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out this video:&lt;/p&gt;

&lt;p&gt;&amp;gt; The 🦉 Owl Store makes sure the Dagger function runs inside a valid environment&lt;/p&gt;

&lt;p&gt;You can run it yourself at home. It's self-contained using Dagger and requires minimal setup and a GCP account. It’s available inside Runme’s &lt;a href="https://github.com/stateful/docs.runme.dev" rel="noopener noreferrer"&gt;docs repo&lt;/a&gt;. All steps to get it up and running are documented in &lt;a href="https://github.com/stateful/docs.runme.dev/blob/main/dagger/README.md" rel="noopener noreferrer"&gt;README.md&lt;/a&gt;, which is itself a Runme notebook. Be sure to switch to Runme's &lt;a href="https://docs.runme.dev/installation/vscode#bleeding-edge-features" rel="noopener noreferrer"&gt;pre-release&lt;/a&gt;; otherwise, you won't see the &lt;code&gt;Env Store&lt;/code&gt; panel.&lt;/p&gt;

&lt;p&gt;Now, let's get into the details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is this hard?
&lt;/h2&gt;

&lt;p&gt;Getting environments “right” is no easy feat. Ask your developer: Docker, lock files, pipelines, and the elasticity of cloud computing resources have undoubtedly increased the reproducibility of environments across the software development lifecycle. Albeit with more tangible success in production(-like) environments. DevOps is all about the left shift; however, arguably, this shift is still miles apart from humans.&lt;/p&gt;

&lt;p&gt;A tell-tale sign I often encounter when talking to engineers in the field is having separate engineers/teams owning &lt;code&gt;Platform Engineering&lt;/code&gt; and &lt;code&gt;DevX&lt;/code&gt;. The idea is to provide narrow &lt;code&gt;git push&lt;/code&gt; interfaces to advance code out of development, which is resource-intensive enough to, at best, cover and support the critical path. It’s where uniformity of operational excellence (&lt;a href="https://12factor.net/" rel="noopener noreferrer"&gt;12factor&lt;/a&gt;) clashes with developers’ need for unconstrained creativity and experimentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crossing the Dev vs. Ops Chasm
&lt;/h2&gt;

&lt;p&gt;I have been pondering why we have yet to overcome the proverbial Dev vs. Ops chasm for several years now. During my time at Smallstep, I learned hands-on how powerful PKI-based strong identity (humans &amp;amp; workloads via OAuth &amp;amp; Workload Identity) is to moving to zero-trust security models (e.g., via &lt;a href="https://smallstep.com/blog/use-tls/" rel="noopener noreferrer"&gt;mTLS&lt;/a&gt; or &lt;a href="https://smallstep.com/blog/use-ssh-certificates/" rel="noopener noreferrer"&gt;SSH certificates&lt;/a&gt;) that liberate us from reliance on the of space-bound perimeters (Hi, VPCs!) to enforce secure computing in the cloud-native age.&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%2Fmedia.graphassets.com%2FkW8xUjrcQRKUAZFtdsnw" 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%2Fmedia.graphassets.com%2FkW8xUjrcQRKUAZFtdsnw" alt="Draw the Owl meme" width="800" height="642"&gt;&lt;/a&gt;&amp;gt; ENV-edition of the Draw the Owl meme&lt;/p&gt;

&lt;p&gt;I have come to the firm belief that Configuration and Secrets Management is what's holding us back. This is not because we haven’t made strides with Sealed Secrets, CloudKMS, Vault, and a slew of Cloud-certified Secret Managers that provide sophisticated ACLing mechanisms.&lt;/p&gt;

&lt;p&gt;It’s because we create JIRA tickets to generate, copy, and paste credentials to resources into GitHub/Gitlab or—close your 🙈 eyes and 🙉 ears now—paste them into Slack channels or Zoom chats. The available solutions aren’t rooted in strong cryptographic identity. They don't work the same for humans and workloads, which, if they did, would massively increase reproducibility and portability—unlocking Single Sign-On for Environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub/Gitlab: Take My Bargaining Chips
&lt;/h2&gt;

&lt;p&gt;This isn’t just time-intensive and error-prone; it makes third parties like GitHub, Gitlab, etc., our system of record. That’s something they love: more usage and more vendor lock-in. What an excellent way to give up all our bargaining chips. And now, we still haven’t solved the problem for developers in their environments, which requires bespoke solutions or running clusters locally. We wind up with spotty “project onboarding instructions,” which leave us with the challenge of figuring out how to draw the rest of the owl on our own—every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter the Owl Store 🦉
&lt;/h2&gt;

&lt;p&gt;As a bourbon-drinking armchair Computer Scientist myself, I spent quite some time dreaming up a solution to switch into building it earnestly well over a year ago. While still experimental, it’s closer to a beta than an alpha. There is an immense amount of ground to cover, so delivering an end-to-end experience was more important to me than going deep on any particular part. There will be bugs!&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%2Fmedia.graphassets.com%2F1TcHqx6fT3e0PghHyTrt" 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%2Fmedia.graphassets.com%2F1TcHqx6fT3e0PghHyTrt" alt="The Owl's simple command line interface" width="800" height="177"&gt;&lt;/a&gt;&amp;gt; The Owl's simple CLI to inspect stores&lt;/p&gt;

&lt;p&gt;While the Owl Store is fully integrated into Runme’s DevOps notebooks (which works well for demos), it’s remarkably self-contained. Given enough interest, I would love to spin it out as a standalone project. It's got a rudimentary CLI interface, which even lets you source a session's ENV vars into a running terminal session:&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%2Fmedia.graphassets.com%2Fek6N5fbR6S0eLURhKIXM" 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%2Fmedia.graphassets.com%2Fek6N5fbR6S0eLURhKIXM" alt="Source the contents of a store into a terminal session" width="800" height="194"&gt;&lt;/a&gt;&amp;gt; Source the Owl store snapshot into a terminal session&lt;/p&gt;

&lt;h2&gt;
  
  
  A Complete Solution That's Unfinished
&lt;/h2&gt;

&lt;p&gt;Please note that the Owl is a work in progress. While it illustrates a complete solution, it’s far from finished. Building it has helped unpack the series of unsolved problems along the way. The code is very pragmatic, prioritizing making it work and then making it right before making it concise/scaleable.&lt;/p&gt;

&lt;p&gt;A warning: If you expect another “Kubernetes API”, the Owl Store isn’t that. However, I’d love a Kubernetes Admission Controller that mounts secrets downstream. Get in touch. I have also looked at various technologies, including DirEnv, Nix, Infisical, Doppler Labs, Vault, Chezmoi, Teller, Cuelang, and Pulumi, all solving parts of the problem, to name a few. My main objection (applicable to end-to-end solutions) is that users have to adopt them wholesale, more often than not, handing over custody of their secrets and/or requiring SDKs that circumvent the treasured environment altogether.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blobs of KEY=VALUE Strings Running the World
&lt;/h2&gt;

&lt;p&gt;Configuration and Secret Management are a “death by papercuts” issue. It’s not “just” secrets; it’s all of configuration. While secrets are exponentially more complex, they are still "configured". Nothing works if your configuration is wrong. This is why the Owl Store gets to the mother of all configuration management challenges: The &lt;strong&gt;Correctness of Environment Variables&lt;/strong&gt;. Blobs of KEY=VALUE Strings are running the world!&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%2Fmedia.graphassets.com%2Fn1p9jx6bTM5ljcD4Yt4G" 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%2Fmedia.graphassets.com%2Fn1p9jx6bTM5ljcD4Yt4G" alt="Whoza Supabase" width="800" height="334"&gt;&lt;/a&gt;&amp;gt; Whoza self-hosted Supabase, so many vars&lt;/p&gt;

&lt;p&gt;Before debriefing the Owl’s implementation details, let's jump into an example. The goal is to paint a picture of how it works from a user’s perspective, using a sysadmin mindset and focusing on the Owl Store's visible parts that concern users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Good Luck Running a Monolith Locally
&lt;/h2&gt;

&lt;p&gt;Below is Stateful's Git repository containing the monolith running our &lt;a href="https://stateful.com/" rel="noopener noreferrer"&gt;Cloud product&lt;/a&gt;. With many third-party API integrations, the amount of environment configuration is substantial. However, 57 environment variables are actually on the low end for a monolith.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❌ Invalid Environment
&lt;/h2&gt;

&lt;p&gt;The Owl Store's UX clearly identifies how “incomplete” my environment’s variables are. &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%2Fmedia.graphassets.com%2FTQ1PJQDdROGv8M8fyt31" 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%2Fmedia.graphassets.com%2FTQ1PJQDdROGv8M8fyt31" alt="Invalid Environment" width="800" height="326"&gt;&lt;/a&gt;&amp;gt; The Owl's &lt;code&gt;Env Store&lt;/code&gt; pane will display invalid variables first&lt;/p&gt;

&lt;p&gt;More importantly, it does so securely, making me comfortable publishing screenshots. Concisely identifying the correctness gap in your environment variables is a tremendous boost in help.&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%2Fmedia.graphassets.com%2FbUmOCdMQQemSo2iL3fZp" 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%2Fmedia.graphassets.com%2FbUmOCdMQQemSo2iL3fZp" alt="CLI's view of the env store" width="800" height="479"&gt;&lt;/a&gt;&amp;gt; The same 'Env Store' snapshot is available via the CLI&lt;/p&gt;

&lt;p&gt;Even better, the Owl’s Env Store UI isn’t locked into a VS Code panel. Thanks to the Owl’s local-only APIs secured by mTLS, the same information is available on the CLI. Looking at this screenshot now, makes me want to color the invalid entries ❌ red. It's on the todo list.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Valid Environment
&lt;/h2&gt;

&lt;p&gt;Now, if your keen eye detected the commented-out resolution path in the upper left editor (above screenshots), let’s return those lines, reset the session (the Owl is a fully managed ENV store), and notice the difference.&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%2Fmedia.graphassets.com%2FgAh1x32oSiQpUkxnxaRH" 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%2Fmedia.graphassets.com%2FgAh1x32oSiQpUkxnxaRH" alt="Specify a resolution path" width="800" height="367"&gt;&lt;/a&gt;&amp;gt; Specifying a resolution path for the Environment&lt;/p&gt;

&lt;p&gt;Magic 🧙! Within seconds, there are no more unresolved ENV variables. The Owl Store now automatically resolved variables via GCP’s secret manager (see &lt;code&gt;[gcp:secrets]&lt;/code&gt;) using my &lt;a href="https://cloud.google.com/docs/authentication/application-default-credentials" rel="noopener noreferrer"&gt;Application Default Credentials&lt;/a&gt; (as in &lt;code&gt;auth: ADC&lt;/code&gt;) in the &lt;code&gt;platform-staging-413816&lt;/code&gt; project, which I previously put in place completing GCP’s OAuth flow. It does so quickly by applying simple transformations (see: &lt;code&gt;expr: [...] key | lower()&lt;/code&gt;) to the variable keys.&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%2Fmedia.graphassets.com%2FVpjT17QWSMW2K7rvvJDC" 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%2Fmedia.graphassets.com%2FVpjT17QWSMW2K7rvvJDC" alt="Valid Environment" width="800" height="233"&gt;&lt;/a&gt;&amp;gt; Based on the resolution path, the Owl will resolve unresolved variables&lt;/p&gt;

&lt;p&gt;It'd be easy to add triggering GCP's OAuth flow if no valid user credentials are available and/or resolve any other prerequisites that aren't met. Here are a few things to understand. Frankly, GCP's Secret Manager is very much low-hanging fruit. We are using it internally, and it is demoing well. Outside of it, though, AWS, Vault, webhooks, etc., or chaining any of these is possible. There is a lot of ground to cover. However, all the same principles apply.&lt;/p&gt;

&lt;h3&gt;
  
  
  Desired State: Description of Environment Variables
&lt;/h3&gt;

&lt;p&gt;This example vastly simplifies The Owl Store’s capabilities for demonstration purposes. We chose to reuse &lt;code&gt;DotEnv&lt;/code&gt; conventions to meet engineers where they are already.&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%2Fmedia.graphassets.com%2FDZaulQjTWuo5nXQdSS4O" 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%2Fmedia.graphassets.com%2FDZaulQjTWuo5nXQdSS4O" alt="ENV spec declarations leaned on .env.example" width="800" height="447"&gt;&lt;/a&gt;&amp;gt; Env Spec declarations leaned on commonplace .env.example or .env.sample&lt;/p&gt;

&lt;p&gt;The Owl will look for &lt;code&gt;.env.example&lt;/code&gt;, &lt;code&gt;.env.sample&lt;/code&gt;, or &lt;code&gt;.env.spec&lt;/code&gt; in the code repository's root, which declares the variable’s keys, a description, and an env spec (aka type). This is a slight variation of how &lt;code&gt;.env.example&lt;/code&gt; files are already being used, but the payoff is worth the while. We'll debrief this soon.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flexible Configuration Frontends
&lt;/h3&gt;

&lt;p&gt;In this example, the Owl’s configuration uses a Custom-Resource-Definition-like configuration frontend we usually see in the Kubernetes-world. However, internally the Owl uses a graph representation independent of any configuration frontend. I built the CRDs in a few hours, and they are far from final. Declarative YAML seemed a sensible choice for this example. It would be possible to give Javascript folks a &lt;code&gt;package.json&lt;/code&gt; way to do this, Rubyists a &lt;code&gt;DSL&lt;/code&gt;, Golang folks a &lt;code&gt;TOML&lt;/code&gt; file, or &lt;code&gt;SDKs&lt;/code&gt; for any language platform to configure any aspect of the Owl Store. More on this further below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multiple Resolution Paths &amp;amp; Mechanisms
&lt;/h3&gt;

&lt;p&gt;In this example, outside of built-in &lt;code&gt;.env.&lt;/code&gt; or &lt;code&gt;.env.local&lt;/code&gt; resolution (non-sensitive config), the CRD-specified value as per &lt;code&gt;path&lt;/code&gt; requires a hard-coded &lt;code&gt;project: platform-staging-413816&lt;/code&gt;. However, with the capability of the “rearrangeable” internal graph, it’s possible to have preceding nodes in the graph match a human or workload identity (e.g., GCP user or service-account) to a set of metadata, including &lt;code&gt;project&lt;/code&gt;, which downstream is used to resolve secrets in GCP’s secret manager. &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%2Fmedia.graphassets.com%2FB7A37VlQRDipnPDElkRG" 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%2Fmedia.graphassets.com%2FB7A37VlQRDipnPDElkRG" alt="Specifying a resolution path" width="800" height="315"&gt;&lt;/a&gt;&amp;gt; Specify a resolution path for the Owl; GCP Secrets in this case&lt;/p&gt;

&lt;p&gt;Instead of specifying a single path, running multiple in parallel is possible, and either the one that succeeds first wins or overwrites the other in a defined sequence. It's also possible to consider configuration backends, not just secret managers. What do you need?&lt;/p&gt;

&lt;h3&gt;
  
  
  Variable Visibility and Validation
&lt;/h3&gt;

&lt;p&gt;Your keen eyes have probably already identified a crucial part of what makes the Owl Store work: &lt;strong&gt;Spec Types&lt;/strong&gt;, e.g., &lt;code&gt;# Secret!&lt;/code&gt; Every Variable acquires a type. Unless specified otherwise, it defaults to &lt;code&gt;Opaque&lt;/code&gt;, which means it’s neither fully visible nor entirely hidden. One-click reveals the value in the UI. Other atomic spec types are &lt;code&gt;Secret&lt;/code&gt;, &lt;code&gt;Password&lt;/code&gt;, and &lt;code&gt;Plain&lt;/code&gt;.  When describing environment variables, you almost always focus on a small yet significant subset. And even without full coverage, secret keys in your shell profile are guarded sufficiently by defaulting to &lt;code&gt;Opaque&lt;/code&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%2Fmedia.graphassets.com%2FFjCuFjEzQ5uU98rCYGyO" 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%2Fmedia.graphassets.com%2FFjCuFjEzQ5uU98rCYGyO" alt="CRD-style Env Spec definition" width="800" height="466"&gt;&lt;/a&gt;&amp;gt; CRD-style Env Spec definition laying validation over visibility&lt;/p&gt;

&lt;p&gt;The Spec types &lt;code&gt;Secret&lt;/code&gt; and &lt;code&gt;Password&lt;/code&gt; are particular. Clear text values are never available in Owl's UI/UX. There is no API to expose them; they are intentionally masked, and the Owl makes no exceptions. Outside of the atomic spec types, it is possible to define custom types to layer validation on top of visibility for built-in security hygiene. More on that below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lifecycle over Time
&lt;/h3&gt;

&lt;p&gt;Another detail I wouldn’t want to be overlooked is the Owl Store's &lt;code&gt;Source&lt;/code&gt; column. There is a reason why the Owl’s CLI command to inspect the session’s store is called &lt;code&gt;... store snapshot&lt;/code&gt;: An Owl session’s internal graph stores the entire lifecycle of how a single variable is loaded, resolved, verified, mutated, removed, etc., over time. &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%2Fmedia.graphassets.com%2FuVLsLAI5QwCujW5eMZyB" 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%2Fmedia.graphassets.com%2FuVLsLAI5QwCujW5eMZyB" alt="Lifecycle tracking of variables" width="800" height="353"&gt;&lt;/a&gt;&amp;gt; The Owl store retains the entire lifecycle of variables, 'Source' shows the last recent mutation&lt;/p&gt;

&lt;p&gt;The store’s UI effectively nets a snapshot. The &lt;code&gt;Source&lt;/code&gt; column in this UI shows the last recent mechanism that mutated a value. This capability is essential because, unlike workloads, humans are interactive. Occasionally, it makes sense to manually provide the last unresolved value, e.g., the "god password," for the master database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactive Resolution
&lt;/h3&gt;

&lt;p&gt;For instance, a last-resort resolution could be to &lt;code&gt;prompt the user for input&lt;/code&gt; when a variable remains unresolved. Runme does precisely that. When it happens, the Owl Store will retain that variable &lt;code&gt;$XYZ&lt;/code&gt; was unresolved and transition to resolved when and by what mechanism. Moreover, if you ran &lt;code&gt;unset XYZ&lt;/code&gt; in a Runme notebook cell, it would record a deletion.&lt;/p&gt;

&lt;p&gt;Of course, if we'd run resolution for a workload, not a human, any variable's unresolved value would be considered an irrecoverable error and exit.&lt;/p&gt;

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

&lt;p&gt;Based on what’s covered in the example above, I will stipulate that Owl’s approach, with human ergonomics first, not just equips it with everything required to configure developer environments but workloads, e.g., CI/CD job, Services running in Kubernetes clusters, too. Running resolution for workloads is a vast simplification since "interactivity" in, e.g., a pipeline makes little sense. Of course, more development effort is required to expand Owl’s graph and integration capabilities to truly unlock this.&lt;/p&gt;

&lt;p&gt;I will also claim that Owl’s principles should be extended further up and downstream, e.g., by providing SDKs that, in code, provide type safety while generating Env Spec type declarations instead of maintaining them by hand. Or, Admission Controllers and GitHub Actions that would enable fully reproducing environments anywhere using identity and, at most, an environment identifier, e.g., &lt;code&gt;team5-staging-us-central1&lt;/code&gt;. This would make every developer's and operator's life much easier. Win-win!&lt;/p&gt;

&lt;p&gt;We need a full-featured tooling ecosystem around “Typed Environments”. The Owl Store 🦉 is precisely that.&lt;/p&gt;

&lt;p&gt;Let's look under the hood.&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the 🦉 Owl Store’s Hood
&lt;/h2&gt;

&lt;p&gt;The Owl Store brings type safety to the 1970s concept of ENV Vars. Remember the skeptics who thought Javascript didn’t need Typescript? Fair enough; don’t use it. The Owl Store is very similar. The Owl in a nutshell:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A smart Environment Store toolchain for humans &lt;strong&gt;and&lt;/strong&gt; workloads&lt;/li&gt;
&lt;li&gt;Specify, validate, and resolve environment variables anchored in strong identity&lt;/li&gt;
&lt;li&gt;Built-in security hygiene to make the right things easy and the wrong things hard&lt;/li&gt;
&lt;li&gt;Formal verification of “correctness” and opening doors for better tooling ecosystem&lt;/li&gt;
&lt;li&gt;All without requiring remote servers, backend APIs, or taking custody of your secrets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We took inspiration from the SSH Agent and the type system behind Typescript, which brings gradual type safety to Javascript. Despite using it daily, for the longest time, I had no clue &lt;a href="https://smallstep.com/blog/ssh-agent-explained/" rel="noopener noreferrer"&gt;how the SSH Agent worked&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%2Fmedia.graphassets.com%2FQaGop4H5QsShznPS8jJY" 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%2Fmedia.graphassets.com%2FQaGop4H5QsShznPS8jJY" alt="Local SSH Agent listing the loaded keys" width="800" height="188"&gt;&lt;/a&gt;&amp;gt; Local SSH Agent listing the loaded keys&lt;/p&gt;

&lt;p&gt;In the SSH Agent, once a private key is loaded, the only APIs available are signing, verifying, encrypting, and decrypting messages and signatures. Keys loaded in plain text can not be extracted as such; it's a one-way door. I can’t blame you if you don’t want to know how the SSH Agent works. It just does; you don’t have to. That’s the killer feature.&lt;/p&gt;

&lt;p&gt;Skipping a pro/con discussion about strong typing, TypeScript's key feature that inspired us is its ability to be adopted gradually. In the Owl's case, any workload's focus is only ever on a subset of the most important environment variables. Use as much of it as you want—no more, no less.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Importance of Strong Identity
&lt;/h3&gt;

&lt;p&gt;Anchoring Environments and their resolution on strong human/workload identity (OAuth, &lt;a href="https://github.com/stateful/linkerd-website/blob/main/.github/workflows/dx.yml#L17-L22" rel="noopener noreferrer"&gt;workload identity federation&lt;/a&gt;, etc.) allows us to decouple from third-party providers. Paired with containers, it makes switching public cloud resource providers (GitHub, AWS, GCP, etc) and/or secret backends (Vault, AWS/GCP Secret Manager, Cloud KMS, etc.) possible, enabling the Owl to stay out-of-band of secrets lifecycles. It unlocks free portability of both human and workload Environments (e.g. my laptop, a CDE in Codespaces, a CI/CD job, Kubernetes clusters running pods).&lt;/p&gt;

&lt;p&gt;The closest comparable technology I've seen is &lt;a href="https://www.pulumi.com/docs/esc/" rel="noopener noreferrer"&gt;Pulumi's ESC&lt;/a&gt;. However, it comes from an Infrastructure Management (IaC) angle and mandates Pulumi's proprietary backend. That's not bad per se; it's just different from the Owl Store's principles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redefining the Relationship between Workload, Repo, and Environment
&lt;/h2&gt;

&lt;p&gt;Looking at the ordinary lifecycle of any one ENV variable, they start existing by the sheer force of being used. Some programs, workloads/services, and scripts validate better and provide more documentation than others. However, when we are asked to provide values based on blank variable keys, it’s usually left up to the environment and its user. Either you copied the proper values into GitHub/Gitlab, specified them in a Kubernetes/Compose manifest, or had enough &lt;code&gt;-e KEY=VAL&lt;/code&gt; in your &lt;code&gt;docker run&lt;/code&gt; calls.&lt;/p&gt;

&lt;p&gt;Being a wise bird, the Owl wants a formal description of environment variables to become an essential part of every code repository. Outside of what the Owl does, this would reap the apparent benefits of Git workflows to track the evolution of environment specs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🦉 This is very important: Without the indirection of a code repository colocated &lt;code&gt;Environment Specification&lt;/code&gt;, we would merely perpetuate the practice of coupling environments to humans (&lt;code&gt;.dotfiles&lt;/code&gt;) or workloads (paste config into your pipelines/orchestrators). Docker decoupled app/runtime and system dependencies from machines. Let's finish the job by doing the same for Configuration and Secrets.&lt;/p&gt;
&lt;/blockquote&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%2Fmedia.graphassets.com%2FviP7k5kQNuwEe6CDKwE6" 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%2Fmedia.graphassets.com%2FviP7k5kQNuwEe6CDKwE6" alt="Golden triangle: Workload, Repo, and Environment" width="800" height="445"&gt;&lt;/a&gt;&amp;gt; Golden triangle: Workload, Repo, and Environment&lt;/p&gt;

&lt;p&gt;Whether or not leaning on &lt;code&gt;.env.example&lt;/code&gt; is the best solution here is debatable. However, these files are &lt;a href="https://sourcegraph.com/search?q=context:global+file:.env.example+or+file:.env.sample&amp;amp;patternType=keyword&amp;amp;sm=0" rel="noopener noreferrer"&gt;everywhere&lt;/a&gt; and effectively mirror what developers are already doing. And the Owl Store is neutral to how Env Specs are inserted into the graph. Currently, the only implementation is to declare variables in &lt;code&gt;.env.example&lt;/code&gt; using spec type annotations. I hope that Copilot or my future bespoke AI model can auto-complete the annotations for you. Optionally, to elevate the importance, one can rename &lt;code&gt;.env.example&lt;/code&gt; to &lt;code&gt;.env.spec&lt;/code&gt; to send a message that its role has been upgraded.&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%2Fmedia.graphassets.com%2F5wYTB3wzTjmOX5tt1y71" 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%2Fmedia.graphassets.com%2F5wYTB3wzTjmOX5tt1y71" alt="Anatomy of Env Spec declarations" width="800" height="267"&gt;&lt;/a&gt;&amp;gt; Anatomy of Env Spec declarations&lt;/p&gt;

&lt;p&gt;It’s not inconceivable to allow multiple ways, e.g., a CRD or an SDK, to declare ENV variables and reconcile them on Git pre-push. If ENV access from code used an Owl SDK, it’s not impossible to detect and/or generate missing spec type definitions and declarations accordingly. Better tooling, yay!&lt;/p&gt;

&lt;h3&gt;
  
  
  Declare Variables Spec Types via Annotations in &lt;code&gt;.env.example&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The anatomy of an environment variable’s Spec type and the resulting triplet is not unusual if you are no stranger to typing. The &lt;code&gt;!&lt;/code&gt; declares variables as required, which will both throw errors when unresolved and consider the variable for resolution (if they aren't &lt;code&gt;Secret&lt;/code&gt; or &lt;code&gt;Password&lt;/code&gt;). While not final, this is merely an implementation detail and felt suitable for demonstration purposes.&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%2Fmedia.graphassets.com%2FRX6OrrsNRoO1h4MszOmJ" 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%2Fmedia.graphassets.com%2FRX6OrrsNRoO1h4MszOmJ" alt="Anatomy of a single ENV var triplet" width="800" height="283"&gt;&lt;/a&gt;&amp;gt; Anatomy of a single ENV var triplet&lt;/p&gt;

&lt;p&gt;The Owl allows defining Custom Spec types which allow both grouping of atomic variables, e.g. &lt;code&gt;Redis&lt;/code&gt; = &lt;code&gt;REDIS_HOST!&lt;/code&gt; + &lt;code&gt;REDIS_PORT!&lt;/code&gt; + &lt;code&gt;REDIS_PASSWORD&lt;/code&gt;, and overlay validation on the atomic-level. E.g. making sure a variable’s value is valid &lt;code&gt;base64&lt;/code&gt;, &lt;code&gt;json&lt;/code&gt;, &lt;code&gt;jwt&lt;/code&gt;, &lt;code&gt;fqdn&lt;/code&gt;, etc. To forgo full turing-completeness (security) in validation, Golang's tag validator library and &lt;a href="https://github.com/go-playground/validator?tab=readme-ov-file#baked-in-validations" rel="noopener noreferrer"&gt;its baked-in tag validators&lt;/a&gt; are used. Below are more ideas on how to make validations more powerful and Env Spec types shareable.&lt;/p&gt;

&lt;p&gt;By the way, validation is not limited to "compile-time". It’s absolutely conceivable to check, e.g. a connection to a &lt;code&gt;Redis&lt;/code&gt; instance, with a single click in the Owl Store UI or TUI. Effectively delivering "runtime" checks on the edge of workloads, services, and scripts. Wouldn’t that be a great feather in the better tooling cap?&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%2Fmedia.graphassets.com%2FUhZXLGE7QlCcopTOjYCw" 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%2Fmedia.graphassets.com%2FUhZXLGE7QlCcopTOjYCw" alt="Proposed CRD-style config to define custom Env Spec types" width="800" height="663"&gt;&lt;/a&gt;&amp;gt; Proposed CRD-style config to define custom Env Spec types&lt;/p&gt;

&lt;p&gt;The idea behind these environment variable declarations is simple: Once you have two (name and spec type) out of the triplet, can you find the third? The demo shows this is possible based on contexts like authentication, authorization, metadata, the runtime machine/device/cluster, etc., and running down a resolution path in its respective graph.&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%2Fmedia.graphassets.com%2FNcgzk2tCS9q7elkTStHb" 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%2Fmedia.graphassets.com%2FNcgzk2tCS9q7elkTStHb" alt="Demystifying validation errors" width="800" height="106"&gt;&lt;/a&gt;&amp;gt; Demystifying validation errors&lt;/p&gt;

&lt;p&gt;Needless to say, it’s powerful to have immediate feedback if a value is absent, invalid, or an error occurs, accompanied by a descriptive error message. Since the Owl Store is fully local, feedback is immediate, making it a perfect fit for an engineer's inner loop while guarding direct access to sensitive values.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Graph Inside Out 🦉
&lt;/h2&gt;

&lt;p&gt;At the core of the Owl Store is a GraphQL-based graph. Now, forget everything you have ever heard about GraphQL APIs, specifically the latter part. The Owl Store leverages GraphQL for its capabilities to express typed graphs, it’s got an integral type system that transcends the boundaries of language platforms with clients available in every language, and it is battle-tested. &lt;/p&gt;

&lt;p&gt;I looked at all sorts of graph libraries, but GraphQL is the only one that checks all the boxes. I even have a rudimentary prototype of the Owl running on React—Preact, to be precise. It just wasn't as language platform neutral, and, let's be honest, how many frontend engineers do you see writing Environment Resolution React components? I'm still not "over" using &lt;code&gt;JSX&lt;/code&gt; as a configuration frontend, but even my days only have 24 hours, and again, are people going to use it?&lt;/p&gt;

&lt;p&gt;I have to admit what ultimately pushed GraphQL over the edge for me was getting wind of the folks at Dagger pushing forward on using GraphQL for &lt;code&gt;Cloak &amp;amp; Dagger&lt;/code&gt;. Wisdom of crowds! I had PoC’d the Owl Store in Javascript’s Apollo first but ultimately decided to implement it inside Runme’s Golang kernel. I'm not a strong Golang developer, so please apply puppy protection to my code. Copilot wrote all the error messages 🤖.&lt;/p&gt;

&lt;p&gt;So, if any of what comes next makes no sense to you, that’s totally okay. I won’t stop you from using the Owl Store. We will now look behind the Owl Store's curtains for those interested in the inner workings. I will also skip how Runme gets hold of Environment Variables since the concept of a managed Env Store is integral to Runme's markdown-based notebooks and universal task runner, with or without Owl Store.&lt;/p&gt;

&lt;h3&gt;
  
  
  GraphQL but no “Data API”
&lt;/h3&gt;

&lt;p&gt;Again, The Owl Store is no GraphQL API. It doesn’t even have a GraphQL endpoint to send queries to. It’s entirely air-gapped and only runs queries programmatically inside the core. Queries are exclusively generated.&lt;/p&gt;

&lt;p&gt;Unless you work on the Owl’s core, you never have to look, write, or understand the monstrosity of a serialized query against this graph. If you care about the abstract science behind it, all you need to know is that it works like a massive map-reduce operation where a map of &lt;code&gt;key/specs&lt;/code&gt;, &lt;code&gt;key/values&lt;/code&gt;, and contextual information such as e.g. GCP auth state is being passed down to every node traversing a query.&lt;/p&gt;

&lt;p&gt;The serialized queries (visually fantastic for debugging) grow infinitely to the right since nested nodes execute serially in a predictable sequence. It's just like calling what looks like "infinitely" nested Javascript callbacks. But again, there is no API for human consumption unless you are working on the core.&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%2Fmedia.graphassets.com%2FTx70ppGzSOyICAdBhHRd" 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%2Fmedia.graphassets.com%2FTx70ppGzSOyICAdBhHRd" alt="String-rendered Owl snapshot query" width="800" height="786"&gt;&lt;/a&gt;&amp;gt; String-rendered Owl snapshot query&lt;/p&gt;

&lt;p&gt;These queries are monstrous because I decided to err on making the Owl’s graph maximum expressive. For instance, unlike a GraphQL data API where errors usually happen "on the edges" processing data queries or mutations, the Owl store needs to represent “unresolved values” as defined "error states" inside the graph, not as an exception of data ingress or egressing. If an error happens on the GraphQL-level, something more fundamental went wrong, very likely a bug or an unhandled edge case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Space + Time + Chaining
&lt;/h3&gt;

&lt;p&gt;Space-time blows up the graph's size. The &lt;code&gt;key/value&lt;/code&gt; and &lt;code&gt;key/spec&lt;/code&gt; maps (not anywhere visible in the serialized queries; passed as GQL variables) can ingress and egress the graph to be fully de/-serialized in between. As mentioned, the Owl Store stores every mutation to ENV vars state and its metadata over time.&lt;/p&gt;

&lt;p&gt;This is like double-entry bookkeeping, where you can "net" a snapshot at any given point in time on a timeline. This allows us to answer other questions, such as about the lifecycle of how a variable was used. For instance, if a Runme notebook cell exports a variable &lt;code&gt;export NEW_VAR=123&lt;/code&gt;, the Owl Store will store a reference to the respective cell in its metadata.&lt;/p&gt;

&lt;p&gt;The capability to egress/ingress the graph makes it possible to chain infinite operations while collapsing the graph state into a snapshot and then ingressing the snapshot into a new graph. The resulting snapshots are virtually identical, and the new graph will no longer have access to previously collapsed history and start writing its own.&lt;/p&gt;

&lt;p&gt;A downside, which eventually needs refactoring, is that the GraphQL definitions are relatively simple when using GraphQL types (lots of &lt;code&gt;String&lt;/code&gt; no &lt;code&gt;Interfaces&lt;/code&gt;, etc.) and have not yet been fully modeled. It's easier to iterate on functionality before going deep on normalization. Strings are easy to de-/serialize.&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%2Fmedia.graphassets.com%2FsYh2ZFEnRLm3mGyv7qIf" 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%2Fmedia.graphassets.com%2FsYh2ZFEnRLm3mGyv7qIf" alt="String-rendered Owl resolve query" width="800" height="695"&gt;&lt;/a&gt;&amp;gt; String-rendered Owl resolve query&lt;/p&gt;

&lt;p&gt;To illustrate how egressing the graph to ingress the snapshot produced into a new graph, let's consider "resolution". Resolution is a query that runs upon constructing a new session and looks very similar to a regular snapshot with running validation twice (before and after) and a few extra nodes in between. Remember, programming the graph is a matter of rearranging its nodes in a different way that’s still valid. It's programmable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query Construction &amp;amp; Execution
&lt;/h2&gt;

&lt;p&gt;One aspect of modeling The Owl store around GraphQL fundamentals that’s been tremendously helpful is that it makes it possible to compartmentalize error state into a series of tiny steps and provide high-fidelity error message as opposed to a wholesale &lt;code&gt;bootstrap-all.sh&lt;/code&gt; that will attempt to do stand up an environment but randomly exits with &lt;code&gt;error: exit 1&lt;/code&gt; or something similar unhelpful. It’s what I call the AST-fication of complexity into tiny, explainable units.&lt;/p&gt;

&lt;p&gt;Remember, no queries in the Owl Store (unless for unit tests), are hand-written. Any query is an output of "mapping and reducing" an input into an output encoding, whether it's a CRD-like YAML or a GraphQL query or GraphQL produces another GraphQL query.&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%2Fmedia.graphassets.com%2F64Z0j0f7SU2D9SW7NIgm" 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%2Fmedia.graphassets.com%2F64Z0j0f7SU2D9SW7NIgm" alt="DotEnv loading expressed as query" width="800" height="379"&gt;&lt;/a&gt;&amp;gt; DotEnv loading expressed as example string-rendered query&lt;/p&gt;

&lt;p&gt;For instance, instead of hard-coding the sequence of how a &lt;code&gt;DotEnv&lt;/code&gt; loads, why not express it in a graph where the “client” can easily rearrange the nodes to change its behavior? Any error can be addressed as a distinct "unit of work".&lt;/p&gt;

&lt;p&gt;It's not unusual to have GraphQL queries return queries. I suppose what I’m describing here are the benefits of strongly-typed contracts. However, what's uniquely powerful in expressing the Owl Store's capabilities through a graph is a strikingly healthy balance between declarative abstractions and programmability. Anyways, I don't want to bore you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;Let us know what you think! The Owl Store is super early. It needs usage and more work to grow into its big promises. Get involved! The owl's code is &lt;a href="https://github.com/stateful/runme/tree/main/internal/owl" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Let's say the code is a bit chaotic. I'm more of a creative who likes solving painful problems than a 10x Golang engineer. Pull Requests are welcome, but more than anything, please try it out!&lt;/p&gt;

&lt;p&gt;Here are open questions that are on our minds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What do you like? What don't you like?&lt;/li&gt;
&lt;li&gt;What configuration frontends resonate? Declarative, SDKs, Queries?&lt;/li&gt;
&lt;li&gt;Are env spec declarations always the same across all Environments?&lt;/li&gt;
&lt;li&gt;Custom Env Spec type definitions are relatively new and are shoe-horned into the code. Refactor pending!&lt;/li&gt;
&lt;li&gt;We'd love to leverage Cuelang to define Spec types, validate them, and consider sharing via its module system&lt;/li&gt;
&lt;li&gt;Perhaps Cuelang can also play a role in layering overwrites commonplace in env configs?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get Involved
&lt;/h2&gt;

&lt;p&gt;Whoa, that was a lot.&lt;/p&gt;

&lt;p&gt;If you haven't used Runme yet, it's executable Notebooks for DevOps: &lt;a href="https://stateful.com/try" rel="noopener noreferrer"&gt;Click here&lt;/a&gt; to launch a DevOps Notebook inside your browser. Easier experienced than explained.&lt;/p&gt;

&lt;p&gt;Again, let us know if any of this interests you. You can find us on &lt;a href="https://discord.gg/runme" rel="noopener noreferrer"&gt;Runme’s Discord&lt;/a&gt;. Thank you!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>computerscience</category>
      <category>devops</category>
    </item>
    <item>
      <title>AWS/GCP/Azure Consoles, Embedded inside Your Docs</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Wed, 03 Jul 2024 16:38:54 +0000</pubDate>
      <link>https://dev.to/sourishkrout/awsgcpazure-consoles-embedded-inside-your-docs-1a3l</link>
      <guid>https://dev.to/sourishkrout/awsgcpazure-consoles-embedded-inside-your-docs-1a3l</guid>
      <description>&lt;p&gt;Today, the team is thrilled to release Runme v3.6, a significant milestone integrating the remaining crucial layer of DevOps and Infrastructure Operations. With Runme v3.6, you now have direct access to AWS/GCP/Azure Cloud Consoles inside your Markdown docs.&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%2Fmedia.graphassets.com%2F51Gh224XTim27qtiiRpC" 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%2Fmedia.graphassets.com%2F51Gh224XTim27qtiiRpC" alt="Yo! Cloud Consoles in Your Docs" width="622" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don't know Xzibit's TV show and the meme, watch this &lt;a href="https://www.youtube.com/watch?v=eeVZQNw5KRU" rel="noopener noreferrer"&gt;video&lt;/a&gt; (totally worth it)&lt;/p&gt;



&lt;p&gt;Yes, you read that right. Instead of having to log into your respective Public Cloud’s walled garden and find the resources you’re looking for, you can now make the Console UIs come to you whether you’re documenting an overview or specific VMs, NICs, VPCs, Services, or Clusters, you just “deep-link” the resource in your docs, which will render widgets for the Cloud resources fresh at the time of reading. You can even launch into everyday troubleshooting actions such as SSH sessions, start/stop VMs, pull up associated logs, or skim deployment manifests.&lt;/p&gt;


    
    


&lt;blockquote&gt;
&lt;p&gt;No need to log into AWS or GCP consoles: interactive cloud resources directly in your docs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Best of ClickOps Without Downsides
&lt;/h2&gt;

&lt;p&gt;The vertical integration of the terminal, editor, and browser with remote-hosted cloud resources makes Runme a perfect fit for documenting and operating your DevOps workflows through its intuitive notebook, editor, and command-line interfaces—all without the additional cost of running separate infrastructure and maintenance. Runme runs entirely locally; servers are optional. And, of course, it’s 100% compatible with your Infra As Code and GitOps.&lt;/p&gt;

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

&lt;p&gt;The idea is as simple as it is powerful. Go ahead and drop the cloud console’s URL/URI to a resource into a cell, click ▶️ and that’s it.&lt;/p&gt;


    
    


&lt;blockquote&gt;
&lt;p&gt;Drop a cloud resource’s URI/URL into a cell to render an interactive widget&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Runme’s Cloud-Native Bash Kernel runs cells containing Shell, Javascript, Python, Lua, PHP, etc., anything you could traditionally run via a shebang (e.g., &lt;code&gt;#!/usr/bin/ruby&lt;/code&gt;). However, what makes Runme specifically “Cloud-Native” is the capability to allow the deep-linking and real-time rendering of resources in AWS, GCP, Azure, etc., as interactive widgets inside your docs.&lt;/p&gt;



&lt;p&gt;These notebook cell-based widgets are W3C-standard &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components" rel="noopener noreferrer"&gt;Web Components&lt;/a&gt;, which make them reusable, extensible, and highly interactive, just like any web app. The resource’s information in the widget is never stale. At the minimum, it’s fresh from when the cell last ran, and where it makes sense, it even updates in real time.&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%2Fmedia.graphassets.com%2FaoT4tKTdu7bqILicfzAx" 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%2Fmedia.graphassets.com%2FaoT4tKTdu7bqILicfzAx" alt="W3C-Standard Web Components" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cloud resources widgets are built using Web Components (open W3C standard)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Access control to your Cloud accounts is entirely enforced by the respective Public Cloud’s officially published SDK. If you’re already using, let’s say, the AWS or GCP’s CLIs, you have no additional setup to get going.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigating Cloud Resources in Docs
&lt;/h2&gt;

&lt;p&gt;Of course, cloud deployments aren’t just a single resource. Instead, they are a cobweb of interlinked resources: VMs, NICs, VPCs, LBs, images, containers, pods, etc. Moreover, most resources provide heaps of metadata, operations one can perform (start, stop, login, backup, etc), and event and time-series logs. In the general UX, we strive to find a pragmatic balance between linking back to the Cloud Console and providing first-class UX support. This is a work in progress, and we’re looking for feedback.&lt;/p&gt;

&lt;p&gt;There are three general types of cloud resource widget interactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Expanding of Listings
&lt;/h3&gt;

&lt;p&gt;What’s excellent about rendering widgets for your cloud resources is that you can highly contextualize your docs. When you provide a listing of e.g. clusters or VMs, traversing into details is a single click away if they are e.g. part of a task or workflow description.&lt;/p&gt;


    
    


&lt;blockquote&gt;
&lt;p&gt;Add the detail view of a cluster with a single click&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Follow-up Actions on Resources
&lt;/h3&gt;

&lt;p&gt;Wherever it makes sense, the widgets will provide follow-up actions. Those are super handy for opening associated event logs and metrics, SSH-ing into machines, or starting/stopping VMS. The widgets largely mimic what’s available in the respective cloud console. Let us know if any resource is missing a desired action.&lt;/p&gt;


    
    


&lt;blockquote&gt;
&lt;p&gt;Easily navigate the cloud's cobweb of resources and associated actions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Zooming in and Out of Details
&lt;/h3&gt;

&lt;p&gt;Not every follow-up action expands into a new cell. Wherever it makes sense, it’s possible to navigate back and forth between listings/overviews and their details. Web Components allow for web app-like behavior, including routing between views.&lt;/p&gt;


    
    


&lt;blockquote&gt;
&lt;p&gt;Intuitively flip back and forth between overview and details&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Interpolation &amp;amp; Variables for Generic Docs
&lt;/h3&gt;

&lt;p&gt;While it’s powerful to deep-link concrete resources, sometimes you do want to distribute generic and parametrized docs. The cloud resource widgets transparently handle environment variables. Let’s say you wanted to generically list all VMs inside GCE in whatever project is currently set for your &lt;code&gt;gcloud&lt;/code&gt; CLI. Just use a shell expression to do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://console.cloud.google.com/compute/instances?project&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;gcloud config get project&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Needless to say, you can use variables set in previous cells in your ENV here for AWS EC2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;.console.aws.amazon.com/ec2/home?region&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="c"&gt;#InstanceDetails:instanceId=$EC2_INSTANCE_ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s all you need to know to get started. However, we put together an end-to-end example to illustrate the power of runnable docs built with Markdown.&lt;/p&gt;



&lt;h2&gt;
  
  
  Example Workflow Docs with Runme &amp;amp; Terramate
&lt;/h2&gt;

&lt;p&gt;Our friends at &lt;a href="https://terramate.io" rel="noopener noreferrer"&gt;Terramate&lt;/a&gt; have built a suite of tools to enable operating OpenTofu &amp;amp; Terraform IaCs at scale. We wanted to use the opportunity to showcase how IaC and DevOps notebooks perfectly combine to provide robust workflow documentation. The example repository, located at &lt;a href="https://github.com/stateful/runme-terramate-example" rel="noopener noreferrer"&gt;stateful/runme-terramate-example&lt;/a&gt;, is super easy to run yourself. Just follow the instructions running the &lt;code&gt;README.md&lt;/code&gt;. Here’s a quick video to illustrate how it works:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Unleash workflows with runnable &amp;amp; interactive documentation built with Markdown: &lt;a href="https://github.com/stateful/runme-terramate-example" rel="noopener noreferrer"&gt;https://github.com/stateful/runme-terramate-example&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Try It Now – Feedback Welcome
&lt;/h2&gt;

&lt;p&gt;While “Cloud Resources” could conceivably be anything from a Kubernetes cluster, a Vercel site, a Netlify deploy, a &lt;a href="https://docs.runme.dev/integrations/embed-github-action" rel="noopener noreferrer"&gt;GitHub Actions workflow&lt;/a&gt;, a Supabase database, or anything running in OpenStack, we wanted to start with the most popular public cloud use cases. However, please don’t hesitate to let us know what your Cloud/DevOps heart desires.&lt;/p&gt;

&lt;p&gt;Today’s release comes with beta support for a sub-selection of AWS &amp;amp; GCP cloud resources. Namely EC2 and EKS for AWS and GCE, GKE, and Cloud Run for GCP. We’re working on adding experimental Azure support right now. Needless to say, there is a lot of ground to cover, and existing renderers still need details to be fleshed out and overall polished. However, we wanted your feedback early, so we decided to release it now. Runme’s canonical examples are a good way to keep an eye on coverage as we continue unlocking better renderers. Please &lt;a href="https://docs.runme.dev/integrations/cloud-render/" rel="noopener noreferrer"&gt;read the docs&lt;/a&gt; and check out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS: &lt;a href="https://github.com/stateful/vscode-runme/tree/main/examples/aws" rel="noopener noreferrer"&gt;https://github.com/stateful/vscode-runme/tree/main/examples/aws&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GCP: &lt;a href="https://github.com/stateful/vscode-runme/tree/main/examples/gcp" rel="noopener noreferrer"&gt;https://github.com/stateful/vscode-runme/tree/main/examples/gcp&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Before you go, please give &lt;a href="https://github.com/stateful/runme/stargazers" rel="noopener noreferrer"&gt;&lt;strong&gt;Runme a ⭐️ Star&lt;/strong&gt;&lt;/a&gt; on GitHub and join &lt;a href="https://discord.gg/runme" rel="noopener noreferrer"&gt;Runme's Discord&lt;/a&gt; to let the Runme team know what you think. Thank you!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloud</category>
      <category>aws</category>
      <category>gcp</category>
    </item>
    <item>
      <title>Runme Gist: A Pastebin for Terminals Inside Your Docs</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Tue, 23 Apr 2024 16:29:21 +0000</pubDate>
      <link>https://dev.to/sourishkrout/runme-gist-a-pastebin-for-terminals-inside-your-docs-5h07</link>
      <guid>https://dev.to/sourishkrout/runme-gist-a-pastebin-for-terminals-inside-your-docs-5h07</guid>
      <description>&lt;p&gt;Pastebins make me nostalgic. I’m told they existed well before the web in the IRC days. The first notable one I remember, &lt;a href="http://pastebin.com/" rel="noopener noreferrer"&gt;Pastebin.com&lt;/a&gt;, was created in 2002 by &lt;a href="https://blog.dixo.net/" rel="noopener noreferrer"&gt;Paul Dixon&lt;/a&gt;, introducing features like syntax highlighting and private pastes. Believe it or not, it’s still going strong today. The latest incarnation I remember using recently was PostBin (clever: Pastebin for Webhooks). It made testing “web callbacks” remarkably easy.&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%2Fmedia.graphassets.com%2FKDAGveaQQGK0sOFiOirb" 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%2Fmedia.graphassets.com%2FKDAGveaQQGK0sOFiOirb" alt="Pastebin example" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Link: &lt;a href="https://pastebin.com/raw/HE0EcLUB" rel="noopener noreferrer"&gt;https://pastebin.com/raw/HE0EcLUB&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course, if you are using Git, you know GitHub’s Gist, which launched back in 2008. Despite technological advancements, Pastebin's core purpose remains the same: to share text or code snippets online. However, it has had its share of security lapses, particularly when unsuspecting users pasted credentials to share a public link via private channels. Just a heads up: Don't do that!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Search &lt;code&gt;runme&lt;/code&gt; in VS Code extension to install.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Runme Gists Are Masked 🎭 By Default
&lt;/h2&gt;

&lt;p&gt;Today, Runme unlocks the concept of a Pastebin for terminals inside your docs. Instead of reinventing wheels, we just combined GitHub Gists, which you likely already use, trust, and love, with Runme’s capabilities to run your Markdown documentation, capture outputs, and mask (best effort) sensitive data. No copy &amp;amp; paste and no other third party required.&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%2Fmedia.graphassets.com%2FOCYE1SxwSqmVx50YQdar" 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%2Fmedia.graphassets.com%2FOCYE1SxwSqmVx50YQdar" alt="WYSIWYG-Editing" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;WYSIWYG-editing ahead of Gist creation. Masked Gist: &lt;a href="https://gist.github.com/sourishkrout/5129f07b3acc00f44b7b04e741308298#file-gist-01hw40094tdkv7141fp619gghg-md" rel="noopener noreferrer"&gt;https://gist.github.com/sourishkrout/5129f07b3acc00f44b7b04e741308298&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Whether you’re running Bash commands, Python snippets, visualizing VMs running in &lt;code&gt;us-east-1&lt;/code&gt;, or running a query inside &lt;code&gt;BigQuery&lt;/code&gt;, Runme can securely capture masked (default; optional) “carbon copies” of working notebook sessions. These are incredibly useful for sharing with your team or for keeping a personal record. &lt;/p&gt;

&lt;p&gt;By default, Runme creates "Secret Gists" (aka unlisted) with best-effort masking enabled. Although masking can be easily toggled and manual redaction is supported ahead of Gist creation, we still advise you to be cautious when sharing your Gist links.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤖 No Copy &amp;amp; Paste and No Other Third Party
&lt;/h2&gt;

&lt;p&gt;Let’s see Runme Gists hosted inside your GitHub in action.&lt;/p&gt;


    
    


&lt;blockquote&gt;
&lt;p&gt;The demo video’s artifacts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Notebook: &lt;a href="https://github.com/stateful/vscode-runme/blob/main/examples/gist.md" rel="noopener noreferrer"&gt;https://github.com/stateful/vscode-runme/blob/main/examples/gist.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Masked: &lt;a href="https://gist.github.com/sourishkrout/5129f07b3acc00f44b7b04e741308298#file-gist-01hw40094tdkv7141fp619gghg-md" rel="noopener noreferrer"&gt;https://gist.github.com/sourishkrout/5129f07b3acc00f44b7b04e741308298&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Unmasked: &lt;a href="https://gist.github.com/sourishkrout/b175b3ed48715b3157a17b037add3282#file-gist-01hw40094tdkv7141fp619gghg-md" rel="noopener noreferrer"&gt;https://gist.github.com/sourishkrout/b175b3ed48715b3157a17b037add3282&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 Search &lt;code&gt;runme&lt;/code&gt; in VS Code extension to install.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Runme’s Gist feature seamlessly integrates into the notebook workflow. Activate &lt;code&gt;Auto-Save&lt;/code&gt; to capture outputs and run your notebook cells. Be sure to upgrade to Runme for VS Code &lt;code&gt;v3.4.0&lt;/code&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%2Fmedia.graphassets.com%2F5wDtXN5OQHSGmp4wfajH" 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%2Fmedia.graphassets.com%2F5wDtXN5OQHSGmp4wfajH" alt="Session Outputs View" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Session Outputs&lt;/code&gt; won’t show up unless &lt;code&gt;Auto-Save&lt;/code&gt; is enabled&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Complete running cells and be sure to finally save the notebook file whenever the file is marked unsaved. This will make sure to synchronize both the original notebook as well as the Session Outputs files. Click &lt;code&gt;Session Outputs&lt;/code&gt; to inspect the locally recorded session before, after, or in between, notebook runs. If you’re looking to record distinct sessions be sure to click &lt;code&gt;Reset Session&lt;/code&gt; in between.&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%2Fmedia.graphassets.com%2FDicrxTD0SUaVDETzvNPQ" 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%2Fmedia.graphassets.com%2FDicrxTD0SUaVDETzvNPQ" alt="Mask vs Unmask" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Toggle between &lt;code&gt;Masked&lt;/code&gt; and &lt;code&gt;Unmasked&lt;/code&gt; Session Outputs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Decide if you want your &lt;code&gt;Session Outputs&lt;/code&gt; to be optionally unmasked. The default is to mask sensitive information on a best-effort basis using the open-source &lt;a href="https://www.npmjs.com/package/data-guardian" rel="noopener noreferrer"&gt;data-guardian&lt;/a&gt; library. Since the library might not catch "everything," and you likely have specific criteria for what needs redaction, feel free to edit the Session Outputs file as necessary.&lt;/p&gt;

&lt;p&gt;Please note that the purpose of editing Session Outputs is to generate a Gist. Subsequent runs of the same session will overwrite manual edits, so use the &lt;code&gt;Reset Session&lt;/code&gt; function if you want to preserve prior results. Creating a GitHub Gist now is as simple as clicking on &lt;code&gt;Generate Gist&lt;/code&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%2Fmedia.graphassets.com%2FabhgEm5bSFiTdn4eQBqC" 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%2Fmedia.graphassets.com%2FabhgEm5bSFiTdn4eQBqC" alt="Generate Runme Gist" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Link to Gist: &lt;a href="https://gist.github.com/sourishkrout/9c079a68fc0801a6bf7fe8a71366dd63#file-bigquery-01hw5jp6e6v0aa496gxc5a327c-md" rel="noopener noreferrer"&gt;https://gist.github.com/sourishkrout/9c079a68fc0801a6bf7fe8a71366dd63&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Runme will first prompt you to log into your GitHub account and grant write access to your Gists. After successful login, it will display a notification containing a link to the Runme Gist hosted inside your GitHub.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Search &lt;code&gt;runme&lt;/code&gt; in VS Code extension to install.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Runme Gist 🤩 Inside Your GitHub
&lt;/h2&gt;

&lt;p&gt;The link is generated as "Secret Gist" which, as long as you keep the link private, will stay private. As always, think twice before sharing.&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%2Fmedia.graphassets.com%2Ft0n8P37iRKSc7VHpcspF" 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%2Fmedia.graphassets.com%2Ft0n8P37iRKSc7VHpcspF" alt="Generated Gist" width="800" height="722"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Link to Gist: &lt;a href="https://gist.github.com/sourishkrout/9c079a68fc0801a6bf7fe8a71366dd63#file-bigquery-01hw5jp6e6v0aa496gxc5a327c-md" rel="noopener noreferrer"&gt;https://gist.github.com/sourishkrout/9c079a68fc0801a6bf7fe8a71366dd63&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  That’s it 💪
&lt;/h2&gt;

&lt;p&gt;Congrats! Save, share, and collaborate with your team. Needless to say, it is also entirely possible to keep the Session Output files offline and local. Read about it &lt;a href="https://runme.dev/blog/runme-v3-pipeline-logs-and-artifacts" rel="noopener noreferrer"&gt;here&lt;/a&gt;. While you're here, please give &lt;a href="https://github.com/stateful/runme/stargazers" rel="noopener noreferrer"&gt;Runme a ⭐️ Star&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;p&gt;If you desire tighter control to govern access and visibility for these useful DevOps workflows and artifacts features inside your teams, please check out &lt;a href="https://stateful.com/" rel="noopener noreferrer"&gt;Stateful&lt;/a&gt;, the platform built around Open Source Runme.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Search &lt;code&gt;runme&lt;/code&gt; in VS Code extension to install.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>devops</category>
      <category>cloud</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>BranchGPT: The AI-Powered Solution to Personalized Branch Names</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Mon, 15 May 2023 17:36:14 +0000</pubDate>
      <link>https://dev.to/sourishkrout/branchgpt-the-ai-powered-solution-to-personalized-branch-names-5dmf</link>
      <guid>https://dev.to/sourishkrout/branchgpt-the-ai-powered-solution-to-personalized-branch-names-5dmf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;💡 TL;DR: Yes, BranchGPT is an attempt to -Tongue-in-cheek- take AI over the top. However, while its utility is questionable, it is enjoyable, like a game. If that's not for you: fair enough. You don't have to use it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;“There are only two hard things in Computer Science: Cache invalidation, naming things, and off-by-1 errors”. Whoever originally coined this quote wasn’t particularly exhaustive, but undoubtedly speaks the truth. It’s incredible how seemingly easy tasks turn out to be the hardest.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why BranchGPT?
&lt;/h1&gt;

&lt;p&gt;Experimentation with OpenAI's API led us to experiment with branch naming. A repo’s branch namespace is global, so giving a git branch a descriptive name is no exception. Issue trackers often provided shortcuts to generate branch names from JIRA or GitHub issue titles but with questionable success. The results are perhaps remarkable for uniformity but often generate comically long names wrapping multiple lines.&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%2Fmedia.graphassets.com%2FQmXemYZkSg2HLTGy9Qla" 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%2Fmedia.graphassets.com%2FQmXemYZkSg2HLTGy9Qla" alt="AI-powered Branch Names" width="800" height="671"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Jump right in with: &lt;code&gt;$ runme branchGPT&lt;/code&gt; (install via &lt;a href="https://github.com/stateful/vscode-runme/blob/main/examples/branchGPT.md" rel="noopener noreferrer"&gt;Homebrew or Scoop&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So what is a good, high-quality branch name? Do they matter since more contextual metadata goes into Pull Requests? In my mind, that’s a wildly subjective question. Here are some conventions devs are using:&lt;/p&gt;

&lt;h2&gt;
  
  
  The Prolific Prefixer 🤓
&lt;/h2&gt;

&lt;p&gt;Prefixes come in different flavors. Work type description of what goes into a branch or nickname prefix to reduce ambiguity. Using a forward-slash &lt;code&gt;/&lt;/code&gt; as a separator is an established convention. Some examples: &lt;code&gt;admc/graph-colors&lt;/code&gt;, &lt;code&gt;seb/exp-prophet&lt;/code&gt;, &lt;code&gt;feat/replace-tink-with-cryptography&lt;/code&gt;, &lt;code&gt;chore/upgrade-deps-for-next-lts&lt;/code&gt;, &lt;code&gt;chore/eslint&lt;/code&gt;, &lt;code&gt;hotfix/631-prod&lt;/code&gt;. Using multiple prefixes, e.g., &lt;code&gt;seb/experiment/prophet&lt;/code&gt;, is not unheard of.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tireless Terser 💂‍♀️
&lt;/h2&gt;

&lt;p&gt;Ideally, just one word, but no more than two. Examples are: &lt;code&gt;fastapi&lt;/code&gt;, &lt;code&gt;ingress&lt;/code&gt;, &lt;code&gt;sharing&lt;/code&gt;, &lt;code&gt;rollups&lt;/code&gt;, &lt;code&gt;score-break&lt;/code&gt;, &lt;code&gt;gtag-fix&lt;/code&gt;, &lt;code&gt;vanilla&lt;/code&gt;, &lt;code&gt;demo&lt;/code&gt;. You get the point. Keep it short and straightforward. Likely this convention won’t scale in a large mono-repo and without recycling the same branch name numerous times.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ruthless Referencer 🥷
&lt;/h2&gt;

&lt;p&gt;Dependabot loves doing this. Stick as much referentially information, like JIRA or GitHub issue IDs, full titles, version numbers, etc., into the branch name. No matter how bulky. Humans do it too; look at these &lt;code&gt;277-update-breaks-score-contributor-to-be-consistent-with-others&lt;/code&gt;, &lt;code&gt;ENG-422-open-vsx-stable-release&lt;/code&gt;, &lt;code&gt;CORE-13128-retry-screen-for-password-recovery-flow-loops-endlessly&lt;/code&gt;. While the shorter ones are more common, folks don’t hesitate to generate branch names that easily exceed 150 characters.&lt;/p&gt;

&lt;h1&gt;
  
  
  Close to Home is Better
&lt;/h1&gt;

&lt;p&gt;There are even more. However, here’s the kicker: there is &lt;strong&gt;no universally best convention&lt;/strong&gt; to branch names!&lt;/p&gt;

&lt;p&gt;You could argue that the right balance between minimum descriptive, not too short, and not too long is the way to go. However, it inevitably depends on your repos, team, and personal preferences. What universally holds is that the best branch names are the ones that &lt;strong&gt;feel natural and familiar to you&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you had your Pull Requests merged before, you might already be recording information in your git log so that a Transformer AI model, namely GPT, can harness to suggest branch names for you. A merge commit is just about perfect (see further below) to seed the layout of your branches.&lt;/p&gt;

&lt;h1&gt;
  
  
  Enter BranchGPT
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://runme.dev/api/runme?repository=https://github.com/stateful/vscode-runme.git&amp;amp;fileToOpen=examples/branchGPT.md" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbadgen.net%2Fbadge%2FRun%2520this%2520%2FDemo%2F5B3ADF%3Ficon%3Dhttps%3A%2F%2Frunme.dev%2Fimg%2Flogo.svg" width="102" height="20"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is why we’ve built this handy integration between your branches and OpenAI’s GPT3/4 for you. Perhaps call it &lt;strong&gt;BranchGPT&lt;/strong&gt;… for no apparent reason 😉. Yes, I am trying to take AI over the top.&lt;/p&gt;

&lt;p&gt;The idea is simple and surprisingly effective. Just enter a free-flow description of what you’re working on and let BranchGPT come back with some suggestions. If you can’t think of a good example for testing. There’s always &lt;a href="https://twitter.com/iamdevloper" rel="noopener noreferrer"&gt;@iamdevloper&lt;/a&gt; on Twitter to help you out:&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%2Fmedia.graphassets.com%2FVSXsCXLTQG9st8rfigRu" 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%2Fmedia.graphassets.com%2FVSXsCXLTQG9st8rfigRu" alt="@iamdevloper" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tweet here: &lt;a href="https://twitter.com/iamdevloper/status/1609848459489599489" rel="noopener noreferrer"&gt;https://twitter.com/iamdevloper/status/1609848459489599489&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s May 2023, so it's just about the “last call” to update the website’s 2022 footer! Drop the loose description into BranchGPT, and voilà, you’ll be presented with a list of suggestions that should ideally look strangely familiar. Check out this demo below; &lt;code&gt;$ runme branch&lt;/code&gt; will do if you find &lt;code&gt;branchGPT&lt;/code&gt; too long.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 By the way, &lt;code&gt;runme&lt;/code&gt; will prompt you to log in with your GitHub to create an account (&lt;a href="https://stateful.com/privacy" rel="noopener noreferrer"&gt;privacy policy&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;


  
  


&lt;blockquote&gt;
&lt;p&gt;Both length and &lt;code&gt;seb/&amp;lt;description-goes-here&amp;gt;&lt;/code&gt; feel familiar using my usual layout.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Adding Some Polish
&lt;/h2&gt;

&lt;p&gt;Suppose the suggestions aren’t quite ready. It’s straightforward to toggle the prefix in the branchGPT terminal UI, just hit &lt;code&gt;t&lt;/code&gt; to toggle prefixes. Similarly, the &lt;code&gt;e&lt;/code&gt; key will transition the selected entry into edit mode to allow putting the final touches on it.&lt;/p&gt;


  
  


&lt;blockquote&gt;
&lt;p&gt;Toggle prefixes with &lt;code&gt;t&lt;/code&gt; and edit the selected entry with &lt;code&gt;e&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Under the hood, BranchGPT processes the context repo’s Merge Commits. Starting with the configured git users’ personal merge commits. If there aren’t any, it will fall back to all available merge commits in the repo before using a fixed list. The latter will produce suggestions that will feel the least personalized.&lt;/p&gt;

&lt;p&gt;Why Merge Commits? Check out the example listing below. You will recognize how commit messages encode branch names (with GitHub org prefix) alongside textual descriptions. Just about perfect for seeding data for a GPT prompt backed by OpenAI’s &lt;code&gt;curie&lt;/code&gt; engine. &lt;code&gt;Curie&lt;/code&gt; provides a fair tradeoff between capabilities and cost.&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%2Fmedia.graphassets.com%2FojKkuBhkSMK60Y0rO6mq" 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%2Fmedia.graphassets.com%2FojKkuBhkSMK60Y0rO6mq" alt="Sebastian's git merge commits" width="800" height="803"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The list is usually longer; however, shortened for brevity&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Outside of authentication, basic rate-limiting, pre- and post-processing, and checking all implementation boxes on OpenAI’s API guidelines, that’s it. We hope you’ll like it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Wishlist
&lt;/h2&gt;

&lt;p&gt;BranchGPT came out of experimentation, and I'd consider it alpha software. A few things I wish we could have added in this version but time's limited:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Close the feedback loop on suggestion edits. We chose to keep it simple and treat all data as ephemeral.&lt;/li&gt;
&lt;li&gt;A fine-tuned model for generic branch suggestions that lack a list of personal/repo merge commits.&lt;/li&gt;
&lt;li&gt;Leverage models that derive branch names from code diffs. It’s too common to come up with a branch name after coding and when ready to create the PR—been meaning to look into &lt;a href="https://carper.ai/diff-models-a-new-way-to-edit-code/" rel="noopener noreferrer"&gt;https://carper.ai/diff-models-a-new-way-to-edit-code/&lt;/a&gt; and other models.&lt;/li&gt;
&lt;li&gt;Choose the GitHub issue to be copied into the prompt from a list of issues assigned to you.&lt;/li&gt;
&lt;li&gt;UX Integration into Runme’s &lt;a href="https://marketplace.visualstudio.com/items?itemName=stateful.runme" rel="noopener noreferrer"&gt;VS Code Extension&lt;/a&gt;. Let us know if this is something you want.&lt;/li&gt;
&lt;li&gt;Experiment with a chat-like UX. We had built this experiment before the release of chatGPT’s APIs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, go ahead and take BranchGPT for a spin. Please be a good citizen. The APIs are running under our OpenAI account (including footing the bill), and we intend to continue making BranchGPT available to the community with our best efforts. Thank you!&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="nv"&gt;$ &lt;/span&gt;scoop bucket add stateful https://github.com/stateful/scoop-bucket.git &lt;span class="c"&gt;# on Windows&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;scoop &lt;span class="nb"&gt;install &lt;/span&gt;stateful/runme&lt;span class="p"&gt;;&lt;/span&gt; runme branchGPT
  &lt;span class="c"&gt;# or&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;stateful/tap/runme &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; runme branchGPT &lt;span class="c"&gt;# on macOS (homebrew)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Full install &lt;a href="https://github.com/stateful/runme/releases/latest" rel="noopener noreferrer"&gt;instructions here&lt;/a&gt;. Note that &lt;code&gt;runme branch&lt;/code&gt; and &lt;code&gt;runme branchGPT&lt;/code&gt; are the same.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Closing Thoughts
&lt;/h1&gt;

&lt;p&gt;Writing this post, one question I wish I had more color on: Do Merge Commits have a bad rep? Most folks I have asked sorted into the &lt;code&gt;Squash &amp;amp; Merge™️&lt;/code&gt; or &lt;code&gt;Rebase &amp;amp; Merge™️&lt;/code&gt; camps. Who else appreciates Merge Commits? Just me? Tell us &lt;a href="https://discord.gg/runme" rel="noopener noreferrer"&gt;on Discord&lt;/a&gt; or ask about a feature request. For more content like this, please subscribe to &lt;a href="https://stateful.com/newsletter" rel="noopener noreferrer"&gt;our email updates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hopefully, BranchGPT will make you like Merge Commits more 😆.&lt;/p&gt;

</description>
      <category>git</category>
      <category>showdev</category>
      <category>bash</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Extension to directly run code blocks from your markdown editor</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Thu, 27 Apr 2023 19:54:35 +0000</pubDate>
      <link>https://dev.to/sourishkrout/extension-to-directly-run-code-blocks-from-your-markdown-editor-31oc</link>
      <guid>https://dev.to/sourishkrout/extension-to-directly-run-code-blocks-from-your-markdown-editor-31oc</guid>
      <description>&lt;p&gt;Makes it straightforward to execute blocks directly inside the editor. And, what's even more convenient is that any changes made to the environment stay with successive runs.&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%2F5fdppvoqkoezx3ia5krg.gif" 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%2F5fdppvoqkoezx3ia5krg.gif" alt="Run code blocks" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Search "runme" in the Extensions tab or &lt;a href="https://marketplace.visualstudio.com/items?itemName=stateful.runme" rel="noopener noreferrer"&gt;install here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let me know what you think! Read more about the feature in the docs: &lt;a href="https://runme.dev/docs/features#run-a-command-block" rel="noopener noreferrer"&gt;https://runme.dev/docs/features#run-a-command-block&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>opensource</category>
      <category>beginners</category>
      <category>devops</category>
    </item>
    <item>
      <title>Visually explore OpenAI's Image APIs without coding custom UI</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Wed, 19 Apr 2023 01:56:39 +0000</pubDate>
      <link>https://dev.to/sourishkrout/simple-curl-shell-for-ai-image-editing-40pa</link>
      <guid>https://dev.to/sourishkrout/simple-curl-shell-for-ai-image-editing-40pa</guid>
      <description>&lt;p&gt;While chatGPT has been all the craze, OpenAI’s underlying APIs offer much more. Outside of GPT4, the core piece to chatGPT, OpenAI provides AI Image-Generation APIs under the DALL-E umbrella.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 OpenAI’s description: DALL·E 2 is an AI system that can create realistic images and art from a description in natural language. 👉 &lt;a href="https://openai.com/product/dall-e-2" rel="noopener noreferrer"&gt;https://openai.com/product/dall-e-2&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These APIs are plain amazing…! They allow you to take an existing image and describe in words what edits you’d like the AI to make for you. It's like magic!&lt;/p&gt;

&lt;h2&gt;
  
  
  🙌 No UI Coding Required
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbcj4mq14q747mm3geve.gif" 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%2Fvbcj4mq14q747mm3geve.gif" alt="Edit image using words via AI" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Edit a ball pit into the image? Easy!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can learn how to use DALL-E's APIs without writing custom code. We'll showcase this using Runme, which lets you create Markdown notebooks with interactive Shell commands, similar to Jupyter for Python.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🛠 Please give Runme a spin, &lt;a href="https://marketplace.visualstudio.com/items?itemName=stateful.runme" rel="noopener noreferrer"&gt;install here&lt;/a&gt; or search &lt;code&gt;runme&lt;/code&gt; inside VS Code&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My dog Luna 🐕 offered to help us make our point! Right below, you’ll see Luna at a doggy friend’s birthday party in real life. All we’re using is a simple scene prompt: “&lt;em&gt;a happy german shepherd dog surrounded by cheeseburgers&lt;/em&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%2Fmedia.graphassets.com%2Fcy7fRH1QtmWcmrLUDZDz" 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%2Fmedia.graphassets.com%2Fcy7fRH1QtmWcmrLUDZDz" alt="Original image of Luna" width="384" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Unedited image of Luna&lt;/p&gt;
&lt;/blockquote&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%2Fmedia.graphassets.com%2FS1rxizxmRxyX0XmfTAV9" 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%2Fmedia.graphassets.com%2FS1rxizxmRxyX0XmfTAV9" alt="Luna with faux cheeseburgers" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No way Luna would sit this calmly if those cheeseburgers were real 🤭&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  👩‍💻 Try It Yourself
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://runme.dev/api/runme?repository=https%3A%2F%2Fgithub.com%2Fsourishkrout%2Floon.git&amp;amp;fileToOpen=AI.md" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbadgen.net%2Fbadge%2FOpen%2520with%2FRunme%2F5B3ADF%3Ficon%3Dhttps%3A%2F%2Frunme.dev%2Fimg%2Flogo.svg" width="115" height="20"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Head to &lt;a href="https://platform.openai.com/" rel="noopener noreferrer"&gt;https://platform.openai.com/&lt;/a&gt; to get an API key and follow our Runme notebook. Depending on how much you plan on using the API, OpenAI puts a limit on its free tier.&lt;/p&gt;

&lt;p&gt;The repo with the notebook is available here: &lt;a href="https://github.com/sourishkrout/loon" rel="noopener noreferrer"&gt;https://github.com/sourishkrout/loon&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%2Fmedia.graphassets.com%2FU00yeJ56RU6VsBKeKbcs" 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%2Fmedia.graphassets.com%2FU00yeJ56RU6VsBKeKbcs" alt="Runme notebook for AI image editing" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🖥 Skip The Notebook, Use The CLI
&lt;/h2&gt;

&lt;p&gt;If you live in the terminal, use the &lt;a href="https://runme.dev/docs/cli" rel="noopener noreferrer"&gt;Runme CLI&lt;/a&gt; instead. After you clone the repo, drop your &lt;code&gt;OPENAI_API_KEY=&amp;lt;super secret&amp;gt;&lt;/code&gt; into your environment. Then, do this:&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="nv"&gt;$ &lt;/span&gt;runme run &lt;span class="nt"&gt;--filename&lt;/span&gt; AI.md install-deps
&lt;span class="nv"&gt;$ &lt;/span&gt;runme run &lt;span class="nt"&gt;--filename&lt;/span&gt; AI.md run-scene | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;".data[0]"&lt;/span&gt; &lt;span class="c"&gt;# btw, output URL expires&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"url"&lt;/span&gt;: &lt;span class="s2"&gt;"https://oaidalleapiprodscus.blob.core.windows.net/private/org-tm5BAbynhBsE9Lzy1HTD6sk0/user-7A9nqIQ8tVXN7epnIqZs6fca/img-Hc1KHk6lkJegAkMqUWSL9D0i.png?st=2023-04-18T13%3A56%3A07Z&amp;amp;se=2023-04-18T15%3A56%3A07Z&amp;amp;sp=r&amp;amp;sv=2021-08-06&amp;amp;sr=b&amp;amp;rscd=inline&amp;amp;rsct=image/png&amp;amp;skoid=6aaadede-4fb3-4698-a8f6-684d7786b067&amp;amp;sktid=a48cca56-e6da-484e-a814-9c849652bcb3&amp;amp;skt=2023-04-18T11%3A36%3A32Z&amp;amp;ske=2023-04-19T11%3A36%3A32Z&amp;amp;sks=b&amp;amp;skv=2021-08-06&amp;amp;sig=9oEyq1os4zwf6rvb67W1rPDkTsPd%2BZ%2B1VHi/gWaz17M%3D"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most terminal emulators will allow you to click the URL to open it in a browser. That's it!&lt;/p&gt;

&lt;h2&gt;
  
  
  🌠 Make Your Own
&lt;/h2&gt;

&lt;p&gt;We've explained how to use your images within the Runme notebook. The originals are also included with the notebook in &lt;a href="https://github.com/sourishkrout/loon" rel="noopener noreferrer"&gt;the repository&lt;/a&gt;. Interestingly, the more background you mask (let the AI know what not to preserve), the more drastically the AI morphs the scene. Let us know what you think. You can find us &lt;a href="https://discord.gg/stateful" rel="noopener noreferrer"&gt;on Discord&lt;/a&gt;. Please drop by and share one of your own DALL-E impressions!&lt;/p&gt;

&lt;p&gt;Thank you.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>bash</category>
    </item>
    <item>
      <title>Integration testing docs in GitHub Actions</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Thu, 30 Mar 2023 01:53:32 +0000</pubDate>
      <link>https://dev.to/sourishkrout/integration-testing-docs-in-github-actions-4h1d</link>
      <guid>https://dev.to/sourishkrout/integration-testing-docs-in-github-actions-4h1d</guid>
      <description>&lt;p&gt;Learn how to test your docs in CI/CD with Runme's latest v1.0 release, which comes with new cool features you can utilize to deliver seamless developer experience. We will leverage Runme's new kernel architecture enabling seamless interoperability between notebook and terminal UX.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⏯ Never heard of Runme before? It's an open source toolkit that let's you run your README.md and other markdown docs in both terminal and as runnable notebook inside VS Code. &lt;a href="https://runme.dev" rel="noopener noreferrer"&gt;Check it out&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&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%2Fswn4byrmpzolwlged2it.gif" 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%2Fswn4byrmpzolwlged2it.gif" alt="Integration testing docs in GitHub Actions" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Integration testing docs in GitHub Actions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Let's See How
&lt;/h2&gt;

&lt;p&gt;Let's jump right into a showcase. A “thank you” goes out to our friends at Buoyant (creators of Linkerd, the open-source service mesh), who openly maintain &lt;a href="https://github.com/linkerd/website/blob/main/linkerd.io/content/2.12/getting-started/_index.md" rel="noopener noreferrer"&gt;Linkerd’s docs&lt;/a&gt; in Markdown. That same Markdown generates &lt;a href="https://linkerd.io/2.12/getting-started/" rel="noopener noreferrer"&gt;static HTML on their website&lt;/a&gt; for developers to copy commands into the terminals. It turns out that Linkerd’s Getting Started Guide makes a great real-world example illustrating how to harness Runme in CI/CD (with minimal to no edits).&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%2Fmedia.graphassets.com%2Fu4CIorabRuS0qcI4o6gG" 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%2Fmedia.graphassets.com%2Fu4CIorabRuS0qcI4o6gG" alt="Markdown are everywhere describing Developer Experience" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Markdown docs are everywhere describing Developer Experience&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The End-to-End Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.runme.dev/api/runme?repository=https%3A%2F%2Fgithub.com%2Fstateful%2Flinkerd-website.git&amp;amp;fileToOpen=tests/runme/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbadgen.net%2Fbadge%2FRun%2520repo%27s%2FREADME.md%2F5B3ADF%3Ficon%3Dhttps%3A%2F%2Frunme.dev%2Fimg%2Flogo.svg" width="147" height="20"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While you could watch the GitHub Action running in real-time, we can’t guarantee that the GitHub Action is running at all times, so we created a video. The time-lapse video (eventual consistency in Kubernetes takes time) illustrates side-by-side what’s going on when testing Linkerd’s Getting Started guide and Kubernetes cluster state. This exact setup will be executed inside a CI/CD job.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/StYPex_PTKY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Full end-to-end demo as time-lapse video&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Inside of GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Once packaged up in a Github Action workflow, running on every commit is just a matter of configuration. Go ahead and send a PR to follow along in real time! It’s all public:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/stateful/linkerd-website/actions/workflows/dx.yml" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2F3fuZcKSCWJ1qg4Igv84g" alt="GitHub Action" width="800" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Live at &lt;a href="https://github.com/stateful/linkerd-website/actions/workflows/dx.yml" rel="noopener noreferrer"&gt;https://github.com/stateful/linkerd-website/actions/workflows/dx.yml&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the curious ones, you can find the details of how we wired up the GitHub Action’s workflow with GCP and Runme &lt;a href="https://github.com/stateful/linkerd-website/blob/main/tests/runme/RUNNING_CI.md" rel="noopener noreferrer"&gt;inside the repo&lt;/a&gt;. The hard part’s done. Now, in about 5min after a commit, you will have assurance (watch out for that 🟢 light!) whether or not the Getting Started Guide still works and your Developer Experience remains intact.&lt;/p&gt;

&lt;h1&gt;
  
  
  Breaking It Down
&lt;/h1&gt;

&lt;p&gt;Before getting into improvements, let’s take a closer look at the moving pieces of this demo. Linkerd (version 2) is a Kubernetes-native service mesh. We will need a functioning cluster to test the Getting Started Guide via the Linkerd CLI. There are many permutations of CI/CD and cluster setups/provider combos. We won’t be covering them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools and Infrastructure
&lt;/h3&gt;

&lt;p&gt;Instead, we’ve chosen well-known and established ingredients to keep it simple. The setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard Kubernetes Cluster in Google’s GKE: 3 nodes with 2 CPUs &amp;amp; 2 GB memory each&lt;/li&gt;
&lt;li&gt;Bats (&lt;a href="https://github.com/bats-core/bats-core" rel="noopener noreferrer"&gt;Bash Automated Testing System&lt;/a&gt;) plus &lt;a href="https://github.com/bats-core/bats-detik" rel="noopener noreferrer"&gt;assertion libraries for kubectl&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub Action that handles scheduling/queuing of subsequent jobs against shared cluster&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Anatomy of a Test Case
&lt;/h3&gt;

&lt;p&gt;The idea is as simple as compelling. Runme’s CLI allows referencing code snippets by name (explicitly defined in command block annotations for clarity). This mirrors precisely what’s being presented to developers on the website’s Getting Started section to copy &amp;amp; paste into their terminals. It goes without saying that Runme’s UX is much more elegant than copy &amp;amp; paste.&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%2Fmedia.graphassets.com%2FxkTWNk6TSMGs9DhDbfHY" 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%2Fmedia.graphassets.com%2FxkTWNk6TSMGs9DhDbfHY" alt="Getting Started Guide markdown snippet" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Asserting Test Conditions
&lt;/h3&gt;

&lt;p&gt;Inside our Bats files, we replicate the sequence of steps and the contained instructions as test cases. We can define pre-conditions, execute the Markdown command block, and check post-conditions for returned exit code, output, and desired Kubernetes cluster state. The &lt;a href="https://github.com/bats-core/bats-detik" rel="noopener noreferrer"&gt;Bats DETIK&lt;/a&gt; assertion library does a phenomenal job of expressing Kubernetes assertions fluently. Bats is also capable of handling the &lt;a href="https://github.com/stateful/linkerd-website/blob/main/tests/runme/setup_suite.bash" rel="noopener noreferrer"&gt;setup and teardown&lt;/a&gt; of a test suite. Feel free to ask us about the details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;@test &lt;span class="s2"&gt;"Verify linkerd injection (step 4)"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;DETIK_CLIENT_NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"emojivoto"&lt;/span&gt;
  run &lt;span class="s2"&gt;"runme run kubectl-get"&lt;/span&gt;
  assert_line &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"deployment &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;emoji&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; injected"&lt;/span&gt;
  assert_line &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"deployment &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;vote-bot&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; injected"&lt;/span&gt;
  assert_line &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"deployment &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;voting&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; injected"&lt;/span&gt;
  assert_line &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"deployment &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;web&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; injected"&lt;/span&gt;
  try &lt;span class="s2"&gt;"at most 10 times every 30s to get pods named 'emoji' and verify that 'status' is 'running'"&lt;/span&gt;
  try &lt;span class="s2"&gt;"at most 10 times every 30s to get pods named 'vote-bot' and verify that 'status' is 'running'"&lt;/span&gt;
  try &lt;span class="s2"&gt;"at most 10 times every 30s to get pods named 'voting' and verify that 'status' is 'running'"&lt;/span&gt;
  try &lt;span class="s2"&gt;"at most 10 times every 30s to get pods named 'web' and verify that 'status' is 'running'"&lt;/span&gt;
  assert_success
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While Bats will support parallel execution, we want these test cases to run serially in a predetermined order. Humans run one command at a time. And, in stateful nature, downstream execution results depend on completing prior commands. While your run-unit-tests-in-parallel-self might object at first, this is, in fact, a good thing. It replicates how developers consume software docs in reality.&lt;/p&gt;

&lt;p&gt;The same idea is transferrable to e.g., internal repos that house libraries, apps, or services. Imagine every repo’s README.md, BUILD.md, or DEPLOY.md being tested this way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let Us Know What You Think
&lt;/h3&gt;

&lt;p&gt;While we’re happy with our demo’s results, there is much room for improvement. Here are some items we have discussed and would love your feedback on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Leverage notebook-serialized cell output for test assertions? The idea is to record cell outputs stored alongside the inputs and provide the functionality to define common assertions, e.g., substrings, expected exit code, or fuzzy threshold diffing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Runme-integrated test-harness? While Bats fits the demo’s use case well, it is likely desirable to use Runme’s notebook parser and structural awareness to maintain a test suite inside of notebooks instead of describing them separately, in this case, &lt;code&gt;*.bats&lt;/code&gt; files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provide an official Runme Github Action for easy integration? Significantly reduce boilerplate, ideally where the workflow auto-detects Runme-enabled Markdown files inside of the repo and runs the associated test suite.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The common theme in the ideas above is to absorb commonly required capabilities to express test cases into Runme and minimize overhead. Unlock docs testing value faster. The better we understand your use cases, the more effectively we can evolve Runme following this philosophy. Please, we urge you, &lt;a href="https://discord.gg/stateful" rel="noopener noreferrer"&gt;get in touch&lt;/a&gt;!&lt;/p&gt;

&lt;h1&gt;
  
  
  Get Involved
&lt;/h1&gt;

&lt;p&gt;Outside of CI/CD-related features, the team is currently heads-down working through Runme's final touches of the Notebook Terminal output UX (experimentally available for non-interactive and background tasks) directly inside your READMEs. Beyond that, our roadmap is full of UX improvements, big and small, to continue streamlining the daily workflows of developers.&lt;/p&gt;

&lt;p&gt;Now go try &lt;a href="https://marketplace.visualstudio.com/items?itemName=stateful.runme" rel="noopener noreferrer"&gt;it out&lt;/a&gt; and help us prioritize! We’d love to hear what you think. If you run into any problems, please don’t hesitate to report them &lt;a href="https://github.com/stateful/runme" rel="noopener noreferrer"&gt;as a GitHub issue&lt;/a&gt; or talk to us &lt;a href="https://discord.gg/stateful" rel="noopener noreferrer"&gt;on Discord&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy Docs Testing 🤩!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>bash</category>
      <category>markdown</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Runme: Road to Testable Docs</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Wed, 21 Dec 2022 02:35:09 +0000</pubDate>
      <link>https://dev.to/sourishkrout/runme-road-to-testable-docs-4ede</link>
      <guid>https://dev.to/sourishkrout/runme-road-to-testable-docs-4ede</guid>
      <description>&lt;p&gt;Today, we are excited to ship Runme v0.4 adding notebook authoring capabilities. The first intermediate step on the road to v1.0. Make changes to your existing READMEs, execute your commands, save and share with your fellow developers. Or, just create a brand new Runme notebook from scratch, saving changes as you go. Runme notebooks are 100% markdown-compatible and the best choice to document your repo’s development environment. Here’s how:&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%2Fpdvhbgofi4l8ffzzr39e.gif" 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%2Fpdvhbgofi4l8ffzzr39e.gif" alt="Open source toolkit for testable docs" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Open source toolkit for reliable docs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you haven’t used Runme yet, it is really neat. It will let you open your README (any markdown file really) as an interactive notebook. Stay focused and save time by clicking ▶️ next to commands to intuitively execute the commands and forget about copy &amp;amp; paste. All open source. No changes required to your markdown, install, open README.md, and go! Keep reading to learn more about this release and what’s planned for Runme v1.0.&lt;/p&gt;

&lt;h1&gt;
  
  
  No More Broken Docs 👉 Roadmap to v1.0
&lt;/h1&gt;

&lt;p&gt;Runme’s vision is to provide a flexible - open source - toolkit to deliver testable docs.&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%2Fmedia.graphassets.com%2FDKR95j3QTeSjR5Q2Tjs8" 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%2Fmedia.graphassets.com%2FDKR95j3QTeSjR5Q2Tjs8" alt="Runme Notebooks" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;More at &lt;a href="https://runme.dev/" rel="noopener noreferrer"&gt;https://runme.dev/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In Runme’s initial release a few weeks back, we decide to forgo “full notebook editing” to ship faster and learn from users. We've done our homework and came up with a plan. For Runme's v1.0, to achieve testable docs, we are planning the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Full editing inside ✍️ of Runme notebooks (v0.4 ✓)&lt;/li&gt;
&lt;li&gt;Shared session-state 💻 between notebook &amp;amp; terminal&lt;/li&gt;
&lt;li&gt;Elevate ergonomics 👩‍💻 inside notebook UX&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Read more about the detailed breakdown of above's line items at &lt;a href="https://www.stateful.com/blog/runme-road-to-reliable-docs" rel="noopener noreferrer"&gt;https://www.stateful.com/blog/runme-road-to-reliable-docs&lt;/a&gt; as well as &lt;a href="https://github.com/stateful/runme/projects" rel="noopener noreferrer"&gt;GitHub Projects boards&lt;/a&gt; to track progress. ETA for v1.0 is planned for February/March 2023.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check it out!
&lt;/h2&gt;

&lt;p&gt;If you haven’t yet, now is a good time to give Runme a spin at &lt;a href="https://runme.dev/" rel="noopener noreferrer"&gt;https://runme.dev/&lt;/a&gt;. You’ll be surprised how quickly it will replace your old markdown editor and associated habits.&lt;/p&gt;

&lt;p&gt;Stay tuned! Thank you.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>programming</category>
      <category>beginners</category>
      <category>devops</category>
    </item>
    <item>
      <title>But it works on MY machine! Debugging GitHub Workflows with VS Code</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Mon, 21 Nov 2022 20:17:11 +0000</pubDate>
      <link>https://dev.to/sourishkrout/but-it-works-on-my-machine-debugging-github-workflows-with-vs-code-lok</link>
      <guid>https://dev.to/sourishkrout/but-it-works-on-my-machine-debugging-github-workflows-with-vs-code-lok</guid>
      <description>&lt;p&gt;Any developer is probably familiar with the “flip the table” moment, when the well crafted test that you’re ready merge into &lt;code&gt;main&lt;/code&gt; fails with an error related to the CI environment. Why why why.&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%2Fmedia.graphassets.com%2FKj8EmL3ZSfRyNlGoHn1w" 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%2Fmedia.graphassets.com%2FKj8EmL3ZSfRyNlGoHn1w" alt="Please don't try this at home" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please don't try this at home, seriously don't&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Generally unit tests are less susceptible to this kind of failure, but as you add more layers of abstraction around your application or for integration testing things become increasingly brittle. Especially end-to-end tests are sensitive to the often absent GPU in CI workflows. The added complexity and the remote nature of CI jobs make the process of debugging difficult, slow, and cumbersome.&lt;/p&gt;

&lt;p&gt;This problem is particularly important to us in our development experience at Stateful, because we are constantly pushing the boundaries of VS Code extensions and want end-to-end confidence when shipping every release. While our extensions tests technically run in a consistent “VS Code environment”, the reality is that VS Code can behave very differently depending on how it’s being used, particularly when running as Electron as opposed to a browser-based webapp on consumer hardware, data center servers, or, what’s even more likely, inside a container leveraging a virtual frame buffer (e.g. &lt;code&gt;xvfb&lt;/code&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 &lt;a href="https://github.com/marketplace/actions/vs-code-server-action" rel="noopener noreferrer"&gt;Use via Github Marketplace&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&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%2Fmedia.graphassets.com%2FIDN5qA7TfqcVqzhecUPg" 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%2Fmedia.graphassets.com%2FIDN5qA7TfqcVqzhecUPg" alt="Attach VS Code to your running Github workflow" width="1080" height="770"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Attach VS Code to your running Github workflow&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fortunately, a great solution just became available that utilizes VS Code’s ability to connect to remote workspaces. Using the &lt;a href="https://code.visualstudio.com/docs/remote/vscode-server" rel="noopener noreferrer"&gt;Visual Studio Code Server&lt;/a&gt; you can configure your Github workflow to start a VS Code server process that makes it easy connecting to the remote workflow execution to debug the problem. Yes, this sounds slightly mind-bending, however, you will indeed be able to use a hosted VS Code instance to tap into a running GitHub workflow. The VS Code Server leverages tunneling to connect both remote instances, the running workflow and the hosted VS Code web UX, transparently. Here’s how we made this super easy for you:&lt;/p&gt;

&lt;p&gt;We created the &lt;a href="https://github.com/stateful/vscode-server-action" rel="noopener noreferrer"&gt;stateful/vscode-server-action&lt;/a&gt; GitHub action to take advantage of a Github Action’s lifecycle hook to just trigger a VS Code session when your tests fail. This action provides you with a configurable time window how long after tests failed you will be able to connect to the machine. If you don’t connect in time, the workflow continues. Here is an example how you can apply it in your workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
   &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
   &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
     &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
   &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🧪 Test&lt;/span&gt;
     &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn run test&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🐛 Debug Build&lt;/span&gt;
     &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stateful/vscode-server-action@v1&lt;/span&gt;
     &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;failure()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the event of a failed build the action attempts to start a VS Code Server on the build machine and requests your authorization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;To grant access to the server, please log into https://github.com/login/device and use code 0328-F81A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't authorize the machine until the timeout is hit, the build just continues. However if you do, a VS Code Server is started and it prints an URL to connect to, e.g.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open this link in your browser https://insiders.vscode.dev/+ms-vscode.remote-server/myMachine/github/workspace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also connect to it through your local VS Code application. Just open the URL, open the command palette and enter &lt;code&gt;Open in VS Code&lt;/code&gt;. And voilà you are connected to GitHubs machine and can start debugging your tests:&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%2Fmedia.graphassets.com%2FxlXDcFBqT1yT2PMHVWl7" 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%2Fmedia.graphassets.com%2FxlXDcFBqT1yT2PMHVWl7" alt="What it does" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Try this at home instead: Fully integrated demo of the Github Action&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This little action has helped us tremendously when it came to drilling into issues that only seem to occur in Github's CI. It's probably not hard to adapt the approach for other CI/CD platforms and serves as a poster-child how convenient and powerful VS Code remote debugging is.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 &lt;a href="https://github.com/marketplace/actions/vs-code-server-action" rel="noopener noreferrer"&gt;Use via Github Marketplace&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One caveat is that bringing up the VS Code Server is currently coupled to Docker which does not allow it to be used with Windows and Mac runners (yet). We’re tracking &lt;a href="https://github.com/stateful/vscode-server-action/issues/7" rel="noopener noreferrer"&gt;an issue&lt;/a&gt; to unlock support for non-Docker environments.&lt;/p&gt;

&lt;p&gt;Thanks for reading! Happy debugging and let us know how it goes. Either &lt;a href="https://discord.gg/stateful" rel="noopener noreferrer"&gt;join Discord&lt;/a&gt; or &lt;a href="https://github.com/stateful/vscode-server-action/issues/new" rel="noopener noreferrer"&gt;file an issue on Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Run your README.md like a notebook in VS Code</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Thu, 20 Oct 2022 01:21:00 +0000</pubDate>
      <link>https://dev.to/sourishkrout/run-your-readmemd-in-vs-code-50l7</link>
      <guid>https://dev.to/sourishkrout/run-your-readmemd-in-vs-code-50l7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;💡 TLDR; Runme's project website's got the cliff notes for you: &lt;a href="https://runme.dev/" rel="noopener noreferrer"&gt;https://runme.dev/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In our ongoing efforts to make documentation more reliable and less susceptible to bit-rot, &lt;a href="https://www.stateful.com/blog/run-readme-in-your-terminal" rel="noopener noreferrer"&gt;we released&lt;/a&gt; the &lt;code&gt;runme&lt;/code&gt; CLI (renamed from &lt;code&gt;rdme&lt;/code&gt;) back in August. The CLI lets you effortlessly execute shell blocks inside your &lt;code&gt;README.md&lt;/code&gt; docs from the terminal. We’ve been pleasantly surprised how well it was received. Thank you all for the comments and feedback!&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%2Fmedia.graphassets.com%2FOhkWDUxRqWtumeAaJA4x" 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%2Fmedia.graphassets.com%2FOhkWDUxRqWtumeAaJA4x" alt="Zero-changes required to turn your README.md into a runnable notebook" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Zero-changes required to turn your README.md into a runnable notebook&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Today we want to take Runme a step further and break out of the confides of the terminal. Anecdotally (yet not the sole motivator) one of the more notable comments in response to the &lt;code&gt;runme&lt;/code&gt; CLI (renamed from &lt;code&gt;rdme&lt;/code&gt;) was this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Install Runme from the &lt;a href="https://marketplace.visualstudio.com/items?itemName=stateful.runme" rel="noopener noreferrer"&gt;VS Code marketplace&lt;/a&gt; or search &lt;code&gt;runme&lt;/code&gt; inside of the Extension Panel&lt;/p&gt;
&lt;/blockquote&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%2Fmedia.graphassets.com%2FDYrwHmkmSkWEmLdSyTsR" 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%2Fmedia.graphassets.com%2FDYrwHmkmSkWEmLdSyTsR" alt="Noteworthy response to runme's CLI" width="800" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The point’s well taken! We wholeheartedly agree that it’s important to &lt;strong&gt;READ&lt;/strong&gt; your &lt;code&gt;README.md&lt;/code&gt; before &lt;strong&gt;running&lt;/strong&gt; the commands it describes. With today’s Runme release, this just got a whole lot easier:&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%2Fmedia.graphassets.com%2FludaFwnQVGCzqt2IVDmw" 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%2Fmedia.graphassets.com%2FludaFwnQVGCzqt2IVDmw" alt="Literally execute your [README.md](http://README.md) by simply clicking play buttons" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Literally execute your README.md by simply clicking play buttons&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Breaking Out of the Terminal
&lt;/h1&gt;

&lt;p&gt;We wanted to expand beyond Runme’s CLI implementation to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable contributors to both learn about and interactively run docs&lt;/li&gt;
&lt;li&gt;Empower maintainers to control and curate the developer execution experience&lt;/li&gt;
&lt;li&gt;Encourage contributors to make suggestions about the Readme experience&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We took a good look around and found inspiration in the Data Science Community: DS loves Jupyter Notebooks! Notebooks elegantly interleave code, computations, numbers, and narrative to lean on the dynamic where scientists prepare notebooks that can be consumed without much fuss by anybody.&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%2Fmedia.graphassets.com%2Fom11URUfRqu4dJ3oZvTM" 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%2Fmedia.graphassets.com%2Fom11URUfRqu4dJ3oZvTM" alt="Longer clip and introduction available at [https://www.codecademy.com/article/introducing-jupyter-notebook](https://www.codecademy.com/article/introducing-jupyter-notebook)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Longer clip at &lt;a href="https://www.codecademy.com/article/introducing-jupyter-notebook" rel="noopener noreferrer"&gt;https://www.codecademy.com/article/introducing-jupyter-notebook&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A notebooks inherent ability to reevaluate (literally run) every paragraph (input &amp;amp; output cells), in a low-code fashion, naturally aids a reader’s comprehension of the information laid out in front of them. This enables improvements to notebooks to be easily upstreamed using Pull Requests as notebooks live in version-tracked repos.&lt;/p&gt;

&lt;p&gt;Bingo 💡! It turns out that repo maintainers and contributors have a similar relationship to the DS community when it comes to technical documentation.&lt;/p&gt;

&lt;h1&gt;
  
  
  From README to RUNME
&lt;/h1&gt;

&lt;p&gt;After a fair amount of experimentation, we decided to build a VS Code Extension UX on top of the Runme parser. This extension will now make your README.md (onboarding and runbook docs) available within a VS Code powered Notebook Experience requiring zero changes to the underlying markdown. To showcase an end-to-end example, we’ve assembled a repo &lt;a href="https://github.com/stateful/runme.dev" rel="noopener noreferrer"&gt;https://github.com/stateful/runme.dev&lt;/a&gt; (backing &lt;a href="https://runme.dev/" rel="noopener noreferrer"&gt;https://runme.dev&lt;/a&gt;) using Deno’s Fresh web framework, a CMS, testing, and deployment. Here we go:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Install Runme from the &lt;a href="https://marketplace.visualstudio.com/items?itemName=stateful.runme" rel="noopener noreferrer"&gt;VS Code marketplace&lt;/a&gt; or search &lt;code&gt;runme&lt;/code&gt; inside of the Extension Panel&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Execution Controls and More
&lt;/h2&gt;

&lt;p&gt;Runme transparently parses README.md files into its constituents sequences (arbitrary markdown) and executable blocks (e.g. shell) that describe your apps and services.&lt;/p&gt;

&lt;p&gt;Leveraging VS Code’s Notebook APIs (that underpin notebook rendering) Runme displays your README.md (or any other markdown file) as an input &amp;amp; output cell in a notebook.&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%2Fmedia.graphassets.com%2FaRiLhuCgSkq6zLV4pJfq" 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%2Fmedia.graphassets.com%2FaRiLhuCgSkq6zLV4pJfq" alt="Forgo tedious copy &amp;amp; paste with notebook-style run controls" width="1183" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Forgo tedious copy &amp;amp; paste with notebook-style run controls&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These notebook entries enable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Per block execution controls&lt;/li&gt;
&lt;li&gt;Shell support &amp;amp; terminal integration&lt;/li&gt;
&lt;li&gt;Basic ENV support across notebook cells&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Curate Your Notebook Experience
&lt;/h2&gt;

&lt;p&gt;Attributes let maintainers control various aspects of the Developer Experience via simple annotations (&lt;a href="https://github.com/stateful/vscode-runme#elevated-notebook-experience" rel="noopener noreferrer"&gt;full list available here&lt;/a&gt;) inside your README’s code blocks. Ordinary markdown viewers will just ignore them. Sharing and merging in notebook changes is just a git clone, git push or a pull request away.&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%2Fmedia.graphassets.com%2FEQowF9yQmOT79YJM5RRw" 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%2Fmedia.graphassets.com%2FEQowF9yQmOT79YJM5RRw" alt="Annotate your fence code blocks to curate your shell execution" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Annotate your fence code blocks to curate your shell execution&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Beyond Shell and Terminal
&lt;/h2&gt;

&lt;p&gt;To provide broad compatibility with existing READMEs and their potential usage of CLI tooling we chose to first unlock shell execution in Runme Notebooks. However, just like Jupyter has first-class integrations with plotting libraries and other rich visual renderers, we saw an opportunity to enrich the UX by going beyond the text representation and bring in rich web experiences.&lt;/p&gt;

&lt;p&gt;To showcase how this will work, we started with our friends at Deno 🦕:&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%2Fmedia.graphassets.com%2FmsctAEajRTOAVNzSefy5" 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%2Fmedia.graphassets.com%2FmsctAEajRTOAVNzSefy5" alt="Deploy to preview and production with ease" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Deploy to both Deno's preview and production with ease&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are envisioning a world where instead of logging into dispersed cloud web consoles (made available by service providers), you could just drop a web component into a cell that exposes a programmable UX for different parts of their APIs inside of your Runme Notebook. We believe that this approach has lots of potential to lead to a more concise and maintainable way to document full stack applications and services.&lt;/p&gt;

&lt;p&gt;What do you think?&lt;/p&gt;

&lt;h2&gt;
  
  
  Interoperability With the CLI
&lt;/h2&gt;

&lt;p&gt;While we believe that Runme Notebooks will provide a much better onboarding experience for new contributors, we understand that maintainers and power contributors may want to skip ahead. The same is true for execution inside of CI/CD, which is why we designed Runme to function in a headless way via the &lt;code&gt;runme&lt;/code&gt; CLI.&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%2Fmedia.graphassets.com%2F42EBw2FrQL6UUEEkhlPa" 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%2Fmedia.graphassets.com%2F42EBw2FrQL6UUEEkhlPa" alt="Interoperability with CLI" width="800" height="627"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Interoperability with CLI&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are still experimenting with UX and deciding where to draw &lt;code&gt;runme&lt;/code&gt;'s architectural boundaries and working to achieve broader interoperability (e.g handling ENV vars in the CLI). One of our goals is to maintain a symbiosis between CLI and Notebook implementations to achieve the best possible Developer Experience for reliably runnable documentation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Install Runme from the &lt;a href="https://marketplace.visualstudio.com/items?itemName=stateful.runme" rel="noopener noreferrer"&gt;VS Code marketplace&lt;/a&gt; or search &lt;code&gt;runme&lt;/code&gt; inside of the Extension Panel&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Get Involved
&lt;/h1&gt;

&lt;p&gt;We chose to release Runme early as an invitation to the dev community to participate in it’s on-going development. Both the extension and CLI are still under heavy development and haven’t yet undergone extensive battle testing. Please &lt;a href="https://github.com/stateful/vscode-runme/issues/new" rel="noopener noreferrer"&gt;send us bug reports and feature requests&lt;/a&gt; if anything gets in your way.&lt;/p&gt;

&lt;p&gt;Here are a few known limitations you should be aware of in this alpha release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Notebooks are currently read-only, to modify your notebook please edit the underlying Markdown/README.md as text file. We absolutely want to support bidirectional editing in the future.&lt;/li&gt;
&lt;li&gt;Be cautious with environment variables interleaved within code blocks. The stateful execution of the notebooks (shell/bash-only; no PowerShell on Windows yet) leverages a naive implementation where the VS Code extension prompts for ENV var values and attempts to expand them. In essence, it does not match an interactive bash/shell session (yet).&lt;/li&gt;
&lt;li&gt;We continue experimenting with aspects of user/developer experience including the passing of information/variables from cell to cell, ENV var handling that more closely matches shell a session, and more robust markdown handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Come find us and let’s chat about Runme (here’s &lt;a href="//mailto:sebastian@stateful.com"&gt;my email&lt;/a&gt; or &lt;a href="https://discord.gg/BQm8zRCBUY" rel="noopener noreferrer"&gt;join discord&lt;/a&gt;), we are excited to hear your thoughts! &lt;/p&gt;

&lt;p&gt;Thank you.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>opensource</category>
      <category>beginners</category>
      <category>devops</category>
    </item>
    <item>
      <title>Go for the streak and celebrate progress 🏆: Strava for VS Code</title>
      <dc:creator>Sebastian Tiedtke</dc:creator>
      <pubDate>Thu, 29 Sep 2022 02:49:23 +0000</pubDate>
      <link>https://dev.to/sourishkrout/go-for-the-streak-and-celebrate-progress-strava-for-vs-code-3cec</link>
      <guid>https://dev.to/sourishkrout/go-for-the-streak-and-celebrate-progress-strava-for-vs-code-3cec</guid>
      <description>&lt;p&gt;Athletes use exercise watches and apps like Strava (or Runkeepr) to measure and challenge themselves to grow, and we’ve been experimenting with ways to unlock similar kinds of value for developers. Think of your codebase or projects as the roads you’re running, VS Code as the Apple or Garmin watch, and &lt;strong&gt;Stateful&lt;/strong&gt; as the Strava that helps make your data organized and easily digestible.&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%2Fmedia.graphassets.com%2FNwTIe0cuR6uWtg0S2LFW" 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%2Fmedia.graphassets.com%2FNwTIe0cuR6uWtg0S2LFW" alt="Strava for VS Code" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Go for the streak and celebrate progress 🏆
&lt;/h2&gt;

&lt;p&gt;As you code you will unlock milestones, enter streaks (language usage, scores, ratings and more) and have the opportunity to high-five yourself and others.&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%2Fmedia.graphassets.com%2FL3zqDJqHTG9kLrQgIefC" class="article-body-image-wrapper"&gt;&lt;img alt="Celebrate your achievements" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FL3zqDJqHTG9kLrQgIefC" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pace yourself with the real-time score 🔥
&lt;/h2&gt;

&lt;p&gt;Your score is based on best practices and customizable contributors. Keep an eye on your score to understand how your coding day is going and change course if needed.&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%2Fmedia.graphassets.com%2FqAgESMqsQPuZ0kFfWlRr" class="article-body-image-wrapper"&gt;&lt;img alt="Keep an eye on your score" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FqAgESMqsQPuZ0kFfWlRr" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unpack your metrics, and setup the next day 📈
&lt;/h2&gt;

&lt;p&gt;Dive into your coding metrics, including: activity, score, self ratings and forecasted “ideal” coding blocks. As your day is wrapping up, Stateful will effortlessly prompt you to reflect on the day, select your star rating and jot down a few notes as reminder for where to pick things up tomorrow.&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%2Fmedia.graphassets.com%2Fa1uWByjSSYquOSy72djy" class="article-body-image-wrapper"&gt;&lt;img alt="Dive into your metrics" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2Fa1uWByjSSYquOSy72djy" width="800" height="641"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Check in with yourself  📃
&lt;/h2&gt;

&lt;p&gt;Explore daily, weekly and monthly summaries of your coding activity. No-brainer standup reports are delivered via notification just in time for your team meeting. Standup reports bring together rolled up progress since your last meeting, git tree activity, and the notes / todos you created right from the code editor.&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%2Fmedia.graphassets.com%2FuGp3pkSkQnORkwYEsDP8" class="article-body-image-wrapper"&gt;&lt;img alt="Get your daily briefings" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FuGp3pkSkQnORkwYEsDP8" width="800" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Maximize your focus time 🤫
&lt;/h2&gt;

&lt;p&gt;Stateful can automatically mute Slack notifications when your editor activity indicates that you are focused. Let others know where you are focused by sharing a custom coding status inside Slack.&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%2Fmedia.graphassets.com%2FdlXpD3QRdWlEiRMTbmdS" class="article-body-image-wrapper"&gt;&lt;img alt="Automatically have Slack notifications muted" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FdlXpD3QRdWlEiRMTbmdS" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect and motivate your network  ✌️
&lt;/h2&gt;

&lt;p&gt;When you and someone else on Stateful are working on the same repo, we encourage you to follow each other and give kudos to support their achievements.&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%2Fmedia.graphassets.com%2FYcjWlrbMSpmdL9loMkA4" class="article-body-image-wrapper"&gt;&lt;img alt="Connect with your network" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FYcjWlrbMSpmdL9loMkA4" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Try it out!
&lt;/h1&gt;

&lt;p&gt;You can install the extension by searching for &lt;code&gt;stateful&lt;/code&gt; in the VS Code extensions panel, or through the &lt;a href="https://marketplace.visualstudio.com/items?itemName=stateful.stable" rel="noopener noreferrer"&gt;VS Code Marketplace&lt;/a&gt;. It only requires that you authenticate with Github and within 15 minutes you will have access to your dashboard.&lt;/p&gt;



&lt;h1&gt;
  
  
  What do you think?!
&lt;/h1&gt;

&lt;p&gt;We would like to hear from you. Do you like this? What do you want to see more or less of? What could we build to help you be more efficient, productive or happy?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://discord.gg/BQm8zRCBUY" rel="noopener noreferrer"&gt;Join our Discord&lt;/a&gt; and let us know please.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>beginners</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
