# Rad > A scripting language designed to make writing CLI tools delightful. Familiar, Python-like syntax with CLI essentials built-in. ## Guide - [Getting Started](https://amterp.dev/rad/guide/getting-started.md): What is Rad?, Installation, Editor Support, Your First Rad Script - Hello World, Adding In Some Rad Features, Improving The Script Usage String, Shebang, A Complete Example - [Basics](https://amterp.dev/rad/guide/basics.md): Variables & Assignment, Data Types, Destructuring, Operators, Functions, Control Flow, List Comprehensions, Truthy / Falsy, Converting Types, Errors - [Args](https://amterp.dev/rad/guide/args.md): Arg Declarations, How Argument Parsing Works, Argument Types and User Input, Constraints - [Functions](https://amterp.dev/rad/guide/functions.md): Syntax, Function Arguments, Custom Functions, Reference - [Strings (Advanced)](https://amterp.dev/rad/guide/strings-advanced.md): String Interpolation, Formatting, Multiline Strings, Raw Strings, Escape Sequences, String Attributes, Patterns: Literal by Default - [Rad Blocks](https://amterp.dev/rad/guide/rad-blocks.md): Basic Example, Additional Rad Block Options, Rad Block Options, Source Types, Understanding HTTP Requests - [Type Annotations](https://amterp.dev/rad/guide/type-annotations.md): The Basics, Collection Types, Optional Types, Defaults, Union Types, Advanced Types, Variadic and Named Parameters - [Error Handling](https://amterp.dev/rad/guide/error-handling.md): Error Propagation, Catch Blocks, The `??` Operator, The `catch` Operator, Creating Your Own Errors, Holding an Error - [Shell Commands](https://amterp.dev/rad/guide/shell-commands.md): Invoking Commands, Which Shell Runs My Command?, Capturing Output, Reading One Result Inline, Error Handling, String Interpolation, Commands As Lists, Modifiers, Practical Examples - [Script Commands](https://amterp.dev/rad/guide/script-commands.md): Basic Syntax, Multiple Commands, Adding Descriptions, Command Arguments, Shared Args, Nested Commands, Default Commands, Command Callbacks, Shared Logic, Getting Help, Practical Example - [Resources](https://amterp.dev/rad/guide/resources.md): `pick`, `pick_kv`, `pick_from_resource` - [Global Flags](https://amterp.dev/rad/guide/global-flags.md): `help`, `interactive`, `debug`, `quiet`, `color`, `src`, `cst-tree`, `ast-tree`, `tls-insecure`, `mock-response`, `reply`, `reply-na` - [Defer & Errdefer](https://amterp.dev/rad/guide/defer-errdefer.md): Defer, Errdefer, Errors in defer blocks - [Stashes](https://amterp.dev/rad/guide/stashes.md): The Basics, State Storage, File Storage, Stash Structure, Managing Stashes - [Configuration](https://amterp.dev/rad/guide/config.md): Invocation Logging - [Built-in Commands](https://amterp.dev/rad/guide/built-in-commands.md): `rad new`, `rad check`, `rad fmt`, `rad docs`, `rad stash`, `rad gen-id`, `rad home`, `rad completion` - [REPL](https://amterp.dev/rad/guide/repl.md): Blocks take several lines, Mistakes don't end the session, Editing, Commands, Two things behave differently than in a script, Piping input, What it doesn't do yet - [Shell Completion](https://amterp.dev/rad/guide/shell-completion.md): Quick Setup, What Gets Completed, Script Completions, Multiple Scripts & Globs, Full Example ## Examples - [Examples](https://amterp.dev/rad/examples/index.md) - [brewi](https://amterp.dev/rad/examples/brewi.md): Preview, Tutorial: Building `brewi`, Concepts demonstrated - [epoch](https://amterp.dev/rad/examples/epoch.md): Preview, Tutorial: Building `epoch`, Concepts demonstrated - [hm](https://amterp.dev/rad/examples/hm.md): Preview, Tutorial: Building `hm`, Concepts demonstrated ## Reference - [Language Reference](https://amterp.dev/rad/reference/syntax.md): Script Structure, Comments, Data Types, Variables and Assignment, String Interpolation, Ternary Operator, Collection Access and Slicing, Control Flow, Additional Control Flow, Functions, List Comprehensions, Argument Parsing, Script Commands, Shell Commands, JSON Processing and Display Blocks, Advanced Features, Operators, Scoping and Variables, Built-in Types and Methods, Type System, Rad Code Style - [Functions](https://amterp.dev/rad/reference/functions.md): How to Read This Document, Crypto, Formatting, HTTP, IO, Lists, Math, Parsing, Random, Stash, Strings, System, Time - [Errors](https://amterp.dev/rad/reference/errors.md): Syntax Errors (RAD1xxxx), Runtime Errors (RAD2xxxx), Type Errors (RAD3xxxx), Validation & Lint Errors (RAD4xxxx) ## Migrations - [How to Migrate](https://amterp.dev/rad/migrations/index.md): Guides, Upgrade Workflow - [v0.12](https://amterp.dev/rad/migrations/v0.12.md): Breaking Change: Shell Commands Quote Interpolated Values, Breaking Change: Shell Captures Bind stdout First, Exit Code Last, Breaking Change: `$` Takes The Command, Not The Whole Expression, Breaking Change: List Args Collect Every Positional Value, Breaking Change: Constraints On A List Arg Are Enforced, Breaking Change: Flag-Like Tokens Are Rejected As Values, Breaking Change: A Bare List Flag Is Rejected, Breaking Change: `split()` and `replace()` Match Literally, Breaking Change: Scripts That Prompt Stop Before Running Without A Terminal, Behavior Change: `??` and `catch` See Errors You Already Hold, New: Reading A Command Inline, New: `len` Bounds On List Args, Error Messages - [v0.9](https://amterp.dev/rad/migrations/v0.9.md): Breaking Change: `request` and `display` Keywords Removed, Breaking Change: `get_stash_dir` Renamed, Migration Steps, Breaking Change: `??` Now Fires on Null, New: `catch` Operator, Breaking Change: Strict `+` Concatenation, Breaking Change: `parse_epoch` Unit Names Shortened, Error Messages, Behavior Change: Invocation Logging Enabled by Default, Breaking Change: `trim_prefix` / `trim_suffix` Behavior Changed - [v0.8](https://amterp.dev/rad/migrations/v0.8.md): Breaking Change: `get_default` Removed, Migration Steps, Why This Change?, Error Messages - [v0.7](https://amterp.dev/rad/migrations/v0.7.md): Breaking Change: For-Loop Index Syntax, Migration Steps, Error Messages, Why This Change?, Bonus: Rad Block Lambda Context ## Other - [Project Status](https://amterp.dev/rad/status.md): Platform Support, Near-term Focus, Long-term Vision, Get Involved - [Releases](https://amterp.dev/rad/releases.md) --- # Getting Started ## What is Rad? *If you want to jump straight to programming, feel free to skip forwards to Installation.* **Rad is a modern programming language and interpreter designed to make writing CLI scripts delightful.** It has a familiar, Python-like syntax with built-in concepts like declarative arguments, JSON handling, first-class shell integration, and user prompts - making common scripting tasks easy and fast to implement. If you've ever written scripts and felt like your tools were fighting you, you're not alone: **With Bash**, you might find yourself: - Wrestling with `while getopts` boilerplate just to parse a few arguments - Doing `curl | jq | awk` gymnastics to process JSON - Skipping the "nice-to-haves" like `--help` or input validation because they're too painful to implement - Delivering scripts that work, but are hard to read and harder to maintain **With Python**, you get better syntax, but: - You need argparse boilerplate before you even start solving your problem, or reach for additional libraries - Sharing scripts means coordinating runtimes and dependencies (virtualenvs, lockfiles) - Simple CLI tasks feel heavier than they should **With Rad**, the language is purpose-built for CLI scripting: - **Delightful to write** - familiar syntax without the footguns - **Self-documenting** - automatic `--help` generation from your code comments - **Declarative arguments** - type checking, validation, and parsing built into the language - **Easy to share** - batteries included, no external dependencies needed If you ever write a CLI script, **Rad is the language to do it in**. **Project Status:** Rad is in early development but useful today for real scripts. Core features work well, though expect breaking changes between versions as the language evolves. Your feedback directly shapes Rad's future! Let's get into it. ## Installation ### macOS (Homebrew) ```bash brew install rad ``` ### Go (from source, all platforms) ```bash go install github.com/amterp/rad@latest go install github.com/amterp/rad/radls@latest ``` The first command installs the `rad` interpreter. The second installs `radls`, the language server for editor support. **Note:** You will need to run `go install` yourself to upgrade Rad as new versions are released. For automated updates, use one of the supported package managers that allow it. ### Binary Downloads Pre-built binaries for macOS, Linux, and Windows: releases page (https://github.com/amterp/rad/releases) Each release archive includes both `rad` (the interpreter) and `radls` (the language server). ### Checking Installation After you've installed Rad and ensured it's on your PATH, you can check your installation: ```sh rad -h ``` If this prints the help string for Rad, you're set! ## Editor Support ### Visual Studio Code Rad has a VS Code extension here (https://marketplace.visualstudio.com/items?itemName=amterp.rad-extension) which provides: - **Syntax highlighting** - makes your Rad code easy to read - **Real-time validation** - catches syntax errors as you type - **Diagnostics** - warnings and hints from the Rad Language Server Installing it is highly recommended! !vsc-example.png **Note: Language Server Requirement** The VS Code extension uses the Rad Language Server (`radls`) for real-time validation and diagnostics. This is installed automatically when you install Rad via Homebrew or `go install`. If you see "Rad Language Server not found", make sure `rad` and `radls` are on your PATH. ### Other Editors The Rad Language Server (`radls`) can be used with any editor that supports the Language Server Protocol (LSP): - **Neovim**: Configure with `nvim-lspconfig` - point it to the `radls` binary - **Sublime Text**: Use the LSP package with the `radls` command For syntax highlighting without LSP, Rad's TextMate grammar can be used in editors that support it. ## Your First Rad Script - Hello World Let's write the classic "Hello, World!" program. We'll then modify it to give it a bit of a Rad twist, demoing a few features that Rad provides. First, create a file, let's call it simply `hello`, and give it the following contents: ```rad print("Hello, World!") ``` **Tip: `print()`** `print()` is the go-to function for outputting to stdout. It behaves a lot like `print()` in Python. You can read more about it in the reference (rad docs print). **Info: File Extension** If you want to give your Rad scripts an extension, you can use `.rad` as a convention. Then, run the script from your CLI by invoking `rad` on it, and you should see it print out like so: ```sh > rad hello ``` ``` Hello, World! ``` Nice! Now, let's spruce it up with a few Rad features. ## Adding In Some Rad Features One of Rad's primary features is its simple, declarative style to defining script arguments. Let's modify the script to greet a name you input from command line. ```rad args: name str print("Hello, {name}!") ``` A couple of things to note here: 1. We define an "args block". Right now it contains just the one line, but you can do lots of things in here (rad docs guide/args). 2. The modified `print()` utilizes string interpolation (rad docs guide/strings-advanced). String interpolation in Rad behaves a lot like it does in Python (you'll see this is a pattern). Now, let's try invoking the script again, and this time, input a name: ```sh > rad hello Alex ``` ``` Hello, Alex! ``` Cool! What happens if we invoke *without* a name? ```sh > rad hello ``` ``` Usage: hello Script args: --name str ``` If you run a Rad script without providing *any* args to a script which expects at least one, Rad will print out the script usage, interpreting your invocation as if you had passed `--help`. **Tip: Positional vs Flag Arguments** Arguments can be passed positionally or via flags. For example, both `./hello Alice` and `./hello --name Alice` work identically. The help text shows both forms: `` for positional usage and `--name str` for the flag form. This shows a little of the automatic script usage that Rad generates for you. Let's explore that a bit more. ## Improving The Script Usage String Rad facilitates writing well-documented and easy-to-use scripts, in part through unique syntax. Let's use a couple of those now. First, we'll add a **file header** to your script. ```rad --- Prints a polite greeting using an input name. --- args: name str print("Hello, {name}!") ``` **Tip: File Headers** File headers, as the name suggests, go at the top of Rad scripts (with the exception of shebangs, to be covered later). They allow you to write a description for your script in between two `---` lines. The contents will get printed as part of the script's usage string. A couple of ideas on what to cover in your file headers: - A brief description of what the script does and how it works - Examples of valid invocations and what they do. Second, we can add **comments** to args that a script declares. Let's do that too: ```rad --- Prints a polite greeting using an input name. --- args: name str # The name of someone to greet. print("Hello, {name}!") ``` **Info: Note on `#` vs. `//`** Rad uses `#` to denote *arg* comments. `#` comments are special and **do get passed** to Rad's parser and can affect script behavior (namely in this case, adding information to the script usage string). Standard code comments in Rad use `//`, similar to Java or C/C++, and **don't** impact script behavior. Now, when someone reads the script, it's pretty clear what the script does and what the expected arguments are. But it gets better! Let's try invoking the script's usage string again (this time let's try using the `-h` flag explicitly, though it's not necessary): ```sh > rad hello -h ``` ``` Prints a polite greeting using an input name. Usage: hello Script args: --name str The name of someone to greet. ``` Not only is the script now easier to maintain for developers, it's also easier for users to understand! ## Shebang Needing to manually invoke `rad` each time you want to run a Rad script can be a little cumbersome. Thankfully, Unix kernels provide a mechanism known as a "shebang". Let's add one to our script. It has to go on the very first line. ```rad #!/usr/bin/env rad --- Prints a polite greeting using an input name. --- args: name str # The name of someone to greet. print("Hello, {name}!") ``` Then, make the script executable using the following command: ```sh chmod +x ./hello ``` Now, you can invoke the script directly: ```sh > ./hello Bob ``` ``` Hello, Bob! ``` When you invoke an executable script this way, the kernel scans for a shebang (`#!`) in the first line. If it finds a path to an interpreter (in this case, it will find `rad`, if set up correctly in your `PATH`), then it will invoke said interpreter on the script (equivalent to `rad hello` like we were doing before). **Tip: rad new** Rad has a command `rad new