Friendly CLI: a natural-language front-end for PatLang automation

The six self-hosted dev tools described a pattern: notice a recurring annoyance in the PatLang workflow, build a small self-hosted tool for it, verify it against the real codebase, and usually find a real bug along the way. Friendly CLI is that pattern applied to the user experience of PatLang itself. It is a domain-specific layer that lets a novice write automation scripts in plain English-like sentences — convert all md files in "docs" to docx — and have them expanded, compiled, and executed by the same self-hosted compiler that builds PatLang's own standard library.

Friendly CLI lives under friendly_cli/ in the PatLang repository. Every file in it is PatLang, compiled by PatLang, following the project's own rule about itself. It is not a toy: it shells out to real system tools (Pandoc, PowerShell, Ollama), persists learned performance models to disk, discovers tools on the system PATH, and in one experimental branch can ask a local LLM to synthesize a missing function it needs — then write a BDD spec, compile the result with patc1.exe, and verify the contract before registering the new action.

How it fits together

Friendly CLI is a pipeline of four cooperating layers, each written in PatLang and each building on the one below it:

Layer 1 — DSL syntax packs

The dsl/ directory contains syntax blocks that define natural-language rules for specific domains. Each rule maps a sentence shape to a PatLang function call. For example, in dsl/file_ops.patlang:

syntax FileOpsDSL {
  trigger: Keyword("do_files");
  tokens {
    Word(w) = regex("[a-zA-Z0-9_.-]+", w);
    StrLit(s) = regex("\"[^\"]*\"", s);
  }
  rule ConvertAllRule {
    expect Symbol("convert");
    expect Symbol("all");
    let ext = expect Word;
    expect Symbol("files");
    expect Symbol("in");
    let folder = expect StrLit;
    expect Symbol("to");
    let target = expect Word;
    return batch_convert_files(ext, folder, target);
  }
  # ... copy and delete rules follow the same pattern
}

A user writes:

do_files {
  convert all md files in "docs" to docx
  copy all txt files in "notes" to "backup"
  delete all tmp files in "cache"
}

and the syntax pack expands each line into the corresponding PatLang call. The do_goals trigger in dsl/goal_ops.patlang works the same way for high-level goal statements like make pdfs from markdown in docs.

Layer 2 — the action library

lib/actions.patlang provides the concrete functions that the DSL rules call: batch file conversion (via Pandoc), batch copy, batch delete, path manipulation, and format normalization. These are the "verbs" of the system — real, working functions that shell out to native tools and verify their results with Design-by-Contract preconditions and postconditions.

Layer 3 — the smart reasoning engine

lib/smart_engine.patlang is where Friendly CLI becomes more than a macro expander. It implements a Goal-Oriented Action Planning (GOAP) engine:

  • Actions are registered with preconditions and effects (e.g., act_md_to_docx requires has_md and produces has_docx).
  • Rules assert initial state facts (e.g., rule_add("has_md", ["docs"])).
  • Planning uses a backward-chaining solver to compute the action sequence that reaches a target state (e.g., archive_backup requires has_pdf, which requires has_docx, which requires has_md).
  • Execution runs the planned actions in order, with each action bound to real PatLang code that performs the work.

When a user writes make pdfs from markdown in docs followed by archive the pdfs into backup.zip, the GOAP engine automatically discovers the chain: convert md → docx, convert docx → pdf, archive pdfs into zip — and executes it end to end.

Layer 4 — adaptive performance model

Every action is timed. lib/adaptive_predictor.patlang and lib/perf_database.patlang implement persistent linear regression models that learn the relationship between input size (lines of code, number of files) and execution time. Before running a plan, the engine predicts the total duration; after running, it updates the model via gradient descent and logs the result to a SQL-style performance database on disk.

[REASONING ENGINE] Estimated total plan execution time: 12450 ms
[SMART GOAP EXECUTING] Step 1: Converting 2 Markdown files (Estimated: 5000 ms)...
  -> Actually took: 4830 ms
[DATABASE UPDATE] Task: pandoc | New w: 32.5 ms/unit | Bias: 4980.0 ms

The goal preprocessor

lib/goal_preprocessor.patlang bridges the gap between human-friendly input and the DSL syntax packs. It transforms block syntax like:

goal:
  make pdfs from markdown in docs
  archive the pdfs into backup.zip

into the do_goals { ... } wrapper that the syntax pack expects. This means a novice never needs to remember curly braces or function names — they just write what they want, in sentences, and the preprocessor handles the boilerplate.

Verification by BDD

Every capability in Friendly CLI is verified by a PatLang BDD spec. The test_*_spec.patlang files use the native Gherkin framework (lib/test.patlang) to assert that:

  • The file operations DSL correctly converts, copies, and deletes files.
  • The GOAP engine automatically chains multi-step plans from high-level goals.
  • Performance predictions improve on subsequent runs via gradient descent learning.
  • The relational performance database is populated with correct SQL records.
  • Synthesized functions (from the self-healing engine) pass their contract checks.

Each spec is run through a preprocessor (run_*_preproc.patlang) that expands includes and writes an expanded file, then compiled and executed with patc1.exe. The BDD runner reports pass/fail per scenario.

The self-healing engine

The most experimental part of Friendly CLI is lib/self_healing_engine.patlang. When a required host function is missing, the engine can:

  1. Query a local Ollama model for the Windows command to accomplish the task.
  2. Synthesize a PatLang wrapper function with Design-by-Contract preconditions and postconditions.
  3. Generate a BDD specification for the synthesized function.
  4. Write both files to disk and compile them with patc1.exe.
  5. Run the BDD spec to verify the function works before registering it as a new action.

This is the full circle of the self-hosting philosophy: not only is the compiler written in PatLang, but the tools that extend the language's capabilities are also written in PatLang, verified by PatLang, and compiled by PatLang.

Dynamic tool discovery

lib/tool_discovery.patlang scans the system PATH for available native tools (Pandoc, PowerShell, etc.) and generates PatLang source code that registers them as GOAP actions with DbC contracts. The generated catalog is written to discovered_catalog.patlang and only rewritten when the set of available tools changes — an incremental check that avoids unnecessary file writes.

Running Friendly CLI

The main demo driver is run_demo.patlang. It dynamically loads the regex DSL, syntax DSL, action library, and file operations pack, then constructs and runs a driver script that:

  1. Loads the syntax pack definitions.
  2. Reads a novice script (the do_files { ... } block).
  3. Expands the natural-language DSL into PatLang statements.
  4. Tokenizes, parses, lowers, and executes the expanded program via run_ir.
pat --ir-run friendly_cli/run_demo.patlang

The BDD verification suites are run similarly, each with its own preprocessor:

pat --ir-run friendly_cli/run_smart_preproc.patlang
pat --ir-run friendly_cli/run_bdd.patlang

Key design insights

The string-bool convention

Throughout Friendly CLI, file existence is checked with file_exists(path) == "1", not == true. This is PatLang's documented "legacy string-bool convention" — file_exists returns the string "1" or "0", not a boolean. The action library handles both forms with (file_exists(path) == "1") or (file_exists(path) == true) for robustness.

Contracts before execution

Every action that touches the filesystem or shells out to a native tool wraps its work in require/ensure contracts. A failed precondition aborts before any work is done; a failed postcondition aborts after, reporting exactly what went wrong. This is not defensive programming – it is correctness by construction, the same principle that governs the rest of the PatLang ecosystem.

Learning from real data

The performance model starts with a rough guess (35 ms/line, 5000 ms startup) and improves with every execution. The gradient descent learning rate is tiny for line-count-based tasks (to avoid overflow from large line numbers) but larger for file-count-based tasks like zipping. The model persists to disk between runs, so the system gets faster and more accurate the more it is used.

Where it lives in the PatLang ecosystem

Friendly CLI sits at the intersection of several PatLang capabilities: