ddonche/goblin-lang
0.46.24
1
0
reference documentation
[[system-process]]

System & Process


Goblin provides a small set of natives for interacting with the host system — running shell commands, reading environment variables, and passing data between processes. These are the primitives that make Goblin useful as a build tool and scripting language.


:run_cmd

Runs a shell command and returns a map containing the result.

result | :json_parse(:run_cmd("echo hello"))
ok     | result["ok"]
stdout | result["stdout"]
result | :json_parse(:run_cmd("echo hello"))
ok     | result["ok"]
stdout | result["stdout"]

Signature

:run_cmd(command)
:run_cmd(command, cwd)
:run_cmd(command)
:run_cmd(command, cwd)

  • command — the shell command to run as a string
  • cwd — optional working directory to run the command from

Return value

:run_cmd returns a JSON string1 — use :json_parse to work with it as a map:

Key Type Description
ok bool true if exit code was 0
code int or nil exit code from the process
stdout string everything the process wrote to stdout
stderr string everything the process wrote to stderr

Example — capturing output

raw    | :run_cmd("deno run build.ts")
result | :json_parse(raw)

if result["ok"] == false
    :say("Build failed: " + result["stderr"])
    return
xx

output | result["stdout"]
raw    | :run_cmd("deno run build.ts")
result | :json_parse(raw)

if result["ok"] == false
    :say("Build failed: " + result["stderr"])
    return
xx

output | result["stdout"]

Example — with working directory

result | :json_parse(:run_cmd("goblin build.gbln", "../site"))
result | :json_parse(:run_cmd("goblin build.gbln", "../site"))

Platform notes

On Windows, the command runs via cmd /C. On Unix, it runs via sh -lc. This means your PATH and shell aliases are available, but the command string should be portable if you intend to run on both platforms.

Error handling

If the process fails to spawn entirely (command not found, bad cwd), Goblin raises a runtime error. If the process runs but exits with a non-zero code, no error is raised — check result["ok"] yourself.

result | :json_parse(:run_cmd("nonexistent-tool"))
/// runtime error: process-spawn-failed
result | :json_parse(:run_cmd("nonexistent-tool"))
/// runtime error: process-spawn-failed


:env

Reads an environment variable by name. Returns nil if the variable is not set.

port | :env("PORT")
port | :env("PORT")

Signature

:env(name)
:env(name)

Example — with fallback

port | :env("PORT") ?? "4242"
port | :env("PORT") ?? "4242"

Example — reading build context

Goblin sets several environment variables automatically when running scripts via the host. These are available through :env:

query  | :trim(:env("GOBLIN_QUERY_STRING"))
method | :env("GOBLIN_METHOD")
body   | :env("GOBLIN_BODY")
query  | :trim(:env("GOBLIN_QUERY_STRING"))
method | :env("GOBLIN_METHOD")
body   | :env("GOBLIN_BODY")

Variable Description
GOBLIN_QUERY_STRING Query string passed by the host
GOBLIN_METHOD HTTP method (GET, POST, etc.)
GOBLIN_BODY Raw request body
GOBLIN_NONINTERACTIVE Set to 1 when running non-interactively

:say

Writes a string to stdout followed by a newline. This is Goblin's primary output primitive.

:say("hello world")
:say("hello world")

When a Goblin script is invoked by the host, stdout is captured and returned as the response. This is how Goblin scripts return data — write to stdout with :say.

out | {"ok": true, "result": value}
:say(:json_stringify(out))
out | {"ok": true, "result": value}
:say(:json_stringify(out))


:input / :ask

Reads a line from stdin. Both names refer to the same native.

name | :input("What is your name? ")
name | :input("What is your name? ")

:input and :ask are only useful in interactive sessions. When Goblin runs non-interactively (e.g. invoked by the host with GOBLIN_NONINTERACTIVE=1), stdin is closed and :input will return nil.


Combining them

A common pattern in Sheriff build scripts is using :run_cmd to invoke external tools, :env to read context passed by the host, and :say to return the result:

query  | :trim(:env("GOBLIN_QUERY_STRING"))
portal | :split(query, "&")[0]

result | :json_parse(:run_cmd("goblin build.gbln", "../site/portals/{portal}"))

out | {
    "ok":     result["ok"],
    "stdout": result["stdout"],
    "stderr": result["stderr"]
}
:say(:json_stringify(out))
query  | :trim(:env("GOBLIN_QUERY_STRING"))
portal | :split(query, "&")[0]

result | :json_parse(:run_cmd("goblin build.gbln", "../site/portals/{portal}"))

out | {
    "ok":     result["ok"],
    "stdout": result["stdout"],
    "stderr": result["stderr"]
}
:say(:json_stringify(out))


  1. :run_cmd returns a raw JSON string rather than a map directly. This keeps the return type simple and consistent regardless of whether the caller needs to inspect the result. Wrap it in :json_parse when you need to access individual fields.