Project

gienah

0.0
The project is in a healthy, maintained state
Content-Length RPC, capability gates, lifecycle management, and a small plugin SDK.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

~> 0.1.0
 Project Readme

Gienah

Run Ruby plugins outside your host process.

Gem version Gem downloads CI Ruby 3.1 or newer MIT license

Website · Features · Installation · Quick start · Capability gates · Development


Gienah is a small, Canopus-independent plugin host for Ruby applications. It launches each plugin in a separate Ruby process and communicates over Content-Length-framed JSON-RPC 2.0, keeping plugin failures and permissions outside the application core.

The name comes from Gienah (γ Corvi), the IAU-approved star name derived from Arabic al-janāḥ — “the wing”.

Features

  • Process isolation — plugins run outside the host process.
  • Capability gates — host methods are denied unless the plugin declares the required capability.
  • Lifecycle management — activation events, graceful shutdown, bounded restart attempts, and crash disabling.
  • Bounded RPC — startup and request deadlines, cancellation, and message-size limits.
  • Portable manifests — recursive discovery of plugin.json and plugin.jsonc files.
  • Small plugin SDK — export methods, handle events, and call back into the host.
  • OS sandbox policies — dangerous filesystem, network, and process capabilities are delegated to Saiph.

Installation

Add Gienah to your bundle:

bundle add gienah

Or install it directly:

gem install gienah

Gienah requires Ruby 3.1 or newer. When an OS sandbox is unavailable, plugins requesting write, network, or process-execution capabilities fail closed before startup.

Quick start

Create a plugin manifest at plugins/hello/plugin.json:

{
  "id": "hello",
  "name": "Hello",
  "version": "1.0.0",
  "api_version": 1,
  "entry": "main.rb",
  "activation": ["onStartup"],
  "capabilities": []
}

Add the plugin entrypoint at plugins/hello/main.rb:

require "gienah"

Gienah::Plugin.export("greet") do |params|
  {"message" => "Hello, #{params.fetch("name")}!"}
end

Gienah::Plugin.run

Discover and activate it from the host:

require "gienah"

host = Gienah::Host.new(api_version: 1)

begin
  host.discover("plugins")
  plugin = host.activate("hello", reason: "onStartup")
  result = plugin.call("greet", {"name" => "Ruby"}).await
  puts result.fetch("message")
ensure
  host.shutdown
end
Hello, Ruby!

Capability gates

The host decides which application methods a plugin may call:

host.expose("workspace/name", capability: "workspace.read") do
  {"name" => "my-project"}
end

The call is accepted only when the plugin manifest declares workspace.read. Unknown capabilities are rejected while loading the manifest.

Capability form Scope
buffer.read, workspace.read, ui.command Built-in host capabilities
fs.read:<path>, fs.write:<path> Filesystem paths or globs
net:<host-pattern> Network hosts
process.exec, exec Process execution

Lifecycle

  1. Host#discover loads manifests and their contributions.
  2. Host#activate starts a plugin only when its activation reason matches.
  3. Host and plugin exchange an initialization handshake with the API version and granted capabilities.
  4. Calls return a Gienah::Future; deadlines and cancellation keep requests bounded.
  5. Failed plugins restart with bounded backoff and are disabled after repeated crashes.

Call Host#shutdown to stop every active plugin cleanly.

Development

bundle install
bundle exec rake

Contributing

Bug reports and pull requests are welcome on GitHub.

License

Gienah is available under the MIT License.