Skip to content
AbishekcsPublic

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

OwlSentry

OwlSentry — the owl on night watch

One terminal inbox for everything that pings you: email, Slack, GitHub, YouTube, Reddit, Twitter/X, calendar, and (through small bridges) WhatsApp, Telegram, Discord and more.

Three panes: accounts and views on the left, a time-grouped feed in the middle, and a daily summary on the right (counts, top sources, what's coming up, quick actions). An AI bar at the bottom can summarize your unread items.

Written in Rust with ratatui. Built for Linux (tested layout on Arch).

OwlSentry in action

OwlSentry only reads from your accounts. Read, archived and starred flags are kept locally in ~/.local/share/owlsentry/state.json.

Try it in 10 seconds

cargo run --release -- --demo

--demo loads sample data so you can look around before connecting anything.

Install (Arch Linux)

sudo pacman -S --needed rust xdg-utils libnotify     # libnotify = desktop alerts (optional)
git clone <this repo> owlsentry && cd owlsentry
cargo install --path .                               # installs to ~/.cargo/bin/owlsentry
owlsentry --init                                     # writes ~/.config/owlsentry/config.toml
$EDITOR ~/.config/owlsentry/config.toml
owlsentry

No system TLS libraries are needed (everything uses rustls). A terminal with true color and a font with common Unicode symbols is enough.

Configure

Every account is a [[source]] block in ~/.config/owlsentry/config.toml. See config.example.toml for all options. Secrets can be inline (secret = "...") or fetched from a command (secret_cmd = "pass show slack/token"), which keeps tokens out of the file.

type What you get Needs
email Unread mail over IMAP (headers only) host, user, password (Gmail: app password)
slack Recent messages in channels/DMs you list user token (xoxp-), channel ids
github Your GitHub notifications token with notifications scope
youtube New videos from channels channel ids (public feeds, no key)
reddit New posts in subreddits nothing (public JSON; Reddit may rate-limit)
twitter Your mentions X API tier that allows reads (paid)
calendar Next 24 hours of events + reminders an .ics URL (Google Calendar "secret address in iCal")
rss Any RSS/Atom feed feed URL
command Anything else a script that prints JSON lines

WhatsApp, Telegram, Discord, Linear...

These have no official personal-account API. The supported route is a command source: any script that prints one JSON object per line:

{"from": "Alex", "body": "are you free tomorrow?", "ts": 1700000000, "count": 2, "url": null}

Optional fields: headline, url, count, tag, mention, important, id. Point a command source at it, with app = "whatsapp" to get the right icon. examples/command-source.sh is a working template.

WhatsApp ships with a ready-made bridge in examples/whatsapp-web: it reads your own Chromium profile (chat list, Status names, unread threads) and prints the JSON lines above — no WhatsApp libraries, decryption happens inside the official Web client. Easiest path: open OwlSentry, press C, open WhatsApp, follow the guided setup. Note: this drives the official client with browser automation, which Meta's terms don't bless — use your own account at your own discretion.

Keys

Key Action Key Action
j k / arrows move o / Enter open in browser (marks read)
h l / Tab switch pane r reply (mail opens a draft)
[ ] previous / next account m / M mark read / mark all shown read
g G top / bottom a archive / unarchive
/ search i star / unstar
f cycle tag filter s summarize this conversation (AI)
u unread only / all : ask the AI about your unread items
t newest / oldest first R refresh now
C connect an app (guided setup) z / Ctrl+Z suspend to shell (fg resumes)
Esc clear search and tag filter e / ? / q source errors / help / quit

Views on the left: Unread, Mentions, Important (starred or tagged important), Today, Archive. Tags (dev, personal, work, ...) default per app and can be set per source with tag = "...". Words in handles = [...] mark matching items as mentions.

AI

Press : and ask something ("what needs a reply today?"), or press s on an item to summarize its conversation. Set ANTHROPIC_API_KEY (or key_cmd under [ai]). The model defaults to claude-sonnet-5-5 and can be changed with model = "...". Nothing is sent anywhere until you ask, and only the notification text needed for that question is sent.

Privacy and safety

  • Credentials are read at fetch time and never written to disk by OwlSentry. Prefer secret_cmd (e.g. a password manager) over inline secret.
  • Text from remote services is stripped of control characters before it reaches the terminal.
  • Links are opened with xdg-open only if they start with https://, http:// or mailto:.
  • The AI is told to treat notification text as data, not instructions.
  • The WhatsApp bridge only ever reads a copy of your browser profile; the live profile is never opened by a second process.

Known limits

  • Email shows unread messages only, and reading them elsewhere removes them here.
  • Calendar: one-off events and simple daily/weekly repeats. Events with a time zone ID are read as local time. Repeats with INTERVAL, COUNT or exceptions are not expanded.
  • Slack uses a user token and the channels you list; it does not discover channels for you.
  • First run shows recent Slack/feed items as unread. Press M to mark everything shown as read.

Project layout

src/main.rs      startup, fetcher thread, event loop
src/app.rs       state, filters, keys, actions, summary numbers
src/ui.rs        all drawing (plus a layout smoke test)
src/model.rs     Notification, Kind, tag colours
src/config.rs    config file (+ one-time rename migration)
src/connect.rs   guided in-app setup, hot source reload
src/state.rs     local read/archive/star state
src/ai.rs        Anthropic API call
src/demo.rs      sample data for --demo
src/sources/     one file per service
examples/whatsapp-web/  headless WhatsApp bridge (Node + system Chromium)
assets/          OwlSentry icon (SVG) and README hero

Add a source

Create src/sources/yours.rs with a struct holding a Meta that implements Source { fn meta(&self) -> &Meta; fn fetch(&self) -> Result<Fetched, String> }, then add one match arm in sources::build. Use meta.note(id, who, headline, body, time) to create items; stable ids keep read/archived state across restarts.

cargo test       # layout and calendar tests

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages