Skip to main content
Version: 0.1.0-alpha.3

Interpreters

By default, Invowk™ executes scripts using a shell. But you can use other interpreters like Python, Ruby, Node.js, or any executable that can run scripts.

Auto-Detection from Shebang

When a script starts with a shebang (#!), Invowk automatically uses that interpreter:

{
name: "analyze"
implementations: [{
script: """
#!/usr/bin/env python3
import sys
import json

data = {"status": "ok", "python": sys.version}
print(json.dumps(data, indent=2))
"""
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}]
}]
}

Common shebang patterns:

ShebangInterpreter
#!/usr/bin/env python3Python 3 (portable)
#!/usr/bin/env nodeNode.js
#!/usr/bin/env rubyRuby
#!/usr/bin/env perlPerl
#!/bin/bashBash (direct path)

Explicit Interpreter

Specify an interpreter directly in the runtime config:

{
name: "script"
implementations: [{
script: """
import sys
print(f"Python {sys.version_info.major}.{sys.version_info.minor}")
"""
runtimes: [{
name: "native"
interpreter: "python3" // Explicit
}]
platforms: [{name: "linux"}, {name: "macos"}]
}]
}

The explicit interpreter takes precedence over shebang detection.

Interpreter with Arguments

Pass arguments to the interpreter:

{
name: "unbuffered"
implementations: [{
script: """
import time
for i in range(5):
print(f"Count: {i}")
time.sleep(1)
"""
runtimes: [{
name: "native"
interpreter: "python3 -u" // Unbuffered output
}]
platforms: [{name: "linux"}, {name: "macos"}]
}]
}

More examples:

// Perl with warnings
interpreter: "perl -w"

// Ruby with debug mode
interpreter: "ruby -d"

// Node with specific options
interpreter: "node --max-old-space-size=4096"

Container Interpreters

Interpreters work in containers too:

{
name: "analyze"
implementations: [{
script: """
#!/usr/bin/env python3
import os
print(f"Running in container at {os.getcwd()}")
"""
runtimes: [{
name: "container"
image: "python:3.11-slim"
}]
platforms: [{name: "linux"}]
}]
}

Or with explicit interpreter:

{
name: "script"
implementations: [{
script: """
console.log('Hello from Node in container!')
console.log('Node version:', process.version)
"""
runtimes: [{
name: "container"
image: "node:20-slim"
interpreter: "node"
}]
platforms: [{name: "linux"}]
}]
}

Accessing Arguments

Arguments work the same with any interpreter:

{
name: "greet"
args: [{name: "name", default_value: "World"}]
implementations: [{
script: """
#!/usr/bin/env python3
import sys
import os

# Via command line args
name = sys.argv[1] if len(sys.argv) > 1 else "World"
print(f"Hello, {name}!")

# Or via environment variable
name = os.environ.get("INVOWK_ARG_NAME", "World")
print(f"Hello again, {name}!")
"""
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}]
}]
}

Supported Interpreters

Any executable in PATH can be used:

  • Python: python3, python
  • JavaScript: node, deno, bun
  • Ruby: ruby
  • Perl: perl
  • PHP: php
  • Lua: lua
  • R: Rscript
  • Shell: bash, sh, zsh, fish
  • Custom: Any executable

Virtual Runtime Limitation

The interpreter field is not supported with the virtual runtime:

// This will NOT work!
{
name: "bad"
implementations: [{
script: "print('hello')"
runtimes: [{
name: "virtual"
interpreter: "python3" // ERROR!
}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}]
}

The virtual runtime uses the built-in mvdan/sh interpreter and cannot execute Python, Ruby, or other interpreters. Use native or container runtime instead.

Fallback Behavior

When no shebang and no explicit interpreter:

  • Native runtime: Uses system's default shell
  • Container runtime: Uses /bin/sh -c

Best Practices

  1. Use shebang for portability: Scripts work standalone too
  2. Use /usr/bin/env: More portable than direct paths
  3. Explicit interpreter for no-shebang scripts: When you don't want a shebang line
  4. Match container image: Ensure interpreter exists in the image

Next Steps