Grounded search monitoring platform for AI-powered conditional automation
Project description
Torale
Grounded search monitoring platform for AI-powered conditional automation.
Monitor the web for specific conditions using Google Search + LLM analysis, then get notified when they're met.
Use Cases
- Product Launches: "Tell me when the next iPhone release date is announced"
- Availability Monitoring: "Notify me when swimming pool memberships open for summer"
- Stock Alerts: "Alert me when PS5 is back in stock at Best Buy"
- Event Tracking: "Let me know when GPT-5 launch date is confirmed"
- Price Monitoring: "Tell me when iPhone 15 price drops below $500"
Installation
pip install torale
Get started at torale.ai or see the Quick Start guide below.
How It Works
- Create a monitoring task with a search query and condition
- Torale runs scheduled searches via Google Search (grounded via Gemini)
- LLM evaluates if your condition is met based on search results
- You get notified when condition triggers (once, always, or on state change)
Quick Start
Option 1: Use the Hosted Service (Recommended)
The fastest way to get started is using the hosted service at torale.ai:
- Sign up at https://torale.ai (Google/GitHub OAuth or email)
- Create monitoring tasks via the web dashboard
- Get notified when conditions are met
Option 2: Install the CLI
Install the Torale CLI to manage tasks from your terminal:
pip install torale
Configure authentication:
# Generate an API key at https://torale.ai (or your self-hosted instance)
torale auth set-api-key
# Create your first monitoring task
torale task create "iPhone Release Monitor" \
--schedule "0 9 * * *" \
--prompt "Search for iPhone release date announcements"
# List all tasks
torale task list
# View task notifications
torale notifications TASK_ID
Option 3: Use the Python SDK
Integrate Torale into your Python applications:
pip install torale
from torale.sdk import ToraleClient
# Initialize client with your API key
client = ToraleClient(
api_key="sk_your_api_key_here",
base_url="https://api.torale.ai" # or http://localhost:8000 for self-hosted
)
# Create a monitoring task
task = client.tasks.create(
name="iPhone Release Monitor",
schedule="0 9 * * *",
executor_type="llm_grounded_search",
search_query="When is the next iPhone being released?",
condition_description="A specific release date has been announced",
notify_behavior="once",
config={"model": "gemini-2.0-flash-exp"}
)
# Get task status
task = client.tasks.get(task.id)
print(f"Task status: {task.is_active}")
# List all notifications
notifications = client.tasks.get_notifications(task.id)
for notification in notifications:
print(f"[{notification.created_at}] {notification.message}")
Option 4: Self-Hosted Setup
Run Torale on your own infrastructure:
1. Install Dependencies
pip install uv
uv sync
2. Set up Environment
cp .env.example .env
Edit .env with your API keys:
- Google AI: Get key from https://aistudio.google.com/app/apikey (required)
- Database: PostgreSQL connection string (local default works)
- Secret Key: Generate with
openssl rand -hex 32
3. Start Services
# Start all services (PostgreSQL + Temporal + API + Workers)
docker compose up -d
# Check status
docker compose ps
4. Access the Web Interface
# Start frontend
cd frontend && npm run dev
# Navigate to http://localhost:3000
# Sign in with Clerk (Google/GitHub OAuth or email/password)
# Create tasks via the dashboard UI
5. Or use the API directly
# Use your API key from the web dashboard
curl -X POST http://localhost:8000/api/v1/tasks \
-H "Authorization: Bearer sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "iPhone Release Monitor",
"schedule": "0 9 * * *",
"executor_type": "llm_grounded_search",
"search_query": "When is the next iPhone being released?",
"condition_description": "A specific release date has been announced",
"notify_behavior": "once",
"config": {
"model": "gemini-2.0-flash-exp"
}
}'
Frontend
The Torale frontend is a React + TypeScript application built with Vite.
Setup
# Install frontend dependencies
cd frontend && npm install
# Create frontend environment file
cat > frontend/.env << EOF
VITE_CLERK_PUBLISHABLE_KEY=your_clerk_publishable_key
VITE_API_BASE_URL=http://localhost:8000
EOF
# Start development server
npm run dev
Features
- Authentication: Clerk (Google/GitHub OAuth + email/password)
- Dashboard: View and manage all monitoring tasks
- Task Creation: Create new monitoring tasks with search queries and conditions
- Task Details: View execution history, notifications, and state changes
- API Key Management: Generate API keys for CLI access
- Real-time Updates: Auto-refresh execution status
- Toast Notifications: User feedback for all actions
Tech Stack
- React 18 + TypeScript
- Vite (build tool)
- Clerk (authentication)
- React Router (routing)
- Tailwind CSS (styling)
- shadcn/ui (component library)
- Sonner (toast notifications)
Access the frontend at http://localhost:3000 after starting the dev server.
Architecture
Local Development
- API: FastAPI with Clerk authentication + API keys
- Database: PostgreSQL 16 via Docker Compose
- Workers: Temporal workflows (self-hosted via Docker Compose)
- Executor: Grounded search + LLM condition evaluation
- Scheduler: Temporal cron schedules
- Search: Google Search via Gemini grounding
- CLI: Python typer with API key authentication
Production (GKE)
- Infrastructure: GKE Autopilot (clusterkit) in us-central1
- Database: Cloud SQL PostgreSQL 16 (managed, zonal)
- Orchestration: Temporal Cloud + GitHub Actions CI/CD
- Cost: Spot pods (60-91% savings), zonal Cloud SQL
- Domains: api.torale.ai (API), torale.ai (Frontend)
Features
✅ Implemented
- Grounded search monitoring via Google Search
- Intelligent condition evaluation (LLM-based)
- Automatic scheduled execution (cron)
- State tracking (no duplicate alerts)
- User-configurable notify behavior:
once: Notify once, then auto-disablealways: Notify every time condition is mettrack_state: Notify only when state changes
- In-app notifications endpoint
- Task templates for common use cases
- Clerk authentication (OAuth + email/password)
- API key authentication for CLI
- CLI for task management
- Temporal Cloud integration (production)
- Frontend dashboard with task management
- GKE deployment with cost optimization
🚧 In Progress
- Enhanced grounding source display
- Historical state comparison UI
- External notifications (email/SMS)
📋 Future Roadmap
- Shareable Tasks: Share monitoring tasks with rich OpenGraph previews
- External notifications (email/SMS via NotificationAPI)
- Browser automation for dynamic sites
- Price tracking with charts
- Multi-step conditional workflows
- Template marketplace
- Team/organization support
Known Issues
Frontend
- Alert Component Layout: The info panel in the task creation dialog has alignment issues with the icon and text. The shadcn/ui Alert component's grid layout may need adjustment for proper spacing.
Research
Systematic evaluation framework for comparing grounded search approaches. See backend/research/ for details.
Results: Perplexity achieves 80% accuracy at ~800 tokens (~9s), outperforming Gemini (60%/~750 tokens/~3.4s) and OpenAI (70%/~14,500 tokens/~28s).
Testing
Torale has comprehensive unit, integration, and E2E tests covering Temporal workflows, grounded search, and scheduled execution.
Unit Tests
Run pytest tests without requiring services:
just test # Run backend unit tests
just test-cov # Run with coverage report
just lint # Run ruff linting
E2E Integration Tests
E2E tests require running services (PostgreSQL, Temporal, API, Workers) and support two authentication modes:
Option 1: No-Auth Mode (Recommended for Development)
# Start services with no-auth mode
TORALE_NOAUTH=1 just dev-bg
# Run all E2E tests
TORALE_NOAUTH=1 just test-e2e
This automatically creates a test user and bypasses Clerk authentication for testing.
Option 2: Clerk Authentication (Production-like)
# Start services normally
just dev-bg
# Get a Clerk session token:
# 1. Login at http://localhost:3000
# 2. Open browser dev tools (F12)
# 3. Go to Application/Storage → Cookies
# 4. Copy the __session cookie value
# Run tests with Clerk token
export CLERK_TEST_TOKEN='your-clerk-session-token'
just test-e2e
Available E2E Tests:
test_temporal_e2e.sh- Tests Temporal workflow executiontest_schedule.sh- Tests automatic scheduled task executiontest_grounded_search.sh- Tests grounded search monitoring functionality
See docs/TESTING.md for detailed testing guide, including debugging workflows and troubleshooting.
Deployment
Local Development
just dev # Start all services via docker-compose
just dev-all # Include frontend dev server
CI/CD (Recommended)
Torale uses GitHub Actions for automated CI/CD with production and branch deployments.
Setup (one-time with keyless auth):
./scripts/setup-github-wif.sh
Then add 3 GitHub secrets (outputted by script):
GCP_PROJECT_IDGCP_SERVICE_ACCOUNTGCP_WORKLOAD_IDENTITY_PROVIDER
See docs/CI-CD.md for detailed setup.
Automatic deployments:
- Push to
main→ Production deployment (toralenamespace) - Push to
feat/**,fix/**→ Branch deployment (torale-{branch}namespace) - Pull Request → Build and scan only (no deployment)
Branch management:
just list-branches # List all branch deployments
just cleanup-branch feat-auth # Delete specific branch
just cleanup-old-branches # Delete branches >7 days old
Workflows:
.github/workflows/production.yml- Production deployment.github/workflows/branch.yml- Branch deployments.github/workflows/pr.yml- PR checks.github/workflows/build.yml- Reusable build/scan job
Features:
- ✅ Parallel Docker builds (3x matrix jobs)
- ✅ Security scanning with Trivy
- ✅ Automated Helmfile deployment to GKE
- ✅ Health checks and rollout verification
- ✅ Isolated branch test environments
Production (GKE ClusterKit)
Prerequisites: gcloud CLI, kubectl, helm, helmfile
# One-time setup
just k8s-auth # Get cluster credentials
just k8s-setup # Create Cloud SQL + IAM
just k8s-secrets # Create K8s secrets from .env
# Manual deploy (if not using CI/CD)
just k8s-deploy-all # Deploy Temporal + Torale
# Manage
just k8s-status # Check deployment status
just k8s-logs-api # View API logs
just k8s-logs-workers # View worker logs
Access:
- Frontend: https://torale.ai
- API: https://api.torale.ai
- Temporal UI:
just k8s-port-forward-temporal→ http://localhost:8080
See docs/k8s-deployment.md for detailed guide.
How Grounded Search Works
- Task Created: User defines search query + condition to monitor
- Scheduled Execution: Temporal triggers task based on cron schedule
- Grounded Search: Gemini performs Google Search with grounding
- LLM Evaluation: LLM analyzes search results and evaluates condition
- State Comparison: Compares with
last_known_stateto detect changes - Notification: If condition met (and not already notified), creates in-app notification
- Auto-disable (optional): If
notify_behavior = "once", task deactivates after first alert
Configuration
Notify Behaviors
once: Alert once when condition is first met, then auto-disable taskalways: Alert every time condition is met (use with caution)track_state: Alert only when underlying state changes (smart deduplication)
Schedule Formats
Use standard cron expressions:
* * * * *: Every minute (testing only)0 * * * *: Every hour0 9 * * *: Every day at 9 AM0 9 * * 1: Every Monday at 9 AM0 9 1 * *: First day of every month at 9 AM
API Endpoints
Authentication
POST /auth/sync-user # Sync Clerk user to database (auto-called)
GET /auth/me # Get current user info
POST /auth/api-keys # Generate API key for CLI
GET /auth/api-keys # List user's API keys
DELETE /auth/api-keys/{id} # Revoke API key
Tasks
POST /api/v1/tasks # Create monitoring task
GET /api/v1/tasks # List tasks
GET /api/v1/tasks/{id} # Get task details
PUT /api/v1/tasks/{id} # Update task
DELETE /api/v1/tasks/{id} # Delete task + schedule
POST /api/v1/tasks/{id}/execute # Manual execution (testing)
GET /api/v1/tasks/{id}/executions # Full execution history
GET /api/v1/tasks/{id}/notifications # Filtered: condition_met = true
CLI Commands
# Authentication
torale auth set-api-key # Configure API key
torale auth status # Check auth status
torale auth logout # Remove credentials
# Tasks
torale task create NAME --schedule CRON --prompt PROMPT
torale task list [--active]
torale task get TASK_ID
torale task update TASK_ID [--name NAME] [--schedule CRON] [--active/--inactive]
torale task delete TASK_ID [--yes]
torale task execute TASK_ID # Manual execution
torale task logs TASK_ID [--limit N] # View execution logs
# Development mode (no auth required)
export TORALE_NOAUTH=1
torale task list
Environment Variables
Backend (.env)
# Database
DATABASE_URL=postgresql://torale:torale@localhost:5432/torale
# Clerk Authentication
CLERK_SECRET_KEY=sk_test_... # Backend: Verify Clerk tokens
CLERK_PUBLISHABLE_KEY=pk_test_... # Backend: Initialize Clerk client
# Temporal
TEMPORAL_HOST=localhost:7233
TEMPORAL_NAMESPACE=default
# AI (Gemini required for grounded search)
GOOGLE_API_KEY=your-gemini-api-key
# Development/Testing (optional)
TORALE_NOAUTH=1 # Disable auth for local testing (DO NOT USE IN PRODUCTION)
Frontend (frontend/.env)
# Clerk
VITE_CLERK_PUBLISHABLE_KEY=pk_test_... # Frontend: Initialize ClerkProvider
VITE_API_BASE_URL=http://localhost:8000 # Frontend: API endpoint
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file torale-0.0.2.tar.gz.
File metadata
- Download URL: torale-0.0.2.tar.gz
- Upload date:
- Size: 219.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.9 {"installer":{"name":"uv","version":"0.9.9"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22f24c475e5addd1b9b343b0859cbdb74a440e8b694406fcdb730cd6611a6a63
|
|
| MD5 |
6cc2a218353825abcd268bbf99e6bfd5
|
|
| BLAKE2b-256 |
a1dbaf8f88c2b58fd648c9b4e880732fa36c9505dbd15e7b48375733087f515f
|
File details
Details for the file torale-0.0.2-py3-none-any.whl.
File metadata
- Download URL: torale-0.0.2-py3-none-any.whl
- Upload date:
- Size: 64.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.9 {"installer":{"name":"uv","version":"0.9.9"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb9ad8ff41ed5c78177a62e35c535953c87e528e3add0a79b0c8f0ab7eece3bf
|
|
| MD5 |
6a055d8105ae68a9a5304b2cbc04ab73
|
|
| BLAKE2b-256 |
b7182e418f9cd70c105af5ec544c2f0c289930bd0f00237f3ee868e06f02b7d6
|