LLM Script Generation Guide

This page is the source of truth for generating Scriptling code with LLMs. There are two ways to put it in front of your agent:

  1. Fetch the docs directly. The full documentation is published as OKF 0.2 knowledge bundles that any markdown-reading agent can pull over HTTP — see Fetching the Docs below.
  2. Copy the guidance into your agent’s instructions. The block below is self-contained: paste it into your AGENTS.md, CLAUDE.md, or system prompt as-is.

AGENTS.md Block

Copy everything inside the fence into your agent instructions:

# Scriptling Script Generation

Scriptling is a sandboxed, Python-like scripting language for Go applications. Generate normal, readable Python 3 style code unless a Scriptling-specific limitation applies. Use `.py` files, 4-space indentation, `True`/`False`, `None`, `def`, `class`, `try`/`except`, comprehensions, and normal Python control flow.

## Write Scriptling Like This

- Prefer clear Pythonic code over custom conventions.
- Use `import json`, `import math`, `import re`, `import time`, and similar module imports; `from m import (a, b)` with parentheses and a trailing comma is fine for long lists.
- Use normal methods such as `d.items()`, `d.keys()`, `d.values()`, `s.split()`, `"x".join(parts)`, and `response.json()`.
- Use keyword arguments naturally: `requests.get(url, timeout=10, headers={...})`.
- Use `f"..."`, `.format()`, list/dict/set comprehensions, and generator expressions.
- Use `for key, value in data.items():` for dictionary iteration.
- Use `super().__init__(...)` in subclasses.
- Use `match` / `case` when it makes the code simpler.
- Use type annotations on signatures (`def f(a: int) -> str:`) if you like; they are parsed and ignored.
- Use `while (chunk := read()):` and `d1 | d2` dict merge freely.

## Supported Language Features

- Functions with defaults, `*args`, `**kwargs`, and argument unpacking with `*` / `**`.
- Lambdas, closures, recursion, `assert`, and conditional expressions.
- Lists, dicts, tuples, sets, slicing, `del`, chained comparisons, and augmented assignment.
- Classes, single inheritance, `super()`, and common dunder methods.
- `try` / `except` / `else` / `finally`; `with` statements and context managers.
- Walrus assignment expressions (`while (chunk := read()):`), type annotations (parsed and ignored), `...` placeholder expressions, and dict merge (`d1 | d2`, `d |= other`).
- `match` / `case`, including guards and structural matching for dicts and sequences.
- `__name__ == "__main__"` patterns.
- Builtins such as `len`, `str`, `int`, `float`, `bool`, `list`, `tuple`, `set`, `dict`, `range`, `enumerate`, `zip`, `map`, `filter`, `sorted`, `sum`, `min`, `max`, `isinstance`, and `issubclass`; `sorted`, `min` and `max` accept `key=` (and `default=` for empty iterables on `min`/`max`).

## Important Differences from Python

- No `async` / `await`.
- No `yield`-based generator functions.
- No `from module import *`; import the names you need.
- A walrus bound inside a comprehension does not leak to the enclosing scope; collect through the comprehension result instead.
- No multiple inheritance (nested classes are supported).
- No built-in `open()`, `eval()`, `exec()`, `globals()`, or `locals()`.
- No custom exception classes (`class MyError(Exception)` fails — classes cannot derive from the built-in exception types); raise the built-ins and check `type(e)` in the handler.
- No positional-only parameters (`def f(a, /, b)`); keyword-only with bare `*` is supported.
- Default arguments are evaluated on each call, not once at `def` time; bind values with a factory function when that matters.
- Regex uses RE2 semantics: no backreferences, no lookaround.
- Booleans display as `True` / `False` (matching Python); machine formats such as `json.dumps` and query parameters stay lowercase.
- `type(x)` returns the type name as a string (`"INTEGER"`, `"STRING"`, a class instance gives its class name, a raised exception gives the class it was raised as such as `"ValueError"`).

Two differences matter a lot:

1. **Scriptling is sandboxed by design.** Filesystem, subprocess, network, and similar capabilities only exist if the host registers the relevant library.
2. **Fatal errors and catchable exceptions are different.** Use `try` / `except` for normal exceptions, but do not assume every runtime failure is catchable.

## Libraries

Built-in functions are intrinsic, but importable library modules depend on the runtime. The CLI registers its documented default libraries. When embedding in Go, the host must register the libraries scripts may import—for example, `stdlib.RegisterAll(p)` registers the standard library set, while extended libraries require their own registration. Prefer standard libraries for general scripting; use `scriptling.*` libraries only when the task depends on host runtime features such as MCP, AI agents, HTTP routes, or networking. When unsure what a host provides, use `help("modules")` or `help("library_name")` from inside a script.

For the complete standard, Scriptling, and extended library API, see the markdown bundle: https://scriptling.dev/okf/scriptling-libraries/index.md

## HTTP and JSON

When generating API code, prefer this pattern:

```python
import json
import requests

response = requests.get(
    "https://api.example.com/items",
    timeout=10,
    headers={"Authorization": "Bearer " + token},
)

response.raise_for_status()
data = response.json()

for item in data:
    print(item["name"])
```

- `requests` supports keyword arguments such as `timeout`, `headers`, `params`, `auth`, and `json`.
- The default HTTP timeout is 5 seconds if none is provided.
- Response objects expose `status_code`, `text`, `body`, `headers`, and `url`; `body` and `text` are aliases.
- `response.json()` and `response.raise_for_status()` are supported.
- Send warnings and errors to stderr so stdout stays clean for the report: `import sys` then `sys.stderr.write("warning\n")` or `print("error", file=sys.stderr)`.

## MCP and AI Agents

When the task involves MCP servers or an agent loop:

- Connect to an MCP server with `mcp.Client(target, namespace="x")`; every client needs a distinct `namespace` (it prefixes tool names like `x__tool` and routes skill URIs). HTTP requests time out after 30 seconds by default; pass `timeout=<seconds>` for a server whose tools are slower. Use `sys.executable` as the target to relaunch the running interpreter as a stdio server.
- Build agents with `import scriptling.ai.agent as agent`; `Agent(client, tools=..., mcp_servers=[...])` registers every server's tools under their namespaced names and lists the servers' skills in the system prompt, fetched on demand through the agent's `get_skill` tool. A failing tool handler does not kill the turn: the error comes back as a tool result the model can see and retry.
- `ai.ToolRegistry().add_schema(name, description, schema, handler)` registers a tool with a full JSON Schema (use it for schemas that arrive from MCP servers).
- When writing an MCP server's decorated `.py` files, `@mcp.tool`, `@mcp.resource` (static or `template=True`), `@mcp.prompt` and `@mcp.skill` all work in one file; `import scriptling.runtime.mcp as mcp` first.
- Package an MCP app with `scriptling pack -o app.zip <dir>` (tools/, resources/, prompts/, skills/ are served by convention) and check the artifact with `scriptling pack --list app.zip`.

## Common Exceptions

- `IndexError` for out-of-range sequence access.
- `KeyError` for missing dictionary keys.
- `AttributeError` for missing attributes.
- `ValueError` for bad values.
- `TypeError` for invalid argument or operand types.
- `ImportError` for optional libraries or imported names that are not available.

Use normal `try` / `except` patterns.

## Deletion

Scriptling supports Python-style `del` in the common cases: `del items[2]`, `del items[1:5:2]`, `del data["name"]`, `del user.email`. Prefer `del` over manual reassignment when the goal is to remove an item, slice, key, or attribute.

## Generation Rules

1. Generate standard Python-like code first, then remove unsupported features.
2. Prefer builtins and standard libraries before Scriptling-specific modules.
3. Use dictionary methods like `.items()` and keyword arguments naturally.
4. Use `del` for list indexes, list slices, dict keys, and object attributes when removing data.
5. For HTTP, always set an explicit timeout and check or raise on status.
6. Dicts keep insertion order, exactly as in Python 3.7+: iteration, `.keys()`/`.values()`/`.items()`, and `json.dumps` all follow it. Sort explicitly (`for k in sorted(d):`) only when you want key order rather than insertion order.
7. For JSON APIs, prefer `response.json()` or `json.loads(response.text)`.
8. For string accumulation in loops, prefer `"".join(parts)` over repeated concatenation.
9. Keep code synchronous, explicit, and small rather than clever.

## Safe Default Template

```python
import json
import requests

def main():
    response = requests.get(
        "https://api.example.com/items",
        timeout=10,
    )
    response.raise_for_status()

    data = response.json()

    for item in data:
        print(item["name"])

if __name__ == "__main__":
    main()
```

## Validation and Reference

- Validate generated scripts with the linter when available: `scriptling --lint script.py`.
- Inspect available libraries from inside a script with `help("modules")`, `help("builtins")`, or `help("library.function")`.
- Full documentation is published as fetchable markdown bundles. Each hosted bundle's `index.md` lists its concepts with absolute `https://scriptling.dev/okf/...` links that can be fetched directly. Downloaded release bundles contain the same concepts but use relative links so they remain portable:
  - For every library's API, see the markdown bundle: https://scriptling.dev/okf/scriptling-libraries/index.md
  - For the language reference (syntax, types, operators, control flow), see the markdown bundle: https://scriptling.dev/okf/scriptling-reference/index.md
  - For guides (CLI, Go integration, security, tutorials), see the markdown bundle: https://scriptling.dev/okf/scriptling-docs/index.md

Fetching the Docs

The complete documentation is published as OKF 0.2 bundles—plain markdown with YAML frontmatter—at stable URLs an agent can fetch directly. The two distributions intentionally use different internal links:

  • Hosted at scriptling.dev: internal links are absolute https://scriptling.dev/okf/... URLs so fetch-only agents such as Claude Code can follow them reliably.
  • Downloadable release archive: internal links are relative so the unzipped bundles remain portable wherever they are served or indexed.
Bundle Contents URL
scriptling-libraries API reference for every library https://scriptling.dev/okf/scriptling-libraries/index.md
scriptling-reference Language reference: syntax, types, operators, control flow https://scriptling.dev/okf/scriptling-reference/index.md
scriptling-docs Guides: CLI, Go integration, security, tutorials https://scriptling.dev/okf/scriptling-docs/index.md

Each hosted bundle’s index.md lists its concepts with absolute links; follow those URLs directly. In a downloaded release bundle, follow the relative links from the local index.md instead. To give an agent search as well as reads, serve the bundles through an MCP server — see the Documentation MCP Server guide.