<?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: Server-lab</title>
    <description>The latest articles on DEV Community by Server-lab (@server-lab).</description>
    <link>https://dev.to/server-lab</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%2F3760193%2Fe2804144-8a81-49dc-bfc3-af07ed742970.png</url>
      <title>DEV Community: Server-lab</title>
      <link>https://dev.to/server-lab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/server-lab"/>
    <language>en</language>
    <item>
      <title>🧱 Bytecraft — The Missing Layer Between AI and Your Filesystem</title>
      <dc:creator>Server-lab</dc:creator>
      <pubDate>Sat, 28 Mar 2026 19:59:49 +0000</pubDate>
      <link>https://dev.to/server-lab/bytecraft-the-missing-layer-between-ai-and-your-filesystem-lc6</link>
      <guid>https://dev.to/server-lab/bytecraft-the-missing-layer-between-ai-and-your-filesystem-lc6</guid>
      <description>&lt;p&gt;We’ve all seen it.&lt;/p&gt;

&lt;p&gt;You ask an AI to build something, and it gives you…&lt;br&gt;
a wall of code.&lt;/p&gt;

&lt;p&gt;Now you’re stuck:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;creating folders manually&lt;/li&gt;
&lt;li&gt;copying files one by one&lt;/li&gt;
&lt;li&gt;fixing small mistakes&lt;/li&gt;
&lt;li&gt;wiring everything together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It works—but it’s friction.&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚠️ The real limitation of AI dev tools
&lt;/h2&gt;

&lt;p&gt;Tools like Google Gemini or Claude are great at generating code…&lt;/p&gt;

&lt;p&gt;…but they &lt;strong&gt;can’t actually create your project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;They stop at:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Here’s what your files should look like”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Here’s your working project”&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  🧱 Enter Bytecraft
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bytecraft&lt;/strong&gt; is a human-readable DSL that turns simple instructions into real files and folders—instantly.&lt;/p&gt;

&lt;p&gt;Instead of writing scripts or boilerplate, you describe what you want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;set-working-folder "my-project"

make-folder "src"
make-file "src/main.py" with "print('Hello, world!')"
make-file "README.md" with ---
# My Project

Built with Bytecraft.
---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bytecraft project.bc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just like that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;folders are created&lt;/li&gt;
&lt;li&gt;files are written&lt;/li&gt;
&lt;li&gt;your project exists&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔍 Why this matters
&lt;/h2&gt;

&lt;p&gt;Bytecraft changes the workflow from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI → text → manual setup → working project&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI → Bytecraft script → &lt;strong&gt;working project&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s a small shift—but a powerful one.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚡ Designed for both humans &lt;em&gt;and&lt;/em&gt; AI
&lt;/h2&gt;

&lt;p&gt;Bytecraft is intentionally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;forgiving (no strict quoting rules)&lt;/li&gt;
&lt;li&gt;readable (no syntax noise)&lt;/li&gt;
&lt;li&gt;predictable (explicit commands)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which makes it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;perfect for AI to generate reliably&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No escaping hell. No weird edge cases.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 Safe by default
&lt;/h2&gt;

&lt;p&gt;Before running anything, you can preview exactly what will happen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bytecraft &lt;span class="nt"&gt;--dry-run&lt;/span&gt; project.bc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[DRY RUN] Would create folder: my-project/src
[DRY RUN] Would create file: my-project/src/main.py
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No surprises. No risk.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌐 It even runs remote scripts
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bytecraft https://example.com/scaffold.bc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;fetched in memory&lt;/li&gt;
&lt;li&gt;nothing saved automatically&lt;/li&gt;
&lt;li&gt;works with &lt;code&gt;--dry-run&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 Bigger picture
&lt;/h2&gt;

&lt;p&gt;Bytecraft isn’t just a DSL.&lt;/p&gt;

&lt;p&gt;It’s a &lt;strong&gt;bridge between AI and real execution&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of giving AI direct access to your filesystem (which is unsafe), Bytecraft acts as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a controlled, transparent execution layer&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🚀 Where this goes next
&lt;/h2&gt;

&lt;p&gt;Imagine this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bytecraft ai &lt;span class="s2"&gt;"make a fastapi app with auth and docker"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;AI generates a Bytecraft script&lt;/li&gt;
&lt;li&gt;Bytecraft executes it&lt;/li&gt;
&lt;li&gt;Your project appears instantly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No setup. No copy-paste.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧱 Final thought
&lt;/h2&gt;

&lt;p&gt;AI is great at describing projects.&lt;/p&gt;

&lt;p&gt;Bytecraft makes them &lt;strong&gt;real&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;If you're building tools, automating scaffolds, or experimenting with AI workflows, I'd love your thoughts.&lt;/p&gt;

&lt;p&gt;This is just the beginning.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>automation</category>
    </item>
    <item>
      <title>Why Your Archives Deserve Better Than Markdown</title>
      <dc:creator>Server-lab</dc:creator>
      <pubDate>Wed, 11 Mar 2026 12:56:59 +0000</pubDate>
      <link>https://dev.to/server-lab/why-your-archives-deserve-better-than-markdown-2761</link>
      <guid>https://dev.to/server-lab/why-your-archives-deserve-better-than-markdown-2761</guid>
      <description>&lt;p&gt;If you've ever tried to open a document from 15 years ago, you know the anxiety. Will the app still exist? Will the formatting survive? Will a future developer even understand what flavor of syntax was used?&lt;/p&gt;

&lt;p&gt;Markdown has become the default for developer documentation — and for good reason. It's lightweight, readable, and widely supported. But "widely supported" is doing a lot of heavy lifting in that sentence. Because the uncomfortable truth is: &lt;strong&gt;Markdown has a fragmentation problem&lt;/strong&gt;, and that makes it a poor choice for anything you want to last.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Markdown Flavor Problem
&lt;/h2&gt;

&lt;p&gt;Ask ten developers what valid Markdown looks like and you'll get ten slightly different answers. There's:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CommonMark&lt;/li&gt;
&lt;li&gt;GitHub Flavored Markdown (GFM)&lt;/li&gt;
&lt;li&gt;MultiMarkdown&lt;/li&gt;
&lt;li&gt;Pandoc Markdown&lt;/li&gt;
&lt;li&gt;Reddit Markdown&lt;/li&gt;
&lt;li&gt;...and many more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each flavor handles edge cases differently — tables, footnotes, nested lists, inline HTML. A document written in GFM today might render incorrectly in a CommonMark parser a decade from now. And critically, &lt;strong&gt;there's nothing in the file itself to tell a future reader which flavor was used.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open a &lt;code&gt;.md&lt;/code&gt; file in the year 2045 and good luck knowing what spec it was written against.&lt;/p&gt;




&lt;h2&gt;
  
  
  Enter Celes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pypi.org/project/celes/" rel="noopener noreferrer"&gt;Celes&lt;/a&gt; is a tag-based markup language that takes a different approach. Here's what a Celes document looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!Celes-0.1&amp;gt;
&amp;lt;header -size=1&amp;gt;{Why Archives Matter}
&amp;lt;line&amp;gt;{This is a &amp;lt;bold&amp;gt;{bold} word in a paragraph.}
&amp;lt;list -bullet=circle&amp;gt;{First item}
&amp;lt;list -bullet=circle&amp;gt;{Second item}
&amp;lt;blockquote&amp;gt;{Preserve knowledge for the future.}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It maps cleanly from Markdown concepts but with one critical difference: &lt;strong&gt;the version is baked right into the file.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That &lt;code&gt;&amp;lt;!Celes-0.1&amp;gt;&lt;/code&gt; declaration at the top tells any future parser, human or machine, exactly what spec was used to write this document. No ambiguity. No guessing.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes Celes Good for Long-Term Archival
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Explicit versioning
&lt;/h3&gt;

&lt;p&gt;Every Celes file declares its spec version on line one. Future tools can branch their parsing logic by version. Future humans know exactly what they're reading.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Unambiguous tag-based syntax
&lt;/h3&gt;

&lt;p&gt;Where Markdown relies on whitespace, indentation, and subtle punctuation rules that vary by flavor, Celes uses a consistent &lt;code&gt;&amp;lt;tag&amp;gt;{content}&lt;/code&gt; structure with named attributes like &lt;code&gt;-size=1&lt;/code&gt; or &lt;code&gt;-bullet=circle&lt;/code&gt;. There's far less room for parser ambiguity.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Plain text at heart
&lt;/h3&gt;

&lt;p&gt;Like Markdown, Celes is plain text. It will open in any text editor in any decade. No proprietary format, no binary encoding, no dependency on a specific application.&lt;/p&gt;

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

&lt;p&gt;Celes ships with built-in converters to and from Markdown and HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;celes&lt;/span&gt;

&lt;span class="c1"&gt;# Convert Markdown to Celes for archival
&lt;/span&gt;&lt;span class="n"&gt;celes_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;celes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert_md_to_celes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_markdown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Convert back to Markdown or render to HTML anytime
&lt;/span&gt;&lt;span class="n"&gt;html_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;celes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_celes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;celes_output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't have to abandon your existing Markdown workflow. Convert on the way &lt;em&gt;into&lt;/em&gt; the archive.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Real-World Example
&lt;/h2&gt;

&lt;p&gt;We recently converted the Godot Engine's documentation files — README, AUTHORS, CONTRIBUTING, DONORS — from Markdown to Celes. The conversion was clean, lossless, and the resulting files are self-describing in a way the originals weren't.&lt;/p&gt;

&lt;p&gt;A developer in 2045 picking up &lt;code&gt;README.celes&lt;/code&gt; will see &lt;code&gt;&amp;lt;!Celes-0.1&amp;gt;&lt;/code&gt; and immediately know the rules of the road. The same developer picking up &lt;code&gt;README.md&lt;/code&gt; would be left guessing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who Should Care About This
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open source projects&lt;/strong&gt; that want their documentation to outlive any particular platform or toolchain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Libraries and institutions&lt;/strong&gt; digitizing historical records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personal knowledge bases&lt;/strong&gt; and journals you want to read in retirement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legal and compliance teams&lt;/strong&gt; storing long-lived documents&lt;/li&gt;
&lt;li&gt;Anyone building a &lt;strong&gt;time capsule&lt;/strong&gt; of knowledge&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;



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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;celes&lt;/span&gt;

&lt;span class="c1"&gt;# Parse Celes to HTML
&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;celes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_celes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Convert from Markdown
&lt;/span&gt;&lt;span class="n"&gt;celes_doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;celes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert_md_to_celes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;markdown_source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Convert back to Markdown
&lt;/span&gt;&lt;span class="n"&gt;md_doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;celes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert_celes_to_md&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;celes_source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Markdown is great for today. Celes is designed for decades from now.&lt;/p&gt;

&lt;p&gt;If you're building something meant to last — documentation, archives, knowledge bases — the explicit versioning and unambiguous syntax of Celes makes it a more honest choice than hoping the right Markdown flavor is still around when someone needs your files.&lt;/p&gt;

&lt;p&gt;The best archive format is one that tells the future exactly how to read it. Celes does that from line one.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have you thought about the long-term survival of your documentation? Drop your thoughts in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Getting Started with Stick And String (SAS 1.1) — A Saner Config Format</title>
      <dc:creator>Server-lab</dc:creator>
      <pubDate>Thu, 05 Mar 2026 12:32:06 +0000</pubDate>
      <link>https://dev.to/server-lab/getting-started-with-stick-and-string-sas-11-a-saner-config-format-4b0m</link>
      <guid>https://dev.to/server-lab/getting-started-with-stick-and-string-sas-11-a-saner-config-format-4b0m</guid>
      <description>&lt;h1&gt;
  
  
  Getting Started with Stick And String (SAS 1.1) — A Saner Config Format
&lt;/h1&gt;

&lt;p&gt;If you've ever stared at a JSON file wondering why you're missing a comma on line 47, or wrestled with YAML indentation that &lt;em&gt;looks&lt;/em&gt; right but somehow isn't — this post is for you.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;SAS (Stick And String)&lt;/strong&gt;, a human-readable data serialization format designed to be strict, predictable, and free from the quirks that make JSON and YAML frustrating to write by hand. It maps 1:1 with JSON's data model, so you get all the expressiveness without the footguns.&lt;/p&gt;

&lt;p&gt;Today I'll walk you through everything you need to know to start using it — the syntax, the libraries, and how to convert your existing JSON files.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Another Format?
&lt;/h2&gt;

&lt;p&gt;Quick comparison before we dive in:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JSON&lt;/strong&gt; — great for machines, annoying for humans. Trailing commas are errors. Comments aren't allowed. Every string needs quotes. One misplaced bracket and the whole file breaks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YAML&lt;/strong&gt; — human-friendly on the surface, but indentation-sensitive parsing leads to subtle bugs, and the implicit type coercion (&lt;code&gt;yes&lt;/code&gt; becoming &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;1.0&lt;/code&gt; staying a float, etc.) causes real-world headaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SAS&lt;/strong&gt; takes a different approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No commas anywhere&lt;/li&gt;
&lt;li&gt;No indentation rules (whitespace is ignored structurally)&lt;/li&gt;
&lt;li&gt;No implicit type conversion&lt;/li&gt;
&lt;li&gt;Named block closers so you always know what you're closing&lt;/li&gt;
&lt;li&gt;Comments that just work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's what a real config file looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# SAS 1.1 config
__sas_version__ -&amp;gt; "1.1"

app ::
    name -&amp;gt; "myservice"
    version -&amp;gt; "2.4.1"
    debug -&amp;gt; false

    db ::
        host -&amp;gt; "db.internal"
        port -&amp;gt; 5432
        credentials -&amp;gt; null
    :: db

    tags -&amp;gt; ["api" | "production" | "v2"]

    allowed_hosts ::
        - "localhost"
        - "127.0.0.1"
        - "myservice.internal"
    :: allowed_hosts
:: app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Readable, unambiguous, and valid. Let's break down the syntax.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Syntax in 5 Minutes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Key → Value pairs
&lt;/h3&gt;

&lt;p&gt;Every value is assigned with &lt;code&gt;-&amp;gt;&lt;/code&gt;, with exactly one space on each side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name    -&amp;gt; "Alice"
port    -&amp;gt; 8080
enabled -&amp;gt; true
ratio   -&amp;gt; 3.14
nothing -&amp;gt; null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SAS supports six value types: &lt;strong&gt;string, number, boolean, null, object, and array&lt;/strong&gt; — exactly matching JSON's model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strings
&lt;/h3&gt;

&lt;p&gt;Strings use double quotes and support standard escape sequences:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;greeting -&amp;gt; "Hello, world!"
path     -&amp;gt; "C:\\Users\\dasso"
tab      -&amp;gt; "column1\tcolumn2"
emoji    -&amp;gt; "\u2728 sparkles"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need a multiline string? Use triple quotes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;description -&amp;gt; """
This is line one.
This is line two.
Content is preserved exactly as written.
"""
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Numbers, Booleans, Null
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;count    -&amp;gt; 42
negative -&amp;gt; -7
pi       -&amp;gt; 3.14159
mass     -&amp;gt; 1.2e10
active   -&amp;gt; true
disabled -&amp;gt; false
value    -&amp;gt; null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: &lt;code&gt;True&lt;/code&gt;, &lt;code&gt;False&lt;/code&gt;, &lt;code&gt;NULL&lt;/code&gt; etc. are &lt;strong&gt;parse errors&lt;/strong&gt;. SAS is strict — lowercase only.&lt;/p&gt;

&lt;h3&gt;
  
  
  Block Objects
&lt;/h3&gt;

&lt;p&gt;Objects use named open/close pairs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server ::
    host -&amp;gt; "localhost"
    port -&amp;gt; 8080
:: server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;:: server&lt;/code&gt; closer must match the opener exactly. This means you always know at a glance what block you're closing — no more hunting for mismatched brackets. Nesting works as deep as you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app ::
    database ::
        primary ::
            host -&amp;gt; "db1.internal"
            port -&amp;gt; 5432
        :: primary
    :: database
:: app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Inline Objects
&lt;/h3&gt;

&lt;p&gt;For small flat objects, there's a compact inline form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;origin  -&amp;gt; { lat -&amp;gt; 37.77 | lon -&amp;gt; -122.41 }
padding -&amp;gt; { top -&amp;gt; 10 | right -&amp;gt; 20 | bottom -&amp;gt; 10 | left -&amp;gt; 20 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fields are separated by &lt;code&gt;|&lt;/code&gt; (space, pipe, space). No nesting allowed in inline form.&lt;/p&gt;

&lt;h3&gt;
  
  
  Arrays
&lt;/h3&gt;

&lt;p&gt;Inline arrays work great for scalars:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tags   -&amp;gt; ["api" | "production" | "v2"]
ports  -&amp;gt; [8080 | 8443 | 9000]
flags  -&amp;gt; [true | false | true]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For longer lists or arrays of objects, use block syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;servers ::
    - "web1.internal"
    - "web2.internal"
    - "web3.internal"
:: servers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Arrays of objects use anonymous blocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;users ::
    - ::
        name -&amp;gt; "Alice"
        role -&amp;gt; "admin"
    :: -
    - ::
        name -&amp;gt; "Bob"
        role -&amp;gt; "viewer"
    :: -
:: users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comments
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This is a comment
    # Leading whitespace is fine too

name -&amp;gt; "Alice"  # THIS IS NOT a comment — inline comments are not allowed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;h3&gt;
  
  
  JavaScript / Node.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;stick-and-string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;stick-and-string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Using the JavaScript Library
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parseSAS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sasToJSON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsonToSAS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stick-and-string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Parse a SAS document into a JS object&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseSAS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
app ::
    name -&amp;gt; "myservice"
    port -&amp;gt; 8080
    debug -&amp;gt; false
:: app
`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// "myservice"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// 8080&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Converting to JSON:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sasToJSON&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stick-and-string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sasToJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;config.sas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// {&lt;/span&gt;
&lt;span class="c1"&gt;//   "app": {&lt;/span&gt;
&lt;span class="c1"&gt;//     "name": "myservice",&lt;/span&gt;
&lt;span class="c1"&gt;//     "port": 8080,&lt;/span&gt;
&lt;span class="c1"&gt;//     "debug": false&lt;/span&gt;
&lt;span class="c1"&gt;//   }&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Converting from JSON:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jsonToSAS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stick-and-string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;jsonToSAS&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sas&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// __sas_version__ -&amp;gt; "1.1"&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// server ::&lt;/span&gt;
&lt;span class="c1"&gt;//     host -&amp;gt; "localhost"&lt;/span&gt;
&lt;span class="c1"&gt;//     port -&amp;gt; 8080&lt;/span&gt;
&lt;span class="c1"&gt;//     tags -&amp;gt; ["api" | "v2"]&lt;/span&gt;
&lt;span class="c1"&gt;// :: server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Error handling:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parseSAS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SASParseError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stick-and-string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;parseSAS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name -&amp;gt; "Alice"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;name -&amp;gt; "Bob"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// duplicate key&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;SASParseError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Parse failed at line &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lineNum&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Parse failed at line 2: [Line 2] E01: Duplicate key "name"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CommonJS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parseSAS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sasToJSON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsonToSAS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stick-and-string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Using the Python Library
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sas_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;parse_sas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sas_to_json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json_to_sas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SASParseError&lt;/span&gt;

&lt;span class="c1"&gt;# Parse SAS → dict
&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_sas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;config.sas&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  &lt;span class="c1"&gt;# "myservice"
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  &lt;span class="c1"&gt;# 8080
&lt;/span&gt;
&lt;span class="c1"&gt;# SAS → JSON string
&lt;/span&gt;&lt;span class="n"&gt;json_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sas_to_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;config.sas&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;# dict → SAS string
&lt;/span&gt;&lt;span class="n"&gt;sas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;json_to_sas&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Error handling:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sas_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;parse_sas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SASParseError&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;parse_sas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name -&amp;gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;name -&amp;gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bob&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;SASParseError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Line &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line_num&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Line 2: [Line 2] E01: Duplicate key "name"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The CLI
&lt;/h2&gt;

&lt;p&gt;Both packages install a &lt;code&gt;sas&lt;/code&gt; command for use in the terminal or CI pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validate a file:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sas validate config.sas
&lt;span class="c"&gt;# ✓  Valid SAS 1.1 document: config.sas&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Convert SAS → JSON:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sas to-json config.sas
sas to-json config.sas &lt;span class="nt"&gt;--output&lt;/span&gt; config.json
sas to-json config.sas &lt;span class="nt"&gt;--compact&lt;/span&gt;   &lt;span class="c"&gt;# minified JSON&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Convert JSON → SAS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sas to-sas data.json
sas to-sas data.json &lt;span class="nt"&gt;--output&lt;/span&gt; data.sas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Round-trip check&lt;/strong&gt; (great for CI):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sas roundtrip config.sas
&lt;span class="c"&gt;# Roundtrip: config.sas  (SAS → JSON → SAS)&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;#   ✓ Parse SAS&lt;/span&gt;
&lt;span class="c"&gt;#   ✓ Re-encode to SAS and re-parse&lt;/span&gt;
&lt;span class="c"&gt;#   ✓ Data preserved exactly&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# ✓  Roundtrip OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Migrating an Existing JSON File
&lt;/h2&gt;

&lt;p&gt;Got an existing &lt;code&gt;config.json&lt;/code&gt; you want to move to SAS? One command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sas to-sas config.json &lt;span class="nt"&gt;--output&lt;/span&gt; config.sas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The converter handles everything automatically — nested objects become block objects, scalar arrays become inline arrays, large arrays of objects become block arrays with anonymous elements.&lt;/p&gt;




&lt;h2&gt;
  
  
  Error Codes
&lt;/h2&gt;

&lt;p&gt;SAS parsers never silently skip errors. Every problem comes with a line number and a code:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;E01&lt;/td&gt;
&lt;td&gt;Duplicate key in same scope&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E02&lt;/td&gt;
&lt;td&gt;Block closer doesn't match opener&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E03&lt;/td&gt;
&lt;td&gt;Unclosed block at end of file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E04&lt;/td&gt;
&lt;td&gt;Invalid escape sequence in string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E05&lt;/td&gt;
&lt;td&gt;Invalid number (leading zero, &lt;code&gt;NaN&lt;/code&gt;, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E06&lt;/td&gt;
&lt;td&gt;Wrong-case boolean or null (&lt;code&gt;True&lt;/code&gt;, &lt;code&gt;NULL&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E07&lt;/td&gt;
&lt;td&gt;Inline comment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E08&lt;/td&gt;
&lt;td&gt;Missing spaces around &lt;code&gt;-&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E09&lt;/td&gt;
&lt;td&gt;Missing spaces around `\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E10&lt;/td&gt;
&lt;td&gt;Trailing {% raw %}`\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E11&lt;/td&gt;
&lt;td&gt;Non-scalar value in inline array&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E12&lt;/td&gt;
&lt;td&gt;Nested inline object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E13&lt;/td&gt;
&lt;td&gt;Key beginning with {% raw %}&lt;code&gt;-&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E14&lt;/td&gt;
&lt;td&gt;Mixed block content (pairs + array items)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E15&lt;/td&gt;
&lt;td&gt;Anonymous closer outside array context&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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

&lt;p&gt;The spec, full API docs, and source code are all on GitHub. Both implementations are fully tested — 69 tests for JavaScript, 68 for Python — and the format spec is available as a readable Markdown document in the repo if you want to build your own parser in another language.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/TheServer-lab/stick-and-string" rel="noopener noreferrer"&gt;https://github.com/TheServer-lab/stick-and-string&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/stick-and-string" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/stick-and-string&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PyPI:&lt;/strong&gt; &lt;a href="https://pypi.org/project/stick-and-string/" rel="noopener noreferrer"&gt;https://pypi.org/project/stick-and-string/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Give it a try and let me know what you think in the comments. And if you do build a parser in another language, I'd love to know!&lt;/p&gt;

</description>
      <category>data</category>
      <category>showdev</category>
      <category>tooling</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I Built DoScript: An Automation Language Because Bash Was Too Hard</title>
      <dc:creator>Server-lab</dc:creator>
      <pubDate>Sun, 15 Feb 2026 12:42:30 +0000</pubDate>
      <link>https://dev.to/server-lab/i-built-doscript-an-automation-language-because-bash-was-too-hard-1ohj</link>
      <guid>https://dev.to/server-lab/i-built-doscript-an-automation-language-because-bash-was-too-hard-1ohj</guid>
      <description>&lt;h2&gt;
  
  
  The Problem That Started It All
&lt;/h2&gt;

&lt;p&gt;I wanted to automate tasks. Build installers. Organize files. You know, the stuff we all need to do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bash?&lt;/strong&gt; Too complicated with its cryptic syntax and arcane rules.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;PowerShell?&lt;/strong&gt; Powerful, sure, but felt like learning a new programming language.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Batch files?&lt;/strong&gt; Outdated and painful to write.&lt;/p&gt;

&lt;p&gt;I just wanted to write automation scripts that read like English. Why wasn't there something simple for that?&lt;/p&gt;

&lt;p&gt;So I thought: &lt;strong&gt;What if I built my own?&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Meet DoScript
&lt;/h2&gt;

&lt;p&gt;DoScript is an automation language designed to be as easy as writing English. No cryptic symbols, no confusing syntax—just straightforward commands that do what they say.&lt;/p&gt;

&lt;p&gt;Here's what backing up PDFs looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make folder "PDFBackup"

for_each file_in "Documents"
    if_ends_with ".pdf"
        copy {file_path} to "PDFBackup"
    end_if
end_for

say "Backup complete!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No pipes, no regex hell, no stackoverflow searches. Just readable automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What DoScript Can Do
&lt;/h2&gt;

&lt;p&gt;DoScript handles the automation tasks I actually needed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File Operations&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make folder "ProjectBackup"
copy "report.docx" to "ProjectBackup"
move "old_data.csv" to "Archive"
delete file "temp.txt"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Loops &amp;amp; Conditionals&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for_each file_in "Downloads"
    if_older_than {file_name} 30 days
        delete file {file_path}
        say "Deleted old file: {file_name}"
    end_if
end_for
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;System Operations&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;run "backup.bat"
open_link "https://example.com"
say "Opening website..."
wait 5 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Data Processing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;json_read data from "config.json"
json_get "settings.theme" from data into theme
say "Current theme: {theme}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plus: CSV handling, ZIP operations, HTTP requests, random generators, system monitoring, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Visual IDE
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. I also built a &lt;strong&gt;visual node-based IDE&lt;/strong&gt; for DoScript.&lt;/p&gt;

&lt;p&gt;Drag commands, connect them with wires, and build automation workflows visually. When you're done, it generates clean DoScript code you can save and run.&lt;/p&gt;

&lt;p&gt;Perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visual learners who prefer flowcharts&lt;/li&gt;
&lt;li&gt;Designing complex workflows&lt;/li&gt;
&lt;li&gt;Learning the language interactively&lt;/li&gt;
&lt;li&gt;Prototyping automation quickly&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Honest Truth About How I Built This
&lt;/h2&gt;

&lt;p&gt;Let me be transparent about the development process:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I designed:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The entire syntax (~90% of the language structure)&lt;/li&gt;
&lt;li&gt;Every command and how it should work&lt;/li&gt;
&lt;li&gt;The visual IDE concept&lt;/li&gt;
&lt;li&gt;The design philosophy: "automation as easy as English"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How I built it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most of the Python implementation code was AI-generated&lt;/li&gt;
&lt;li&gt;I designed the syntax, AI helped write the interpreter&lt;/li&gt;
&lt;li&gt;I tested everything, debugged, and iterated&lt;/li&gt;
&lt;li&gt;The visual IDE was coded with AI assistance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not a Python expert. I'm someone who wanted better automation tools and had a clear vision of what the language should look like. AI helped me implement that vision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My take:&lt;/strong&gt; You don't need to write every line of code yourself to create something valuable. Good design and clear vision matter more than pure coding prowess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Use Cases
&lt;/h2&gt;

&lt;p&gt;Here are actual things I use DoScript for:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Daily File Cleanup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for_each file_in "Downloads"
    if_older_than {file_name} 7 days
        delete file {file_path}
    end_if
end_for
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Project Backup Automation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make folder "Backup_{today}"
for_each file_in "Projects"
    if_ends_with ".py"
        copy {file_path} to "Backup_{today}"
    end_if
end_for
zip "Backup_{today}" into "Backups/backup_{today}.zip"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. System Health Check&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;system_cpu into cpu_usage
system_memory into mem_usage

if greater_than {cpu_usage} 80
    say "Warning: CPU usage high at {cpu_usage}%"
end_if
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try DoScript
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/TheServer-lab/DoScript" rel="noopener noreferrer"&gt;github.com/TheServer-lab/DoScript&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repository includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Python interpreter (&lt;code&gt;doscript.py&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Visual IDE (single HTML file, runs in browser)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Installer&lt;/strong&gt; (only 8.5 MB!) - Install once, run &lt;code&gt;.do&lt;/code&gt; scripts from any terminal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VS Code extension&lt;/strong&gt; - Syntax highlighting and support for DoScript files&lt;/li&gt;
&lt;li&gt;Example scripts&lt;/li&gt;
&lt;li&gt;Full command reference&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quick Start (with installer):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# After installing, just run from anywhere:&lt;/span&gt;
&lt;span class="k"&gt;do &lt;/span&gt;myscript.do
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Quick Start (without installer):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Current version:&lt;/strong&gt; v0.6.6&lt;/p&gt;

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

&lt;p&gt;I'm actively developing DoScript based on what I need and what the community suggests. Some ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More built-in commands&lt;/li&gt;
&lt;li&gt;Better error messages&lt;/li&gt;
&lt;li&gt;Package manager for sharing scripts&lt;/li&gt;
&lt;li&gt;More visual IDE features&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Questions I'm Expecting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Why not just learn Bash/PowerShell properly?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A: I did try. For complex automation, they're great. For quick tasks, DoScript is faster and more readable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Is this production-ready?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A: It works for my daily automation. Use it, break it, tell me what needs fixing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I contribute?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A: Absolutely! It's open source. Ideas, bug reports, and code contributions all welcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Why Python as the base?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A: Cross-platform, widely available, and easy to extend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I built DoScript because existing tools felt unnecessarily complex for simple automation. If you've ever felt the same frustration, give it a try.&lt;/p&gt;

&lt;p&gt;Is it perfect? No.&lt;br&gt;&lt;br&gt;
Does it solve a real problem? For me, absolutely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What would YOU automate if the language was this simple?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Drop a comment, star the repo, or just try it out. I'd love to hear what you think.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with: Vision (mine), Python (AI-assisted), and a lot of coffee.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
