An AI-powered newsroom application where AI agents act as reporters and an editor, automatically generating articles and newspaper editions. The system uses scheduled jobs to create content based on predefined beats and editorial guidelines.
attonews is an AI-powered news platform that revolutionizes journalism through automated content creation. Our system employs specialized AI reporters covering various beats (Politics, Technology, Business, etc.) who continuously generate articles based on real-time events and editorial guidelines. An AI editor then curates the most newsworthy stories into comprehensive newspaper editions and daily compilations.
attonews operates 24/7, producing fresh content hourly with editions compiled every 6 hours and daily newspapers every 24 hours. The platform combines human-like journalistic standards with the efficiency of AI to deliver timely, relevant news coverage.
Access attonews's AI-generated news content through our intuitive web interface:
- Articles: Browse individual news stories generated by our AI reporters, each covering specific topics and beats
- Newspaper Editions: Read curated hourly editions that compile the most important stories of the period
- Daily Editions: Access comprehensive daily newspapers with front-page headlines, in-depth coverage, and editorial selections
- Archive Access: Depending on your subscription tier, explore historical content dating back to the platform's inception
All users can freely access recent content without registration. Visit the following pages to start reading:
/- Main page with latest stories and opinion articles/about- About the project/editions- View recent newspaper editions/events- Browse event-level news developments
- AI Reporters: Specialized AI agents covering different beats (Politics, Technology, Business, etc.)
- AI Editor: Curates and selects the most newsworthy stories for publication
- External Scheduling: System crontab triggers API endpoints for content generation
- Daily Editions: Comprehensive newspaper editions compiled from recent articles
- Web Interface: Next.js frontend for managing reporters, editor, articles
- Admin Authentication: Secure login system for editorial control (can be disabled for development with
npm run dev:noauth) - Configurable Storage: Redis/Sqlite data persistence for articles, reporters, and editions
- Node.js 18+
- Redis server running on
redis://localhost:6379(default database) - PostgreSQL server (optional, for PostgreSQL backend)
- Docker (optional, for Docker Compose testing)
-
Install dependencies:
npm install
-
Set up environment variables: Create a
.env.localfile with:OPENAI_API_KEY=your_openai_api_key DATA_STORAGE_BACKEND=redis -
Start the development server:
npm run dev
-
Open http://localhost:3000 to access the application.
For development or testing without setting up user accounts, start with:
npm run dev:noauthThis runs the app with AUTH_DISABLED=true, which bypasses all authentication checks and grants admin-level access to every visitor. All API routes respond as if an admin user is logged in, without requiring tokens or login. The editor page, admin panels, and permission-gated features are all fully accessible.
For isolated testing without local dependencies:
docker compose run --rm testOr start the dev server:
docker compose up appsrc/app/- Next.js app router pages and API routessrc/services/- Business logic services (AI, Redis, Editor, Reporter)src/models/- TypeScript types and schemascrontab.txt- System crontab for scheduling jobs
The system operates through 4 interconnected pipelines triggered by system crontab:
| Pipeline | Cron Schedule | Default Throttle | Endpoint | Description |
|---|---|---|---|---|
| Event Generation | Hourly (:00) |
30 min | /api/cron/events |
Fetches real-time social media from Bluesky, generates events per reporter |
| Article Generation | Hourly (:00) |
15 min | /api/cron/articles |
Generates articles for each enabled reporter using Bluesky data |
| Newspaper Edition | Every 6 hours | 180 min | /api/cron/edition |
Curates articles from last 3 hours into newspaper edition |
| Daily Edition | Daily at 8am | — | /api/cron/daily |
Aggregates 24h of editions into comprehensive daily newspaper |
| News Ticker | Daily at 8:10am | — | /api/cron/ticker |
Condenses daily edition into scrolling ticker text |
1. Event Generation (/api/cron/events)
- Fetches real-time messages from Bluesky/Jetstream
- For each enabled reporter, AI generates new events based on their beat + history
- Updates existing events or creates new ones
- Location:
src/app/services/reporter.service.ts:260
2. Article Generation (/api/cron/articles)
- For each enabled reporter:
- Fetches latest Bluesky messages
- Calls AI to generate structured article
- Saves article to storage
- Location:
src/app/services/reporter.service.ts:11
3. Newspaper Edition (/api/cron/edition)
- Collects all articles from the last 3 hours
- AI selects most newsworthy stories
- Creates newspaper edition with selected story IDs
- Location:
src/app/services/editor.service.ts:11
4. Daily Edition (/api/cron/daily)
- Aggregates all newspaper editions from the last 24 hours
- AI creates comprehensive front page headline/article
- AI generates topic-by-topic breakdown with summaries
- Location:
src/app/services/editor.service.ts:85
Each pipeline has a configurable "generation period" stored in editor settings. This acts as a throttle to prevent excessive runs:
- Article Generation: Default 15 minutes (cron runs hourly, but skips if <15min since last run)
- Event Generation: Default 30 minutes (cron runs hourly, but skips if <30min since last run)
- Edition Generation: Default 180 minutes (cron runs every 6h, but skips if <3h since last run)
The cron job will return { "skipped": true } if the generation period hasn't elapsed. Configure these values on the Editor page (/editor).
The production system uses a system crontab (crontab.txt) to trigger API endpoints. These define the maximum frequency — actual runs may be skipped based on the generation period throttle settings:
0 * * * * wget http://localhost:8080/api/cron/articles
0 * * * * wget http://localhost:8080/api/cron/events
0 */6 * * * wget http://localhost:8080/api/cron/edition
0 8 * * * wget http://localhost:8080/api/cron/daily
0 0 * * * redis-cli -n 0 saveManual triggers: Jobs can also be triggered manually via the Editor page (/editor).
Bluesky/Jetstream → Events → Articles → Newspaper Editions → Daily Edition → Home Page
- ReporterService: Handles event and article generation per reporter
- EditorService: Handles edition curation and compilation
- AIService: All LLM calls (article, event, edition generation)
- BlueskyService: Real-time social media ingestion
- Reporters Page: View and edit reporter profiles and their articles
- Editor Page: Configure editor settings and manually trigger jobs
- Articles Page: Browse generated articles
- Editions Page: View compiled newspaper editions
Tests use Node's built-in node:test framework with tsx for TypeScript support. Test files are named *.test.ts and are auto-discovered.
Locally (requires a local Node.js install):
DATA_STORAGE_BACKEND=sqlite npm testWith Docker Compose (isolated, no local dependencies needed):
docker compose run --rm testRun a single test file:
docker compose run --rm test node --import tsx --test src/app/services/sqlite-data-storage.test.tsTests use node:test and node:assert/strict:
import { describe, it, before, after } from "node:test";
import assert from "node:assert/strict";The primary test file at src/app/services/sqlite-data-storage.test.ts contains 47 tests covering:
| Group | Tests | Areas |
|---|---|---|
| Editor | 3 | save/get, null when missing |
| Reporter | 5 | CRUD, empty beats, disabled state |
| Article | 7 | CRUD, 4 query patterns (latest, by reporter, time range, global) |
| Event | 4 | CRUD, by reporter, latest updated |
| NewspaperEdition / DailyEdition | 6 | CRUD, ordering, empty topics |
| User | 8 | create, lookup by ID/email, login tracking, delete, unique constraint |
| Job status, KPI, Log | 8 | running/lastRun/lastSuccess, set/get/increment, add/get |
| clearAllData | 1 | wipes all tables for isolation |