{"id":47744037,"url":"https://github.com/backmeupplz/omens","last_synced_at":"2026-04-26T20:00:39.723Z","repository":{"id":348300764,"uuid":"1191642239","full_name":"backmeupplz/omens","owner":"backmeupplz","description":"AI-filtered X/Twitter feed. Signal from noise.","archived":false,"fork":false,"pushed_at":"2026-04-22T21:48:52.000Z","size":3428,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-22T23:31:45.824Z","etag":null,"topics":["ai","bun","cli","hono","llm","preact","reddit","self-hosted","signal-extraction","social-media","twitter"],"latest_commit_sha":null,"homepage":"https://omens.online","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/backmeupplz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-25T12:55:02.000Z","updated_at":"2026-04-22T21:48:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"978540a4-3a18-4585-a287-51ee09e17687","html_url":"https://github.com/backmeupplz/omens","commit_stats":null,"previous_names":["backmeupplz/omens"],"tags_count":54,"template":false,"template_full_name":null,"purl":"pkg:github/backmeupplz/omens","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/backmeupplz%2Fomens","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/backmeupplz%2Fomens/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/backmeupplz%2Fomens/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/backmeupplz%2Fomens/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/backmeupplz","download_url":"https://codeload.github.com/backmeupplz/omens/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/backmeupplz%2Fomens/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32310804,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T19:15:34.056Z","status":"ssl_error","status_checked_at":"2026-04-26T19:15:15.467Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","bun","cli","hono","llm","preact","reddit","self-hosted","signal-extraction","social-media","twitter"],"created_at":"2026-04-03T00:20:58.787Z","updated_at":"2026-04-26T20:00:39.678Z","avatar_url":"https://github.com/backmeupplz.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Omens\n\n**Signal from noise.** AI-filtered social feed that surfaces only what matters to you.\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)\n\n## What it does\n\n1. **Connect your sources** — Log in with X and/or add subreddit RSS feeds\n2. **Choose an AI provider** — OpenAI, Anthropic, Google Gemini, Groq, xAI, Fireworks, OpenRouter, Ollama, or any OpenAI-compatible endpoint\n3. **Get signal** — Omens fetches your home timeline, scores every post 0-100 for relevance, and shows you only what matters\n\n## Features\n\n- **AI-filtered feed** — Every post scored by your AI provider, filtered to your configured threshold\n- **AI reports** — Daily digest reports summarizing your feed's highlights\n- **Reddit via RSS** — Add public subreddits as RSS-backed inputs\n- **Generic input model** — RSS is the first generic non-X input path; more feed types can reuse it\n- **Prompt tuning** — Thumbs up/down on posts + text instructions to refine your filter\n- **Auto-fetch** — Configurable polling interval (5min to 1hr)\n- **Shareable posts** — Public share pages with OG metadata for link previews\n- **Shareable reports** — Share AI reports with OG images\n- **Any LLM** — 9 built-in providers or any OpenAI-compatible endpoint\n- **Self-hostable** — Docker Compose with PostgreSQL. Your data stays yours.\n- **Tiny frontend** — Preact + Tailwind, minimal bundle\n\n## Quick start\n\n### Self-host with Docker Compose\n\n```bash\ngit clone https://github.com/backmeupplz/omens.git\ncd omens\ncp docker/.env.sample .env\n# Edit .env — at minimum set JWT_SECRET, ENCRYPTION_KEY, POSTGRES_PASSWORD\n./docker/deploy-prod.sh\n```\n\nIf `DOMAIN` is blank, Caddy stays disabled and Omens is served directly on `http://localhost:3000` or `http://SERVER_IP:${PORT}`.\n\nSet `SINGLE_USER_MODE=true` for personal use.\n\n### Development\n\n```bash\n# Prerequisites: Node 22+, pnpm, PostgreSQL\npnpm install\npnpm dev\n```\n\nAPI runs on `:3000`, web dev server on `:5173`.\n\n## Architecture\n\n```\napps/\n  api/       Hono + Bun backend\n  web/       Preact frontend\n  landing/   Static landing page (GitHub Pages)\npackages/\n  shared/    Zod schemas\n  db/        Drizzle ORM + PostgreSQL\n```\n\n## Environment variables\n\nOmens uses one real env file at the repo root: `.env`.\n\nThis repo ships two starter templates:\n\n- [`.env.sample`](.env.sample): app-focused example for local/non-Docker runs\n- [`docker/.env.sample`](docker/.env.sample): Docker/prod-flavored example that includes optional infra vars like `DOMAIN` and `GRAFANA_*`\n\nThe overlapping app vars are intentionally the same in both. `./docker/deploy-prod.sh` prefers the repo-root `.env`, so the distinction is just which starter template is more convenient for your setup.\n\nAI provider API keys are not server env vars. Each user enters them in the Omens settings UI.\n\n### Local app runtime\n\nUse this when running Omens directly with `pnpm dev` or a custom process manager.\n\n| Variable | Required | Where to get it | Notes |\n|----------|----------|-----------------|-------|\n| `DATABASE_URL` | Yes | Your PostgreSQL instance | Example local value: `postgres://omens:omens@localhost:5432/omens` |\n| `JWT_SECRET` | Yes | Generate with `openssl rand -hex 32` | Used for session JWT signing |\n| `ENCRYPTION_KEY` | Yes | Generate with `openssl rand -hex 32` | Used for encrypting saved provider/API credentials |\n| `PORT` | No | Choose locally | Defaults to `3000` |\n| `SINGLE_USER_MODE` | No | Set manually | `true` skips registration for personal self-hosting |\n| `POLL_INTERVAL_MINUTES` | No | Set manually | Global fetch loop cadence, default `5` |\n| `CORS_ORIGIN` | Only if web and API are on different origins | Your frontend URL | Example: `https://omens.example.com` |\n| `DEMO_USER_EMAIL` | Optional | One of your Omens user emails | Enables the logged-out demo feed |\n\n### Docker deployment\n\nFor Docker, the intended flow is:\n\n```bash\ncp docker/.env.sample .env\n```\n\nThen edit the repo-root `.env` before running [`./docker/deploy-prod.sh`](docker/deploy-prod.sh).\n\n#### Required for Omens\n\n| Variable | Required | Where to get it | Notes |\n|----------|----------|-----------------|-------|\n| `JWT_SECRET` | Yes | Generate with `openssl rand -hex 32` | Must be unique per deployment |\n| `ENCRYPTION_KEY` | Yes | Generate with `openssl rand -hex 32` | Must be different from `JWT_SECRET` |\n| `POSTGRES_PASSWORD` | Yes | Choose/generate a strong password | Docker compose uses this to build the app `DATABASE_URL` |\n| `PORT` | No | Choose locally/on server | Host port for Omens when running without Caddy; defaults to `3000` |\n| `SINGLE_USER_MODE` | No | Set manually | `true` for one-user self-hosting |\n| `POLL_INTERVAL_MINUTES` | No | Set manually | Global fetch cadence |\n| `CORS_ORIGIN` | Only if served from another origin | Your frontend URL | Leave blank when browsing Omens directly on the same host/port |\n| `DEMO_USER_EMAIL` | Optional | One of your Omens user emails | Enables logged-out demo mode |\n\n#### Optional: Caddy / HTTPS\n\n| Variable | Required to enable feature | Where to get it | Notes |\n|----------|----------------------------|-----------------|-------|\n| `DOMAIN` | Yes | Your DNS provider | Point an A/AAAA record for this hostname at your server |\n\nIf `DOMAIN` is set, `deploy-prod.sh` enables the `caddy` profile and serves Omens on `https://DOMAIN`.  \nIf `DOMAIN` is blank, Caddy stays off and Omens is only exposed on `PORT`.\n\n#### Optional: Grafana\n\n| Variable | Required to enable feature | Where to get it | Notes |\n|----------|----------------------------|-----------------|-------|\n| `GRAFANA_DOMAIN` | Yes | Your DNS provider | Example: `dash.omens.example.com` pointed at the same server |\n| `GRAFANA_ADMIN_PASSWORD` | Yes | Generate a strong password | Used for the Grafana admin login |\n| `GRAFANA_DB_PASSWORD` | Yes | Generate a strong password | Used for the read-only `grafana_ro` PostgreSQL role |\n| `GRAFANA_ADMIN_USER` | No | Set manually | Defaults to `admin` |\n| `GRAFANA_SHARED_DASHBOARD_UID` | No | Set manually | Stable UID for the shared dashboard |\n| `GRAFANA_SHARED_DASHBOARD_ACCESS_TOKEN` | No | Set manually | Public token used by the Caddy rewrite; use a valid opaque token such as 32 hex chars |\n\nIf `GRAFANA_DOMAIN`, `GRAFANA_ADMIN_PASSWORD`, and `GRAFANA_DB_PASSWORD` are all set, `deploy-prod.sh` enables the Grafana profile.  \nIf any of them are missing, the entire Grafana stack stays disabled.\n\n### Deployment behavior\n\n`./docker/deploy-prod.sh` now auto-enables optional services based on env:\n\n- `DOMAIN` set: enables `caddy`\n- `GRAFANA_DOMAIN` + `GRAFANA_ADMIN_PASSWORD` + `GRAFANA_DB_PASSWORD` set: enables `grafana`\n- missing optional vars: those services are skipped instead of starting half-configured\n\n## Grafana dashboards\n\nWhen enabled, production compose provisions Grafana 12.4.2 behind Caddy at `https://GRAFANA_DOMAIN`.\n\n- `/` is rewritten to a public externally shared dashboard with high-level aggregate metrics only.\n- `/login` and the normal Grafana UI stay authenticated for private admin dashboards and Explore-based SQL against curated `grafana.*` views.\n- PostgreSQL access is through a read-only `grafana_ro` role created idempotently by `docker/postgres/provision-grafana.sh`.\n- Grafana does not get direct `SELECT` access to the `public` schema. Both public and admin panels query curated views in the `grafana` schema instead.\n- Public aggregate views stay on coarse, non-user-level metrics; admin views expose operational data without database secrets or provider tokens.\n\nDashboard queries are managed in git, not by editing prod in place:\n\n- Public dashboard JSON: [`docker/grafana/dashboards/public/omens-public-overview.json`](docker/grafana/dashboards/public/omens-public-overview.json)\n- Private admin dashboard JSON: [`docker/grafana/dashboards/admin/omens-admin-overview.json`](docker/grafana/dashboards/admin/omens-admin-overview.json)\n- Datasource/dashboard provisioning: [`docker/grafana/provisioning`](docker/grafana/provisioning)\n\nThe compose setup uses Grafana file provisioning with `allowUiUpdates: false`, so redeploys overwrite drift. Use Grafana Explore for ad hoc read-only SQL against the provisioned `grafana.*` views; commit dashboard JSON or view changes when you want permanent shared/admin query updates.\n\n## Tech stack\n\n- **Runtime**: [Bun](https://bun.sh)\n- **Backend**: [Hono](https://hono.dev)\n- **Frontend**: [Preact](https://preactjs.com) + [wouter](https://github.com/molefrog/wouter) + [Tailwind CSS](https://tailwindcss.com)\n- **Database**: PostgreSQL + [Drizzle ORM](https://orm.drizzle.team)\n- **Monorepo**: pnpm workspaces + [Turborepo](https://turbo.build)\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbackmeupplz%2Fomens","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbackmeupplz%2Fomens","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbackmeupplz%2Fomens/lists"}