botiasloop 0.0.1

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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +343 -0
  3. data/bin/botiasloop +155 -0
  4. data/data/skills/skill-creator/SKILL.md +329 -0
  5. data/data/skills/skill-creator/assets/ruby_api_cli_template.rb +151 -0
  6. data/data/skills/skill-creator/references/specification.md +99 -0
  7. data/lib/botiasloop/agent.rb +112 -0
  8. data/lib/botiasloop/channels/base.rb +248 -0
  9. data/lib/botiasloop/channels/cli.rb +101 -0
  10. data/lib/botiasloop/channels/telegram.rb +348 -0
  11. data/lib/botiasloop/channels.rb +64 -0
  12. data/lib/botiasloop/channels_manager.rb +299 -0
  13. data/lib/botiasloop/commands/archive.rb +109 -0
  14. data/lib/botiasloop/commands/base.rb +54 -0
  15. data/lib/botiasloop/commands/compact.rb +78 -0
  16. data/lib/botiasloop/commands/context.rb +34 -0
  17. data/lib/botiasloop/commands/conversations.rb +40 -0
  18. data/lib/botiasloop/commands/help.rb +30 -0
  19. data/lib/botiasloop/commands/label.rb +64 -0
  20. data/lib/botiasloop/commands/new.rb +21 -0
  21. data/lib/botiasloop/commands/registry.rb +121 -0
  22. data/lib/botiasloop/commands/reset.rb +18 -0
  23. data/lib/botiasloop/commands/status.rb +32 -0
  24. data/lib/botiasloop/commands/switch.rb +76 -0
  25. data/lib/botiasloop/commands/system_prompt.rb +20 -0
  26. data/lib/botiasloop/commands.rb +22 -0
  27. data/lib/botiasloop/config.rb +58 -0
  28. data/lib/botiasloop/conversation.rb +189 -0
  29. data/lib/botiasloop/conversation_manager.rb +225 -0
  30. data/lib/botiasloop/database.rb +92 -0
  31. data/lib/botiasloop/loop.rb +115 -0
  32. data/lib/botiasloop/skills/loader.rb +58 -0
  33. data/lib/botiasloop/skills/registry.rb +42 -0
  34. data/lib/botiasloop/skills/skill.rb +75 -0
  35. data/lib/botiasloop/systemd_service.rb +300 -0
  36. data/lib/botiasloop/tool.rb +24 -0
  37. data/lib/botiasloop/tools/registry.rb +68 -0
  38. data/lib/botiasloop/tools/shell.rb +50 -0
  39. data/lib/botiasloop/tools/web_search.rb +64 -0
  40. data/lib/botiasloop/version.rb +5 -0
  41. data/lib/botiasloop.rb +45 -0
  42. metadata +250 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6b2c58deeefe3094bad216a8dd08b0fa9df9ea5e79924a088f77723d88542a64
4
+ data.tar.gz: 0d7bc8c46234f75313694d9c6adc1c35642ef012bf8cce15202d63bdadf52c93
5
+ SHA512:
6
+ metadata.gz: 6f17a7416ca693846a9070b998a59355de00dd9bbf707461bf28d6ab6469dfb0e6544619f6097a809b86f11acec6e2de33371f1ec60499484ca0c7aaa09fb03c
7
+ data.tar.gz: ff0d76df0c00904b848581c840fa1bae29c8f707a23e38da07698894e488482194c9368760a2c78fced02d0604f750cd3b1f1cae8e29256c240d4d8fbcf4ec7d
data/README.md ADDED
@@ -0,0 +1,343 @@
1
+ # BotiasLoop
2
+
3
+ A minimal agentic AI application built on the ReAct (Reasoning + Acting) loop pattern. BotiasLoop provides an AI agent with shell access and web search capabilities via OpenRouter, designed for dedicated infrastructure following the Rails Doctrine.
4
+
5
+ [![Ruby](https://img.shields.io/badge/ruby-3.4%2B-red.svg)](https://www.ruby-lang.org/)
6
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+ [![StandardRB](https://img.shields.io/badge/code_style-standard-success.svg)](https://github.com/standardrb/standard)
8
+
9
+ ## Philosophy
10
+
11
+ **Sharp Knives**: BotiasLoop intentionally provides full shell access without restrictions. This is a feature, not a bug. It's designed for dedicated infrastructure where raw power is needed, not personal devices. The agent can execute any shell command, read any file, and make system changes.
12
+
13
+ Following the Rails Doctrine:
14
+ - **Optimize for programmer happiness**: Beautiful, readable Ruby code
15
+ - **Convention over Configuration**: Sensible defaults, minimal setup required
16
+ - **The menu is omakase**: Curated stack (ruby_llm, StandardRB, RSpec)
17
+ - **No one paradigm**: Practical over pure - use what works
18
+
19
+ ## Features
20
+
21
+ ### Core
22
+ - **ReAct Loop**: AI reasons, acts using tools, observes results, and repeats
23
+ - **Shell Access**: Execute any shell command (full system access)
24
+ - **Web Search**: Search the web via SearXNG
25
+ - **Conversation Persistence**: SQLite-backed conversation storage with UUID tracking
26
+ - **Token Tracking**: Monitor input/output tokens per conversation
27
+
28
+ ### Channels
29
+ - **CLI Mode**: Interactive REPL for local usage
30
+ - **Telegram Bot**: Chat with the agent via Telegram
31
+ - **Multi-Channel**: Run multiple channels simultaneously
32
+ - **Boot Auto-Start**: systemd service with automatic startup on boot
33
+
34
+ ### Commands
35
+ Slash commands for conversation management:
36
+ - `/new` - Start a new conversation
37
+ - `/switch <label|uuid>` - Switch to a different conversation
38
+ - `/label <name>` - Label the current conversation
39
+ - `/conversations` - List all conversations
40
+ - `/reset` - Clear current conversation history
41
+ - `/compact` - Summarize and archive old messages
42
+ - `/status` - Show current model, token usage
43
+ - `/archive` - Archive old conversations
44
+ - `/system_prompt` - Show current system prompt
45
+ - `/help` - Show available commands
46
+
47
+ ### Skills System
48
+ Skills follow the [agentskills.io](https://agentskills.io) specification:
49
+ - Load default skills from `data/skills/`
50
+ - Load custom skills from `~/skills/`
51
+ - Progressive disclosure: name/description in system prompt, full content on demand
52
+ - Includes `skill-creator` skill for creating new skills
53
+
54
+ ## Installation
55
+
56
+ ### Prerequisites
57
+
58
+ - Ruby 3.4 or higher
59
+ - OpenRouter API key
60
+ - (Optional) SearXNG instance for web search
61
+
62
+ ### Via RubyGems
63
+
64
+ ```bash
65
+ gem install botiasloop
66
+ ```
67
+
68
+ ### From Source
69
+
70
+ ```bash
71
+ git clone https://github.com/0x7466/botiasloop.git
72
+ cd botiasloop
73
+ bundle install
74
+ bundle exec rake install
75
+ ```
76
+
77
+ ### Using mise (Recommended)
78
+
79
+ ```bash
80
+ # Install mise if not already installed
81
+ curl https://mise.run | sh
82
+
83
+ # Install Ruby and dependencies
84
+ mise install
85
+
86
+ # Run with mise-managed Ruby
87
+ mise exec ruby -- bundle install
88
+ ```
89
+
90
+ ## Configuration
91
+
92
+ Create `~/.config/botiasloop/config.yml`:
93
+
94
+ ```yaml
95
+ # Required: OpenRouter configuration
96
+ providers:
97
+ openrouter:
98
+ api_key: "your-openrouter-api-key" # Or set BOTIASLOOP_API_KEY env var
99
+ model: "moonshotai/kimi-k2.5" # Any OpenRouter model
100
+
101
+ # Optional: Web search configuration
102
+ tools:
103
+ web_search:
104
+ searxng_url: "http://localhost:8080" # Your SearXNG instance
105
+
106
+ # Optional: Maximum ReAct iterations (default: 20)
107
+ max_iterations: 20
108
+
109
+ # Optional: Telegram channel
110
+ channels:
111
+ telegram:
112
+ bot_token: "your-telegram-bot-token"
113
+ allowed_users: [] # Empty = allow all, or list specific user IDs
114
+ ```
115
+
116
+ ### Environment Variables
117
+
118
+ - `BOTIASLOOP_API_KEY` - OpenRouter API key (overrides config file)
119
+ - `BOTIASLOOP_SEARXNG_URL` - SearXNG URL (overrides config file)
120
+
121
+ ## Usage
122
+
123
+ ### CLI Mode
124
+
125
+ Start interactive REPL:
126
+
127
+ ```bash
128
+ botiasloop cli
129
+ ```
130
+
131
+ Exit with: `exit`, `quit`, `\q`, or Ctrl+C
132
+
133
+ ### Gateway Mode (Telegram Bot)
134
+
135
+ Start the gateway to enable Telegram and other channels:
136
+
137
+ ```bash
138
+ # Run in foreground
139
+ botiasloop gateway
140
+
141
+ # Systemd service management (boot auto-start)
142
+ botiasloop gateway enable # Install and enable boot auto-start
143
+ botiasloop gateway start # Start the service now
144
+ botiasloop gateway status # Check service status
145
+ botiasloop gateway stop # Stop the service
146
+ botiasloop gateway disable # Disable boot auto-start and uninstall
147
+ ```
148
+
149
+ ### One-Shot Mode
150
+
151
+ Send a single message:
152
+
153
+ ```bash
154
+ botiasloop "What's the weather in Tokyo?"
155
+ ```
156
+
157
+ ### Example Session
158
+
159
+ ```bash
160
+ $ botiasloop cli
161
+
162
+ botiasloop v0.0.1 - Interactive Mode
163
+ Type 'exit', 'quit', or '\q' to exit
164
+
165
+ You: What files are in this directory?
166
+
167
+ Agent: I'll check what files are in the current directory for you.
168
+
169
+ [Tool] Executing shell with arguments: {"command"=>"ls -la"}
170
+
171
+ Exit: 0
172
+ Stdout:
173
+ total 128
174
+ drwxr-xr-x 10 user staff 320 Feb 22 14:00 .
175
+ drwxr-xr-x 5 user staff 160 Feb 22 13:00 ..
176
+ -rw-r--r-- 1 user staff 2345 Feb 22 14:00 README.md
177
+ ...
178
+
179
+ Here are the files in your current directory...
180
+
181
+ You: /label my-project
182
+
183
+ Agent: **Conversation labeled as `my-project`**
184
+
185
+ You: exit
186
+
187
+ Goodbye!
188
+ ```
189
+
190
+ ## Development
191
+
192
+ ### Setup
193
+
194
+ ```bash
195
+ # Clone repository
196
+ git clone https://github.com/0x7466/botiasloop.git
197
+ cd botiasloop
198
+
199
+ # Install dependencies
200
+ bundle install
201
+ ```
202
+
203
+ ### Testing
204
+
205
+ Test-first development is required:
206
+
207
+ ```bash
208
+ # Run all tests
209
+ bundle exec rspec
210
+
211
+ # Run specific test file
212
+ bundle exec rspec spec/unit/agent_spec.rb
213
+
214
+ # Run specific test by line number
215
+ bundle exec rspec spec/unit/agent_spec.rb:42
216
+
217
+ # Check coverage (after running tests)
218
+ open coverage/index.html
219
+ ```
220
+
221
+ ### Linting
222
+
223
+ Code must pass StandardRB with zero offenses:
224
+
225
+ ```bash
226
+ # Check for offenses
227
+ bundle exec standardrb
228
+
229
+ # Auto-fix offenses
230
+ bundle exec standardrb --fix
231
+ ```
232
+
233
+ ### Default Rake Task
234
+
235
+ ```bash
236
+ # Run tests + linting
237
+ bundle exec rake
238
+ ```
239
+
240
+ ## Architecture
241
+
242
+ ```
243
+ botiasloop/
244
+ ├── bin/
245
+ │ └── botiasloop # CLI executable
246
+ ├── lib/
247
+ │ ├── botiasloop.rb # Main entry point
248
+ │ └── botiasloop/
249
+ │ ├── agent.rb # Main orchestrator
250
+ │ ├── loop.rb # ReAct cycle implementation
251
+ │ ├── config.rb # Configuration management
252
+ │ ├── conversation.rb # Conversation persistence (SQLite)
253
+ │ ├── tool.rb # Base tool class
254
+ │ ├── tools/
255
+ │ │ ├── registry.rb # Tool registration
256
+ │ │ ├── shell.rb # Shell execution
257
+ │ │ └── web_search.rb # SearXNG search
258
+ │ ├── skills/
259
+ │ │ ├── skill.rb # Skill model
260
+ │ │ ├── loader.rb # Skill loading
261
+ │ │ └── registry.rb # Skill registry
262
+ │ ├── commands/
263
+ │ │ ├── registry.rb # Command registry
264
+ │ │ ├── context.rb # Execution context
265
+ │ │ └── *.rb # Individual commands
266
+ │ ├── channels/
267
+ │ │ ├── base.rb # Channel base class
268
+ │ │ ├── cli.rb # CLI channel
269
+ │ │ └── telegram.rb # Telegram bot
270
+ │ └── channels_manager.rb # Multi-channel orchestration
271
+ ├── data/
272
+ │ └── skills/ # Default skills
273
+ ├── spec/ # Test suite
274
+ └── README.md # This file
275
+ ```
276
+
277
+ ## Security
278
+
279
+ ⚠️ **IMPORTANT**: BotiasLoop provides full shell access. The AI agent can:
280
+ - Execute any shell command
281
+ - Read, write, and delete any file
282
+ - Install software
283
+ - Modify system configuration
284
+ - Access network resources
285
+
286
+ **Use only on dedicated infrastructure**, never on personal devices or production systems containing sensitive data.
287
+
288
+ ### Future Security Features (Roadmap)
289
+ - Sandboxed execution (Docker/Firejail)
290
+ - Command whitelist/blacklist
291
+ - Confirmation for destructive operations
292
+ - Read-only mode option
293
+ - Secret management integration
294
+
295
+ ## Roadmap
296
+
297
+ See [ROADMAP.md](ROADMAP.md) for detailed planned features including:
298
+
299
+ - **Persistent Memory**: Vector database for semantic search
300
+ - **Custom Tools**: Load tools from `~/tools/`
301
+ - **Conversation Compaction**: Automatic summarization
302
+ - **Subagents**: Specialized agent instances
303
+ - **Streaming Responses**: Real-time token display
304
+ - **Multi-Modal**: Image analysis, audio transcription
305
+ - **Web Dashboard**: Browser-based management UI
306
+ - **Plugin System**: Load plugins from gems
307
+
308
+ ## Contributing
309
+
310
+ 1. Fork the repository
311
+ 2. Create a feature branch
312
+ 3. Write tests first (TDD required)
313
+ 4. Implement the feature
314
+ 5. Ensure all tests pass: `bundle exec rspec`
315
+ 6. Ensure zero linting offenses: `bundle exec standardrb`
316
+ 7. Commit with descriptive message
317
+ 8. Push to your fork
318
+ 9. Create a Pull Request
319
+
320
+ ### Development Principles
321
+
322
+ - **Test-First**: All features built using TDD
323
+ - **Sharp Knives**: Keep raw power, minimal restrictions
324
+ - **Rails Doctrine**: Optimize for programmer happiness
325
+ - **Privacy First**: Local-first, user-controlled data
326
+ - **Unix Philosophy**: Do one thing well, compose with other tools
327
+
328
+ ## License
329
+
330
+ MIT License - see [LICENSE](LICENSE) file for details.
331
+
332
+ ## Credits
333
+
334
+ Built by [Tobias Feistmantl](https://github.com/0x7466) with inspiration from nanobot and the Ruby on Rails doctrine.
335
+
336
+ Powered by:
337
+ - [ruby_llm](https://github.com/crmne/ruby_llm) - Unified LLM API
338
+ - [OpenRouter](https://openrouter.ai/) - Unified LLM API gateway
339
+ - [SearXNG](https://docs.searxng.org/) - Privacy-respecting metasearch
340
+
341
+ ---
342
+
343
+ **⚡ Built with sharp knives. Use responsibly.**
data/bin/botiasloop ADDED
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/botiasloop"
5
+
6
+ def print_help
7
+ puts "botiasloop - Minimal agentic AI with ReAct loop"
8
+ puts
9
+ puts "Usage: botiasloop [OPTIONS] [COMMAND]"
10
+ puts
11
+ puts "Options:"
12
+ puts " -h, --help Show this help message"
13
+ puts " -v, --version Show version information"
14
+ puts
15
+ puts "Commands:"
16
+ puts " cli Start interactive REPL mode"
17
+ puts " gateway Start gateway (Telegram bot and other channels)"
18
+ puts " help Show this help message"
19
+ puts
20
+ puts "Gateway Commands:"
21
+ puts " start Start the systemd service"
22
+ puts " stop Stop the systemd service"
23
+ puts " restart Restart the systemd service"
24
+ puts " status Show systemd service status"
25
+ puts " enable Install and enable systemd service (auto-start on login)"
26
+ puts " disable Disable and uninstall systemd service"
27
+ end
28
+
29
+ def start_gateway(config)
30
+ # Check if any channels are configured (excluding CLI)
31
+ available_channels = Botiasloop::Channels.registry.channels.except(:cli)
32
+
33
+ if available_channels.empty?
34
+ puts "No gateway channels configured."
35
+ puts "Configure at least one channel (e.g., Telegram) in ~/.config/botiasloop/config.yml"
36
+ exit 1
37
+ end
38
+
39
+ manager = Botiasloop::ChannelsManager.new(config)
40
+
41
+ # Start all channels and wait
42
+ manager.start_channels.wait
43
+ end
44
+
45
+ if ARGV[0] == "-h" || ARGV[0] == "--help"
46
+ print_help
47
+ elsif ARGV[0] == "-v" || ARGV[0] == "--version"
48
+ puts "botiasloop #{Botiasloop::VERSION}"
49
+ elsif ARGV[0] == "gateway"
50
+ config = Botiasloop::Config.new
51
+
52
+ if ARGV[1] == "start"
53
+ service = Botiasloop::SystemdService.new(config)
54
+ if service.systemd_available?
55
+ begin
56
+ service.start
57
+ puts "Service started"
58
+ rescue Botiasloop::SystemdError => e
59
+ puts "Error: #{e.message}"
60
+ exit 1
61
+ end
62
+ else
63
+ puts "Error: systemd is not available on this system"
64
+ exit 1
65
+ end
66
+ elsif ARGV[1] == "stop"
67
+ service = Botiasloop::SystemdService.new(config)
68
+ if service.systemd_available?
69
+ begin
70
+ service.stop
71
+ puts "Service stopped"
72
+ rescue Botiasloop::SystemdError => e
73
+ puts "Error: #{e.message}"
74
+ exit 1
75
+ end
76
+ else
77
+ puts "Error: systemd is not available on this system"
78
+ exit 1
79
+ end
80
+ elsif ARGV[1] == "restart"
81
+ service = Botiasloop::SystemdService.new(config)
82
+ if service.systemd_available?
83
+ begin
84
+ service.restart
85
+ puts "Service restarted"
86
+ rescue Botiasloop::SystemdError => e
87
+ puts "Error: #{e.message}"
88
+ exit 1
89
+ end
90
+ else
91
+ puts "Error: systemd is not available on this system"
92
+ exit 1
93
+ end
94
+ elsif ARGV[1] == "status"
95
+ service = Botiasloop::SystemdService.new(config)
96
+ if service.systemd_available?
97
+ status = service.status
98
+ puts "Service status: #{status[:message]}"
99
+ exit(status[:active] ? 0 : 1)
100
+ else
101
+ puts "Error: systemd is not available on this system"
102
+ exit 1
103
+ end
104
+ elsif ARGV[1] == "enable"
105
+ service = Botiasloop::SystemdService.new(config)
106
+ if service.systemd_available?
107
+ begin
108
+ service.install unless service.installed?
109
+ service.enable
110
+ puts "Service installed and enabled. Run 'botiasloop gateway start' to start now."
111
+ puts "The service will start automatically on your next login."
112
+ rescue Botiasloop::SystemdError => e
113
+ puts "Error: #{e.message}"
114
+ exit 1
115
+ end
116
+ else
117
+ puts "Error: systemd is not available on this system"
118
+ exit 1
119
+ end
120
+ elsif ARGV[1] == "disable"
121
+ service = Botiasloop::SystemdService.new(config)
122
+ if service.systemd_available?
123
+ begin
124
+ if service.installed?
125
+ service.uninstall
126
+ puts "Service disabled and uninstalled"
127
+ else
128
+ puts "Service is not installed"
129
+ end
130
+ rescue Botiasloop::SystemdError => e
131
+ puts "Error: #{e.message}"
132
+ exit 1
133
+ end
134
+ else
135
+ puts "Error: systemd is not available on this system"
136
+ exit 1
137
+ end
138
+ else
139
+ start_gateway(config)
140
+ end
141
+ elsif ARGV[0] == "cli"
142
+ # CLI interactive mode
143
+ config = Botiasloop::Config.new
144
+ cli_channel = Botiasloop::Channels::CLI.new(config)
145
+ cli_channel.start
146
+ elsif ARGV.empty? || ARGV[0] == "help"
147
+ # Default to help when no args or explicit help command
148
+ print_help
149
+ else
150
+ # Unknown command
151
+ puts "Unknown command: #{ARGV[0]}"
152
+ puts
153
+ print_help
154
+ exit 1
155
+ end