Last validated: 2026-03-22 (local ci-check + service orchestration)
SPECTER is a threat-intelligence prototype that ingests public OSINT indicators, normalizes and scores them, and exposes analyst-ready outputs through APIs, an agent service, and a dashboard.
It is designed for a "collect -> validate -> score -> explain -> export" workflow, with a built-in adversarial mirror that simulates poisoning attempts and tracks detection performance.
Most student TI demos stop at data collection. SPECTER is built to show an end-to-end pipeline that can:
- collect from multiple OSINT providers,
- run deterministic validation and scoring,
- expose operational APIs for SOC-style workflows,
- generate export artifacts (STIX and report),
- run an adversarial loop (red vs blue style) for pipeline integrity testing.
- Go collector that pulls and processes providers concurrently (
cmd/collector/main.go) - Go API server for health, events, metrics, exports, and manual injections (
cmd/api/main.go,internal/api/) - Go worker service that processes validated records with concurrency + graceful shutdown (
cmd/worker/main.go) - SQLite-backed repository with schema initialization and indices (
internal/storage/repository.go,internal/storage/migrations/001_init.sql) - Python FastAPI agent service with blue/red agent endpoints and adversarial mirror endpoints (
agents/app/main.py) - Agent mirror red/blue balancing with auto-red guardrails + Go real-event sync (
agents/app/adversarial/service.py) - Tauri + React desktop dashboard consuming agent-service mirror endpoints (
frontend/) - Task runners and bootstrap tooling (
justfile,Makefile,scripts/bootstrap.sh)
OSINT Providers (Go)
crt.sh, Shodan, URLHaus, AbuseIPDB, OTX
|
v
Collector + Normalize + Detect + Score (Go)
cmd/collector -> internal/ingest -> internal/validation -> internal/scoring
|
v
Persistence (SQLite)
internal/storage (threat_records table)
|
+------------------------------+
| |
v v
Go REST API Python Agent Service
/api/v1/events, metrics, /agents/*, /mirror/*
exports, injections talks to Go API
| |
+--------------+---------------+
|
v
Tauri + React Desktop Dashboard
SPECTER/
├── cmd/
│ ├── api/ # Go API server entrypoint
│ ├── collector/ # Go collection + pipeline processing
│ └── worker/ # Worker runtime service (validated -> scored processing)
├── internal/
│ ├── api/ # HTTP handlers and router
│ ├── config/ # Env-based runtime config
│ ├── ingest/ # Normalization/dedup helpers
│ ├── output/ # STIX/report exporters
│ ├── providers/ # External OSINT provider collectors
│ ├── scoring/ # Threat scoring logic
│ ├── storage/ # SQLite repository + migration
│ └── validation/ # Detection/quarantine rules
├── pkg/models/ # Shared domain models
├── agents/ # Python FastAPI agents service
├── frontend/ # Tauri + React desktop dashboard
├── scripts/ # Bootstrap and local run helpers
├── justfile # Developer task runner (dotenv-aware)
├── Makefile # Build/test task runner (CI friendly)
└── .env.example # Environment template
- Go 1.24+
- Python 3.11+
- Node.js 18+
- Rust toolchain (for Tauri desktop build)
- Bash (Linux/macOS shell)
Optional but recommended:
justfor local developer commandsmakefor CI-style or conventional build workflows
This repository supports both make and just.
They intentionally overlap for most targets (build, check, run-local, run-agents, run-dashboard, test). The practical separation is:
make: conventional build/CI entrypoint, especially useful in CI and automation pipelines.just: local developer convenience with automatic.envloading.
Important behavior difference:
justfilehasdotenv-load := true, sojustauto-loads.envinto recipe processes.Makefiledoes not auto-load.env; it uses variables already exported in your shell.
Suggested usage:
- Compile and finalization checks:
make build,make check - Local developer scripts and orchestration:
just run-local,just run-agents,just run-dashboard
Type just to see the full just command list.
Operational runbook: docs/RUNNING_GUIDE.md
Active task tracker: TEAM_TASK_LIST.md
Comprehensive technical reference: PROJECT_DOCUMENTATION.md
./scripts/bootstrap.shWhat this does:
- verifies
goandpython3are installed, - creates
.envfrom.env.exampleif missing, - creates
.venvif missing, - installs Python dependencies,
- downloads Go modules,
- builds Go binaries,
- runs baseline Go and Python tests.
Before starting services, verify local DB mode in .env:
DB_DSN=file:specter.db?_busy_timeout=5000&_journal_mode=WALThe current runtime storage implementation is SQLite-backed.
Single-command local orchestration:
./scripts/run_local.sh startor
make run-localThis starts Go API + worker + collector + agents + React dev dashboard with pid/log supervision.
You can still run services individually (make run-agents, make run-dashboard) for debugging.
Service orchestration helpers:
./scripts/run_local.sh status
./scripts/run_local.sh logs
./scripts/run_local.sh stop
./scripts/run_local.sh restartEquivalent Make/Just targets:
make status-local/just status-localmake logs-local/just logs-localmake stop-local/just stop-localmake restart-local/just restart-local
./scripts/seed_demo_data.sh
./scripts/agent_smoke.sh
./scripts/rehearse_demo.shThese scripts seed realistic demo IOC records, validate agent workflow paths (blue, red, run, mirror ingest), and run a smoke rehearsal path (health checks, seed, mirror trigger, exports).
make ci-check
# or
just ci-checkThis runs the CI-equivalent local quality profile: Go tests, Python tests, contract tests (temporary Go API fixture), compile checks, and shell script syntax checks.
./scripts/load_offline_snapshot.sh
./scripts/create_artifact_bundle.shOr use task runners:
make offline-load
make bundle
# or
just offline-load
just bundlecurl -s http://localhost:8080/health
curl -s http://localhost:8001/healthcp .env.example .env
python3 -m venv .venv
.venv/bin/python -m pip install --upgrade pip setuptools wheel
.venv/bin/python -m pip install -r agents/requirements.txt
.venv/bin/python -m pip install pytest requests
npm install --prefix frontend
go mod downloadEnvironment loading behavior differs by entrypoint:
- Go services load
.envthroughgodotenvininternal/config/config.go. justauto-loads.envbecausejustfileenablesdotenv-load.make, directuvicorn, and directnpmcommands do not auto-parse.env; they use exported shell variables and code defaults.
| Variable | Purpose | Default in code |
|---|---|---|
API_PORT |
Go API listen port | 8080 |
API_ALLOWED_ORIGINS |
Allowed browser/webview origins for Go API CORS | empty |
WORKER_CONCURRENCY |
Worker parallelism setting | 4 |
COLLECTION_INTERVAL_SECONDS |
Collector tick interval | 60 |
DB_DSN |
SQLite DSN | file:specter.db?_busy_timeout=5000&_journal_mode=WAL |
ABUSEIPDB_API_KEY |
AbuseIPDB provider key | empty |
OTX_API_KEY |
OTX provider key | empty |
SHODAN_API_KEY |
Shodan provider key | empty |
URLHAUS_API_KEY |
URLHaus provider key | empty |
LOG_LEVEL |
Logging level | INFO |
DEMO_MODE |
Demo-mode toggle (no implicit provider seeds) | false |
SHODAN_TARGETS |
Comma-separated Shodan collector targets | empty |
ABUSEIPDB_TARGETS |
Comma-separated AbuseIPDB collector targets | empty |
OTX_TARGETS |
Comma-separated OTX collector targets | empty |
URLHAUS_HOSTS |
Comma-separated URLHaus host targets | empty |
CRTSH_QUERY |
crt.sh query string | empty |
ENABLE_SHODAN |
Hard disable Shodan provider even if targets/key exist | true |
ENABLE_ABUSEIPDB |
Hard disable AbuseIPDB provider even if targets/key exist | true |
ENABLE_OTX |
Hard disable OTX provider even if targets/key exist | true |
ENABLE_URLHAUS |
Hard disable URLHaus provider even if targets/key exist | true |
ENABLE_CRTSH |
Hard disable crt.sh provider even if query exists | true |
CRTSH_DEDUPLICATE |
Add deduplicate=Y for crt.sh query |
true |
CRTSH_EXCLUDE_EXPIRED |
Add exclude=expired for crt.sh query |
true |
CRTSH_MAX_RESULTS |
Max unique domains accepted per crt.sh collection run (0 = no cap) |
1000 |
Collector note:
- Providers with empty target lists are skipped.
- Providers requiring API keys are skipped if targets are set but keys are missing (collector logs a clear skip reason).
- Providers can be explicitly disabled regardless of target lists via
ENABLE_*flags.
Rate-limit and plan-limit note:
- AbuseIPDB
429 Too Many Requestsnow causes temporary provider cooldown instead of immediate retry each tick. - Shodan plan/auth errors (e.g.
Requires membership or higher) now trigger extended suppression (24h) to reduce noise. - You can immediately mute noisy providers with:
ENABLE_ABUSEIPDB=false
ENABLE_SHODAN=false| Variable | Purpose | Default |
|---|---|---|
GO_API_BASE_URL |
Go API base URL used by agents | http://localhost:8080 |
AGENT_ALLOWED_ORIGINS |
Allowed browser/webview origins for Agents API CORS | http://localhost:1420,tauri://localhost |
AGENT_REQUEST_TIMEOUT_SECONDS |
HTTP timeout to Go API | 10 |
AGENT_MAX_RETRIES |
Retries for agent HTTP calls | 2 |
AGENT_MODEL |
Agent model label/config | gpt-4.1-mini |
RED_AGENT_INTERVAL_SECONDS |
Red agent background interval | 30 |
RED_MAX_RATIO |
Max allowed auto red ratio (injections/real_events) |
1.0 |
MIN_REAL_EVENTS_BEFORE_AUTO_RED |
Auto red waits for baseline real telemetry | 5 |
GO_SYNC_INTERVAL_SECONDS |
Agent mirror sync interval for Go real events | 15 |
GO_SYNC_BATCH_LIMIT |
Max Go events fetched per sync cycle | 20 |
GO_SYNC_ON_STARTUP |
Run first Go sync immediately on service start | false |
ADVERSARIAL_DB_PATH |
Adversarial mirror sqlite path | ./specter_adversarial.db |
| Variable | Purpose | Default |
|---|---|---|
AGENT_API_BASE_URL |
Agent API base URL used by dashboard requests | http://localhost:8001 |
VITE_AGENT_API_BASE_URL |
Agent API base URL used by React frontend | http://127.0.0.1:8001 |
VITE_GO_API_BASE_URL |
Go API base URL used by React frontend | http://127.0.0.1:8080 |
Note about DB_DSN:
- Runtime defaults are SQLite-backed (
internal/config/config.go+internal/storagemigration path). - For local usage, keep
DB_DSN=file:specter.db?_busy_timeout=5000&_journal_mode=WALunless you intentionally run another backend.
Defined in internal/api/router.go:
GET /healthGET /api/v1/eventsGET /api/v1/events/quarantinedGET /api/v1/metrics/pipelinePOST /api/v1/exports/stixPOST /api/v1/exports/reportPOST /api/v1/agents/injections/trigger
GET /api/v1/metrics/pipeline now includes freshness fields to verify continuous pulls under upsert-heavy workloads:
last_collected_atlast_updated_atfreshness_age_secondsdistinct_sourcessource_freshness_age_seconds
Defined in agents/app/main.py:
GET /healthGET /readyPOST /mirror/ingestPOST /mirror/injections/triggerPOST /api/v1/agents/injections/trigger(alias)GET /mirror/eventsGET /mirror/injectionsGET /mirror/metricsGET /mirror/dashboard(atomic snapshot for metrics + feed + injections)POST /mirror/exports/stix(STIX generated from same mirror snapshot)POST /mirror/exports/report(report/PDF generated from same mirror snapshot)
Dashboard sync note:
- The React/Tauri dashboard now uses
GET /mirror/dashboardso Pipeline Overview and Live IOC Feed are rendered from one agents-side snapshot (snapshot_generated_at) to avoid cross-endpoint drift. - STIX/report exports now use this same mirror snapshot contract and embed snapshot metadata (
snapshot_generated_at, derived snapshot id basis) for anti-drift traceability. - In snapshot metrics,
total_eventsis pipeline-aligned (from Go pipeline metrics when reachable), whilemirror_total_eventspreserves the local mirror event count. POST /agents/blue/analyzePOST /agents/red/injectPOST /agents/run
make help
make bootstrap
make build
make check
make test
make cleanjust
just setup
just run-local
just run-agents
just run-dashboard
just build-dashboard
just checkbuild-dashboard targets Linux deb and rpm bundles by default for reproducible packaging in environments where AppImage tooling may be unavailable.
Optional AppImage build (Linux):
npm run tauri --prefix frontend -- build --bundles appimage./scripts/bootstrap.sh
./scripts/run_local.sh
./scripts/seed_demo_data.sh- STIX export writes timestamped files to
artifacts/stix/. - Report export writes timestamped files to
artifacts/reports/. - Report export now writes a valid PDF structure with metrics, legend, and highlight sections.
Go:
go fmt ./...
go vet ./...
go test ./... -vPython agents:
.venv/bin/python -m pytest agents/testsOr run unified checks:
make check
# or
just checkscripts/run_local.shnow orchestrates API/worker/collector/agents/dashboard withstart|stop|status|logs|restart.- Network-dependent provider tests may be slow or occasionally skip/pass differently depending on upstream availability.
- Contract tests spin a temporary Go API process in
agents/tests/conftest.py. scripts/seed_demo_data.sh,scripts/agent_smoke.sh, andscripts/rehearse_demo.share live operational scripts.
Only keep and maintain these documents as source-of-truth:
README.md(overview, setup, API surface summary, troubleshooting)docs/RUNNING_GUIDE.md(operational run sequence and demo/verification flows)TEAM_TASK_LIST.md(current backlog and ownership)
PROJECT_DOCUMENTATION.md is a comprehensive reference document generated for full-project onboarding and handoff. It may include broader explanatory content than the minimal maintained source-of-truth set above.
All historical audit/sprint planning notes are intentionally removed to keep maintenance overhead low.
Ensure DB_DSN is SQLite-compatible for local runs:
DB_DSN=file:specter.db?_busy_timeout=5000&_journal_mode=WALpython3 -m venv .venv
.venv/bin/python -m pip install -r agents/requirements.txtVerify both dependencies are up:
- Go API reachable at
http://localhost:8080/health - Agents service reachable at
http://localhost:8001/health
If APIs are healthy but frontend requests fail, verify API_ALLOWED_ORIGINS and AGENT_ALLOWED_ORIGINS include your dashboard origin(s):
API_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173,http://localhost:1420,http://127.0.0.1:1420,tauri://localhost
AGENT_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173,http://localhost:1420,http://127.0.0.1:1420,tauri://localhostRun the Tauri desktop app:
npm run tauri dev --prefix frontendRun this after fresh setup to verify documentation flow end-to-end:
./scripts/run_local.sh start
./scripts/run_local.sh status
./scripts/seed_demo_data.sh
./scripts/agent_smoke.sh
./scripts/rehearse_demo.sh
make ci-checkUse just (auto dotenv) or export variables in your shell before make.
This project is licensed under the terms in LICENSE.