Rubot is a code-first Ruby framework. The library should read like Ruby written for humans, not generic generated code.
This guide is intentionally small. It captures the main idioms we want contributors and codegen to follow in lib/rubot.
Prefer the most readable Ruby expression that preserves the runtime contract.
That usually means:
- small methods
- clear naming
- guard clauses for early exits
- explicit domain boundaries
- idiomatic Ruby defaults and collection handling
Do not force an idiom if it obscures meaning or changes behavior.
Good:
@rubot_tools ||= []Use this when nil means “not initialized yet.”
Do not use ||= if false is a meaningful value you need to preserve.
Good:
return unless handlerAvoid:
return if !handlerGood:
run.subject_ref&.to_hThis is preferred over manual nil checks when the code is simply traversing an optional value.
Use:
any?over!empty?one?overlength == 1filter_mapwhen selecting and transformingmap(&:method_name)when it is genuinely clearer
Examples:
tool_classes.one?
selected.any?
rows.filter_map { |row| row[:value] if row[:enabled] }Do not use &:method_name if the explicit block is easier to read.
Methods returning booleans should end in ?.
Examples already used in Rubot:
completed?waiting_for_approval?terminal?
Reserve return for:
- guard clauses
- early exits
- branching that is clearer with an explicit exit
Good:
def terminal?
completed? || failed? || canceled?
endRubot’s public surface should remain explicit and self-describing.
Good:
Rubot.run(workflow, input:, subject:, context:)This is preferred over positional argument piles.
Do not hide API calls, persistence, or file actions inside agents when they should be explicit tools.
Branching, approvals, resumability, and sequencing belong in workflows, not prompts.
Rubot::Operation is the capability boundary. Favor names and defaults that make the operation legible at a glance.
Rubot is expressive, but the framework is also infrastructure. Avoid metaprogramming or compressed one-liners that make operational behavior harder to inspect.
Rubot uses RuboCop as a lightweight enforcement layer for the library.
Run:
bundle exec rubocop libThe goal is not style maximalism. The goal is to keep the framework readable, predictable, and pleasant to extend.