Open source · MIT licensed
Vibescript is a small Ruby-like language that runs inside your Go app. Users and AI agents write scripts to add features. Your app decides exactly what each script can touch.
def late_fee(overdue: duration) -> money
if overdue <= 3.days
money("0.00 USD")
elsif overdue <= 14.days
money("5.00 USD")
else
money("15.00 USD")
end
end
def run
{
on_time: late_fee(2.days),
grace: late_fee(10.days),
overdue: late_fee(3.weeks)
}
end
Language
Ruby-like syntax, optional types, and built-in money, duration, and enum values. Everything is designed to be read at a glance, by your team and by the models writing it.
Blocks, ranges, calls without parentheses, and symbol-keyed hashes will look familiar to Ruby users. Types are optional. When you use them, Vibescript checks arguments and return values. Nullable types stay explicit.
def shipping_quote(speed, subtotal: money) -> hash
fee = shipping_fee(speed, subtotal)
transit = transit_time(speed)
{
speed: speed.name,
fee: fee,
total: subtotal + fee,
transit: transit.iso8601
}
end
One go get, then three calls: create an engine, compile the script,
call a function. The script exposes functions to your app. Your app exposes only
the capabilities it chooses to share back.
engine, _ := vibes.NewEngine(vibes.Config{
StepQuota: 250_000,
})
script, _ := engine.Compile(userScript)
fee, _ := script.Call(ctx, "late_fee", args, opts)
fee.String() // "5.00 USD"
A runaway loop, a hostile script, an AI hallucination with a while-true in it. The engine stops each one at the step, memory, or recursion limit and returns a clean error to your Go app. No goroutine leak, no OOM, no incident channel.
$ cat untrusted.vibe def run balance = 0 while true balance = balance + 1 end end $ # host calls script.Call(ctx, "run", ...) RuntimeError: step quota exceeded ✓ stopped at 250k steps, Go app keeps running
3.days is a duration, not an integer with a comment. Money uses exact
decimal values, so float rounding cannot lose a cent. Enums are real values, not
strings you promise to spell consistently.
enum ShippingSpeed
Economy
Priority
Overnight
end
def transit_time(speed: ShippingSpeed) -> duration
if speed == ShippingSpeed::Overnight
6.hours
else
5.days
end
end
def net_after_fee(cents)
gross = money_cents(cents, "USD")
gross - money("1.75 USD")
end
Extension model
Lua is often embedded in games and tools so people can extend them with scripts. Vibescript brings that model to Go apps.
Each Vibescript extension works through the functions, data, and services your app exposes. The rest of the host stays out of reach.
Extending an app this way feels more like HyperCard than traditional software development. Flexible, but within bounds. Scripts get an opinionated set of primitives that combine into predictable features, not a blank slate that can take your app down.
Featured
These examples use the language for common app logic. Each one runs in your browser.
Score many records at the same time with Tasks.map.
Report whether a release is ready from its state, approvals, and schedule.
Price a subscription invoice from the plan and quantity.
Build an exponential retry schedule with enums, durations, and timestamps.
Calculate delivery dates and prices for each shipping speed.
Use enums, money, and durations to decide whether to refund an order.
Try it
206 programs are compiled against the real interpreter when the site starts and run with one click. No install or setup needed.