Just an exploration of building my own agent
git clone git@github.com:Hyper-Unearthing/gruv.git
cd gruv
Using OpenAI OAuth Codex
ruby setup_provider.rb openai
./gruv -p openai_oauth_codexUsing Anthropic provider (OAuth from auth file if present, otherwise API key env var)
ruby setup_provider.rb anthropic
./gruv -p anthropic_apikey_messagesUsing OpenAI API key providers
OPENAI_API_KEY=... ./gruv -p openai_apikey_completions
OPENAI_API_KEY=... ./gruv -p openai_apikey_responses-p maps directly to llm_gateway provider keys. Use -m/--model for model selection.
Use --message for single-message mode.
OAuth auth is read from ~/.config/gruv/auth.json.
Stream test provider/model combinations:
# openai_apikey_completions_gpt_5_1
OPENAI_API_KEY=... ./gruv -p openai_apikey_completions -m gpt-5.1
# anthropic_apikey_messages_claude_sonnet_4
# (uses anthropic OAuth token from auth.json if present, else ANTHROPIC_API_KEY)
ANTHROPIC_API_KEY=... ./gruv -p anthropic_apikey_messages -m claude-sonnet-4-20250514
# openai_apikey_responses_gpt_5_4
OPENAI_API_KEY=... ./gruv -p openai_apikey_responses -m gpt-5.4
# openai_oauth_codex_gpt_5_4
ruby setup_provider.rb openai
./gruv -p openai_oauth_codex -m gpt-5.4Run the unified setup wizard (can be run multiple times safely):
bundle exec ruby setup.rb
./gruv -p openai_oauth_codex -m gpt-5.4The wizard lets you pick which things to configure:
- Anthropic / OpenAI — OAuth flow; re-running the same provider refreshes tokens
- Telegram — bot token
- Discord — bot token, app credentials, install URL generation
- AssemblyAI — transcription API key
Gruv uses an event-based logging system (lib/logging.rb) instead of direct puts for operational messages.
- Runtime and operational logs are emitted via
Logging.instance.notify(name, payload). - Use scoped names (for example:
daemon.start,daemon.message.complete,setup.error.provider_not_found) and include details in the payload hash. - Logs are written as JSONL by
LogFileWriter.- Supervisor-managed processes (
gruv,daemon_supervisor,telegram_writer,discord_writer) write toinstance/daemon_logs.jsonl. - Interactive/message modes write to
instance/interactive_logs.jsonlandinstance/message_logs.jsonl.
- Supervisor-managed processes (
Each JSONL log entry includes:
name(event name, e.g.log,setup.start,daemon.message.complete)payload(event data)timestampprocess(emitter name, e.g.daemon,telegram_writer)pid(OS process id)source_location(filepath,lineno,label) when available
# Interactive mode
./gruv # Single message mode
./gruv --message "whats this app" # Resume a session (works in --message or interactive mode)
./gruv -s sessions/20260224_164714_1846b412-9260-4e18-aa96-c1b67eb93581.jsonl # Daemon mode (supervisor): starts ALL
# 1) daemon worker (inbox reader/agent)
# 2) registered writers (inbox writer)
./gruv --daemon # Poll every 1 second (default)
./gruv --daemon --poll-interval 5 # Poll every 5 secondsCapability configs are set here instance/config.json
Ctrl+C (SIGINT) on ./gruv --daemon interrupts all child processes.
Gruv can manage cron jobs via bash/crontab. To keep scheduling safe and maintainable:
- Only manage entries marked with a Gruv job marker comment:
# gruv:job_id=<id>
- Do not edit unrelated crontab entries.
- Reuse/update an existing
job_idinstead of creating duplicates. - Prefer checked-in scripts over complex inline cron commands.
- Capture output to logs so runs can be inspected.
- Default notifications to failure-only. Notify on success only when agent follow-up is needed.
- After creating/updating a cron entry, verify with
crontab -land manually test the target script.
Example:
# gruv:job_id=daily_inbox_summary
0 9 * * * /app/gruv/scripts/daily_inbox_summary.sh >> /app/gruv/instance/logs/cron_daily_inbox_summary.log 2>&1Gruv includes a SQLite-backed inbox for message processing with priority-based queuing and daemon mode.
📚 Full documentation: docs/INBOX_INDEX.md
Database file:
instance/gruv.sqlite3
Migration files:
db/migrate/*.rb
Install deps (once):
bundle installCreate a migration:
bundle exec ruby db_tool.rb new create_usersRun migrations:
bundle exec ruby db_tool.rb migrateRollback one step:
bundle exec ruby db_tool.rb rollbackUseful commands:
bundle exec ruby db_tool.rb status
bundle exec ruby db_tool.rb version
bundle exec ruby db_tool.rb migrate 20260224130000 # migrate to specific version
bundle exec ruby db_tool.rb rollback 2 # rollback 2 steps
DB_LOG=1 bundle exec ruby db_tool.rb migrate # show SQL logsPackaging/distributable tarball flow has been removed.
Run Gruv directly from source with Bundler (./gruv ...).