Module: Rubino::Modes
- Defined in:
- lib/rubino/modes.rb
Overview
In-process switch that gates two orthogonal concerns from a single name:
:default — tutti i tool registrati, approval rules from config
:plan — solo tool read-only (read/grep/glob/web/todo/question)
:yolo — tutti i tool, ApprovalPolicy bypassata (sempre :allow)
Lives at the process level intentionally — alpha rule: no premature persistence. A new ‘rubino chat` boots in :default; an explicit `/mode yolo` or `Modes.set(:yolo)` from the API caller takes effect for the rest of that process. We can move it onto Session later if users actually want it sticky.
Boot pinning (#3): the process forgets the active mode on restart, which surprises callers when an external supervisor re-applies config and bounces the process out from under an already-set mode. Rather than introduce on-disk state, the initial mode is read once from the RUBINO_BOOT_MODE env var: an unattended supervisor can pin it in the process environment so a restart comes back up in the same mode it was configured for. Unset (the normal interactive case) keeps the :default boot. An unknown value is ignored so a typo in the environment can never crash boot.
Constant Summary collapse
- DEFAULT =
:default- PLAN =
:plan- YOLO =
:yolo- ALL =
[DEFAULT, PLAN, YOLO].freeze
- READ_ONLY_TOOLS =
Tool names allowed in plan mode. Pulled by string against Tool#name in the Registry — see Tools::Registry.enabled_tools. Keep this list in sync with the actual tool names registered in Tools::Registry.register_defaults!; the spec pins both sides.
%w[read grep glob webfetch websearch todowrite question shell_output skill].freeze
- DESCRIPTIONS =
{ DEFAULT => "all tools, approvals from config", PLAN => "read-only tools only, no edits/shell/git", YOLO => "all tools, approvals skipped" }.freeze
Class Method Summary collapse
-
.allows_tool?(tool_name) ⇒ Boolean
Used by Tools::Registry.enabled_tools.
-
.boot_default ⇒ Object
Initial mode for a fresh process.
- .current ⇒ Object
- .description(name = current) ⇒ Object
- .reset! ⇒ Object
-
.set(name) ⇒ Object
Switches the active mode.
-
.skip_approvals? ⇒ Boolean
Used by Security::ApprovalPolicy#decide.
Class Method Details
.allows_tool?(tool_name) ⇒ Boolean
Used by Tools::Registry.enabled_tools. Plan is the only mode that filters; default and yolo both pass everything through.
78 79 80 81 82 |
# File 'lib/rubino/modes.rb', line 78 def allows_tool?(tool_name) return true unless current == PLAN READ_ONLY_TOOLS.include?(tool_name.to_s) end |
.boot_default ⇒ Object
Initial mode for a fresh process. Honours RUBINO_BOOT_MODE so an external supervisor can pin the mode across a restart without any on-disk state; an unset or unknown value falls back to DEFAULT.
60 61 62 63 64 65 66 |
# File 'lib/rubino/modes.rb', line 60 def boot_default raw = ENV.fetch("RUBINO_BOOT_MODE", nil) return DEFAULT if raw.nil? || raw.strip.empty? sym = raw.strip.downcase.to_sym ALL.include?(sym) ? sym : DEFAULT end |
.current ⇒ Object
43 44 45 |
# File 'lib/rubino/modes.rb', line 43 def current @current ||= boot_default end |
.description(name = current) ⇒ Object
72 73 74 |
# File 'lib/rubino/modes.rb', line 72 def description(name = current) DESCRIPTIONS[name.to_s.downcase.to_sym] end |
.reset! ⇒ Object
68 69 70 |
# File 'lib/rubino/modes.rb', line 68 def reset! @current = DEFAULT end |
.set(name) ⇒ Object
Switches the active mode. Returns the new mode symbol. Raises on an unknown name so a typo in a slash command surfaces immediately rather than silently leaving the previous mode in place.
50 51 52 53 54 55 |
# File 'lib/rubino/modes.rb', line 50 def set(name) sym = name.to_s.downcase.to_sym raise ArgumentError, "unknown mode: #{name.inspect} (valid: #{ALL.join(", ")})" unless ALL.include?(sym) @current = sym end |
.skip_approvals? ⇒ Boolean
Used by Security::ApprovalPolicy#decide. Yolo short-circuits to :allow before any pattern matching; plan never reaches the policy because the tools it would gate are already filtered out of the registry.
88 89 90 |
# File 'lib/rubino/modes.rb', line 88 def skip_approvals? current == YOLO end |