CLI Reference

Scriptling includes a command-line interface for running scripts, interactive mode, and HTTP/MCP server.

Installation

Homebrew (macOS & Linux)

brew install paularlott/tap/scriptling

GitHub Releases

Download pre-built binaries from GitHub Releases:

Platform Architectures
Linux AMD64, ARM64
macOS AMD64, ARM64
Windows AMD64, ARM64

Go Install

If you have Go installed:

go install github.com/paularlott/scriptling/scriptling-cli@latest

Build from Source

# Clone the repository
git clone https://github.com/paularlott/scriptling.git
cd scriptling

# Build for current platform
make build
# or use Task: task build

# Build for all platforms
make build-all
# or use Task: task build-all

Basic Usage

Run a Script

scriptling script.py

Pipe Script

echo 'print("Hello")' | scriptling
cat script.py | scriptling

Interactive Mode

scriptling --interactive
# or
scriptling -i

Lint Mode

Lint scripts for syntax errors without executing them:

# Lint a file
scriptling --lint script.py

# Lint from stdin
echo 'x = 1 +' | scriptling --lint

# JSON output format
scriptling --lint --lint-format json script.py

Text output format:

script.py:3: expected token COLON (error)

JSON output format:

{
  "files_checked": 1,
  "has_errors": true,
  "errors": [
    {
      "file": "script.py",
      "line": 3,
      "message": "expected token COLON",
      "severity": "error",
      "code": "parse-error"
    }
  ]
}

The linter exits with code 0 if no errors are found, and code 1 if any errors exist.

Command Line Options

Flag Environment Variable Description Default
-i, --interactive - Start interactive mode false
-l, --lint - Lint script files without executing false
--lint-format SCRIPTLING_LINT_FORMAT Output format for lint (text/json) text
--libdir SCRIPTLING_LIBDIR Directory to load libraries from (current dir)
--log-level SCRIPTLING_LOG_LEVEL Log level (trace/debug/info/warn/error) info
--log-format SCRIPTLING_LOG_FORMAT Log format (console/json) console
-S, --server SCRIPTLING_SERVER HTTP server address (host:port) (disabled)
--mcp-tools SCRIPTLING_MCP_TOOLS Directory containing MCP tools (disabled)
--mcp-exec-script - Enable MCP script execution tool false
--bearer-token SCRIPTLING_BEARER_TOKEN Bearer token for authentication none
--allowed-paths SCRIPTLING_ALLOWED_PATHS Comma-separated allowed filesystem paths (no restriction)
--tls-cert SCRIPTLING_TLS_CERT TLS certificate file none
--tls-key SCRIPTLING_TLS_KEY TLS key file none
--tls-generate - Generate self-signed certificate false

Environment Configuration

The CLI automatically loads environment variables from a .env file in the current directory (if it exists). This is useful for setting default values for flags without typing them on the command line.

Example .env file:

# Log configuration
SCRIPTLING_LOG_LEVEL=debug
SCRIPTLING_LOG_FORMAT=console

# Library directory
SCRIPTLING_LIBDIR=./mylibs

# Server configuration
SCRIPTLING_SERVER=:8000
SCRIPTLING_MCP_TOOLS=./tools
SCRIPTLING_BEARER_TOKEN=your-secret-token

# Filesystem restrictions
SCRIPTLING_ALLOWED_PATHS=/tmp/data,./uploads

Script Execution Modes

Scriptling supports three levels of filesystem access control:

Mode Flag Filesystem Access Path Restrictions
Full (default) All libraries None
Restricted --allowed-paths /path1,/path2 All libraries Only specified paths
None --allowed-paths - All libraries No paths allowed

Full Mode (default)

All libraries available, no restrictions:

scriptling script.py

Restricted Mode

All libraries available, but filesystem operations restricted to specified paths:

# Restrict to specific directories
scriptling --allowed-paths "/tmp/data,./uploads" script.py

# With relative paths
scriptling --allowed-paths "./data,../shared" script.py

# Via environment variable
SCRIPTLING_ALLOWED_PATHS="/var/www,./public" scriptling script.py

No File Access Mode

Disable all filesystem access (useful for running untrusted scripts):

scriptling --allowed-paths - script.py

All file operations (os.read_file, os.write_file, pathlib, glob, sandbox.exec_file) will be denied.

When a script tries to access a path outside the allowed directories:

import os
# This will raise an error if /etc/passwd is not in allowed paths
try:
    content = os.read_file("/etc/passwd")
except Exception as e:
    print(f"Access denied: {e}")
    # Output: Access denied: access denied: path '/etc/passwd' is outside allowed directories

Available libraries:

  • Standard libraries: json, math, random, re, time, base64, hashlib, urllib
  • datetime - Date and time operations
  • yaml, toml - YAML and TOML parsing
  • html.parser - HTML parsing
  • requests - HTTP client
  • os - Environment variables and file operations (path-restricted)
  • pathlib, glob - File system access (path-restricted)
  • secrets - Cryptographic random number generation
  • scriptling.runtime - Runtime utilities including sandbox and background tasks
  • subprocess - Process execution
  • wait_for - Process monitoring
  • AI, agent, and MCP libraries

Accessing Environment Variables in Scripts

You can access environment variables from within Scriptling scripts using the os library:

import os

# Get a specific environment variable
api_key = os.getenv("API_KEY", "default-key")
print(f"API Key: {api_key}")

# Get all environment variables
env = os.environ()
print(f"Home: {env['HOME']}")
print(f"Path: {env['PATH']}")

HTTP Server Mode

Start an HTTP server with optional MCP tools:

# Start HTTP server on port 8000
scriptling --server :8000 setup.py

# With TLS (self-signed certificate)
scriptling --server :8443 --tls-generate setup.py

# With MCP tools from directory
scriptling --server :8000 --mcp-tools ./tools setup.py

# With MCP script execution tool
scriptling --server :8000 --mcp-exec-script setup.py

# With both MCP tools and exec tool
scriptling --server :8000 --mcp-tools ./tools --mcp-exec-script setup.py

# With authentication
scriptling --server :8000 --bearer-token my-secret-token setup.py

# With filesystem restrictions
scriptling --server :8000 --allowed-paths "/var/www,./uploads" setup.py

MCP Script Execution Tool

The --mcp-exec-script flag enables a built-in MCP tool that allows LLMs to execute Scriptling code directly:

# Enable script execution tool
scriptling --server :8000 --mcp-exec-script setup.py

# Combine with custom tools
scriptling --server :8000 --mcp-tools ./tools --mcp-exec-script setup.py

Tool Details:

  • Name: execute_script
  • Description: Execute Scriptling code and return the result. Scriptling is a Python 3-like scripting language.
  • Parameters:
    • code (string, required): Scriptling code to execute

Return Behavior:

  • Output from print() statements is automatically captured and returned
  • For structured data (JSON), use import scriptling.mcp.tool and call tool.return_object(data)
  • For text output, use tool.return_string(text)

Usage Example:

# Call the tool via MCP - print() output is captured
curl -X POST http://127.0.0.1:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":1,
    "method":"tools/call",
    "params":{
      "name":"execute_script",
      "arguments":{
        "code":"for i in range(1, 21, 3):\n    print(i)"
      }
    }
  }'

Returning Structured Data:

import scriptling.mcp.tool as tool

# Return JSON object
data = {"users": ["Alice", "Bob"], "count": 2}
tool.return_object(data)

# Or return text
tool.return_string("Operation completed successfully")

The tool description instructs LLMs to use help(topic) to discover available functions and libraries:

# Get help on built-in functions
help('builtins')

# Get help on string methods
help('str')

# Get help on a library
import json
help('json')

MCP Tools

Tools consist of two files: a .toml metadata file and a .py script file.

Metadata File (.toml)

Defines the tool’s description, parameters, and registration mode:

hello.toml:

description = "Greet a person by name"
keywords = ["hello", "greet", "welcome"]

# Optional: Registration mode
# discoverable = false  (default) - Native mode: tool appears in tools/list, directly callable
# discoverable = true             - Discovery mode: hidden from tools/list, found via tool_search

[[parameters]]
name = "name"
type = "string"
description = "Name of the person to greet"
required = true

[[parameters]]
name = "times"
type = "int"
description = "Number of times to repeat the greeting"

Parameter Types:

Type Aliases Description
string Text values
int integer Integer numbers
float number Floating point numbers
bool boolean True/false values
array:string Array of strings
array:number array:int, array:integer, array:float Array of numbers
array:bool array:boolean Array of booleans

Parameter Fields:

Field Required Description
name Yes Parameter name
type Yes Data type (see table above)
description Yes Description shown to the LLM
required No Whether the parameter must be provided (default: false)

Registration Modes:

  • Native mode (default): Tool appears in tools/list and can be called directly
  • Discovery mode (discoverable = true): Tool is hidden from tools/list, searchable via tool_search, and callable via execute_tool

Script File (.py)

Implements the tool logic using the scriptling.mcp.tool library:

hello.py:

import scriptling.mcp.tool as tool

# Get parameters with defaults
name = tool.get_string("name", "World")
times = tool.get_int("times", 1)

# Implement tool logic
greetings = []
for i in range(times):
    greetings.append(f"Hello, {name}!")

result = "\n".join(greetings)

# Return result
tool.return_string(result)

Available Tool Functions:

# Get parameters
tool.get_string(name, default="")     # Get string parameter
tool.get_int(name, default=0)         # Get integer parameter
tool.get_float(name, default=0.0)     # Get float parameter
tool.get_bool(name, default=False)    # Get boolean parameter
tool.get_list(name, default=[])       # Get list parameter

# Return results
tool.return_string(text)              # Return text result
tool.return_object(obj)               # Return object as JSON
tool.return_toon(obj)                 # Return object as TOON format
tool.return_error(message)            # Return error message

Complete Example

A tool that calculates the sum of two numbers:

add.toml:

description = "Calculate the sum of two numbers"
keywords = ["math", "add", "sum", "calculate"]
discoverable = true  # Hidden from tools/list, searchable

[[parameters]]
name = "a"
type = "int"
description = "First number"
required = true

[[parameters]]
name = "b"
type = "int"
description = "Second number"
required = true

add.py:

import scriptling.mcp.tool as tool

a = tool.get_int("a")
b = tool.get_int("b")

result = a + b
tool.return_string(f"{a} + {b} = {result}")

Testing Tools

# Start server with MCP tools
scriptling --server :8000 --mcp-tools ./tools setup.py &

# List available tools
curl -X POST http://127.0.0.1:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

# Call a native tool directly
curl -X POST http://127.0.0.1:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"hello","arguments":{"name":"Alice","times":2}}}'

# Search for discoverable tools
curl -X POST http://127.0.0.1:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"tool_search","arguments":{"query":"math"}}}'

# Execute a discoverable tool
curl -X POST http://127.0.0.1:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"execute_tool","arguments":{"name":"add","arguments":{"a":5,"b":3}}}}'

Features

  • File execution: Run Scriptling scripts from files
  • Stdin execution: Pipe scripts to stdin
  • Interactive mode: REPL-like interactive execution
  • Lint mode: Check scripts for syntax errors without execution
  • HTTP Server: Start HTTP server with custom routes via --server
  • MCP Server: Serve tools via Model Context Protocol with --mcp-tools
  • MCP Script Execution: Allow LLMs to execute Scriptling code via --mcp-exec-script
  • Path restrictions: Restrict filesystem access with --allowed-paths
  • Custom libraries: Load libraries from custom directories with --libdir
  • Environment configuration: Auto-load settings from .env file
  • Configurable logging: Set log level with --log-level (debug, info, warn, error)
  • Cross-platform: Built for Linux, macOS, and Windows on AMD64 and ARM64
  • Minimal size: Optimized with stripped binaries (~10MB)

Examples

REST API Client

scriptling api_client.py
# api_client.py
import json
import requests

response = requests.get("https://api.example.com/users")
if response.status_code == 200:
    users = response.json()
    for user in users:
        print(user["name"])

HTTP Server with Routes

scriptling --server :8000 setup.py
# setup.py
import scriptling.runtime as runtime

# Register routes (handler functions referenced as "module.function")
runtime.http.get("/api/hello", "handlers.hello")
runtime.http.post("/api/echo", "handlers.echo")
# handlers.py
import scriptling.runtime as runtime

def hello(request):
    return runtime.http.json(200, {"message": "Hello, World!"})

def echo(request):
    return runtime.http.json(200, request.json())

Help

scriptling --help