Ruby SDK
The Ruby SDK is the in-code half of smplkit: one client resolves flags, reads config, controls log levels, and emits audit events. You manage the underlying resources — creating flags, configs, loggers, and forwarders — with the MCP tools or the Console; this page covers the code.
Install
gem install smplkitOr add it to your Gemfile:
gem "smplkit"Requires Ruby 3.3+. The version published to RubyGems is always the latest.
Initialize the client
One Smplkit::Client exposes all four products as sub-namespaces — client.flags, client.config, client.logging, and client.audit. You never build a per-product client in app code.
The SDK key (sk_api_...) is read from the SMPLKIT_API_KEY environment variable or the ~/.smplkit profile; you can also pass api_key: explicitly. Set environment: once on the client (or via SMPLKIT_ENVIRONMENT) — it's optional, and when unset the server derives it from the key. It is never a per-call argument.
Smplkit::Client.open takes a block and auto-closes the client when the block exits. The SDK is fully synchronous — there is no async variant. Call wait_until_ready to deterministically pre-warm the flag/config caches and open the WebSocket before your first evaluation.
require "smplkit"
Smplkit::Client.open(environment: "production", service: "my-service") do |client|
client.wait_until_ready
# use client.flags / client.config / client.logging / client.audit
endSmplkit::Client.new(...) is also available when you need to manage the lifecycle yourself.
Flags
Use flags for runtime decisions you want to change without a deploy — rollouts, kill-switches, per-account targeting. Declare a typed handle with a safe default, attach context, and evaluate with .get. The default is served if the flag is missing or smplkit is unreachable, so pick the conservative value.
Ruby uses ambient context: client.set_context([...]) takes a block and auto-reverts when the block exits. You can also pass context: per call.
# declare flags — default values are used if the flag does not exist or
# smplkit is unreachable
checkout_v2 = client.flags.boolean_flag("checkout-v2", default: false)
banner_color = client.flags.string_flag("banner-color", default: "red")
max_retries = client.flags.number_flag("max-retries", default: 3)
client.set_context([Smplkit::Context.new("user", "alice.adams@acme.com", plan: "enterprise")]) do
if checkout_v2.get
# show new checkout
end
end
# or pass context explicitly per call
checkout_v2.get(context: [Smplkit::Context.new("user", "john.smith@acme.com", plan: "free")])→ Full reference (every language, all context modes, change listeners): Flags Runtime
Config
Use config for structured settings you want to update live without a deploy. bind returns an object that is mutated in place as the config changes on the server; get_value reads a single key with a default and never raises.
Billing = Struct.new(:max_seats, :trial_days, :tier, keyword_init: true)
# bind a Struct (or plain Hash) — the returned object updates in place
billing = client.config.bind("billing", Billing.new(max_seats: 5, trial_days: 14, tier: "free"))
puts billing.max_seats # reflects live changes from the server
# or read a single key directly, with a default if the key is absent
slow_query_ms = client.config.get_value("database", "slow_query_threshold_ms", 500)Logging
Use logging to control your application's log levels from smplkit at runtime. Wire your loggers normally, then call install once — the stdlib Logger and the semantic_logger gem are auto-discovered when present (Rails maps in via ActiveSupport::Logger). After install, levels are server-driven; keep using your loggers as usual.
Smplkit::Client.open do |client|
client.logging.install
# all discovered loggers are now controlled by smplkit
endOn Rails, run rails generate smplkit:install to scaffold an initializer. To support another framework, subclass Smplkit::Logging::Adapters::Base and client.logging.register_adapter(...) before install.
Audit
Use audit to record an immutable event whenever something noteworthy happens. client.audit.events.record(...) is fire-and-forget — it buffers in memory and retries — so call flush when you need durability (CLI tools, tests, before exit). Arguments are keyword-only; resource_type must not start with smpl. (reserved → 403).
client.audit.events.record(
event_type: "invoice.created",
resource_type: "invoice",
resource_id: "o-1",
severity: "WARN",
data: {
"snapshot" => { "total_cents" => 4900, "currency" => "USD" }
}
)
client.audit.events.flush(timeout: 5.0) # or omit to flush asynchronouslyThe author + operate loop
The SDK call and the resource are two halves of one workflow: write the call in code, provision the resource with the MCP tools (create_flag / create_config / set_log_level), then verify with the read tools (get_flag / get_config / query_events). The id in code must equal the key you provision.
A checkout-v2 kill-switch end to end:
checkout_v2 = client.flags.boolean_flag("checkout-v2", default: false)
render_new_checkout if checkout_v2.get- Provision:
create_flag(key="checkout-v2", type="boolean", default=false) - Verify:
get_flag(key="checkout-v2")
The default stays false in code, so until the flag exists (or if smplkit is unreachable) the old checkout is served — the safe path.

