9.1 KiB
AGENTS.md
Overview
This is Antigravity Agent — an autonomous AI agent platform built with a Rust backend and a vanilla JS frontend. Users create "tasks" (goals), and the system dispatches an LLM-powered agent to accomplish them. Tasks can be run on-demand or on a cron schedule. Each execution produces logs and a final answer, all persisted to PostgreSQL.
Architecture
┌─────────────────────────────────────────────────────────┐
│ Frontend (Vite + Vanilla JS) │
│ - OAuth login via Authentik │
│ - Dashboard: recent runs, task list, logs, answers │
│ - Polls /api/tasks every 3s for live updates │
└──────────────────────┬──────────────────────────────────┘
│ /api/*
┌──────────────────────▼──────────────────────────────────┐
│ Axum HTTP Server (src/server/) │
│ - CORS, CSP, rate limiting (1 MB body) │
│ - Cookie-based + Bearer token auth │
│ - Routes: tasks CRUD, runs, auth (callback/refresh) │
├─────────────────────────────────────────────────────────┤
│ Domain Layer (src/domain/) │
│ ├─ agent/ Agent loop, LLM API client, tool defs │
│ ├─ auth JwksVerifier, Authenticator (OIDC) │
│ └─ tasks Task execution, run management │
├─────────────────────────────────────────────────────────┤
│ Scheduler (src/scheduler.rs) │
│ - tokio-cron-scheduler for recurring task execution │
├─────────────────────────────────────────────────────────┤
│ Entities (src/entities/) │
│ - task, task_run (SeaORM models) │
├─────────────────────────────────────────────────────────┤
│ PostgreSQL │
│ - Migrations managed via sea-orm-migration │
└─────────────────────────────────────────────────────────┘
Project Structure
bot/
├── Cargo.toml # Workspace root (members: ".", "migration")
├── src/
│ ├── main.rs # Entrypoint: tracing init → server::start()
│ ├── config.rs # Config struct loaded from env vars
│ ├── error.rs # AppError enum (thiserror) → Axum responses
│ ├── scheduler.rs # Cron job scheduler (wraps tokio-cron-scheduler)
│ ├── tests.rs # Unit tests for error handling & config
│ ├── domain/
│ │ ├── agent/
│ │ │ ├── mod.rs # Agent struct: agentic loop with turn/time limits
│ │ │ ├── api.rs # LLM request/response types, Tavily search client
│ │ │ └── tools.rs # Tool definitions (google_search, finish) & dispatch
│ │ ├── auth.rs # JwksVerifier (RSA/JWKS), Authenticator (code exchange, refresh)
│ │ └── tasks.rs # Task execution logic, response DTOs
│ ├── entities/
│ │ ├── task.rs # SeaORM entity: tasks table
│ │ └── task_run.rs # SeaORM entity: task_runs table (belongs_to task)
│ └── server/
│ ├── mod.rs # App bootstrap: DB, scheduler, auth, router, CORS
│ ├── auth.rs # Auth routes & AuthenticatedUser extractor
│ └── tasks.rs # Task CRUD & run endpoints
├── migration/
│ └── src/ # SeaORM migrations (tasks, answer col, runs table, cron col)
├── frontend/
│ ├── index.html # SPA shell with glassmorphism dark theme
│ ├── src/
│ │ ├── main.js # All app logic: auth flow, task/run rendering, polling
│ │ └── style.css # Styles
│ ├── vite.config.js # Dev proxy: /api → localhost:3000
│ └── package.json # Deps: vite, marked, dompurify
└── .forgejo/workflows/
└── pipeline.yaml # CI: build frontend + cargo build → deploy via systemd
Agent System
The agent (src/domain/agent/) is a turn-based autonomous loop:
- A system prompt is injected with the current date and instructions not to ask the user for clarification.
- The user's goal is sent as the initial message.
- Each turn calls the Kimi K2.5 model via the Zen API (
https://opencode.ai/zen/v1/chat/completions). - The model can invoke tools:
google_search— web search via the Tavily API.finish— signals completion and provides the final answer.
- Tool results are appended to the conversation and the loop continues.
- The loop terminates when
finishis called, the turn limit is hit (AGENT_MAX_TURNS, default 20), or the time limit expires (AGENT_MAX_DURATION_SECS, default 120s).
All turns and tool calls are logged. The final answer (if any) and the full log are persisted to the task_runs table.
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
✅ | — | PostgreSQL connection string |
PORT |
3000 |
HTTP server port | |
ZEN_API_KEY |
— | API key for Zen/Kimi LLM | |
TAVILY_API_KEY |
— | API key for Tavily web search | |
AUTHENTIK_ISSUER |
✅ | — | OIDC issuer URL (Authentik) |
AUTHENTIK_CLIENT_ID |
✅ | — | OAuth client ID |
AUTHENTIK_CLIENT_SECRET |
✅ | — | OAuth client secret |
CORS_ALLOWED_ORIGINS |
— | Comma-separated allowed origins (or mirror) | |
COOKIE_SECURE |
false |
Set true for HTTPS-only cookies |
|
AGENT_MAX_TURNS |
20 |
Max LLM turns per agent run | |
AGENT_MAX_DURATION_SECS |
120 |
Max wall-clock seconds per agent run |
API Routes
All task/run routes require authentication (cookie or Bearer token).
| Method | Path | Description |
|---|---|---|
| GET | /api/tasks |
List all tasks with their runs |
| POST | /api/tasks |
Create a new task |
| GET | /api/tasks/:id |
Get a single task with runs |
| PUT | /api/tasks/:id |
Update task goal/cron schedule |
| POST | /api/tasks/:id/runs |
Trigger a manual re-run |
| GET | /api/runs/recent |
Latest 50 runs across all tasks |
| GET | /api/auth/session |
Check current session |
| GET | /api/auth/callback |
OAuth code → token exchange |
| POST | /api/auth/refresh |
Refresh access token |
| POST | /api/auth/logout |
Clear auth cookies |
Database Schema
tasks — id (UUID PK), goal (text), cron (text, nullable), created_at (timestamptz)
task_runs — id (UUID PK), task_id (FK → tasks, cascade delete), status (text), logs (text), answer (text, nullable), created_at (timestamptz)
Migrations are in migration/src/ and run automatically on startup via Migrator::up().
Development
# Backend (from repo root)
cargo run # requires DATABASE_URL + Authentik vars
# Frontend (from frontend/)
npm install
npm run dev # Vite dev server on :5173, proxies /api to :3000
# Tests
cargo test
CI / Deployment
The Forgejo Actions pipeline (.forgejo/workflows/pipeline.yaml) triggers on release publish:
- Builds the frontend (
npm install && npm run build). - Builds the Rust binary (
cargo build -r). - Uploads the binary as a release asset.
- Deploys to the host: copies binary + frontend dist, restarts the
botsystemd user service.