A command-line interface for executing Starlark scripts with rich module support, interactive mode, and web server capabilities.
StarCLI is a versatile tool that provides a convenient environment for running Starlark scripts from the command line. Starlark is a dialect of Python designed for configuration, extensibility, and embedding. StarCLI extends Starlark with additional modules and utilities to make it more powerful for various automation and scripting tasks.
-
Multiple Execution Modes:
- REPL (Read-Eval-Print Loop) for interactive script development
- Direct code execution from command line arguments
- Script file execution
- Web server mode that creates a Starbox environment for HTTP requests
-
Configurable Environment:
- Load custom modules
- Control recursion and global variable reassignment
- Set include paths for module loading
- Configure logging levels
-
Rich Module Support:
- Standard library modules (json, math, time, etc.)
- File system operations
- Network and HTTP requests
- Regular expressions
- Base64 encoding/decoding
- Email functionality
- LLM (Language Model) integration
- And many more
Clone the repository and build from source:
git clone https://github.com/1set/starcli.git
cd starcli
make buildThe project includes a Dockerfile to build and run StarCLI in a container:
# Build the Docker image
docker build -t starcli .
# Run in interactive mode
docker run -it starcli
# Run a specific script
docker run -v $(pwd):/scripts starcli sh -c "/root/starcli /scripts/your-script.star"$ ./starcli -h
Usage of ./starcli:
--allow-cmd widen a restrictive tier with the cmd module (host command execution)
--allow-fs widen a restrictive tier with filesystem modules (file, path)
--allow-net widen a restrictive tier with network modules (http, net, email, llm)
--caps string capability tier: open (default, everything) | full | network | safe; or env STAR_CAPS
--check syntax/resolve check the script (-c or file) without running it
-c, --code string Starlark code to execute
-C, --config string config file to load
-g, --globalreassign allow reassigning global variables in Starlark code (default true)
-I, --include string include path for Starlark code to load modules from (default ".")
-i, --interactive enter interactive mode after executing
-l, --log string log level: debug, info, warn, error, dpanic, panic, fatal (default "info")
--log-file string append the script's log module output to this file
--log-format string log file format: console (human) or json (machine) (default "console")
--max-output uint max top-level output entries per run (0=unlimited)
--max-steps uint max Starlark execution steps per run, guards runaway loops (0=unlimited)
-m, --module strings allowed modules to preload and load (default [args,atom,base64,cmd,csv,email,file,go_idiomatic,gum,hashlib,http,json,llm,log,markdown,math,net,path,random,re,regex,runtime,serial,sqlite,stats,string,struct,sys,time,web])
-o, --output string output printer: none,stdout,stderr,basic,lineno,since,auto (default "auto")
--record string record the complete session output (stdout+stderr) to this transcript file
-r, --recursion allow recursion in Starlark code
-V, --version print version & build information
-w, --web uint16 run web server on specified port, it provides request and response structs for Starlark code to useBy default StarCLI runs open β every wired module is available, so scripts
just work. To sandbox an untrusted script, tighten the capability tier with
--caps (or the STAR_CAPS env var) and a default-deny load gate is installed:
| tier | loadable modules |
|---|---|
(default) open |
everything, including cmd (host command execution) |
--caps full |
network and filesystem (but not cmd) |
--caps network |
safe + network (http, net, email, llm) |
--caps safe |
pure / log / process only (math, json, sys, gum, markdown, β¦) |
From a restrictive tier the granular flags widen the grant: --allow-net,
--allow-fs, and --allow-cmd (cmd is never granted by a tier β not even
full β only by --allow-cmd). A module is classified by the union of
everything it can do, so the dual-capability modules β web (HTTP +
static_dir) and sqlite (DB + remote connect_remote) β need both
--allow-net and --allow-fs (or --caps full).
Set a stricter default for a whole deployment with the env var:
export STAR_CAPS=safe # default every invocation to the safe tierUnder a restrictive tier, a script that load()s a withheld module fails with a
non-zero exit code (4 for a withheld builtin). Execution budgets bound runaway
scripts: --max-steps caps Starlark computation steps and --max-output caps a
run's result size.
# open by default: anything loads
$ ./starcli -c 'load("http", "get"); print(get)'
# sandbox down to safe: a network module is now withheld
$ ./starcli --caps safe -c 'load("http", "get")' # fails (exit 4)
# from safe, opt back into the network
$ ./starcli --caps safe --allow-net -c 'load("http", "get"); print(get)'
# host command execution always needs its own explicit flag
$ ./starcli --caps safe --allow-cmd -c 'load("cmd", "run"); print(run("echo", "hi"))'Start an interactive REPL session:
$ ./starcliRun a single line of Starlark code:
$ ./starcli -c 'print("Hello, World!")'Run a Starlark script file:
$ ./starcli path/to/script.starExecute code and then enter interactive mode with the environment preserved:
$ ./starcli -c 'greeting = "Hello, World!"' -iStart a web server that executes Starlark code for HTTP requests:
$ ./starcli -w 8080 -c 'def handle_request(request): return {"message": "Hello from Starlark!"}'Run with debug-level logging:
$ ./starcli --log debug path/to/script.starThe args module is an argparse-style parser for the script's own arguments
(everything after --). argv[0] is the script name (or -c), like Python's
sys.argv; parse_args() parses argv[1:].
load("args", "ArgumentParser")
p = ArgumentParser(description = "greet someone")
p.add_argument("--name", default = "World", help = "who to greet")
p.add_argument("--count", type = int, default = 1)
p.add_argument("--shout", action = "store_true")
p.add_argument("file", help = "input file")
ns = p.parse_args()
print(ns.name, ns.count, ns.shout, ns.file)$ ./starcli greet.star -- --name Kevin --count 3 --shout in.txt
Kevin 3 True in.txtWhen a script uses the log module, --log-file routes all of its output to a
file at the interpreter level (the parent directory is created if needed, and
runs append):
load("log", "info", "warn")
info("starting up")
warn("careful now")$ ./starcli --log-file run.log job.star
$ cat run.log
2026-06-21T17:32:07.373+0800 info starting up
2026-06-21T17:32:07.373+0800 warn careful nowUse --log-format json for machine-readable logs (structured fields included):
$ ./starcli --log-file run.log --log-format json job.star
{"level":"info","ts":"2026-06-21T17:32:07.373+0800","msg":"starting up"}--record saves the complete session output β print output, results, REPL
interaction and errors β to a transcript file (appended, with a timestamped
session header), while still showing it live. Handy for replay and review.
$ ./starcli --record session.log job.star # works in REPL mode too
$ cat session.log
===== starcli session 2026-06-21T17:43:24+08:00 =====
... everything the run printed (stdout + stderr) ...The sys module reads piped data from standard input (the script itself
still comes from a file or -c). sys.read() returns all of stdin; sys.lines()
is a lazy iterator (a large stream is not buffered whole); sys.isatty()
tells interactive from piped input.
load("sys", "lines")
for line in lines():
print(line.upper())$ printf 'foo\nbar\n' | ./starcli upper.star
FOO
BARSyntax- and resolve-check a script without executing it (reports problems as
file:line:col: message, non-zero exit on any problem):
$ ./starcli --check path/to/script.star
$ ./starcli --check -c 'print(undefined_name)'
direct.star:1:7: undefined: undefined_name
check: 1 problem(s) foundStarCLI can be configured through a config file (YAML format) using the -C or --config flag:
# Example config.yaml
host_name: MyStarCLIServer- Go 1.25 or later
# Build for current platform
make build
# Build for specific platforms
make build_linux
make build_mac
make build_windowsmake testThis project is licensed under the MIT License. See the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
For any questions or support, please open an issue on GitHub.