rubino-agent 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +115 -0
- data/.rubocop_todo.yml +955 -0
- data/.ruby-version +1 -0
- data/AGENTS.md +97 -0
- data/CHANGELOG.md +344 -0
- data/CONTRIBUTING.md +69 -0
- data/LICENSE +21 -0
- data/README.md +200 -0
- data/Rakefile +8 -0
- data/docs/agents.md +190 -0
- data/docs/api/v1.md +414 -0
- data/docs/architecture.md +177 -0
- data/docs/commands.md +375 -0
- data/docs/configuration.md +590 -0
- data/docs/getting-started.md +143 -0
- data/docs/jobs.md +332 -0
- data/docs/mcp.md +128 -0
- data/docs/memory.md +98 -0
- data/docs/models-and-keys.md +173 -0
- data/docs/oauth-providers.md +145 -0
- data/docs/plugins.md +195 -0
- data/docs/security.md +145 -0
- data/docs/skills.md +322 -0
- data/docs/tools.md +395 -0
- data/docs/troubleshooting.md +73 -0
- data/exe/rubino +9 -0
- data/install.sh +275 -0
- data/lib/rubino/active_skill.rb +50 -0
- data/lib/rubino/agent/agent_registry.rb +120 -0
- data/lib/rubino/agent/backoff_policy.rb +116 -0
- data/lib/rubino/agent/definition.rb +128 -0
- data/lib/rubino/agent/degenerate_recovery.rb +271 -0
- data/lib/rubino/agent/fallback_chain.rb +194 -0
- data/lib/rubino/agent/iteration_budget.rb +50 -0
- data/lib/rubino/agent/loop.rb +617 -0
- data/lib/rubino/agent/model_call_runner.rb +383 -0
- data/lib/rubino/agent/prompts/build.txt +69 -0
- data/lib/rubino/agent/prompts/compaction.txt +20 -0
- data/lib/rubino/agent/prompts/explore.txt +19 -0
- data/lib/rubino/agent/prompts/general.txt +20 -0
- data/lib/rubino/agent/prompts/plan.txt +31 -0
- data/lib/rubino/agent/response_validator.rb +70 -0
- data/lib/rubino/agent/router.rb +65 -0
- data/lib/rubino/agent/runner.rb +195 -0
- data/lib/rubino/agent/tool_executor.rb +402 -0
- data/lib/rubino/agent/truncation_continuation.rb +137 -0
- data/lib/rubino/api/middleware/auth.rb +43 -0
- data/lib/rubino/api/middleware/error_handler.rb +65 -0
- data/lib/rubino/api/middleware/json_parser.rb +100 -0
- data/lib/rubino/api/middleware/observability.rb +59 -0
- data/lib/rubino/api/middleware/rate_limit.rb +136 -0
- data/lib/rubino/api/operations/approvals/decide_operation.rb +49 -0
- data/lib/rubino/api/operations/clarifications/decide_operation.rb +44 -0
- data/lib/rubino/api/operations/cron_jobs/create_operation.rb +46 -0
- data/lib/rubino/api/operations/cron_jobs/delete_operation.rb +36 -0
- data/lib/rubino/api/operations/cron_jobs/list_operation.rb +55 -0
- data/lib/rubino/api/operations/cron_jobs/pause_operation.rb +34 -0
- data/lib/rubino/api/operations/cron_jobs/resume_operation.rb +34 -0
- data/lib/rubino/api/operations/cron_jobs/schedule_validation.rb +30 -0
- data/lib/rubino/api/operations/cron_jobs/show_operation.rb +32 -0
- data/lib/rubino/api/operations/cron_jobs/trigger_operation.rb +38 -0
- data/lib/rubino/api/operations/cron_jobs/update_operation.rb +42 -0
- data/lib/rubino/api/operations/files/read_operation.rb +40 -0
- data/lib/rubino/api/operations/files/upload_operation.rb +175 -0
- data/lib/rubino/api/operations/health_operation.rb +46 -0
- data/lib/rubino/api/operations/memory/delete_operation.rb +32 -0
- data/lib/rubino/api/operations/memory/index_operation.rb +80 -0
- data/lib/rubino/api/operations/memory/stats_operation.rb +28 -0
- data/lib/rubino/api/operations/metrics_operation.rb +18 -0
- data/lib/rubino/api/operations/mode/show_operation.rb +29 -0
- data/lib/rubino/api/operations/mode/update_operation.rb +42 -0
- data/lib/rubino/api/operations/models/list_operation.rb +45 -0
- data/lib/rubino/api/operations/oauth/connections/disconnect_operation.rb +77 -0
- data/lib/rubino/api/operations/oauth/connections/list_operation.rb +36 -0
- data/lib/rubino/api/operations/oauth/providers/callback_operation.rb +82 -0
- data/lib/rubino/api/operations/oauth/providers/connect_operation.rb +44 -0
- data/lib/rubino/api/operations/oauth/providers/list_operation.rb +35 -0
- data/lib/rubino/api/operations/oauth/serializer.rb +21 -0
- data/lib/rubino/api/operations/runs/create_operation.rb +77 -0
- data/lib/rubino/api/operations/runs/events_operation.rb +195 -0
- data/lib/rubino/api/operations/runs/stop_operation.rb +34 -0
- data/lib/rubino/api/operations/sessions/create_operation.rb +46 -0
- data/lib/rubino/api/operations/sessions/delete_operation.rb +33 -0
- data/lib/rubino/api/operations/sessions/index_operation.rb +82 -0
- data/lib/rubino/api/operations/sessions/retry_operation.rb +45 -0
- data/lib/rubino/api/operations/sessions/show_operation.rb +59 -0
- data/lib/rubino/api/operations/sessions/undo_operation.rb +38 -0
- data/lib/rubino/api/operations/skills/list_operation.rb +34 -0
- data/lib/rubino/api/operations/skills/toggle_operation.rb +40 -0
- data/lib/rubino/api/operations/tasks/index_operation.rb +30 -0
- data/lib/rubino/api/operations/tasks/serializer.rb +60 -0
- data/lib/rubino/api/operations/tasks/show_operation.rb +33 -0
- data/lib/rubino/api/operations/tasks/stop_operation.rb +47 -0
- data/lib/rubino/api/request.rb +54 -0
- data/lib/rubino/api/responses.rb +64 -0
- data/lib/rubino/api/router.rb +72 -0
- data/lib/rubino/api/schemas.rb +103 -0
- data/lib/rubino/api/server.rb +102 -0
- data/lib/rubino/api/tls.rb +108 -0
- data/lib/rubino/attachments/classification.rb +16 -0
- data/lib/rubino/attachments/classify.rb +171 -0
- data/lib/rubino/attachments/defang.rb +47 -0
- data/lib/rubino/attachments/policy.rb +36 -0
- data/lib/rubino/attachments/preamble.rb +120 -0
- data/lib/rubino/boot/encryption_key.rb +32 -0
- data/lib/rubino/cli/chat/bang_shell.rb +257 -0
- data/lib/rubino/cli/chat/completion_builder.rb +290 -0
- data/lib/rubino/cli/chat/idle_card_host.rb +69 -0
- data/lib/rubino/cli/chat/image_inbox.rb +168 -0
- data/lib/rubino/cli/chat/session_resolver.rb +176 -0
- data/lib/rubino/cli/chat_command.rb +1674 -0
- data/lib/rubino/cli/commands.rb +250 -0
- data/lib/rubino/cli/config_command.rb +96 -0
- data/lib/rubino/cli/doctor_command.rb +251 -0
- data/lib/rubino/cli/jobs_command.rb +60 -0
- data/lib/rubino/cli/memory_command.rb +135 -0
- data/lib/rubino/cli/onboarding_wizard.rb +207 -0
- data/lib/rubino/cli/server_command.rb +139 -0
- data/lib/rubino/cli/session_command.rb +125 -0
- data/lib/rubino/cli/setup_command.rb +107 -0
- data/lib/rubino/cli/skills_command.rb +85 -0
- data/lib/rubino/cli/tools_command.rb +81 -0
- data/lib/rubino/cli/trust_gate.rb +71 -0
- data/lib/rubino/commands/built_ins.rb +46 -0
- data/lib/rubino/commands/command.rb +116 -0
- data/lib/rubino/commands/executor.rb +550 -0
- data/lib/rubino/commands/handlers/agents.rb +510 -0
- data/lib/rubino/commands/handlers/config.rb +88 -0
- data/lib/rubino/commands/handlers/help.rb +148 -0
- data/lib/rubino/commands/handlers/jobs.rb +71 -0
- data/lib/rubino/commands/handlers/mcp.rb +229 -0
- data/lib/rubino/commands/handlers/memory.rb +200 -0
- data/lib/rubino/commands/handlers/sessions.rb +207 -0
- data/lib/rubino/commands/handlers/skills.rb +195 -0
- data/lib/rubino/commands/handlers/status.rb +211 -0
- data/lib/rubino/commands/loader.rb +90 -0
- data/lib/rubino/config/configuration.rb +455 -0
- data/lib/rubino/config/defaults.rb +569 -0
- data/lib/rubino/config/loader.rb +115 -0
- data/lib/rubino/config/reasoning_prefs.rb +67 -0
- data/lib/rubino/config/writer.rb +72 -0
- data/lib/rubino/context/compressor.rb +149 -0
- data/lib/rubino/context/environment_inspector.rb +176 -0
- data/lib/rubino/context/file_discovery.rb +45 -0
- data/lib/rubino/context/message_boundary.rb +39 -0
- data/lib/rubino/context/prompt_assembler.rb +382 -0
- data/lib/rubino/context/summary_builder.rb +159 -0
- data/lib/rubino/context/token_budget.rb +68 -0
- data/lib/rubino/context/tool_pair_sanitizer.rb +70 -0
- data/lib/rubino/database/connection.rb +77 -0
- data/lib/rubino/database/migrations/001_create_initial_schema.rb +156 -0
- data/lib/rubino/database/migrations/002_create_runs.rb +45 -0
- data/lib/rubino/database/migrations/003_create_skill_states.rb +15 -0
- data/lib/rubino/database/migrations/004_create_cron_jobs.rb +36 -0
- data/lib/rubino/database/migrations/005_create_oauth_connections.rb +27 -0
- data/lib/rubino/database/migrations/006_create_webhook_deliveries.rb +34 -0
- data/lib/rubino/database/migrations/007_create_messages_fts.rb +59 -0
- data/lib/rubino/database/migrations/008_create_memory_facts.rb +75 -0
- data/lib/rubino/database/migrations/009_create_memory_graph.rb +55 -0
- data/lib/rubino/database/migrations/010_add_owner_pid_to_sessions.rb +20 -0
- data/lib/rubino/database/migrator.rb +48 -0
- data/lib/rubino/documents/converters/csv.rb +79 -0
- data/lib/rubino/documents/converters/docx.rb +129 -0
- data/lib/rubino/documents/converters/html.rb +28 -0
- data/lib/rubino/documents/converters/json.rb +35 -0
- data/lib/rubino/documents/converters/pdf.rb +59 -0
- data/lib/rubino/documents/converters/plain.rb +68 -0
- data/lib/rubino/documents/converters/pptx.rb +64 -0
- data/lib/rubino/documents/converters/xlsx.rb +62 -0
- data/lib/rubino/documents/converters/xml.rb +45 -0
- data/lib/rubino/documents/html.rb +71 -0
- data/lib/rubino/documents/registry.rb +68 -0
- data/lib/rubino/documents/table.rb +63 -0
- data/lib/rubino/documents.rb +50 -0
- data/lib/rubino/errors.rb +119 -0
- data/lib/rubino/files/workspace.rb +93 -0
- data/lib/rubino/interaction/cancel_token.rb +43 -0
- data/lib/rubino/interaction/clipboard_image.rb +84 -0
- data/lib/rubino/interaction/event_bus.rb +48 -0
- data/lib/rubino/interaction/events.rb +101 -0
- data/lib/rubino/interaction/image_input.rb +127 -0
- data/lib/rubino/interaction/input_queue.rb +117 -0
- data/lib/rubino/interaction/lifecycle.rb +299 -0
- data/lib/rubino/interaction/probe.rb +65 -0
- data/lib/rubino/interaction/state.rb +56 -0
- data/lib/rubino/jobs/cron_job_repository.rb +75 -0
- data/lib/rubino/jobs/handlers/cleanup_sessions_job.rb +32 -0
- data/lib/rubino/jobs/handlers/compact_session_job.rb +21 -0
- data/lib/rubino/jobs/handlers/distill_skill_job.rb +186 -0
- data/lib/rubino/jobs/handlers/extract_memory_job.rb +37 -0
- data/lib/rubino/jobs/handlers/summarize_session_job.rb +21 -0
- data/lib/rubino/jobs/queue.rb +184 -0
- data/lib/rubino/jobs/registry.rb +45 -0
- data/lib/rubino/jobs/runner.rb +79 -0
- data/lib/rubino/jobs/scheduler.rb +138 -0
- data/lib/rubino/jobs/webhook_delivery.rb +225 -0
- data/lib/rubino/jobs/worker.rb +59 -0
- data/lib/rubino/llm/adapter_factory.rb +47 -0
- data/lib/rubino/llm/adapter_response.rb +65 -0
- data/lib/rubino/llm/auxiliary_client.rb +61 -0
- data/lib/rubino/llm/bedrock_bearer_client.rb +235 -0
- data/lib/rubino/llm/content_builder.rb +55 -0
- data/lib/rubino/llm/credential_check.rb +93 -0
- data/lib/rubino/llm/error_classifier.rb +364 -0
- data/lib/rubino/llm/fake_provider.rb +292 -0
- data/lib/rubino/llm/inline_think_filter.rb +58 -0
- data/lib/rubino/llm/model_catalog.rb +29 -0
- data/lib/rubino/llm/provider_resolver.rb +48 -0
- data/lib/rubino/llm/reasoning_manager.rb +100 -0
- data/lib/rubino/llm/request.rb +56 -0
- data/lib/rubino/llm/ruby_llm_adapter.rb +794 -0
- data/lib/rubino/llm/scenario_loader.rb +68 -0
- data/lib/rubino/llm/scenario_selector.rb +80 -0
- data/lib/rubino/llm/scenarios/agent-creates-cron-failure.yml +29 -0
- data/lib/rubino/llm/scenarios/agent-creates-cron.yml +36 -0
- data/lib/rubino/llm/scenarios/analysis.yml +501 -0
- data/lib/rubino/llm/scenarios/complex-analysis.yml +598 -0
- data/lib/rubino/llm/scenarios/failure.yml +65 -0
- data/lib/rubino/llm/scenarios/happy-path.yml +24 -0
- data/lib/rubino/llm/scenarios/provider-quota-completed.yml +14 -0
- data/lib/rubino/llm/scenarios/wide-table.yml +121 -0
- data/lib/rubino/llm/scenarios/with-approvals.yml +50 -0
- data/lib/rubino/llm/scenarios/with-artifacts.yml +98 -0
- data/lib/rubino/llm/scenarios/with-clarify.yml +32 -0
- data/lib/rubino/llm/scenarios/with-reasoning.yml +175 -0
- data/lib/rubino/llm/scenarios/with-uploads.yml +104 -0
- data/lib/rubino/llm/thinking_support.rb +84 -0
- data/lib/rubino/llm/tool_bridge.rb +89 -0
- data/lib/rubino/logger.rb +99 -0
- data/lib/rubino/mcp/manager.rb +180 -0
- data/lib/rubino/mcp/mcp_tool_wrapper.rb +69 -0
- data/lib/rubino/mcp.rb +57 -0
- data/lib/rubino/memory/backend.rb +104 -0
- data/lib/rubino/memory/backends/default.rb +101 -0
- data/lib/rubino/memory/backends/sqlite.rb +653 -0
- data/lib/rubino/memory/backends.rb +53 -0
- data/lib/rubino/memory/deduplicator.rb +74 -0
- data/lib/rubino/memory/extractor.rb +85 -0
- data/lib/rubino/memory/flusher.rb +31 -0
- data/lib/rubino/memory/retriever.rb +50 -0
- data/lib/rubino/memory/sqlite_extraction_prompt.rb +70 -0
- data/lib/rubino/memory/sqlite_graph.rb +154 -0
- data/lib/rubino/memory/store.rb +228 -0
- data/lib/rubino/memory/threat_scanner.rb +68 -0
- data/lib/rubino/metrics.rb +175 -0
- data/lib/rubino/modes.rb +93 -0
- data/lib/rubino/oauth/connection_repository.rb +95 -0
- data/lib/rubino/oauth/provider/github.rb +75 -0
- data/lib/rubino/oauth/provider/google.rb +59 -0
- data/lib/rubino/oauth/provider.rb +149 -0
- data/lib/rubino/oauth/registry.rb +86 -0
- data/lib/rubino/oauth/token_encryptor.rb +87 -0
- data/lib/rubino/plugins/registry.rb +75 -0
- data/lib/rubino/plugins.rb +86 -0
- data/lib/rubino/run/approval_gate.rb +243 -0
- data/lib/rubino/run/attachment_downloader.rb +166 -0
- data/lib/rubino/run/event_store.rb +74 -0
- data/lib/rubino/run/executor.rb +383 -0
- data/lib/rubino/run/gate_registry.rb +39 -0
- data/lib/rubino/run/recorder.rb +69 -0
- data/lib/rubino/run/repository.rb +118 -0
- data/lib/rubino/run/session_approval_cache.rb +118 -0
- data/lib/rubino/security/allowlist_persister.rb +55 -0
- data/lib/rubino/security/approval_policy.rb +227 -0
- data/lib/rubino/security/command_allowlist.rb +24 -0
- data/lib/rubino/security/dangerous_patterns.rb +118 -0
- data/lib/rubino/security/deny_persister.rb +73 -0
- data/lib/rubino/security/doom_loop_detector.rb +43 -0
- data/lib/rubino/security/hardline_guard.rb +105 -0
- data/lib/rubino/security/pattern_matcher.rb +62 -0
- data/lib/rubino/security/prefix_deriver.rb +124 -0
- data/lib/rubino/security/readonly_commands.rb +211 -0
- data/lib/rubino/session/exporter.rb +101 -0
- data/lib/rubino/session/message.rb +77 -0
- data/lib/rubino/session/repository.rb +295 -0
- data/lib/rubino/session/store.rb +198 -0
- data/lib/rubino/session/summary_store.rb +65 -0
- data/lib/rubino/skills/prompt_index.rb +85 -0
- data/lib/rubino/skills/registry.rb +208 -0
- data/lib/rubino/skills/skill.rb +176 -0
- data/lib/rubino/skills/skill_tool.rb +215 -0
- data/lib/rubino/skills/state_repository.rb +37 -0
- data/lib/rubino/skills/toggle.rb +26 -0
- data/lib/rubino/tools/answer_child_tool.rb +83 -0
- data/lib/rubino/tools/ask_parent_tool.rb +232 -0
- data/lib/rubino/tools/attach_file_tool.rb +120 -0
- data/lib/rubino/tools/background_tasks.rb +520 -0
- data/lib/rubino/tools/base.rb +222 -0
- data/lib/rubino/tools/custom_tool_loader.rb +119 -0
- data/lib/rubino/tools/edit_tool.rb +122 -0
- data/lib/rubino/tools/git_tool.rb +71 -0
- data/lib/rubino/tools/github_tool.rb +233 -0
- data/lib/rubino/tools/glob_tool.rb +69 -0
- data/lib/rubino/tools/grep_tool.rb +206 -0
- data/lib/rubino/tools/memory_tool.rb +184 -0
- data/lib/rubino/tools/multi_edit_tool.rb +110 -0
- data/lib/rubino/tools/patch_tool.rb +260 -0
- data/lib/rubino/tools/probe_tool.rb +175 -0
- data/lib/rubino/tools/question_tool.rb +128 -0
- data/lib/rubino/tools/read_attachment_tool.rb +180 -0
- data/lib/rubino/tools/read_tool.rb +212 -0
- data/lib/rubino/tools/read_tracker.rb +98 -0
- data/lib/rubino/tools/registry.rb +166 -0
- data/lib/rubino/tools/result.rb +113 -0
- data/lib/rubino/tools/ruby_tool.rb +0 -0
- data/lib/rubino/tools/session_search_tool.rb +103 -0
- data/lib/rubino/tools/shell_input_tool.rb +96 -0
- data/lib/rubino/tools/shell_kill_tool.rb +76 -0
- data/lib/rubino/tools/shell_output_tool.rb +72 -0
- data/lib/rubino/tools/shell_registry.rb +158 -0
- data/lib/rubino/tools/shell_tail_tool.rb +118 -0
- data/lib/rubino/tools/shell_tool.rb +330 -0
- data/lib/rubino/tools/steer_tool.rb +118 -0
- data/lib/rubino/tools/subagent_probe.rb +89 -0
- data/lib/rubino/tools/summarize_file_tool.rb +182 -0
- data/lib/rubino/tools/task_result_tool.rb +90 -0
- data/lib/rubino/tools/task_stop_tool.rb +80 -0
- data/lib/rubino/tools/task_tool.rb +622 -0
- data/lib/rubino/tools/test_tool.rb +454 -0
- data/lib/rubino/tools/todo_tool.rb +93 -0
- data/lib/rubino/tools/tool_call_repository.rb +33 -0
- data/lib/rubino/tools/vision_tool.rb +85 -0
- data/lib/rubino/tools/webfetch_tool.rb +153 -0
- data/lib/rubino/tools/websearch_tool.rb +179 -0
- data/lib/rubino/tools/write_tool.rb +61 -0
- data/lib/rubino/trust.rb +88 -0
- data/lib/rubino/ui/api.rb +296 -0
- data/lib/rubino/ui/base.rb +252 -0
- data/lib/rubino/ui/bottom_composer.rb +1599 -0
- data/lib/rubino/ui/cli.rb +1987 -0
- data/lib/rubino/ui/completion_menu.rb +321 -0
- data/lib/rubino/ui/completion_source.rb +284 -0
- data/lib/rubino/ui/escape_reader.rb +169 -0
- data/lib/rubino/ui/indented_io.rb +88 -0
- data/lib/rubino/ui/input_history.rb +108 -0
- data/lib/rubino/ui/live_region.rb +183 -0
- data/lib/rubino/ui/markdown_renderer.rb +506 -0
- data/lib/rubino/ui/notifier.rb +163 -0
- data/lib/rubino/ui/null.rb +195 -0
- data/lib/rubino/ui/paste_store.rb +176 -0
- data/lib/rubino/ui/printer_base.rb +79 -0
- data/lib/rubino/ui/probe_wait_indicator.rb +75 -0
- data/lib/rubino/ui/queued_indicators.rb +66 -0
- data/lib/rubino/ui/status_bar.rb +100 -0
- data/lib/rubino/ui/stdout_proxy.rb +161 -0
- data/lib/rubino/ui/streaming_markdown.rb +186 -0
- data/lib/rubino/ui/subagent_cards.rb +134 -0
- data/lib/rubino/ui/subagent_view.rb +255 -0
- data/lib/rubino/ui.rb +21 -0
- data/lib/rubino/update_check.rb +187 -0
- data/lib/rubino/util/duration.rb +23 -0
- data/lib/rubino/util/hyperlink.rb +105 -0
- data/lib/rubino/util/output.rb +145 -0
- data/lib/rubino/util/secrets_mask.rb +83 -0
- data/lib/rubino/version.rb +5 -0
- data/lib/rubino/workspace.rb +85 -0
- data/lib/rubino-agent.rb +5 -0
- data/lib/rubino.rb +318 -0
- data/mise.toml +2 -0
- data/rubino-agent.gemspec +103 -0
- data/skills/ruby-expert/SKILL.md +67 -0
- data/skills/ruby-expert/references/concurrency.md +357 -0
- data/skills/ruby-expert/references/datetime-and-encoding.md +363 -0
- data/skills/ruby-expert/references/errors-and-types.md +460 -0
- data/skills/ruby-expert/references/gem-authoring.md +459 -0
- data/skills/ruby-expert/references/language-idioms.md +465 -0
- data/skills/ruby-expert/references/metaprogramming.md +339 -0
- data/skills/ruby-expert/references/oo-design.md +553 -0
- data/skills/ruby-expert/references/performance.md +383 -0
- data/skills/ruby-expert/references/rails.md +424 -0
- data/skills/ruby-expert/references/security.md +404 -0
- data/skills/ruby-expert/references/testing.md +473 -0
- data/skills/ruby-expert/references/tooling.md +466 -0
- metadata +856 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
# Configuration Reference
|
|
2
|
+
|
|
3
|
+
All values below are checked against `lib/rubino/config/defaults.rb` (`MODULE_DEFAULTS`) — the single source of truth. Only keys that ship a default are shown with one; everything else is opt-in.
|
|
4
|
+
|
|
5
|
+
## File Locations
|
|
6
|
+
|
|
7
|
+
- **User config:** `~/.rubino/config.yml` (created by `rubino setup`)
|
|
8
|
+
- **Project config:** `.rubino/config.yml` (overrides user config)
|
|
9
|
+
- **Secrets:** `~/.rubino/.env`
|
|
10
|
+
- **Database:** `~/.rubino/rubino.sqlite3`
|
|
11
|
+
|
|
12
|
+
> **`RUBINO_HOME` relocates everything.** When set, the home directory, `config.yml`, `.env`, and the database all follow it (the `database.path` default is a sentinel resolved at read time against the resolved home — issue #96). The CLI and the API server share one resolver, so they never disagree about where state lives.
|
|
13
|
+
|
|
14
|
+
## Precedence (highest to lowest)
|
|
15
|
+
|
|
16
|
+
1. Environment variables (`RUBINO_*`)
|
|
17
|
+
2. Project-local `.rubino/config.yml`
|
|
18
|
+
3. User global `~/.rubino/config.yml`
|
|
19
|
+
4. Built-in defaults
|
|
20
|
+
|
|
21
|
+
## Substitutions
|
|
22
|
+
|
|
23
|
+
Use in any string value:
|
|
24
|
+
- `{env:VAR_NAME}` or `${VAR_NAME}` — inserts an environment variable
|
|
25
|
+
- `{file:path/to/file}` — inserts file contents
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Full Config Reference
|
|
30
|
+
|
|
31
|
+
### model
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
model:
|
|
35
|
+
default: "openai/gpt-4.1" # Model identifier (NOTE: resolves to OpenRouter — see models-and-keys.md)
|
|
36
|
+
provider: "auto" # auto | openai | anthropic | bedrock | gemini | minimax | gateway
|
|
37
|
+
context_length: null # Override context window (null = use model default)
|
|
38
|
+
temperature: 0.3 # Generation temperature
|
|
39
|
+
max_tokens: null # Max output tokens (anthropic-family path); null = adapter default (16384)
|
|
40
|
+
thinking_budget: null # LEGACY — superseded by thinking.effort (below); null = adapter default (8000), 0 disables
|
|
41
|
+
max_tokens_text_headroom: 4096 # Visible-output headroom reserved on top of the thinking budget
|
|
42
|
+
supports_vision: null # null = auto-detect from model id; true/false to override
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
> The shipped default `openai/gpt-4.1` resolves to OpenRouter in ruby_llm's registry. See [models-and-keys.md](models-and-keys.md) for the per-provider blocks and the fail-fast behavior.
|
|
46
|
+
|
|
47
|
+
### providers
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
providers:
|
|
51
|
+
openai:
|
|
52
|
+
base_url: null # Custom endpoint (Azure, proxy)
|
|
53
|
+
request_timeout_seconds: 600 # Per-read socket inactivity timeout (resets per chunk)
|
|
54
|
+
stale_timeout_seconds: 300 # Stale connection timeout
|
|
55
|
+
anthropic:
|
|
56
|
+
base_url: null
|
|
57
|
+
request_timeout_seconds: 600
|
|
58
|
+
bedrock:
|
|
59
|
+
region: "us-east-1"
|
|
60
|
+
request_timeout_seconds: 600
|
|
61
|
+
gemini:
|
|
62
|
+
request_timeout_seconds: 600
|
|
63
|
+
gateway: # OpenAI-compatible gateway
|
|
64
|
+
openai_compatible: true
|
|
65
|
+
assume_model_exists: true
|
|
66
|
+
base_url: null
|
|
67
|
+
request_timeout_seconds: 600
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Per-provider you may also set `api_key`, and for custom gateways `anthropic_compatible: true` (MiniMax) or `openai_compatible: true`. See [models-and-keys.md](models-and-keys.md).
|
|
71
|
+
|
|
72
|
+
Per-provider `supports_thinking: true | false` declares whether the backend handles an Anthropic-style thinking budget correctly; `false` means no budget is ever sent to it, regardless of `thinking.effort`. Unset, MiniMax-family model ids default to `false`, everything else to `true` — see [reasoning & thinking](#reasoning--thinking).
|
|
73
|
+
|
|
74
|
+
### auxiliary
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
auxiliary:
|
|
78
|
+
compression:
|
|
79
|
+
provider: "main" # "main" uses default model
|
|
80
|
+
model: "" # Specific model for compression
|
|
81
|
+
base_url: null
|
|
82
|
+
timeout: 120
|
|
83
|
+
approval:
|
|
84
|
+
provider: "main"
|
|
85
|
+
model: ""
|
|
86
|
+
base_url: null
|
|
87
|
+
timeout: 30
|
|
88
|
+
vision: # `vision` tool delegates here so a text-only primary can "see"
|
|
89
|
+
provider: "main"
|
|
90
|
+
model: "" # "auto-vision" lets an OpenAI-compatible gateway pick
|
|
91
|
+
base_url: null
|
|
92
|
+
timeout: 120
|
|
93
|
+
summarize: # `summarize_file` tool map-reduces big files out-of-context here
|
|
94
|
+
provider: "main"
|
|
95
|
+
model: ""
|
|
96
|
+
base_url: null
|
|
97
|
+
timeout: 300
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### agent
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
agent:
|
|
104
|
+
max_turns: 90 # Max turns per session
|
|
105
|
+
max_tool_iterations: 8 # Max consecutive tool calls
|
|
106
|
+
max_turn_seconds: 120 # Timeout per turn
|
|
107
|
+
api_max_retries: 5 # LLM API retry count (exp backoff)
|
|
108
|
+
api_retry_backoff_cap_seconds: 16 # Max per-retry backoff draw
|
|
109
|
+
api_retry_backoff_overload_cap_seconds: 60 # Higher cap used only for overload (529/503)
|
|
110
|
+
empty_response_max_retries: 2 # In-turn retries for a 200-OK-but-empty response
|
|
111
|
+
fallback_models: [] # Ordered provider/model fallback chain (empty = none)
|
|
112
|
+
disabled_toolsets: [] # Tool names to disable
|
|
113
|
+
tool_use_enforcement: "auto"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### run
|
|
117
|
+
|
|
118
|
+
```yaml
|
|
119
|
+
run:
|
|
120
|
+
idle_event_timeout: 300 # SSE watchdog: mark a stalled run failed after N idle seconds (null = off)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### database
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
database:
|
|
127
|
+
path: "<RUBINO_HOME>/rubino.sqlite3" # sentinel; resolved against the home at read time
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
An explicit `path` in `config.yml` is used verbatim and overrides the sentinel.
|
|
131
|
+
|
|
132
|
+
### paths
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
paths:
|
|
136
|
+
home: "~/.rubino"
|
|
137
|
+
memory: "~/.rubino/memories"
|
|
138
|
+
skills: "~/.rubino/skills"
|
|
139
|
+
cron: "~/.rubino/cron"
|
|
140
|
+
sessions: "~/.rubino/sessions"
|
|
141
|
+
logs: "~/.rubino/logs"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### ui
|
|
145
|
+
|
|
146
|
+
```yaml
|
|
147
|
+
ui:
|
|
148
|
+
adapter: "cli" # cli | api | null
|
|
149
|
+
theme: "default" # default | dark | light | monokai
|
|
150
|
+
verbose: false
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### notifications
|
|
154
|
+
|
|
155
|
+
Attention signals for the moments the agent needs human eyes: a long turn finishing, an approval prompt parking the run on a decision, or a background subagent escalating an `ask_parent` to you (the ⛔ banner).
|
|
156
|
+
|
|
157
|
+
```yaml
|
|
158
|
+
notifications:
|
|
159
|
+
enabled: true # master switch for all attention signals
|
|
160
|
+
bell: true # terminal bell (BEL) per event; on iTerm2 an OSC 9 escape is also sent (native macOS notification)
|
|
161
|
+
command: null # optional shell command spawned non-blocking per event, e.g. "osascript -e \"display notification ...\""
|
|
162
|
+
min_turn_seconds: 10 # a turn must run at least this long before its completion notifies; quick turns stay silent
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
- **Events**: `turn_finished` (only when the turn ran ≥ `min_turn_seconds`), `needs_approval` (the main agent's approval card or a background child flipping to `needs approval`), `blocked` (a background child escalated `ask_parent` to the human).
|
|
166
|
+
- **Bell hygiene**: the BEL byte is only ever written to a real terminal — never into a pipe — and is routed to the real terminal IO even while the bottom composer owns the screen (BEL doesn't move the cursor).
|
|
167
|
+
- **`command` hook**: runs detached and best-effort (stdio nulled, errors swallowed to the log) with `RUBINO_EVENT` (`turn_finished` | `needs_approval` | `blocked`) and `RUBINO_MESSAGE` in its environment — the seam for `osascript` (macOS), `notify-send` (Linux), or any custom notifier.
|
|
168
|
+
- **Spam control**: events within ~1s of the last emitted one coalesce into a single signal.
|
|
169
|
+
|
|
170
|
+
### reasoning & thinking
|
|
171
|
+
|
|
172
|
+
Two orthogonal first-class knobs — these are what `/reasoning` and `/think` write:
|
|
173
|
+
|
|
174
|
+
```yaml
|
|
175
|
+
display:
|
|
176
|
+
reasoning: collapsed # hidden | collapsed | full — how reasoning is RENDERED
|
|
177
|
+
|
|
178
|
+
thinking:
|
|
179
|
+
effort: "off" # "off" | low | medium | high — how hard the model thinks
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
- `display.reasoning` controls rendering: `hidden` (nothing shown; Ctrl+O can still reveal the last thought), `collapsed` (default — a dim "✻ thought for Ns · ctrl-o to show" cue), `full` (the whole reasoning as a dim `┊` aside).
|
|
183
|
+
- `thinking.effort` maps to an Anthropic-style thinking-token budget (`off`→0, `low`→4000, `medium`→8000, `high`→16000) on the anthropic-family path. Unset (`null`) falls back to the `thinking_budget` chain, whose default is 8000 — i.e. the effective default effort is `medium`.
|
|
184
|
+
- **Quote `"off"`**: bare YAML `off` parses as the boolean `false`. The reader coerces `false` back to `off`, but quoting keeps `config get thinking.effort` honest.
|
|
185
|
+
- **Provider caveat**: some anthropic-compatible backends reject thinking budgets. The adapter detects the rejection, retries the turn once without the budget, and prints `provider doesn't support thinking — effort off` — set `effort: "off"` to skip the first-turn retry entirely.
|
|
186
|
+
- **Provider capability gate**: other backends *accept* the budget but, lacking a separate reasoning channel, dump the model's chain-of-thought as plain content — the reasoning appears inside the assistant message. `providers.<name>.supports_thinking: false` stops the budget from ever being sent to that backend, regardless of `thinking.effort`. Unset, MiniMax-family model ids (`MiniMax*`/`abab*`) default to `false` (they return no thinking blocks and leak reasoning when sent a budget); set `supports_thinking: true` explicitly to re-enable. For a model outside ruby_llm's registry (`assume_model_exists`, e.g. MiniMax on the anthropic-compatible path) the explicit opt-in sends the Anthropic-style `thinking` block via raw request params — ruby_llm's `with_thinking` only renders for registry models that declare a budget reasoning option and would otherwise raise client-side, silently killing the opt-in.
|
|
187
|
+
|
|
188
|
+
The legacy `display.show_reasoning` boolean maps in only when `display.reasoning` is unset (`true`→full, `false`→hidden); `model.thinking_budget` is likewise superseded by `thinking.effort`.
|
|
189
|
+
|
|
190
|
+
### streaming
|
|
191
|
+
|
|
192
|
+
```yaml
|
|
193
|
+
display:
|
|
194
|
+
streaming: true
|
|
195
|
+
reasoning: collapsed # see "reasoning & thinking" above
|
|
196
|
+
show_reasoning: true # LEGACY — superseded by display.reasoning
|
|
197
|
+
language: "en"
|
|
198
|
+
runtime_footer: { enabled: false }
|
|
199
|
+
interim_assistant_messages: false
|
|
200
|
+
statusbar: true # the model + context bar under the chat input
|
|
201
|
+
tool_output_preview_lines: 3 # head lines of tool output shown in the transcript (0 = full dump)
|
|
202
|
+
input_max_rows: 8 # chat input grows up to this many rows, then scrolls
|
|
203
|
+
|
|
204
|
+
paste:
|
|
205
|
+
collapse_lines: 5 # pastes longer than this collapse to a placeholder
|
|
206
|
+
file_threshold_tokens: 8000 # bigger pastes overflow to a session paste_N.txt
|
|
207
|
+
|
|
208
|
+
streaming:
|
|
209
|
+
enabled: true
|
|
210
|
+
transport: "off"
|
|
211
|
+
edit_interval: 0.3
|
|
212
|
+
buffer_threshold: 40
|
|
213
|
+
cursor: " ▉"
|
|
214
|
+
|
|
215
|
+
context:
|
|
216
|
+
engine: "compressor"
|
|
217
|
+
max_tokens: null
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
- `display.statusbar` (default `true`) pins a dim one-line bar UNDER the chat input — the session mode first (plus the branch/skill tokens when set), then the resolved model id and context saturation, e.g. `default · MiniMax-M3 · ctx ~8.4k/64k (13%)` (the percentage is omitted below 1%). The mode token is the live mode indicator (the prompt itself is a constant `▍❯ `): dim `default`, yellow `plan`, red `yolo`. Saturation uses the REAL usage the provider reported for the last response when available (the full assembled prompt, recorded by the agent loop), else the same chars/4 estimate compaction runs on (`Context::TokenBudget`); the window comes from `model.context_length` / `context.max_tokens`. It refreshes at turn boundaries (after each turn footer, and on session resume), never per stream delta. The percentage turns yellow at 70% and red at 90%; with no usable window only the token count shows. The bar is omitted off a TTY or on terminals narrower than 40 columns.
|
|
221
|
+
- `display.tool_output_preview_lines` (default `3`) caps how many head lines of each tool's output the transcript shows before a dim `… +N lines (full output → context)` marker. DISPLAY-ONLY: the model always receives the full output (subject to the `tool_output` truncation caps) — only the scrollback rendering collapses. Set `0` to restore the old full dump.
|
|
222
|
+
- `display.input_max_rows` (default `8`) caps how many visual rows the chat input grows to as a long or multi-line prompt wraps; past the cap the input scrolls vertically, keeping the caret row in view.
|
|
223
|
+
- `paste.collapse_lines` (default `5`) — the file-backed paste pipeline's first tier. Pasting MORE than this many lines into the chat input inserts a single cyan `[Pasted text #N +M lines]` placeholder instead of flooding the composer; the placeholder is one editable token (backspace deletes it whole, you can type around it, it survives ↑ draft recall and Alt+Enter queueing) and expands to the full pasted body when the message is sent — the model sees everything, while the transcript echo keeps the compact placeholder. Pastes at or under the threshold inline as real rows, exactly as before.
|
|
224
|
+
- `paste.file_threshold_tokens` (default `8000`) — the second tier. A paste estimated above this many tokens (chars/4, the same rule compaction uses) is written to `<RUBINO_HOME>/sessions/<session-id>/paste_N.txt` instead of being held inline, and the sent message carries `[Pasted text #N saved to <path> — too large to inline; read it with the read tool]` so the model reads just the parts it needs. The files persist for the session; `/clear-images` does not touch them (it only drops staged image attachments).
|
|
225
|
+
|
|
226
|
+
### compression
|
|
227
|
+
|
|
228
|
+
```yaml
|
|
229
|
+
compression:
|
|
230
|
+
enabled: true
|
|
231
|
+
threshold: 0.50 # Trigger at 50% of context window
|
|
232
|
+
gateway_threshold: 0.85 # Critical threshold
|
|
233
|
+
target_ratio: 0.20 # Compress to 20% of window
|
|
234
|
+
protect_first_n: 3 # Keep first N messages
|
|
235
|
+
protect_last_n: 20 # Keep last N messages
|
|
236
|
+
max_summary_tokens: 12000
|
|
237
|
+
preserve_tool_pairs: true
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### memory
|
|
241
|
+
|
|
242
|
+
```yaml
|
|
243
|
+
memory:
|
|
244
|
+
enabled: true
|
|
245
|
+
backend: "sqlite" # tiny-Zep FTS5/BM25 + graph-lite recall (default). "default" = legacy non-ranked store
|
|
246
|
+
auto_extract: true
|
|
247
|
+
auto_save: true
|
|
248
|
+
user_profile_enabled: true
|
|
249
|
+
project_context_enabled: true
|
|
250
|
+
memory_char_limit: 2200 # injection budget at RETRIEVAL time
|
|
251
|
+
user_char_limit: 1375
|
|
252
|
+
ingest_char_limit: null # cap on the live set at STORE time (null = unbounded)
|
|
253
|
+
sqlite:
|
|
254
|
+
vector: false # opt-in sqlite-vec/embedding KNN on top of FTS5 (needs RubyLLM.embed)
|
|
255
|
+
graph: true # graph-lite 1-hop entity/edge blend
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
See [memory.md](memory.md) for the backend internals.
|
|
259
|
+
|
|
260
|
+
### jobs
|
|
261
|
+
|
|
262
|
+
```yaml
|
|
263
|
+
jobs:
|
|
264
|
+
mode: "inline" # inline | manual | worker
|
|
265
|
+
poll_interval: 2 # Worker poll interval (seconds)
|
|
266
|
+
max_attempts: 3
|
|
267
|
+
retry_backoff_seconds: 30
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### tasks
|
|
271
|
+
|
|
272
|
+
Caps on the nested-subagent (`task` delegation) tree, all enforced in one place (`Tools::BackgroundTasks#reserve`). See [agents.md](agents.md#nesting-and-caps) for the model.
|
|
273
|
+
|
|
274
|
+
```yaml
|
|
275
|
+
tasks:
|
|
276
|
+
max_depth: 2 # max nesting depth (human → child → grandchild)
|
|
277
|
+
max_children_per_node: 3 # max LIVE direct children per node
|
|
278
|
+
max_concurrent_total: 8 # hard ceiling on total LIVE subagents across the tree
|
|
279
|
+
max_live_probes_per_child: 5 # per-child budget for billed live probes (probe(live: true))
|
|
280
|
+
ask_parent_timeout: 900 # seconds a blocking ask_parent waits before the child self-heals
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### tools
|
|
284
|
+
|
|
285
|
+
```yaml
|
|
286
|
+
tools:
|
|
287
|
+
workspace_strict: true # Sandbox write/edit/delete to workspace_root; false = any reachable path
|
|
288
|
+
git: true
|
|
289
|
+
shell: true # ON by default (the agent ships to run inside an isolated VM);
|
|
290
|
+
# every command is still gated by security.require_confirmation_for_shell
|
|
291
|
+
ruby: true
|
|
292
|
+
web: false # Gates BOTH the webfetch and websearch tools
|
|
293
|
+
memory: true
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Each tool declares its own `tools.<key>` gate (`Tools::Base#config_key`). A key
|
|
297
|
+
absent from config means the tool is enabled (opt-out model); only an explicit
|
|
298
|
+
`false` disables it. So the keys above are the ones that ship a default — file
|
|
299
|
+
tools (`read`/`write`/`edit`/`multi_edit`/`grep`/`glob`/`apply_patch`),
|
|
300
|
+
`github`, and the rest are on by default and don't need a config entry. Note
|
|
301
|
+
both web tools share a single gate: `tools.web` controls `webfetch` **and**
|
|
302
|
+
`websearch` (there is no `tools.webfetch` / `tools.websearch`).
|
|
303
|
+
|
|
304
|
+
### tool_output
|
|
305
|
+
|
|
306
|
+
```yaml
|
|
307
|
+
tool_output:
|
|
308
|
+
max_bytes: 50000
|
|
309
|
+
max_lines: 2000
|
|
310
|
+
max_line_length: 2000
|
|
311
|
+
|
|
312
|
+
file_read:
|
|
313
|
+
max_chars: 100000
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### terminal
|
|
317
|
+
|
|
318
|
+
```yaml
|
|
319
|
+
terminal:
|
|
320
|
+
backend: "local"
|
|
321
|
+
cwd: null # workspace root override; null = Dir.pwd
|
|
322
|
+
file_sync_enabled: false
|
|
323
|
+
file_sync_max_mb: 100
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### approvals
|
|
327
|
+
|
|
328
|
+
```yaml
|
|
329
|
+
approvals:
|
|
330
|
+
mode: "manual" # manual | auto | skip
|
|
331
|
+
auto_allow_readonly: true # auto-allow provably read-only shell commands (ls, grep, git log, ...) without a prompt
|
|
332
|
+
readonly_commands: [] # extra command names / leading-token prefixes (e.g. "docker ps") merged into the built-in read-only set
|
|
333
|
+
wait_timeout_seconds: 900 # how long a run waits on a human decision before auto-DENYing (null = forever)
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
See [security.md](security.md#auto-allowed-read-only-commands) for the read-only parse rules (the hardline floor and `permissions: deny` always run first).
|
|
337
|
+
|
|
338
|
+
### permissions
|
|
339
|
+
|
|
340
|
+
Pattern-based rules (wildcard support):
|
|
341
|
+
|
|
342
|
+
```yaml
|
|
343
|
+
permissions:
|
|
344
|
+
"git *": "allow"
|
|
345
|
+
"shell rm -rf *": "deny"
|
|
346
|
+
"shell bundle *": "allow"
|
|
347
|
+
"write ~/.env": "deny"
|
|
348
|
+
"read *": "allow"
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Actions: `allow`, `ask`, `deny`
|
|
352
|
+
|
|
353
|
+
### attachments
|
|
354
|
+
|
|
355
|
+
SSRF guard + secure-by-default file-attachment policy. See [security.md](security.md).
|
|
356
|
+
|
|
357
|
+
The policy is enforced on **every** attachment surface: API/server run attachments and CLI image attachments (`-i`/`--image`, `@image` tokens, dropped paths, `/paste`) all pass the same classification (magic bytes win over extension) and `max_file_bytes` cap **before** anything is sent to a provider. A rejected CLI attachment is a clean one-line error, never a provider call.
|
|
358
|
+
|
|
359
|
+
```yaml
|
|
360
|
+
attachments:
|
|
361
|
+
allowed_hosts: [] # hosts allowed for URL attachments (loopback always allowed; ALLOWED_FILE_URL_HOSTS env merged in)
|
|
362
|
+
policy:
|
|
363
|
+
max_file_bytes: 26214400 # 25 MB hard cap (checked before reading)
|
|
364
|
+
inline_text_budget_bytes: 100000
|
|
365
|
+
allow_kinds: [image, text, document, archive, binary]
|
|
366
|
+
auto_extract_documents: false
|
|
367
|
+
aux_vision_egress: true
|
|
368
|
+
archive: { max_entries: 2000, max_uncompressed_bytes: 268435456, max_entry_ratio: 100, max_total_ratio: 50, max_nesting_depth: 1 }
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### security
|
|
372
|
+
|
|
373
|
+
```yaml
|
|
374
|
+
security:
|
|
375
|
+
# confirm_policy: "confirm_all" # confirm_all (default) | dangerous_only; derived from the alias below when absent
|
|
376
|
+
require_confirmation_for_shell: true # legacy alias for confirm_policy; true => confirm_all
|
|
377
|
+
command_allowlist: # prefix-matched commands pre-approved (empty = approve nothing)
|
|
378
|
+
- "git status"
|
|
379
|
+
- "git diff"
|
|
380
|
+
- "bundle exec rspec"
|
|
381
|
+
website_blocklist:
|
|
382
|
+
enabled: false
|
|
383
|
+
domains: []
|
|
384
|
+
shared_files: []
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
The hardline floor (catastrophic commands) and `permissions: deny` rules always run **before** any allow path, including `yolo`. See [security.md](security.md).
|
|
388
|
+
|
|
389
|
+
### mcp
|
|
390
|
+
|
|
391
|
+
```yaml
|
|
392
|
+
mcp:
|
|
393
|
+
servers:
|
|
394
|
+
filesystem:
|
|
395
|
+
transport: stdio
|
|
396
|
+
command: "npx"
|
|
397
|
+
args: ["@modelcontextprotocol/server-filesystem", "."]
|
|
398
|
+
env:
|
|
399
|
+
DEBUG: "1"
|
|
400
|
+
remote_api:
|
|
401
|
+
transport: streamable
|
|
402
|
+
url: "https://mcp.example.com/api"
|
|
403
|
+
headers:
|
|
404
|
+
Authorization: "Bearer {env:MCP_TOKEN}"
|
|
405
|
+
oauth:
|
|
406
|
+
client_id: "{env:MCP_CLIENT_ID}"
|
|
407
|
+
scope: "mcp:read mcp:write"
|
|
408
|
+
timeout: 15000
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
Experimental. Configuring servers is the opt-in; `mcp.enabled: false` switches MCP off. The `oauth` hash is forwarded verbatim to `ruby_llm-mcp` — rubino implements no OAuth flow itself. See [mcp.md](mcp.md).
|
|
412
|
+
|
|
413
|
+
### skills
|
|
414
|
+
|
|
415
|
+
```yaml
|
|
416
|
+
skills:
|
|
417
|
+
enabled: true
|
|
418
|
+
auto_distill: true # post-turn skill distillation (DistillSkillJob); separate from `enabled`
|
|
419
|
+
include_builtin: true # also scan the gem-bundled skills/ catalogue (e.g. ruby-expert)
|
|
420
|
+
paths:
|
|
421
|
+
- ".rubino/skills"
|
|
422
|
+
- "~/.rubino/skills"
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
The agent loads a skill's instructions on demand (`tools.skill` gates the loading
|
|
426
|
+
tool). With `skills.enabled` (default true) the agent also creates skills: the
|
|
427
|
+
deterministic post-turn `DistillSkillJob` distils complex, repeatable runs into a
|
|
428
|
+
new skill (gated on a tool-count threshold, default 5 — set
|
|
429
|
+
`RA_DISTILL_TOOL_THRESHOLD` to tune), and the agent can author one on demand via
|
|
430
|
+
`skill(action: "create", ...)`. Setting `skills.enabled: false` turns off both
|
|
431
|
+
the distillation cost and the create affordance.
|
|
432
|
+
|
|
433
|
+
Skill activity is exported on `GET /v1/metrics` as two Prometheus counters:
|
|
434
|
+
|
|
435
|
+
- `skills_loaded_total` — number of times a skill body was successfully loaded via
|
|
436
|
+
the `skill` tool (usage/adoption).
|
|
437
|
+
- `skills_created_total` — number of new skills created (the on-demand create tool
|
|
438
|
+
and the registry's re-scan disk-diff both feed this).
|
|
439
|
+
|
|
440
|
+
A successful load emits the `SKILL_LOADED` event (`skill.loaded`); a creation emits
|
|
441
|
+
`SKILL_CREATED`. See **[docs/skills.md](skills.md)** for the full skill system,
|
|
442
|
+
including creation and the 3-level disclosure model.
|
|
443
|
+
|
|
444
|
+
### commands
|
|
445
|
+
|
|
446
|
+
```yaml
|
|
447
|
+
commands:
|
|
448
|
+
paths:
|
|
449
|
+
- ".rubino/commands"
|
|
450
|
+
- "~/.rubino/commands"
|
|
451
|
+
shell_injection_enabled: false # true = allow !`shell` interpolation in command templates
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### formatters
|
|
455
|
+
|
|
456
|
+
```yaml
|
|
457
|
+
formatters:
|
|
458
|
+
"*.rb": "rubocop -A --fail-level=fatal"
|
|
459
|
+
"*.js": "prettier --write"
|
|
460
|
+
"*.ts": "prettier --write"
|
|
461
|
+
"*.py": "black"
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### agents
|
|
465
|
+
|
|
466
|
+
Custom agent definitions:
|
|
467
|
+
|
|
468
|
+
```yaml
|
|
469
|
+
agents:
|
|
470
|
+
security:
|
|
471
|
+
type: subagent
|
|
472
|
+
model: "anthropic/claude-sonnet-4-20250514"
|
|
473
|
+
description: "Security-focused code review"
|
|
474
|
+
tools: [read, grep, glob]
|
|
475
|
+
mcp_servers: []
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### prompts
|
|
479
|
+
|
|
480
|
+
System-prompt layering. The defaults ship the built-in role prompts.
|
|
481
|
+
|
|
482
|
+
```yaml
|
|
483
|
+
prompts:
|
|
484
|
+
preamble: null # block prepended after the role identity (customer context)
|
|
485
|
+
environment:
|
|
486
|
+
enabled: true # inject an [Environment] block (date/OS/cwd/git/runtimes/PATH utilities)
|
|
487
|
+
extra_utilities: [] # extra binaries to probe beyond the defaults
|
|
488
|
+
overrides: {} # prompts.overrides.<role> fully replaces a built-in role prompt
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### clarify / worktree / privacy / quick_commands
|
|
492
|
+
|
|
493
|
+
```yaml
|
|
494
|
+
clarify:
|
|
495
|
+
timeout: 120 # seconds to wait for a clarification answer
|
|
496
|
+
|
|
497
|
+
worktree:
|
|
498
|
+
enabled: false # run in a git worktree
|
|
499
|
+
|
|
500
|
+
privacy:
|
|
501
|
+
redact_pii: false
|
|
502
|
+
|
|
503
|
+
quick_commands: {} # named one-line shortcuts
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### formatters
|
|
507
|
+
|
|
508
|
+
```yaml
|
|
509
|
+
formatters:
|
|
510
|
+
"*.rb": "rubocop -A --fail-level=fatal"
|
|
511
|
+
"*.js": "prettier --write"
|
|
512
|
+
"*.ts": "prettier --write"
|
|
513
|
+
"*.py": "black"
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### agents (planned)
|
|
517
|
+
|
|
518
|
+
Custom agent definitions (multi-agent routing is not fully wired yet — see [agents.md](agents.md)):
|
|
519
|
+
|
|
520
|
+
```yaml
|
|
521
|
+
agents:
|
|
522
|
+
security:
|
|
523
|
+
type: subagent
|
|
524
|
+
model: "anthropic/claude-sonnet-4-20250514"
|
|
525
|
+
description: "Security-focused code review"
|
|
526
|
+
tools: [read, grep, glob]
|
|
527
|
+
mcp_servers: []
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### server / api
|
|
531
|
+
|
|
532
|
+
```yaml
|
|
533
|
+
server:
|
|
534
|
+
port: 4820
|
|
535
|
+
auth: false
|
|
536
|
+
|
|
537
|
+
api:
|
|
538
|
+
max_body_bytes: 5242880 # 5 MB cap on JSON request bodies (413 past this)
|
|
539
|
+
max_upload_bytes: 52428800 # 50 MB cap on multipart uploads
|
|
540
|
+
rate_limit_enabled: true
|
|
541
|
+
rate_limit_unauth_per_minute: 60
|
|
542
|
+
rate_limit_auth_per_minute: 600
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## Environment Variables
|
|
548
|
+
|
|
549
|
+
### Provider keys
|
|
550
|
+
|
|
551
|
+
| Variable | Purpose |
|
|
552
|
+
|----------|---------|
|
|
553
|
+
| `MINIMAX_API_KEY` | MiniMax API key |
|
|
554
|
+
| `OPENAI_API_KEY` | OpenAI key (also the fallback for `openai_compatible` gateways) |
|
|
555
|
+
| `ANTHROPIC_API_KEY` | Anthropic key (also the fallback for `anthropic_compatible` gateways) |
|
|
556
|
+
| `GEMINI_API_KEY` / `GOOGLE_API_KEY` | Google Gemini key |
|
|
557
|
+
| `BEDROCK_API_KEY` | AWS Bedrock bearer key |
|
|
558
|
+
|
|
559
|
+
### Agent runtime
|
|
560
|
+
|
|
561
|
+
| Variable | Purpose |
|
|
562
|
+
|----------|---------|
|
|
563
|
+
| `RUBINO_HOME` | Relocate the home dir; config, `.env`, and the database all follow it |
|
|
564
|
+
| `RUBINO_ALLOW_FAKE` | `1` to allow the fake provider in `chat`/`server` (dev only) |
|
|
565
|
+
| `RUBINO_HYPERLINKS` | Toggle terminal hyperlink output |
|
|
566
|
+
| `RUBINO_LOG_LEVEL` / `RUBINO_LOG_FORMAT` | Logging verbosity / format |
|
|
567
|
+
|
|
568
|
+
### HTTP API server
|
|
569
|
+
|
|
570
|
+
| Variable | Purpose |
|
|
571
|
+
|----------|---------|
|
|
572
|
+
| `RUBINO_API_KEY` | Bearer token required on every API request |
|
|
573
|
+
| `RUBINO_API_HOST` / `RUBINO_API_PORT` | Bind interface / port |
|
|
574
|
+
| `RUBINO_ENCRYPTION_KEY` | Required to encrypt OAuth tokens at rest |
|
|
575
|
+
| `RUBINO_TLS` | `1` to serve the API over a self-signed, client-pinned cert |
|
|
576
|
+
| `RUBINO_WEBHOOK_URL` / `RUBINO_WEBHOOK_SECRET` | Outbound webhook target + signing secret |
|
|
577
|
+
|
|
578
|
+
### Tools & network
|
|
579
|
+
|
|
580
|
+
| Variable | Purpose |
|
|
581
|
+
|----------|---------|
|
|
582
|
+
| `GITHUB_TOKEN` | GitHub access token for the `github` tool |
|
|
583
|
+
| `TAVILY_API_KEY` | Tavily search key for `websearch` |
|
|
584
|
+
| `SEARXNG_URL` | SearXNG instance URL for `websearch` |
|
|
585
|
+
| `ALLOWED_FILE_URL_HOSTS` | Comma-separated extra hosts for URL attachments (merged with `attachments.allowed_hosts`) |
|
|
586
|
+
| `SUDO_PASSWORD` | When set, relaxes the `sudo -S` hardline guard |
|
|
587
|
+
| `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` | Standard network proxy (full HTTP/HTTPS/SOCKS support) |
|
|
588
|
+
| `SSL_CERT_FILE` | Custom CA certificate bundle |
|
|
589
|
+
|
|
590
|
+
> There is no `RUBINO_PROXY_URL`; the agent uses the standard `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY` variables (and SOCKS) for outbound network proxying.
|