Everything you need to go from "never coded before" to a running program — and from there to a real API you can ship.
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.
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.
upgrade ide to open the built-in browser IDE with live syntax highlighting and friendly errors as you type.Every Upgrade program is built from exactly three things:
| Word | Does | Example |
|---|---|---|
say | Show something | say "Hello!" |
remember | Store a value under a name | remember age = 21 |
do | Call 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.
if age < 13 say "kid" else say "adult" end
repeat 5 times say "hi" end
repeat for each task in ["plan", "build", "ship"] say "Doing: " + task end
Comparisons: == != < > <= >=. Boolean logic: and, or, not.
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.
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.
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.
| Action | What it does |
|---|---|
do web.get with url into result | HTTP GET, returns text |
do web.get_json with url into result | HTTP GET, parsed as JSON |
do web.post with url, data into result | HTTP POST |
do file.read with path into result | Read a file |
do file.write with path, content | Write a file |
do file.append with path, content | Append to a file |
do file.exists with path into result | Check a file exists |
do automation.wait with seconds | Pause |
do automation.now into result | Current timestamp |
do automation.run with command into result | Run an allow-listed shell command |
do api.serve with port | Start the web server for declared routes |
UPGRADE_SANDBOX_NETWORK=1 to block private/loopback addresses if you ever run Upgrade somewhere shared.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.
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.
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.
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.
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
define classify with age if age < 13 return "kid" else return "adult" end end say classify(9) say classify(34)
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.