Nest is a content moderation rules engine that evaluates user-submitted items against Starlark-based rules, producing verdicts (approve, block, review) with optional webhook actions and manual review routing. It is a single Go binary backed by PostgreSQL.
- Go 1.25+
- PostgreSQL 16+
- Python 3.11+ (for the admin UI only)
Create a PostgreSQL database:
createdb nestDATABASE_URL="postgres://user:pass@localhost:5432/nest?sslmode=disable" make migrateCheck migration status:
DATABASE_URL="..." go run ./cmd/migrate/ statusThe seed tool creates a default org, admin user, and MRT queues for development/testing:
DATABASE_URL="..." go run ./cmd/seed/Or with make:
DATABASE_URL="..." make seedThis creates:
| Entity | ID | Details |
|---|---|---|
| Org | org-default |
"Default Org" |
| Admin User | usr-admin-default |
Email: admin@nest.local, Password: admin123, Role: ADMIN |
| MRT Queue | mrtq-default |
"default" |
| MRT Queue | mrtq-urgent |
"urgent" |
| MRT Queue | mrtq-escalation |
"escalation" |
WARNING: Do not use these credentials in production.
All seed operations are idempotent (safe to run multiple times).
Required:
export DATABASE_URL="postgres://user:pass@localhost:5432/nest?sslmode=disable"
export SESSION_SECRET="your-secret-key-at-least-32-chars"Optional (with defaults):
| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
HTTP listen port |
WORKER_COUNT |
runtime.NumCPU() |
Starlark worker pool size |
RIVER_WORKER_COUNT |
100 |
Background job worker count |
RULE_TIMEOUT |
1s |
Per-rule evaluation timeout |
EVENT_TIMEOUT |
5s |
Per-event total evaluation timeout |
LOG_LEVEL |
info |
Logging level (debug, info, warn, error) |
DEV_MODE |
false |
Enable development mode |
COUNTER_BACKEND |
memory |
Counter storage: memory or postgres |
OPENAI_API_KEY |
(empty) | OpenAI API key (enables moderation signal adapter, empty = disabled) |
OPENAI_MODERATION_MODEL |
omni-moderation-latest |
OpenAI moderation model name |
OPENAI_MODERATION_TIMEOUT |
5s |
HTTP timeout for OpenAI moderation requests |
OPENAI_MODERATION_MAX_INPUT |
102400 |
Max input bytes for OpenAI moderation |
make build
./nestOr run directly:
go run ./cmd/server/cd nest-ui
pip install nicegui httpx
NEST_API_URL="http://localhost:8080" python main.pyThe UI runs on http://localhost:8090 by default. Optional environment variables:
| Variable | Default | Description |
|---|---|---|
UI_PORT |
8090 |
UI server port |
UI_SECRET |
change-me-in-production |
NiceGUI storage secret |
make build # Compile binary (CGO_ENABLED=0)
make test # Run full test suite
make vet # Run go vet
make lint # Run go vet (alias for vet)
make docker # Build Docker image
make migrate # Apply database migrations
make seed # Seed default org, admin user, and MRT queues
make run # Run server directly with go run
make clean # Remove compiled binaryRun a single test:
go test ./internal/engine/... -run TestCompiler -vThe Jetstream test connects to the live Bluesky AT Protocol firehose via WebSocket, consumes real posts and likes, submits them to a local Nest instance for rule evaluation, and validates the results. This is an end-to-end integration test using real-world data.
- Docker (for PostgreSQL via docker-compose)
- Go 1.25+ (to build all binaries)
- Internet access (the consumer connects to
wss://jetstream2.us-east.bsky.network/subscribe) - Ports 8080 and 9090 must be free (Nest API and webhook receiver respectively)
There are two modes:
Consumes a fixed number of items from the firehose, then validates:
# Default: 1000 items
./jetstream/run.sh
# Custom count: 500 items
./jetstream/run.sh 500This script runs through 8 steps:
- Starts PostgreSQL via docker-compose (port 5433)
- Builds all binaries (nest server, migrate, seed, setup, consumer, receiver, validate)
- Runs migrations, seeds default data, and cleans test tables
- Starts a webhook receiver on port 9090
- Starts the Nest server on port 8080
- Runs test setup (creates item types, rules, actions, API key)
- Runs the Jetstream consumer until the item count is reached
- Waits for the pipeline to drain, then runs validation
Consumes from the firehose for a fixed duration, then validates:
# Default: 2 minutes
./jetstream/run_timed.sh
# Custom duration: 5 minutes
./jetstream/run_timed.sh 5Same setup steps as run.sh, but the consumer runs continuously in the background for the specified number of minutes. Progress is printed every 30 seconds. After the timer expires, the consumer is stopped and validation runs.
The test scripts automatically create the following via the seed and setup tools:
| Entity | Details |
|---|---|
| Org | Default Org (ID: org-default) |
| Admin User | Email: admin@nest.local, Password: admin123, Role: ADMIN |
| MRT Queues | default, urgent, escalation |
| Item Types | post (text + entity_id), like (entity_id + subject_uri) |
| Actions | webhook-notify (WEBHOOK to :9090), mrt-review (ENQUEUE_TO_MRT to default queue) |
| Rules | Loaded from loadtest/rules/*.star (catchall, spam detection, content filters, etc.) |
| API Key | nest-test-key (auto-generated, saved to /tmp/nest_test_api_key.txt) |
To log in to the Nest API or UI during a test run:
| Field | Value |
|---|---|
admin@nest.local |
|
| Password | admin123 |
WARNING: These credentials are for development and testing only. Do not use them in production.
While a test is running (especially useful with run_timed.sh for longer durations):
- Nest API:
http://localhost:8080(e.g.,http://localhost:8080/api/v1/health) - Login:
POST http://localhost:8080/api/v1/auth/loginwith{"email": "admin@nest.local", "password": "admin123"}
You can create additional rules, inspect items, review MRT queues, and observe verdicts in real time against live Bluesky data.
If you set OPENAI_API_KEY before running the test, the setup will load additional rules from loadtest/rules/optional/ that use the OpenAI moderation signal adapter. An openai MRT queue is also created for flagged content review.
export OPENAI_API_KEY="sk-..."
./jetstream/run_timed.sh 5For a fully self-contained demo with PostgreSQL, Nest, Jetstream consumer, and the NiceGUI admin UI in a single container:
docker build -f Dockerfile.demo -t nest-demo .
docker run -p 8080:8080 -p 8090:8090 nest-demoAfter startup completes:
- Nest API:
http://localhost:8080 - Admin UI:
http://localhost:8090 - Login:
admin@nest.local/admin123
The demo container automatically runs migrations, seeds data, starts the Nest server, begins consuming from the Bluesky firehose, and launches the admin UI.
The test scripts clean up automatically on exit (processes are killed, temp binaries removed). To stop the PostgreSQL container started by docker-compose:
docker compose -f loadtest/docker-compose.yml downTo also remove the persisted data volume:
docker compose -f loadtest/docker-compose.yml down -vNine Go packages under internal/:
domain -- Pure types, zero imports
config -- Environment configuration
store -- PostgreSQL data access (pgx)
auth -- Sessions, API keys, RBAC, password hashing, webhook signing
signal -- Signal adapter framework (TextRegex, TextBank, HTTP)
engine -- Starlark rule evaluation: Pool, Workers, Snapshots
service -- Business logic orchestration
worker -- Background jobs via river (item processing, snapshot rebuild)
handler -- HTTP handlers and chi routing
Dependency flow: domain -> store -> auth/signal -> engine -> service -> worker/handler. No cycles.
- Rules Engine -- Rule syntax, verdict types, MRT routing, and examples
- Writing UDFs -- Built-in functions available in rules
- Admin Guide -- Org, user, and RBAC management
- Integration Guide -- Submitting items and receiving verdicts
- Analytics Queries -- SQL queries for reporting
- Design Document -- Full architecture specification
- Module Contracts -- Package interfaces and invariants
Copyright 2026 Vinay Rao. Licensed under the Apache License, Version 2.0.