Documentation

Everything you need to go from "never coded before" to a running program — and from there to a real API you can ship.

Install

Download the installer for your OS from the homepage and run it — nothing else to install — it just works.

upgrade --version

That's it. No accounts, no config files. upgrade is now a command on your machine.

5-minute tutorial

Create a file called hello.up and write:

say "Hello, world!"
remember name = "Caleb"
say "Hi, " + name

Run it:

upgrade hello.up

You should see:

Hello, world!
Hi, Caleb

Now add a loop:

repeat 3 times
    say "Counting..."
end

Run the file again. Every block in Upgrade ends with end — there's no indentation rule to memorize; indentation is just for you to read.

Prefer a visual editor? Run upgrade ide to open the built-in browser IDE with live syntax highlighting and friendly errors as you type.

Three primitives

Every Upgrade program is built from exactly three things:

WordDoesExample
sayShow somethingsay "Hello!"
rememberStore a value under a nameremember age = 21
doCall an action (a built-in or your own function)do file.write with "a.txt", "hi"

remember always refers to the same variable wherever it's used — updating it inside a loop or an if updates the outer value, it never silently creates a hidden shadow copy.

Control flow

if / else

if age < 13
    say "kid"
else
    say "adult"
end

repeat ... times

repeat 5 times
    say "hi"
end

repeat for each ... in ...

repeat for each task in ["plan", "build", "ship"]
    say "Doing: " + task
end

Comparisons: == != < > <= >=. Boolean logic: and, or, not.

Functions

define double with x
    return x * 2
end

say double(21)   # 42

# or call it as an action:
do double with 21 into result

Functions can call themselves (recursion) and parameters never leak into the caller's variables.

Lists & collections

remember nums = [1, 2, 3]
say nums[0]              # 1
remember nums[1] = 99
say nums               # [1, 99, 3]

remember person = {"name": "Caleb"}
say person["name"]      # Caleb
say keys(person)        # [name]

Negative indices work (list[-1] is the last item). Built-ins: range, len, str, int, float, round, upper, lower, join, split, now, keys, values, contains, get, add_to.

Multilingual keywords

A file is English by default. To write in another language, the very first line must declare it:

# lang: es
decir "Hola!"
recordar nombre = "Caleb"

Supported packs: es (Spanish), fr (French), hi (Hindi, Roman script). Each pack is fully isolated — a short word that's a keyword in one language can never collide with a variable name in another.

Standard library

ActionWhat it does
do web.get with url into resultHTTP GET, returns text
do web.get_json with url into resultHTTP GET, parsed as JSON
do web.post with url, data into resultHTTP POST
do file.read with path into resultRead a file
do file.write with path, contentWrite a file
do file.append with path, contentAppend to a file
do file.exists with path into resultCheck a file exists
do automation.wait with secondsPause
do automation.now into resultCurrent timestamp
do automation.run with command into resultRun an allow-listed shell command
do api.serve with portStart the web server for declared routes
Reaching local/private network addresses is allowed by default (handy for testing your own dev server). Set UPGRADE_SANDBOX_NETWORK=1 to block private/loopback addresses if you ever run Upgrade somewhere shared.

Routes & APIs

define submit_handler with data
    remember name = get(data, "name", "stranger")
    return "Hello, " + name
end

route POST "/submit" calls submit_handler
do api.serve with 5000

route accepts an optional method (GET, POST, PUT, DELETE, PATCH) before the path; default is GET. A handler takes 0 parameters, or exactly 1 — that one parameter receives a dict merging the request's JSON body, form fields, and query parameters. Errors inside a handler come back as a friendly JSON error, never a raw crash page.

Shipping (ship app)

Add ship app as the last line of a program. Running it produces a self-contained build/ folder: a standalone runner, auto-detected requirements.txt, a working Dockerfile, a run.sh, and plain-English deploy notes for whatever still needs a human.

The IDE

upgrade ide

Opens a local browser IDE: live three-color syntax highlighting for say/remember/do, real line numbers, an Examples menu, and an "Explain this error" button. Each run executes in its own short-lived process with a 5-second time budget, so an accidental infinite loop can't freeze the tab. do api.serve is safely skipped inside the IDE (it would hang the request) — use the command line or ship app to actually serve.

Errors

Every Upgrade error is plain English with a line number and usually a fix — never a raw technical stack trace, even from inside a live web route.

Oops! I don't know anything called 'mystery_var' (line 1).
  Tip: Did you 'remember' it first, or is it spelled differently?

The IDE's "Explain this error" button gives a richer, rule-based explanation by default, or a real AI-generated one if you opt in by setting an API key environment variable.

Examples

Automation script

remember tasks = ["check email", "deploy app", "write docs"]
repeat for each task in tasks
    say "- " + task
end
do automation.now into timestamp
say "Finished at " + timestamp

Web app logic

define classify with age
    if age < 13
        return "kid"
    else
        return "adult"
    end
end

say classify(9)
say classify(34)

A tiny API

define status_check
    return "ok"
end

route "/status" calls status_check
do api.serve with 5000

More worked examples ship with the package itself, in its examples/ folder.