Dutch for the steel barrier at the edge of a road. It does not stop you driving; it stops one bad moment becoming a worse one.
vangrail is guardrails that run inside a Ruby process. Input, context, and output rails, against any OpenAI-compatible endpoint, with no Python service in the path and nothing outside the standard library at runtime.
- Documentation: docs/orgmode/index.org
- Tutorial: Stop an injected instruction in ten minutes
- Source: https://github.com/HaoZeke/vangrail
- RubyGems: https://rubygems.org/gems/vangrail
- API (YARD): https://haozeke.github.io/vangrail/
- Contributing: CONTRIBUTING.md
- Changelog: CHANGELOG.md
It provides:
- a rail protocol: one object, one method, three statuses (
passed/modified/blocked) pluscertain? - three sides: the question, the retrieved documents, and the model's answer
- deterministic rails that need no network
- model-backed rails that call a local proxy first, then whatever endpoint you name
- provenance-labelled values and a locked plan for monitored tool calls
- versioned score providers for optional encoder, embedding, and judge readers
- checksum-verified joint-risk and evaluation artifacts
- a Colang 1.0 rail-flow subset executed in process
Detection and authority are separate. A risk result may restrict an explicit
tool grant, but it cannot create one. Heavy readers remain optional processes
or endpoints; the core gem does not gain their runtime dependencies. The
optional vangrail-native gem accelerates the hashed linear kernel without
changing the Ruby fallback.
Ruby 3.1 or newer. There is no bundle.
gem install vangrailThat installs the complete enforcement plane and Ruby risk kernels with zero runtime gem dependencies. Native linear scoring is a separate package:
gem install vangrail-nativeEncoder, embedding, and judge runtimes are not gem dependencies. Connect them as optional bounded-command or endpoint readers; an unconfigured reader reports abstention. See Detection is not authority.
From a clone:
git clone https://github.com/HaoZeke/vangrail.git
cd vangrail
ruby -Ilib -e 'require "vangrail"; puts Vangrail::VERSION'No API key. The deterministic rails run; model-backed ones report themselves missing rather than pretending they ran.
require 'vangrail'
engine = Vangrail.from_env
puts engine.describe
engine.check_input('How do I submit a GPU job?').passed? # => true
answer = engine.check_output('Set api_key=sk-live-9c2f1 in the file.')
answer.modified? # => true
answer.content # => "Set api_key=[redacted] in the file."A custom rail is the same protocol as the built-in ones:
class TicketRail < Vangrail::Rail
def decide(text, _context)
return pass if text.match?(/EINF-\d+/)
block(reason: 'no ticket id')
end
end| I want to… | Go here |
|---|---|
| Learn the three sides by running five short programs | Tutorial |
| Point the model rails at a local proxy | llmlite |
| Name any other endpoint | Choosing an endpoint |
| Screen retrieved documents | Screening |
| Enforce arguments, sinks, confirmation, and use counts | Enforce tool calls |
| Understand optional readers and joint risk | Detection is not authority |
| Look up a variable or a rail | Environment, rails |
Read why certain? exists |
Three statuses |
| Read what this does not do | Coverage |
The long argument (evidence, measurements, reading list) lives under docs/orgmode/explanation/, not on this page.
gem install minitest
rake testStdlib minitest, one process, no bundle, no outbound network. A single file
is ruby -Ilib test/test_engine.rb.
MIT. See LICENSE.
