npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

aegis-desktop

v1.0.0

Published

Thin Electron host for AEGIS — a local chat UI over the shared client/aegis.js transport. Ships transport + UI only; engine logic stays server-side.

Readme

AEGIS Desktop

AEGIS Desktop running: the three-class model picker, an agent turn, a gated tool-approval diff, and the unattended work queue

A standalone Electron chat app over the AEGIS API, with an agentic tool loop: the model can read, write, and edit files, list directories, glob, grep, run shell commands in a persistent session, and delegate whole sub-tasks to subagents. It does not require Claude Code.

Install

Prebuilt binaries (AppImage / MSI+NSIS / dmg) ship with each release, and the package is on npm:

npm install -g aegis-desktop     # requires Node 18+
aegis                            # launch

Either way, on first launch:

  1. Open Settings in the sidebar.
  2. Paste an AEGIS key into the API key row — get a free one at https://aegiscloud.org. AEGIS_API_KEY is picked up from the environment if you would rather not paste it.
  3. Pick a model class from the picker at the bottom of the composer.

The published package is aegis-desktop on npm; this repo is its source. Two of the three classes bill your AEGIS account — either the pooled margin, or the BYOK handling fee on top of your own provider key; the free Local class runs on your own hardware and bills nobody.

Using it

Everything is in the window — there is no slash-command line to learn. Plain text in the composer is a prompt.

| Where | What it does | |---|---| | Composer | Type and press Enter. Shift+Enter for a newline. | | Class picker | Bottom of the composer — switches the route mid-conversation, context intact. | | Model dropdown | Next to it — pins a model id for the selected class, or leaves it on "server default (auto)". | | Settings (sidebar) | API key, provider keys, tool-confirmation toggle. | | Queue card (sidebar) | The unattended work queue — same file the CLI drains. | | Quick Launcher card | Enable/rebind the global hotkey. | | remember (on any reply) | Pin that message to cross-machine cloud memory. |

Approval cards appear inline before exec, writeFile or editFile runs: Allow once, Allow for this session, or Deny. Turn them off entirely with Settings → "Confirm before running tools" — on by default.

Model classes

Pick from three routes on the model-class picker, switchable mid-conversation with context intact:

| Class | Transport | Key held in | Billed? | |---|---|---|---| | Aegis Cloud | aegiscloud.org — the pooled route, on the server's own default model; the pool auto-routes across whichever providers are live | main process | yes — pooled margin | | Bring your own key | your provider key, relayed by AEGIS — see below | main process | yes — flat AEGIS handling fee | | Local | a model on your own machine or network — your Ollama daemon at localhost:11434 by default | n/a — no key | no — free, no AEGIS account needed |

The Cloud class offers everything the server advertises: the pooled brain first, as one row (Nexus — the nexus-brain/aegis-brain and the -smart/-neo spellings the server sends as aliases of it are folded into that one row, because they all name the same route), then every per-provider id the same catalogue lists, so deepseek, anthropic, groq, openai … can be pinned directly. Both hosts build that list from one shared rule (client/brain-catalog.js, offerableCatalog), so the GUI and the terminal cannot show one account two different lists. A pinned per-provider id is still a pooled turn: your account key pays the pool's margin, and the plan and balance gates on /api/v1/chat/completions apply to it exactly as they do to the brain row. The same models are also reachable through Bring your own key below — your provider key, and a flat handling fee instead of the pool's margin.

Get a free AEGIS key at https://aegiscloud.org for the Cloud and BYOK classes. The generic OpenAI-/Anthropic-compatible direct-dial lanes that used to live here were removed for good — those providers are reachable only through Bring your own key, which bills the handling fee. Local is narrower: it points at a model on your own machine or your own network, and the endpoint check (desktop/lib/local/local.js) refuses anything public — fail-closed, run when the base URL is saved and again before a request is dialled. Your Ollama daemon at localhost:11434 is the default, and any OpenAI-compatible server on that box — llama.cpp, LM Studio, vLLM — works by pointing the base URL at it. So there's no vendor to bill and no key to hold.

Bring your own key (BYOK)

For the providers AEGIS does not run in its pool — bring your own key and the models that key unlocks appear as their own entries, one per provider.

  1. Settings → find the row named BYOK: <Provider> (OpenAI, Anthropic, DeepSeek, Groq, xAI, Mistral, Gemini, OpenRouter, …), paste your provider key and Save. There is no base-URL field on these rows: a BYOK turn always talks to AEGIS's own relay (/api/v1/byok/chat/completions), which is what attaches your AEGIS key.
  2. Or skip the UI and put the key in ~/.aegiscode/.env (OPENAI_API_KEY=…, ANTHROPIC_API_KEY=…); the app reads that file into the environment at startup, and a provider with no key saved in Settings is resolved from it.
  3. Select the Bring your own key class and pick a model.

A model the catalogue does not name yet. Vendors ship models faster than any client release, and the relay forwards whatever model string it is handed — so Settings ends with an Add model row (provider + model id + Add model). It writes the same ~/.aegiscode/models.json the CLI's /model-add writes, so a model added here appears in the terminal's /models immediately and one added there appears in this picker on its next refresh; the row prints the file path, which is also the bulk-edit path. The provider id is offered from the live catalogue but you may type one, and a provider the relay takes no key for is refused rather than stored (a declaration nothing can attach a key to would show up in no picker at all). Each declared model gets a Remove row.

What it costs. AEGIS pays your provider nothing on this lane, so there is no provider cost to take a margin on — instead your AEGIS account is charged a flat handling fee per 1k tokens, for the routing, prompt assembly, caching, tool bridging and uptime that still happen server-side. The rate is the server's own (published on GET /api/v1/byok/providers) and is shown in Settings directly under the provider rows; it is never hardcoded here, so it cannot drift from the ledger that bills you. It is deliberately below the pooled price for the same traffic — BYOK stays the cheaper lane, it just is not the free one.

Two keys are needed. Your provider key and an AEGIS account key: the handling fee has to be billed somewhere. With no AEGIS key connected the class shows every model but says exactly that, rather than failing opaquely.

And the relay decides whether your bank has to be funded. The route publishes its own policy on GET /api/v1/byok/providers (fee.gate_mode, fee.require_account, fee.require_balance) and the app reads it there rather than assuming one: in the balance mode the live deployment runs, a BYOK turn needs an account with a balance, and a zero bank answers 402 Insufficient balance. Top up to continue using BYOK. — your provider key is still valid, the AEGIS handling fee is what ran out (see the top-up surface). In the softer owner mode a named account is enough and an unfunded fee is recorded as owed. An anonymous caller (no AEGIS key at all) is refused in every enforcing mode, which is the released clients' own gate too — this class does not serve a turn nobody can be billed for.

The agentic tool loop works here too. The relay's BYOK route accepts the OpenAI-shaped tools/tool_choice and translates them to each provider's own wire format (Anthropic-backed callers get real tool calls), so file, shell and search access below are available on this lane — the engine sends the same tool schema it sends on the pooled lane. What the class does not get is the cloud drain in the autonomous queue, which is Aegis Cloud-only (see desktop/lib/local/autonomous.js) — that is the fan-out Pro buys, not the tool loop.

Screenshots

Captured from the real app, not mocked up: the stills come from scripts/capture-marketing-shots.mjs and the demo at the top of this page from scripts/record-demo-gif.mjs. Both drive the actual renderer against a local stub and refuse to publish an asset that fails their assertions.

The model-class picker — all three routes, switchable mid-conversation:

The model-class picker listing Aegis Cloud, Bring your own key, and Local

A completed answer in the transcript:

A completed answer in the transcript

The tool-call approval card with a proposed edit — what blocks exec, writeFile and editFile until you allow, allow for the session, or deny:

The tool-call approval card with a proposed edit

Tools available to the model

| Tool | What it does | |---|---| | readFile · writeFile · editFile | File access scoped to the working directory | | listDir · glob · grep | Navigate and search a tree | | exec | Run commands in a persistent shell session | | task | Delegate a self-contained sub-task to a subagent |

Before exec, writeFile, or editFile runs, a diff/approval card asks you to confirm — approve once, approve for the rest of the conversation, or deny. Flip Settings → "Confirm before running tools" off if you'd rather the agent run mutating tool calls without asking; it's on by default.

Conversations persist locally and sync to AEGIS cloud memory via a pending queue that flushes on each "Sync now" or heartbeat retry. The remember button on any assistant reply pins that message to cross-machine memory — queued locally if you're offline.

Autonomous queue

The unattended work queue, shared with the CLI: tasks are appended to ~/.aegiscode/queue.jsonl and drained later, one at a time, with tool approval disabled — there is nobody there to click an approval card. The desktop sidebar's queue card and aegiscode autonomous are two views of the same file.

aegiscode autonomous add "fix the flaky retry test" --cwd ~/repo --commit
aegiscode autonomous list
aegiscode autonomous run                 # drain one task, then stop
aegiscode autonomous proceed --max 3     # drain up to three
aegiscode autonomous reconcile --auto    # queue the next unfinished phase of your plan file, then drain it
aegiscode autonomous retry <id>          # put a finished task back
aegiscode autonomous clear --all         # empty the queue

A task's text is stored verbatim — add "fix --json in the parser" is a task, not a flag. Drains commit only the paths that task's own tool layer wrote, so a drain never sweeps a peer's in-flight edits into your commit.

Aegis Cloud only

A queued task runs on the pooled brain — nexus-brain (alias aegis-brain) — for the same reason the Claude Code plugin is cloud-only: the queue hands work to a loop with no human in it, and the pooled class is the one the server can route, budget, and bill on its own. A task that states another model id is refused where you can still see it, instead of failing minutes into a drain as an opaque server error:

| Where the model was stated | What happens | |---|---| | autonomous add --model <id> | refused, with the reason, at add time — nothing is queued | | A hand-edited queue.jsonl | refused pre-flight by the worker (ms: 0), before any turn is billed | | AEGIS_MODEL=<id> in the environment | ignored for queue runs, and reported as a note — that variable is shared with the interactive surfaces, which do run direct providers | | nothing stated | nexus-brain |

What a queued task costs

The queue has two shapes, and the cheap one is the default:

| | Single pass (default) | Fan-out (opt in) | |---|---|---| | Provider calls | 1 | workers + 1 (investigation passes, then synthesis) | | Effort rung | medium | high | | How to ask for it | nothing — it is the default | AEGIS_AUTONOMOUS_FANOUT=1 |

An earlier version sent every queued task as a fan-out at the priciest rung: one queued line could become several reasoning calls plus a synthesis, all at high. Making the fan-out opt-in, and letting effort follow the shape of the task rather than always topping out, removes the worker multiplication and roughly halves the budget on a one-line task. --effort (or AEGIS_AUTONOMOUS_EFFORT) still wins outright, and --workers N is only sent when you are actually fanning out.

Known gap: there is no --fanout flag yet — the opt-in is the environment variable or singlePass: false in the task record. --single-pass still parses, but it now agrees with the default instead of overriding it.

A turn that runs out of rounds keeps its work

The tool loop runs against a round horizon: 24 rounds for an interactive turn (AEGIS_CHAT_MAX_ROUNDS), 40 for a queued one (AEGIS_AUTONOMOUS_MAX_ROUNDS). A model that reached it mid-turn used to lose everything it had assembled, because the cap was turn state.

The horizon is now session state, held in lib/local/session-rounds.js. When a turn stops at the cap the interruption is filed against the session, and the next message in that conversation is prefixed with a continuation preamble — cut off after N tool rounds; continue, do not restart — along with max(4, ⌈horizon/4⌉) extra rounds so re-orientation does not eat the new horizon. The resume is announced in the transcript, so it is visible rather than silent.

  • In-memory and process-local (30-minute TTL, 64 entries) — it never leaves the process and never touches disk.
  • Claiming an entry consumes it: one resume per interruption, so a chain of interruptions is a chain of deliberate asks, never an automatic loop.
  • A stated horizon always wins; the ledger only pads its own default.
  • A caller that mints a fresh session key every turn adopts the most recent held entry (bounded to 10 minutes) instead of losing the work.

Keyboard shortcuts

In the main window

| Shortcut | Action | |---|---| | Cmd/Ctrl+N | New chat | | Cmd/Ctrl+K | Open search (memory inspector) | | Cmd/Ctrl+S | Save as… (export the open session as Markdown) | | Cmd/Ctrl+R | Reload | | Cmd/Ctrl+Shift+I | Toggle DevTools | | Enter | Send the composer prompt | | Shift+Enter | Newline in the composer | | Esc | Close the memory inspector overlay |

Global quick launcher

Cmd/Ctrl+Shift+Space (default, configurable in the sidebar's Quick Launcher card) toggles a small, frameless, always-on-top prompt window near your cursor — from anywhere on the desktop, even when AEGIS Desktop isn't the focused app. It streams a one-shot answer over the same transport the main window uses, with the agent's tool-calling loop turned off (no file/shell access, no approval prompts) — just a fast question and an answer.

| Shortcut | Action | |---|---| | Cmd/Ctrl+Shift+Space (default, configurable) | Toggle the quick launcher | | Enter | Ask the typed prompt | | Shift+Enter | Newline in the prompt | | Cmd/Ctrl+Enter | Add the current answer to the main window as a new chat turn | | Esc | Close the quick launcher | | (click away) | Also closes it — closing never steals focus from whatever window had it before |

Packaged builds (the installed app) always register the global shortcut. Dev runs (npm start / electron .) do not, unless you turn on "enable global shortcut" in the sidebar's Quick Launcher card — this keeps a local dev session from silently grabbing a systemwide hotkey. If the configured accelerator is already claimed by another application, registration fails gracefully: a warning is logged to the main process console and the Quick Launcher card shows the reason instead of the app crashing or hanging.

Deep links

The app registers an aegis:// protocol handler:

| Link | What it does | |---|---| | aegis://open?session=<id> | Resumes a saved session | | aegis://new?prompt=<text> | Starts a fresh chat with that prompt pre-filled |

Run from source

A source checkout is available to contributors with repository access only — the desktop host is not a public repository. From the checkout, run this directory directly:

cd desktop
npm install
npm start

Build a distributable

npm run dist        # packaged app (AppImage / MSI+NSIS / dmg)
npm run dist:dir    # unpacked dir, for quick testing

Checks

npm run check                    # node --check every main-process + renderer file
node ../test/desktop-shell.mjs   # headless IPC smoke test (no Electron binary needed)

Structure

main.js              Electron main process — window + IPC shell only
preload.js           Context-isolated IPC bridge exposed to the renderer
renderer/            UI (vanilla JS, no framework)
lib/local/           Model classes, agentic tool loop, prompt
lib/local/queue.js   The shared work queue (~/.aegiscode/queue.jsonl)
lib/local/autonomous.js  The unattended worker — directive, digest, commits
lib/local/session-rounds.js  Session-scoped tool-round ledger (in-memory)
lib/sync/            Local session/memory persistence + sync queue
vendor/aegis.js      The AEGIS transport client (thin — no engine logic)
bin/aegis.js         `aegis` CLI entry point for the global npm install

This directory is part of the aegiscode-plugin monorepo, which also ships a Claude Code plugin and the shared client/aegis.js transport over the same AEGIS backend — see the repo root for that fuller architecture picture, and cli/README.md for the terminal host over the same engine.

One source of truth. This directory is it. The npm package aegis-desktop is built from a git subtree split of it — same code, published without the rest of the monorepo. Edits land here and are synced out; nothing is authored elsewhere.


Built by Niklas Borneklint — aegiscloud.org · @aegisinfo

Part of the ÆGIS ecosystem.