Listening Post
The Omarchy companion for Perception, the private web signal room at
oma.intentsolutions.io/perception/. Listening Post carries the same ranked field,
five-item brief, and read state into the bar. The pill only speaks when a model
shipped, the bill changed, or a provider is down.
The bar has three deliberate states:
- Nothing new: the slot collapses completely.
- AI: 3 new: unseen releases or pricing changes need a look.
- OpenAI incident: a provider status page has an open incident.
Why this is not another RSS reader
- The source list is the product. Thirty-three curated feeds across every major lab, provider, and AI tool. For the vendors that publish no first-party blog feed (Anthropic, xAI, Mistral, Meta, and more), Listening Post pulls a curated community RSS mirror for news plus their GitHub release atoms for SDK versions, so the radar keeps working where marketing sites drop RSS. Every shipped URL was fetched live before release.
- Lanes, not folders. Every item is classified: Model releases, Pricing and limits, Status incidents (louder, first), and Engineering posts (shown, never counted, never notified). A vendor's same-week release burst clusters into one row.
- Optionally ranked by local agent-usage filenames. With the first-party Agents plugin installed, Listening Post reads only the file names in its usage folder (read-only, nothing parsed, degrades to off) and can float matching vendors to the top.
- Quiet by design. Install starts read. Engineering chatter never reaches the pill. Nothing new means no pill at all.
Install
omarchy plugin add https://github.com/jeremylongshore/omarchy-listening-post-entry --enable
Then add Listening Post to your bar layout (Omarchy menu, Bar, or
~/.config/omarchy/shell.json). Sign in to Perception with the email used for
your Lemon Squeezy purchase, open Omarchy, create a device, and paste the
one-time token into the plugin's private connector:
~/.config/omarchy/plugins/io.github.jeremylongshore.listening-post/connect-perception.sh
The script prompts without echo and writes the credential to a mode-0600 file;
the token never enters shell history, process arguments, shell.json, or QML.
Refresh Listening Post and it will use your account's ranked snapshot and brief.
Until a device token is added, the original 33-source local radar remains available as a migration fallback. After the first valid Perception response, the plugin stays on that account field and preserves its last-good snapshot through offline, malformed-response, entitlement, or API failures.
Remove
omarchy plugin remove io.github.jeremylongshore.listening-post
State lives in ~/.local/state/omarchy/listening-post/ and is safe to
delete at any time; the next poll rebuilds it.
The panel
Standard Omarchy panel keys, same as the Herald and the first-party panels:
| Key | Action |
|---|---|
j / k or arrows |
Move the cursor |
Enter or o |
Open the source in your browser |
w |
Open the selected signal in Perception |
p |
Open Perception |
x or a |
Mark the selected row read |
c |
Mark everything read |
r |
Refresh now |
Esc |
Close |
Tab / Shift+Tab |
Switch to the neighboring bar panel |
Left-click opens, right-click marks read. Middle-click the pill to refresh.
Sources
Thirty-three curated sources.
- Vendor news (first-party RSS): OpenAI, Google AI, Google DeepMind, Hugging Face, Together AI.
- Vendor news (community RSS mirror, for vendors with no first-party feed): Anthropic (news, engineering, research), xAI, Mistral, Meta, Cohere, Groq, Perplexity.
- AI commentary and research: The Batch, The Verge AI, Chip Huyen, Lil'Log.
- Status incidents: Claude Status, OpenAI Status.
- Releases and changelogs: Claude Code (releases and changelog), the Anthropic / xAI / Mistral SDKs, Ollama, vLLM, MCP Servers, Cursor.
- Omarchy platform: Omarchy, Hyprland and Quickshell releases, and DHH's blog. This plugin lives in the Omarchy bar, so it should notice when the desktop, its compositor or its shell toolkit ships. Releases land in the release lane and the blog in engineering.
The community RSS mirror (Olshansk/rss-feeds) is third-party and labeled as such; every source is polled independently, so if the mirror lags, only those rows go quiet.
A changelog feed (Claude Code, Cursor) never headlines the release lane: its entries collapse into one quiet "Cursor changelog · N this week" row, so a routine version bump never masquerades as a model release.
Custom feeds were removed in 1.1.0
Earlier versions let you add your own feed URLs through an extra-sources.json
file. That feature is gone, and it is not coming back in the same shape.
It was the only place this plugin fetched a host it did not ship, and it was
guarded by a host allowlist. A marketplace reviewer took that allowlist apart in
three rounds: first a userinfo bypass (https://user@127.0.0.1/feed), then the
alternate IPv4 spellings inet_aton accepts (127.1, 0177.0.0.1), and finally
the one that ended it. A host policy can only check the name. An ordinary
hostname an attacker controls resolves to whatever they point it at, and DNS
rebinding can change that after any separate lookup. The parsing was never the
problem, because the resolution belongs to curl and no amount of regex reaches it.
Making it safe would have meant resolving each host, rejecting every non-public result, pinning the validated address to the request, and revalidating every redirect hop. That is a real amount of machinery to protect a field nobody installs this plugin for. Thirty-three curated sources is the pitch.
Every source is now a compile-time constant. If a feed you want is missing, open an issue and it can be added to the curated list where it gets reviewed like everything else.
Notifications
Only two things notify: a new model release and a new unresolved
status incident. Notifications ride omarchy-notification-send, so they
land in whatever notification center you run, click-to-open included. More
than three new items in one poll collapse into a single summary. Changelog
commits and engineering posts never notify. Turn it all off in settings.
Settings
| Setting | Default | What it does |
|---|---|---|
| Desktop notifications | On | New releases and unresolved incidents only |
| Rank by agents you use | On | Read-only file listing of the Agents plugin usage folder |
| Perception API | https://api.perception.intentsolutions.io |
Canonical endpoint; other origins fail closed |
| Perception credential file | ~/.config/perception/listening-post.curlrc |
Managed by connect-perception.sh; other paths fail closed |
Polling cadence is fixed at 15 minutes, the same house rate the first-party Agents plugin uses. Feed publishing cadence is hours; polling harder buys nothing and costs the publishers.
Architecture
Service.qml account snapshot + local migration poller, no Node/Python daemon
| short-lived descriptor helper -> curl header on stdin
| Model.js validates contract v1 on Quickshell's JS engine
v
~/.local/state/omarchy/listening-post/state.json descriptor-bound atomic write
^
| last-good render + queued read sync
BarWidget.qml + Panel.qml (render + keys)
No Node.js or Python service. Polling and rendering stay inside Quickshell.
A short-lived absolute-system-Perl helper opens settings, state, locks, and
credentials with descriptor-bound no-follow operations, then invokes the stock
curl for authenticated requests. The optional pairing command uses the same
helper for mode-0600 credential publication. Nothing remains running afterward.
Service.qml owns the item store: it fetches, merges, persists through the
bounded helper, and notifies. The panel renders that store and calls straight into the service, so
marking an item read takes effect immediately instead of round-tripping
through a subprocess. Parsing, classification, merging, and sanitizing live in
Model.js, pure ES5 functions loaded identically by Quickshell and by the
offline unit suite.
When paired, the plugin contacts only api.perception.intentsolutions.io for
snapshot reads and read-state writes. The helper reads the bearer token from a
mode-0600 config inside the mode-0700 Perception config directory and passes its
HTTP header to curl on standard input. It is never loaded into QML or put in
shell.json, process arguments, notifications, links, logs, or state.json. API endpoints
from settings are accepted only when they equal the canonical origin.
In unpaired migration mode, network hosts contacted are the curated feed hosts (openai.com,
blog.google, deepmind.google, huggingface.co, together.ai,
raw.githubusercontent.com, theverge.com, huyenchip.com,
lilianweng.github.io, status.claude.com, status.openai.com,
code.claude.com, cursor.com, github.com, world.hey.com). That list is fixed at build
time and there is no way for a user, a config file or a feed body to add a host
to it. No telemetry is collected in either mode.
Testing
npm run test:product
npm run build:product
The root CI workflow runs the following exact validation commands when the change-scope classifier selects the full lane:
npm test
npm run test:race
npm run test:mutation
npm run audit
shellcheck --severity=warning scripts/*.sh e2e/*.sh .githooks/pre-push
The product lane runs 117 plugin tests, 7 shared-contract tests, 8 web tests, and
65 API tests (192 total), then builds both product surfaces. The plugin lane requires at
least 95% line, statement, and function coverage, 90% branch coverage, a 90%
mutation score, and three concurrent race passes. Parser tests exercise RSS and
Atom against captured bodies from all thirty-three live sources, lane
classification, week clustering, merge and retention, read-state, notification
gating, personalization mapping, the feed-list parser, and the state record.
Offline by design; the capture procedure is in docs/FIXTURES.md. CI also runs
the vendored Omarchy gate lane and builds the deployable Docker image.
Perception operators should also use
docs/PERCEPTION-OPERATIONS.md for production
secrets, privacy handling, backup and restore, smoke checks, credential
containment, and rollback; docs/PERCEPTION-ROLLOUT.md
for the fail-closed go-live sequence; and
docs/PERCEPTION-ANALYTICS.md for the minimal
first-party funnel and retention boundary.
Maintainers wanted
These plugins are growing, and we are looking for dependable Omarchy users who want to review issues, test releases, and keep a plugin healthy over time. Start with a small pull request or open a maintainer interest issue titled Maintainer interest. Tell us which plugin you use and how you want to help. Consistent contributors can earn maintainer responsibility.
License
MIT