1Passchy
Read-only 1Password access from the Omarchy bar. Search your vaults, watch live 2FA codes tick down on screen, and copy a password, a username, or a one-time code — without secrets ever entering the shell process.
Contents: Features · Requirements · Install · Usage · Settings · How secrets are handled · External dependencies and state · Uninstalling · Troubleshooting · Development · Known limits
Features
- Live 2FA codes, always on screen. Every visible 2FA row renders its
current code next to a ring counting down the 30-second window. All codes
come from a single bulk
opcall per window and refresh the moment the window rolls. - "Only 2FA" by default. Getting a code is what a password panel is
opened for most, so the list opens straight to your 2FA logins. One switch
(or
Ctrl+2) flips to the full vault. - Fast fuzzy search over titles, usernames and hostnames. Accent-folded
(
conexaofindsConexão), and every word must match —goog rafaelnarrows instead of widening. - One-click copy. Click a row for the password, right-click for the username, click the TOTP zone for the code. All keyboard-driven too.
- Clipboard hygiene. Copies are marked sensitive (skipped by Omarchy's clipboard history) and auto-cleared after 30s — unless you copied something else in the meantime.
- Nothing to migrate, nothing new to trust. Your items, master password,
biometric unlock and session all stay inside 1Password; this plugin is a
front-end for the official
opCLI. Read-only by design: no create, edit, or delete path exists anywhere in it. - Instant on a 1000-item vault. Item titles are cached, and a one-time background sweep (parallel bulk probing, progress in the header) learns which items carry a code; afterwards only edited items are ever re-checked.
Requirements
| Dependency | Why |
|---|---|
| 1Password desktop app | Owns unlocking. The plugin never sees your master password. |
1password-cli (op 2.x) |
The only thing that ever touches a secret. |
wl-clipboard |
wl-copy --sensitive, so copies stay out of clipboard history. |
jq |
Parses op output inside the helper script. |
sudo pacman -S 1password 1password-cli wl-clipboard jq
Then enable Settings → Developer → Integrate with 1Password CLI in the 1Password desktop app, and verify with:
op vault list
If that prints your vaults, the plugin will work. (Note: op whoami reports
"account is not signed in" even when everything is fine — with desktop
integration the session is minted per command, so it is not a useful health
check. The plugin does not use it.)
Install
omarchy plugin add https://github.com/rafaelsantana6/1passchy.git --enable
omarchy bar put io.github.rafaelsantana6.1passchy --section right
Optional keybinding in ~/.config/hypr/bindings.conf:
bindd = SUPER, P, 1Password, exec, omarchy-shell io.github.rafaelsantana6.1passchy toggle
On first open the plugin indexes your vault (a few seconds) and starts a background sweep to learn which items carry a 2FA code (about two minutes per thousand items, shown as "Scanning 2FA n/m" in the header). Both are one-time costs; every later open is instant.
Usage
Click the key icon (or hit your keybind) and start typing.
| Key | Action |
|---|---|
| type | filter |
↑ ↓ PgUp PgDn |
move selection |
Enter |
copy password |
Ctrl+U |
copy username |
Ctrl+T |
copy one-time code |
Ctrl+F |
focus the search field (selects the current query) |
Ctrl+2 |
toggle the "only 2FA" filter |
Ctrl+O |
open the item's URL |
Ctrl+R |
rebuild the index |
Esc |
close |
Mouse: click a row to copy its password, right-click it for the username (middle-click still works as an alias). Right-clicking the bar icon rebuilds the index.
A row is split in two. Left of the divider is the login. Right of it, on items that carry a one-time code, is the TOTP zone — a ring counting down the current 30-second window, the live code, and the seconds left. Clicking anywhere in that zone copies the code.
By default the list shows only logins that carry a one-time code. The switch
riding the section header (or Ctrl+2) flips to the full vault for the rest
of the session; the persistent default lives in Setup → Plugins.
Codes are fetched for the first 24 results — enough for the screen and then some. Rows past that show the ring without a code until the list is narrowed, and clicking them still copies.
<p> <img src="screenshots/search.png" width="340" alt="Search filtering to matching 2FA logins with their codes"> <img src="screenshots/full-vault.png" width="340" alt="Full vault view mixing items with and without a one-time code"> </p>All screenshots show a demo vault — no real accounts.
Settings
Configurable from Setup → Plugins:
| Setting | Default | What it does |
|---|---|---|
| Only show logins with 2FA | on | List only items with a one-time code. The in-panel switch and Ctrl+2 override it per session. |
| Clear clipboard after | 30s | 0 disables. A copy you made in the meantime is never clobbered. |
| Item index cache | 15 min | How long titles are cached before a refresh. |
| Show vault name | off | Print the vault on each row. |
| Max results | 200 | How many rows to render at once. |
How secrets are handled
The Omarchy shell is one long-lived, unsandboxed process that hosts every plugin. A password assigned to a QML property would stay resident in that process until you log out. So this plugin never puts one there.
Everything sensitive happens in op-bridge, a short-lived helper the panel
spawns per action:
- Passwords and usernames never cross into QML.
op-bridge copypipes the value fromopstraight intowl-copyand prints only{"ok":true}. The panel learns whether a copy succeeded, never what was copied. - The displayed one-time codes are the one exception. Rendering codes
next to their countdown means they have to reach the panel, so they live in
QML strings while the panel is open. They are dropped when the 30-second
window rolls and when the panel closes, and never written to any cache. A
one-time code is worthless within 30 seconds, which is the whole reason it
is the only value granted this exception — a password never gets it, and
neither does the TOTP seed: the helper reads the field's
totpattribute and never itsvalue, so the seed dies inside the helper's pipeline. - Secrets never appear in argv.
/proc/<pid>/cmdlineis whatpsprints. Item IDs and field names travel as arguments; values never do. - Copies are marked sensitive.
wl-copy --sensitivesets thex-kde-passwordManagerHinttype, which Omarchy's clipboard manager checks before recording anything — without it your password would be written to the clipboard history file on disk. - The clipboard wipe is content-aware. The helper stores a SHA-256 of what it copied and only clears the clipboard later if that is still what is on it. Copy something else in the meantime and the wipe is skipped.
- The caches hold no secrets. The index stores titles, vaults and URLs;
the probe cache stores field names and a
hasOtpflag. Both live as0600files inside a0700directory, because which accounts you hold is worth protecting even when the passwords are not there. - Authentication is not reimplemented. Unlocking is the 1Password
desktop app's job. The plugin calls
opand reports what happened.
External dependencies and state
Tools invoked at runtime: op, wl-copy/wl-paste, jq, sha256sum,
xdg-open (only for Ctrl+O), and standard coreutils. No file outside the
plugin's own state directory is ever modified.
State lives in ~/.local/state/omarchy-1passchy/ (0700):
| File | Contents |
|---|---|
index.json |
Item titles, vaults, URLs — no secrets |
probes.json |
Per-item field names and hasOtp flags — no secrets |
sweep.lock |
Empty lockfile preventing concurrent sweeps |
Updating
The plugin checks its git origin for new commits a few times a day (cached;
Ctrl+R forces a check). When an update is pending, the bar icon grows a
dot and the panel footer shows how many commits are waiting — click the
footer line (or Ctrl+Shift+R) to apply it on the spot. Applying delegates
to omarchy plugin update --yes,
so the official updater still validates the result and rolls back a broken
update; the shell then reloads the plugin by itself.
Prefer reviewing the incoming diff first? The stock CLI flow shows it:
omarchy plugin update io.github.rafaelsantana6.1passchy
Uninstalling
omarchy plugin remove io.github.rafaelsantana6.1passchy
rm -rf ~/.local/state/omarchy-1passchy # metadata caches (optional)
If you added the keybinding, remove it from ~/.config/hypr/bindings.conf.
Nothing else is left behind.
Troubleshooting
-
"locked" in the header / copy fails — the 1Password app is locked. Unlock it (the first copy also triggers its unlock dialog) and retry.
-
Panel says "No items indexed" — check
op vault listin a terminal. If it errors, CLI integration is off in the 1Password app settings. -
A row is missing its TOTP zone — the background sweep may still be running (header shows progress), or the item gained its code after the last sweep.
Ctrl+Rforces a full re-index and re-sweep. -
Debugging — every
op-bridgecommand works standalone and prints JSON:cd ~/.config/omarchy/plugins/io.github.rafaelsantana6.1passchy ./op-bridge status # is op present and unlocked ./op-bridge index # titles/urls, no secrets ./op-bridge sweep # probe unprobed/stale items, streamed ./op-bridge otp-batch <id> <id>… # current codes in bulk, streamed
Development
omarchy plugin validate .
qmllint -I "$OMARCHY_PATH/shell" Panel.qml
bash -n op-bridge
Saving a file under ~/.config/omarchy/plugins/ reloads the plugin, but an
already-instantiated panel keeps running the old code — run
omarchy-restart-shell after changing Panel.qml.
Model.js is pure (no I/O, no state) and testable with plain node. The
panel follows the first-party conventions: PanelHero, PanelSectionHeader,
PanelSeparator from qs.Ui, and colors read off bar.foreground rather
than Color.popups.text (themes are free to paint the latter an accent
color).
Known limits
- Only the primary one-time password per item is supported.
- The countdown assumes a 30-second period. RFC 6238 allows others, but the period is recorded only inside the otpauth URI — which lives in the field value the helper deliberately never reads — and every issuer in practice uses 30.
- The first sweep of a large vault takes a couple of minutes (~2 min per 1000 items, bounded by the 1Password desktop app's per-call latency). It runs in the background, survives the panel closing, persists per batch (an interrupted sweep resumes where it stopped), and never runs in full again.
- If the 1Password app is locked, the first copy triggers its unlock dialog. The panel stays responsive while that happens.