
Discover rust products found across trusted public sources.
On Avan Market, you can quickly buy and sell CS2, CS:GO, Dota 2, Rust, and TF2 skins with instant payouts. Buy skins or get real money for selling Steam skins and items.

agent-browser Browser automation CLI for AI agents. Fast native Rust CLI. Installation Global Installation (recommended) Installs the native Rust binary: npm install -g agent-browser agent-browser install # Download Chrome from Chrome for Testing (first time only) Project Installation (local dependency) For projects that want to pin the version in package.json: npm install agent-browser agent-browser install Then use via package.json scripts or by invoking agent-browser directly. Homebrew (macOS) brew install agent-browser agent-browser install # Download Chrome from Chrome for Testing (first time only) Cargo (Rust) cargo install agent-browser agent-browser install # Download Chrome from Chrome for Testing (first time only) From Source Requires Node.js 24+, pnpm 11+, and Rust. git clone https://github.com/vercel-labs/agent-browser cd agent-browser pnpm install pnpm build pnpm build:native # Requires Rust (https://rustup.rs) pnpm link --global # Makes agent-browser available globally agent-browser install Linux Dependencies On Linux, install system dependencies: agent-browser install --with-deps This exits nonzero if the package manager cannot install every required browser library. Updating Upgrade to the latest version: agent-browser upgrade Detects your installation method (npm, Homebrew, or Cargo) and runs the appropriate update command automatically. Requirements Chrome - Run agent-browser install to download Chrome from Chrome for Testing (Google's official automation channel). Existing Chrome, Brave, Playwright, and Puppeteer installations are detected automatically. No Playwright or Node.js required for the daemon. Node.js 24+ and pnpm 11+ - Only needed when building from source. Rust - Only needed when building from source (see From Source above). Quick Start agent-browser open example.com agent-browser snapshot # Get accessibility tree with refs agent-browser click @e2 # Click by ref from snapshot agent-browser fill @e3 "[email protected]" # Fill by ref agent-browser get text @e1 # Get text by ref agent-browser screenshot page.png agent-browser close Clicks fail early when another element covers the target's click point, for example a consent banner or modal. Dismiss or interact with the reported covering element, then take a fresh snapshot before retrying the original ref. Headless Chromium screenshots hide native scrollbars for consistent image output. Pass --hide-scrollbars false when launching to keep native scrollbars visible. Traditional Selectors (also supported) agent-browser click "#submit" agent-browser fill "#email" "[email protected]" agent-browser find role button click --name "Submit" Commands Core Commands agent-browser open # Launch browser (no navigation); stays on about:blank agent-browser open <url> # Launch + navigate to URL (aliases: goto, navigate) agent-browser read [url] # Fetch agent-readable text, or read rendered active-tab DOM agent-browser click <sel> # Click element (--new-tab to open in new tab) agent-browser dblclick <sel> # Double-click element agent-browser focus <sel> # Focus element agent-browser type <sel> <text> # Type into element agent-browser fill <sel> <text> # Clear and fill agent-browser press <key> # Press key (Enter, Tab, Control+a) (alias: key) agent-browser keyboard type <text> # Type with real keystrokes (no selector, current focus) agent-browser keyboard inserttext <text> # Insert text without key events (no selector) agent-browser keydown <key> # Hold key down agent-browser keyup <key> # Release key agent-browser hover <sel> # Hover element agent-browser select <sel> <val> # Select dropdown option agent-browser check <sel> # Check checkbox agent-browser uncheck <sel> # Uncheck checkbox agent-browser scroll <dir> [px] # Scroll (up/down/left/right, --selector <sel>) agent-browser scrollintoview <sel> # Scroll element into view (alias: scrollinto) agent-browser drag <src> <tgt> # Drag and drop agent-browser upload <sel> <files> # Upload files agent-browser screenshot [path] # Take screenshot (--full for full page, saves to a temporary directory if no path) agent-browser screenshot --annotate # Annotated screenshot with numbered element labels agent-browser screenshot --screenshot-dir ./shots # Save to custom directory agent-browser screenshot --screenshot-format jpeg --screenshot-quality 80 agent-browser pdf <path> # Save as PDF agent-browser snapshot # Accessibility tree with refs (best for AI) agent-browser eval <js> # Run JavaScript (-b for base64, --stdin for piped input) agent-browser connect <port> # Connect to browser via CDP agent-browser stream enable [--port <port>] # Start runtime WebSocket streaming agent-browser stream status # Show runtime streaming state and bound port agent-browser stream disable # Stop runtime WebSocket streaming agent-browser close # Close browser (aliases: quit, exit) agent-browser close --all # Close all active sessions agent-browser chat "<instruction>" # AI chat: natural language browser control (single-shot) agent-browser chat # AI chat: interactive REPL mode Get Info agent-browser get text <sel> # Get text content agent-browser get html <sel> # Get innerHTML agent-browser get value <sel> # Get input value agent-browser get attr <sel> <attr> # Get attribute agent-browser get title # Get page title agent-browser get url # Get current URL agent-browser get cdp-url # Get CDP WebSocket URL (for DevTools, debugging) agent-browser get count <sel> # Count matching elements agent-browser get box <sel> # Get bounding box agent-browser get styles <sel> # Get computed styles Read Agent-Friendly Text agent-browser read agent-browser read https://example.com/article agent-browser read https://example.com/article --filter overview agent-browser read https://example.com/article --outline agent-browser read https://docs.example.com --llms index --filter auth agent-browser read https://docs.example.com --llms full --filter auth agent-browser read example.com/article --require-md agent-browser read https://example.com/article --json read fetches a URL without launching Chrome. Omit the URL to read the rendered DOM of the active tab in the current browser session, including browser auth state and client-side updates. Explicit URL reads send Accept: text/markdown by default, try the same URL with .md appended when the first response is not markdown, walk ancestor paths toward / to find the nearest llms.txt for a matching docs link, print markdown or plain text when available, and fall back to readable text extracted from HTML. --llms and --require-md with no URL use the active tab URL because they depend on HTTP resources. read does not read llms-full.txt unless you ask for it. Options: --raw prints the response body without HTML extraction, --require-md fails unless the server returns Content-Type: text/markdown, --outline prints a compact heading outline for one page, --llms index prints a compact nearest-ancestor llms.txt link list, --llms full reads the nearest-ancestor llms-full.txt, --filter <text> narrows page sections, llms links/sections, or outline headings, and --timeout <ms> changes the request timeout. Global safeguards such as --allowed-domains, --content-boundaries, and --max-output also apply to read fetches and output. Check State agent-browser is visible <sel> # Check if visible agent-browser is enabled <sel> # Check if enabled agent-browser is checked <sel> # Check if checked Find Elements (Semantic Locators) agent-browser find role <role> <action> [value] # By ARIA role agent-browser find text <text> <action> [value] # By text content agent-browser find label <label> <action> [value] # By label agent-browser find placeholder <ph> <action> [value] # By placeholder agent-browser find alt <text> <action> [value] # By alt text agent-browser find title <text> <action> [value] # By title attr agent-browser find testid <id> <action> [value] # By data-testid agent-browser find first <sel> <action> [value] # First match agent-browser find last <sel> <action> [value] # Last match agent-browser find nth <n> <sel> <action> [value] # Nth match Actions: click, fill, check, hover, text Options: --name <name> (filter role by accessible name), --exact (exact, case-sensitive match; for role it applies to the accessible name, whose default is a case-insensitive substring) Examples: agent-browser find role button click --name "Submit" agent-browser find role heading text --name "Skills" # implicit roles work: <h2>=heading, <ul>=list, top-level <header>=banner agent-browser find text "Sign In" click agent-browser find label "Email" fill "[email protected]" agent-browser find first ".item" click agent-browser find nth 2 "a" text Wait agent-browser wait <selector> # Wait for element to be visible agent-browser wait <ms> # Wait for time (milliseconds) agent-browser wait --text "Welcome" # Wait for text to appear (substring match) agent-browser wait --url "**/dash" # Wait for URL pattern agent-browser wait --load networkidle # Wait for load state agent-browser wait --fn "window.ready === true" # Wait for JS condition # Wait for text/element to disappear agent-browser wait --fn "!document.body.innerText.includes('Loading...')" agent-browser wait "#spinner" --state hidden Load states: load, domcontentloaded, networkidle Batch Execution Execute multiple commands in a single invocation. Commands can be passed as quoted arguments or piped as JSON via stdin. This avoids per-command process startup overhead when running multi-step workflows. # Argument mode: each quoted argument is a full command agent-browser batch "open https://example.com" "snapshot -i" "screenshot" # With --bail to stop on first error agent-browser batch --bail "open https://example.com" "click @e1" "screenshot" # Stdin mode: pipe commands as JSON echo '[ ["open", "https://example.com"], ["snapshot", "-i"], ["click", "@e1"], ["screenshot", "result.png"] ]' | agent-browser batch --json Clipboard agent-browser clipboard read # Read text from clipboard agent-browser clipboard write "Hello, World!" # Write text to clipboard agent-browser clipboard copy # Copy current selection (Ctrl+C) agent-browser clipboard paste # Paste from clipboard (Ctrl+V) Mouse Control agent-browser mouse move <x> <y> # Move mouse agent-browser mouse down [button] # Press button (left/right/middle) agent-browser mouse up [button] # Release button agent-browser mouse wheel <dy> [dx] # Scroll wheel Browser Settings agent-browser set viewport <w> <h> [scale] # Set viewport size (scale for retina, e.g. 2) agent-browser set device <name> # Emulate device ("iPhone 14") agent-browser set geo <lat> <lng> # Set geolocation agent-browser set offline [on|off] # Toggle offline mode agent-browser set headers <json> # Extra HTTP headers agent-browser set credentials <u> <p> # HTTP basic auth agent-browser set media [dark|light] # Emulate color scheme Cookies & Storage agent-browser cookies # Get all cookies agent-browser cookies set <name> <val> # Set cookie agent-browser cookies set --curl <file> # Import cookies from a Copy-as-cURL dump, # JSON array, or bare Cookie header (auto-detected) agent-browser cookies clear # Clear cookies agent-browser storage local # Get all localStorage agent-browser storage local <key> # Get specific key agent-browser storage local set <k> <v> # Set value agent-browser storage local clear # Clear all agent-browser storage session # Same for sessionStorage Network agent-browser network route <url> # Intercept requests agent-browser network route <url> --abort # Block requests agent-browser network route <url> --body <json> # Mock response agent-browser network route '*' --abort --resource-type script # Block scripts only agent-browser network unroute [url] # Remove routes agent-browser network requests # View tracked requests agent-browser network requests --filter api # Filter requests agent-browser network requests --type xhr,fetch # Filter by resource type agent-browser network requests --method POST # Filter by HTTP method agent-browser network requests --status 2xx # Filter by status (200, 2xx, 400-499) agent-browser network request <requestId> # View full request/response detail agent-browser network har start # Start HAR recording (embeds text response bodies) agent-browser network har start --content all # Embed all response bodies (binary as base64) agent-browser network har start --content none # Metadata only, no bodies agent-browser network har stop [output.har] # Stop and save HAR (temp path if omitted) Tabs & Windows agent-browser tab # List tabs (shows `tabId` and optional label) agent-browser tab new [url] # New tab (optionally with URL) agent-browser tab new --label docs [url] # New tab with a user-assigned label agent-browser tab <t<N>|label> # Switch to a tab by id or label agent-browser tab close [t<N>|label] # Close a tab (defaults to active) agent-browser window new # New window Tab ids are stable strings of the form t1, t2, t3. They're never reused within a session, so scripts and agents can keep referring to the same tab even after other tabs are opened or closed. Positional integers like tab 2 are not accepted; the t prefix disambiguates handles from indices and mirrors the @e1 convention used for element refs. You can also assign a memorable label (docs, app, admin) and use it interchangeably with the id. Labels are never auto-generated and never rewritten on navigation — they're yours to name and keep:
PocketJS High-performance component UI outside the browser, with native rendering, standard Vue Vapor and Solid support, a Tailwind design system, and 60 FPS animation under an 8 MB memory budget. Write Solid JSX, Vue Vapor JSX, or Vue single-file components, run them on QuickJS, and let PocketJS move layout, styling, text and animation into a tiny no_std Rust core. It runs on real PSP and PS Vita hardware, PPSSPP, Vita3K, the browser (WASM), native macOS windows (wgpu) and headless Bun. Full design + contracts: docs/DESIGN.md. PocketJS is growing into a family of specialized runtimes — Rust cores, spec-pinned surfaces, one QuickJS guest — documented in docs/RUNTIMES.md; the 3D base lives in engine/pocket3d/, and its first game runtime is OpenStrike. Screenshots pocketjs-hardware-demo.mp4 These PocketJS UIs run smoothly at 60 FPS on a Sony PSP within an 8 MB memory budget, including animated transitions and input feedback. Gallery Settings Motion Lab — baked keyframe timelines Motion Lab — 3D pipeline Quickstart bun install bun run bootstrap # one-time pinned PSP toolchain setup bun pocket check --target psp # schema + capabilities + ordinary app TypeScript bun pocket compile --target psp # check + emit JS/pak from the resolved plan bun pocket build --target psp -- --release # Low-level compiler commands used by framework apps/tests: bun tools/build.ts hero # -> dist/hero.js + dist/hero.pak bun tools/build.ts hero-vue-vapor-main --framework=vue-vapor bun tools/build.ts hero-vue-sfc-main --framework=vue-vapor Or drive everything through the pocket CLI: npm i -g @pocketjs/cli, then pocket doctor checks the Bun / Rust / PSP toolchain (pocket setup runs the same pinned bootstrap), pocket create <name> scaffolds a format-2 manifest, and pocket check|compile|build --target psp|vita delegate to the canonical resolver. Low-level host-development commands such as pocket dev, pocket psp, pocket vita, and pocket play remain available. The build is two-pass: pass 1 transforms every module reachable from the entry (framework-specific JSX + TypeScript, or Vue SFC compiled directly to Vapor; content-hash cached in .cache/) while collecting class strings + text codepoints from the AST. The Tailwind compiler then writes styles.bin + framework/src/styles.generated.ts, the font baker rasterizes Inter atlas slots for exactly the characters your app uses, and everything is packed into dist/<app>.pak. Pass 2 bundles the cached transforms with Bun (iife, unminified). import { createSignal } from "solid-js"; import { Text, View } from "@pocketjs/framework/components"; export default function Counter() { const [count, setCount] = createSignal(0); return ( <View class="flex-col items-center gap-4 p-4 bg-slate-50"> <Text class="text-xl text-slate-950">Count: {count()}</Text> <View class="p-2 rounded-md bg-blue-600 focus:bg-blue-500 transition-colors duration-150" focusable onPress={() => setCount(count() + 1)} /> </View> ); } Mounting entries should look like ordinary app bootstrap code; the framework handles host detection, the generated style table, pak image uploads and the host frame callback: import { mount } from "@pocketjs/framework/solid"; import App from "./app.tsx"; mount(() => <App />); Styling rules (compile-time, no runtime CSS): a class literal compiles iff every token is a supported utility (see docs/DESIGN.md "Tailwind subset (v1)"); dynamic styling is ternaries of full literals, style={{...}}, or animate(). classList, hover: and template-interpolated classes are compile errors. rounded-full requires w-N h-N in the same literal. Framework selection is explicit: product builds set app.framework to "solid" or "vue-vapor" in pocket.json. Low-level framework/compiler/host work can still use pocket.config.ts or pass --framework=... to the individual scripts. App state and component lifecycle come from the native framework package (solid-js or vue); PocketJS supplies host components, input, animation, assets and native runtime wiring. Vue single-file components Set "framework": "vue-vapor" in pocket.json, then import .vue files from the app entry. PocketJS compiles them in Vapor mode, so ordinary <script setup> is enough; no vapor attribute is required in the SFC. import { mount } from "@pocketjs/framework/vue-vapor"; import App from "./App.vue"; mount(App); The supported shape is <script setup> plus <template>. Import reactivity from vue and host components from @pocketjs/framework/vue-vapor/components. Runtime <style> blocks, template preprocessors, external blocks, and Options-API-only components are not supported. apps/hero-vue-sfc renders the same screen as the JSX Hero demos. See apps/vue-sfc-lab for v-model, conditionals, lists, props, events, and slots. @pocketjs/framework/components also exposes small app-shell primitives: Screen, Focusable, FocusScope, ActionHandler, FocusGrid, Portal, Modal, and ActionBar. FocusGrid gives a subtree explicit row/column d-pad traversal today; a virtualized grid can sit behind the same focus contract later. Portal mounts into the runtime overlay root, so modal/action-bar UI never participates in the active screen's flex layout. Modal owns a focus scope and blocks background button handlers while leaving frame animation lifecycle callbacks running; route switching is still ordinary app state, not a required router package. Commands bun run bootstrap # idempotent PSP toolchain setup bun play vita hero # build, install and launch in Vita3K bun play vita gallery --fullscreen # stretch to the host's full screen bun play --help # list every runnable demo bun run test # spec contract + tailwind parser tests bun pocket check --target psp # validate pocket.json + resolved target contract bun pocket compile --target psp # typecheck and compile, for custom native hosts bun pocket build --target psp # typecheck, compile, and package the target pocket build --target vita -- --release pocket play vita hero # build, install and launch in Vita3K bun tools/build.ts <app> [--framework=solid|vue-vapor] [--extra-chars=…] bun run psp <app> # low-level PSP demo build bun run vita <app> # low-level Vita demo build bun run dev [app] # browser dev host bun run wasm # rebuild the wasm core bun run e2e:vita # Vita3K, native-density 960x544 golden E2E bun run e2e:launcher:vita # Vita3K, multi-app launcher/swap E2E bun psplink # interactive real PSP switcher over PSPLINK bun run hw hero --trace # real PSP via PSPLINK + host0 trace bun symbian doctor --device # inspect the Nokia E7 toolchain and USB MTP path bun symbian doctor --coda-usb # verify CODA 4.x directly over USB interface 4 bun symbian build probe # build a visible self-signed Qt/Symbian SIS bun tools/symbian.ts build app --manifest apps/hero/pocket.json --sis-version 1.0.0 bun symbian deploy dist/symbian/pocketjs-e7-runtime.sis bunx tsc --noEmit # typecheck (babel owns the JSX transform) The Nokia E7 bootstrap and its current PocketJS port boundary are documented in docs/SYMBIAN_E7.md. It establishes a pinned, repeatable GCCE/Qt/QuickJS/Rust/E32/SIS build and physical-device staging path. The private symbian-e7-dev profile can package PocketJS applications for hardware testing with a native viewport that follows the E7's landscape and portrait geometry, but it is intentionally absent from the production target registry until device acceptance and golden testing are complete. The PSP bootstrap owns every production input: Rust nightly + rust-src, the cargo-psp tools built at an exact pocket-stack/rust-psp revision, and a SHA-256-verified pocket-stack/pspdev SDK release. It installs them under the shared ${XDG_CACHE_HOME:-~/.cache}/pocket-stack cache, so independent PocketJS and downstream-app checkouts can reuse one installation. Set POCKET_STACK_CACHE_DIR to move that cache. An explicit PSP_SDK takes precedence over PSPDEV, which takes precedence over the pinned cache; an invalid explicit path fails rather than silently selecting another SDK. PSP builds export both variables to the resolved path. PSPLINK is only needed by the real-hardware hw/psplink loop, not to compile an EBOOT. Manifest-driven builds resolve pocket.json once into a small ResolvedBuildPlan. The JS/font/pak compiler and native backend consume that same serialized plan; planHash is only its build-time checksum. At startup, the bundle checks the native host's target and HostOps ABI. The app entry and its reachable imports use the app's ordinary TypeScript configuration. The selected target profile also resolves viewport.rasterDensity. Layout and DrawList coordinates stay in the app's logical viewport; the compiler bakes font coverage and SVGs at that density, prefers same-directory @2x PNG, sprite and raw-PAK siblings when present, and asks the core to bake its own masks at the same density. Dynamic texture producers read the identical value from platform.pixelRatio—they never branch on a target name: import { platform } from "@pocketjs/framework/platform"; const canvas = makeTexture(logicalWidth * platform.pixelRatio); Missing raster siblings deliberately fall back to the 1x source; malformed siblings fail the build if their dimensions do not preserve logical size. Capabilities are plain framework API identifiers. requires must exist on the selected host; enhances resolves to booleans available from @pocketjs/framework/platform: import { hasFeature } from "@pocketjs/framework/platform"; if (hasFeature("input.analog.left")) installAnalogNavigation(); else installButtonNavigation(); Literal hasFeature() calls are folded to booleans during a manifest build, so the unavailable branch is absent from the target bundle. platform.features remains available for computed queries and introspection. Capabilities describe fixed host API support, not permissions or live device state. Custom native hosts should use extractHostBuildInputs() and hostBuildEnvironment() from @pocketjs/framework/manifest; the complete Plan remains an internal build IR. The complete design, including authority boundaries, compatibility rules, typed backend dispatch, target/ABI runtime checks, extension points, and current limitations, is documented in Platform contracts. The Vita host is documented in hosts/vita/README.md. It preserves PocketJS's 480x272 logical layout while rasterizing geometry, fonts, vectors and core masks at Vita's native 960x544 density. Physical controls, left-analog input, and front-panel multi-touch snapshots are supported; PSP builds retain their controller-only fallback. The Pocket Launcher (on-device app switching) One PSP EBOOT or Vita VPK can embed every app admitted by that target plus a Cover Flow launcher (docs/LAUNCHER.md): pick an app with the deck, press SELECT inside any app to summon the deck back over a frozen shot of where you were, then resume or pick another. Switching is a whole-guest swap (fresh QuickJS realm + core + guest GPU resources per app); three append-only surface ops (appTable/appLaunch/appShot) carry the protocol, and ordinary single-app packages retain the original path. bun run launcher scan --target vita # target admission -> registry bun run launcher covers --target vita # + deterministic sim covers bun run launcher build --target psp -- --release # -> multi-app PSP EBOOT bun run launcher build --target vita -- --release # -> dist/vita/launcher-main.vpk bun run e2e:launcher # PPSSPPHeadless 3-swap journey bun run e2e:launcher:vita # Vita3K 7-swap/resource-reuse journey DevTools + time travel Pocket DevTools (docs/DEVTOOLS.md) is built into every bundle: a component tree with semantic names (debugName / <Named>), hover-to- highlight on the device screen (real PSP included, over the PSPLINK USB cable), pause/step, a REPL, console.log from hardware, and an always-on input-tape flight recorder — sessions replay byte-exactly because the whole runtime is fixed-dt deterministic. bun run devtools # panel + hub + USB bridge, one process bun run devtools cards # + build, link and launch cards on a real PSP bun run tape replay <app> <tape.json> --png 60 # render any frame headlessly bun run tape:check # session-golden replay regression On-demand screenshots (📷 in the panel) work in the browser host and through the PSP mailbox. On a real PSP the raw VRAM rides the usbhostfs mount and the bridge encodes the PNG desktop-side. Vita exposes the core inspection ops, but its DevTools transport and screenshot capture are not wired yet. Determinism + the sim host Time is a frame counter, not the wall clock (docs/DETERMINISM.md): the virtual clock (@pocketjs/framework/clock) makes the simulation rate a host policy (?hz=2 on the web host runs the 2 FPS world on a real screen), the effect shell (@pocketjs/framework/effects) quantizes async results onto frame boundaries, and the headless sim host (hosts/sim/) replays scripted user journeys as byte-exact per-frame pixel traces — tests/sim.test.ts is the proof, tools/flake-lab.ts the wall-clock control experiment. Fonts: Inter (OFL), vendored in assets/fonts/.
The Parlan Programming Language Parlan is an open-source programming language designed to make programming simpler. Overview Parlan was designed to be a simple, reliable, and beginner-friendly programming language. Parlan achieves this because it does not "reinvent the wheel" with syntax or semantics—it simply polishes what already exists. Documentation Everything you need to know about Parlan is located in our documentation here Why Parlan? Honestly, there is no groundbreaking reason. Parlan isn't trying to be the next "X-language killer." Parlan isn't trying to become the new standard for writing software. Parlan just exists. If you want to use it, that's awesome. If not, that's totally fine too. Contributing Thank you for considering contributing! We truly appreciate community support. Whether you are fixing a bug, optimizing performance, or fixing a typo in the docs, please check out our Contribution Guidelines before getting started.
Aerial A single Rust binary for AI agent-to-agent messaging: peer-to-peer, durable, and resumable without requiring Kafka, Redis, Postgres, or a cloud account. Current Status Aerial currently ships as one Rust binary with: a local daemon over a Unix domain socket native Windows support through AF_UNIX, distributed for 64-bit Windows as the aerial-local npm package durable per-agent JSONL mailboxes an append-only message history transcript CLI commands agents can use to register, send, read, ack, and inspect history name-rich envelopes, strict recipient validation, and aerial agents peer discovery wake notifications so an agent can watch its mailbox and be woken when mail arrives — optionally running an --exec hook — instead of polling an agent supervisor so a mailbox message can launch a real worker command, including a Codex wrapper Homebrew packaging is available as aerial-local. An MCP adapter over the daemon protocol is available through the hidden aerial mcp stdio subcommand — see MCP. Windows is a tested first-class target. The npm release runs the same Rust binary and validates daemon messaging, MCP stdio, wake notifications, and supervisor execution on windows-latest before publication. Roadmap aerial-local: local agentic development. One machine, one local daemon, durable mailboxes, transcript history, and CLI/MCP adapters for agents working in the same development environment. aerial-server: cross-computer agent communication. A server/daemon mode for agents on different machines to exchange the same envelope-shaped messages without giving up durable mailboxes or resumable history. Quickstart Install the CLI: # Windows npm install --global aerial-local # macOS brew tap dcdeniz/aerial brew trust dcdeniz/aerial brew install dcdeniz/aerial/aerial-local Run the daemon: aerial up In another shell, register two agents: aerial join engineer aerial join researcher Send a message: aerial send --from engineer --to researcher --body "Please inspect the architecture." Recipients must be registered, which catches misspelled names before mail is written to an unread mailbox. Use --create only when deliberately creating a new recipient: aerial send --from engineer --to new-agent --body "Start here." --create List known peers and their pending counts: aerial agents Read the recipient mailbox: aerial read researcher Ack a delivered envelope: aerial ack --agent researcher <envelope-id> View prompt/message history: aerial log --limit 20 Or use the bundled flow macros: aerial exchange --from engineer --to researcher --body "Please inspect the architecture." aerial status researcher aerial drain researcher The default history view is intentionally compact: Agent 28y49uhrfquf -> Agent 14u1rj13ru1 "Message First 50 Characters ...." Use --json on history when an agent or tool needs structured output. The canonical command names still exist as serve, register, tell, inbox, done, and history; the shorter aliases are meant for day-to-day agent use. Set AERIAL_SOCKET once when agents run from different working directories: export AERIAL_SOCKET=/absolute/path/to/.aerial/aerial.sock PowerShell uses $env:AERIAL_SOCKET = 'C:\path\to\.aerial\aerial.sock'. An explicit --socket always takes precedence. MCP Agents that speak MCP can drive the daemon through a hidden stdio adapter: aerial mcp --socket .aerial/aerial.sock It exposes primitive tools — register, tell, inbox, done, and history — plus flow macros — status, drain, and exchange. Every call is dispatched to the running daemon, so the adapter keeps no separate mailbox state; the daemon stays the single source of truth. See docs/MCP.md for the tool reference, client configuration, and an example session. Waking agents Delivery is durable and pull-based: a message sent to an agent waits in that agent's mailbox until the agent reads and acks it. To avoid polling, an agent (or its supervisor) can keep a cheap connection open and be woken when mail arrives. Stream arrival events as JSONL: aerial watch researcher Each new envelope emits one line: {"event":"message","agent":"researcher","id":"..."} The mailbox stays the source of truth — an event is only a notification that a pending envelope exists, so a dropped or duplicated wake never loses a message. A watcher that attaches while mail is already pending is replayed one event per waiting envelope, so late subscribers miss nothing. Run a command on each arrival instead of printing events: aerial watch researcher --exec "codex ..." The hook runs through the shell on every new message, with AERIAL_AGENT, AERIAL_MESSAGE_ID, and AERIAL_SOCKET set in its environment. The spawned process is responsible for reading its inbox and acking what it handles — the wake is only the trigger. Agent supervisor For autonomous local work, use the higher-level supervisor. It watches an agent's mailbox, runs a worker for each pending message, and acknowledges the message only when the worker exits successfully: aerial agent exec researcher -- ./handle-message.sh For Codex, Aerial builds a prompt from the envelope, recent history, and workspace path: aerial agent codex researcher --cd . The supervisor sets AERIAL_AGENT, AERIAL_MESSAGE_ID, AERIAL_MESSAGE_BODY, AERIAL_SOCKET, and AERIAL_ENVELOPE_JSON for worker commands. Use --once for deterministic smoke tests or demos: aerial agent exec researcher --once -- ./handle-message.sh Smoke Tests Run the package-style e2e against aerial on PATH: scripts/installed-e2e.sh Run the lower-level two-agent exchange against aerial on PATH: scripts/two-agent-smoke.sh The script starts a temporary daemon, registers engineer and researcher, sends one message, acks it, prints compact history, and removes the temporary data directory. Install On 64-bit Windows with npm: npm install --global aerial-local aerial --version With Homebrew: brew tap dcdeniz/aerial brew trust dcdeniz/aerial brew install dcdeniz/aerial/aerial-local See docs/INSTALL.md for packaging details.
theta Rust CLI for managing agent configurations defined by theta-spec. Installation curl -sfL https://raw.githubusercontent.com/tamarillo-ai/theta/main/scripts/install.sh | bash Quick start theta init # scaffold theta.toml theta add rule python-types # add a rule theta add tool fetch --command "uvx mcp-server-fetch" # MCP tool (stdio) theta add tool context7 --command "npx -y @upstash/context7-mcp@latest" # another MCP tool theta add skill vercel-labs/agent-skills/skills/web-design-guidelines@main # skill from GitHub theta check # validate everything theta cast to claude-code # --> CLAUDE.md + .mcp.json + .claude/ What it does theta reads theta.toml and resolves, locks, materializes, and casts agent configurations to any supported harness by solving resources in a common .theta/ folder. Like a package manager but for agent harness resources. Create from harnesses Natively supported harnesses include: Claude Code Codex CLI GitHub Copilot Cursor cd /path/to/your/project theta cast from claude-code Commands Group Commands Lifecycle init, check, lock, sync, cast to, cast from, tree Dependencies add rule/system/tool/skill/subagent, rm rule/system/tool/skill/subagent Inspection describe, list rules/tools/skills/subagents System store register skill/rule/agent, list store, rm store, init --from Documentation Full docs: theta, and it is more than recommended to read theta-spec first, given that this is the standard that theta implements against. Getting started Concepts — manifest, sources, locking, casting, system store CLI reference — every verb, every flag Settings — environment variables, directory overrides Or alternatively build the docs locally: uv run mkdocs serve --livereload Regenerate CLI reference from clap definitions: just gen-cli-docs Contributing Prerequisites Rust stable toolchain (see rust-version in Cargo.toml for MSRV) just — task runner (cargo install just) lefthook — git hooks (installation guide) All other dev tools (nextest, deny, shear, typos) are installed via just install-tools. Setup git clone [email protected]:tamarillo-ai/theta.git cd theta just setup # installs dev tools, hooks, fetches deps Common tasks just --list # see all available recipes just test # local tests (no network) just test-online # tests including live registries just check # run all CI checks locally just gen-cli-docs # regenerate docs/reference/cli.md just fmt # format all code Conventions See STYLE.md for documentation style clippy::pedantic is enabled workspace-wide — check [workspace.lints.clippy] in Cargo.toml for allowed lints Hypertextuality with theta-spec theta is the canonical implementation of theta-spec. Behavioral changes in theta SHOULD be accompanied by a respective change in theta-spec. Hotfixes, refactors, and non-protocol changes MAY be pushed without a change in theta-spec. Version-modification-triggering changes MUST follow from a TEP.
🕹️ mtg Your terminal has been all work and no play. Let's fix that. Arcade-feel games that live where you do — one command, zero browser tabs. Rust + Ratatui · 60 Hz fixed-timestep physics · optional arcade SFX brew install mtg → play ⚡ Play in 30 seconds brew tap modern-terminal-games/mtg brew trust modern-terminal-games/mtg # Homebrew 6+ third-party taps brew install mtg mtg Rustacean? Even faster: cargo install modern-terminal-games && mtg That's it. A menu appears. Pick a game. Your build can wait. 🎮 The lineup Small on purpose. Every game here is built for the terminal first — not a sad port of something that belongs elsewhere. 🧱 Breaker — neon brick-clearing, pure focus Angle-aware paddle physics. Multi-hit blocks. Levels that get meaner the longer you survive. mtg breaker ← → or A D move · Space launch · p pause · m mute · r restart · q quit 🏓 Paddle Battle — arena duel vs an AI that fights fair Two paddles. One ball. First to seven. Proper bounce angles, no cheap shots. mtg paddle-battle W S or ↑ ↓ move · Space serve · p pause · m mute · r restart · q quit 🐍 Snek — classic snake, pure muscle memory Eat apples. Grow longer. Don't hit the walls — or yourself. Speed ramps up as you feast. mtg snek WASD / arrows turn · p pause · m mute · r restart · q quit 👾 Alien Raid — sky defense, pure focus A classic invader swarm. Strafe, shoot, hide behind bunkers. They get faster as the ranks thin — and they shoot back. mtg alien-raid A D or ← → move · Space fire · p pause · m mute · r restart · q quit More coming. The catalog stays curated — quality over quantity. Got a game that deserves to exist? Make the case. 🤔 Why does this exist? Because your compile takes four minutes and doomscrolling is a trap. One command, everything. Install once, launch any game with mtg. Actually polished. Braille canvas rendering, fixed-timestep physics, intentional color, synthesized SFX. This isn't ASCII snake from 1997. Goes where you go. SSH session? tmux pane? Remote box in another timezone? Works. Respects your machine. No Electron. No browser. No 400MB of Chromium to play Pong. Pure Rust TUIs. Built to grow. Shared mtg-core engine means new games ship fast and feel consistent. 📦 Install options Homebrew (recommended) brew tap modern-terminal-games/mtg brew trust modern-terminal-games/mtg brew install mtg Upgrade later: brew update && brew upgrade mtg Cargo cargo install modern-terminal-games Want just one game as a standalone binary? cargo install mtg-breaker cargo install mtg-paddle-battle cargo install mtg-snek cargo install mtg-alien-raid # Alien Raid From source git clone https://github.com/modern-terminal-games/mtg.git cd mtg cargo install --path crates/mtg mtg Requirements: a modern terminal with color support. Audio is a bonus, not a dependency — no speakers, no problem. 🕹️ Usage mtg # interactive menu mtg list # list games mtg breaker # jump straight in mtg paddle-battle # or here mtg snek # or here mtg alien-raid # or here mtg help 🧩 Under the hood Project layout & crates mtg/ ├── crates/ │ ├── mtg/ # Launcher binary (`mtg`) │ ├── mtg-core/ # Shared loop, input, audio, theme, UI │ ├── breaker/ # Breaker │ ├── paddle-battle/ # Paddle Battle │ ├── snek/ # Snek │ └── alien-raid/ # Alien Raid ├── docs/assets/ ├── LICENSE └── README.md Crate Role modern-terminal-games Launcher (mtg) mtg-core Game loop, input, audio, UI primitives mtg-breaker Breaker mtg-paddle-battle Paddle Battle mtg-snek Snek mtg-alien-raid Alien Raid 🗺️ Roadmap Unified mtg launcher Breaker & Paddle Battle Shared mtg-core engine Snek (classic snake + arcade SFX) Alien Raid (Space Invaders-style defense) More curated games — puzzles, roguelite sketches Local 2-player where it fits High-score persistence (bragging rights, saved) Prebuilt Homebrew bottles for instant installs 🛠️ Add your game The bar is one sentence: it should feel intentional in a terminal. Fork, then add a crate under crates/ exposing pub fn run() -> anyhow::Result<()> Lean on mtg-core for the loop, input, audio, and UI chrome Register it in crates/mtg/src/main.rs Open a PR — tell us the controls and the feel you're going for cargo run -p modern-terminal-games -- <your-game> Enjoying the arcade? A ⭐ keeps the neon lights on. Made for people who live in the terminal — and still want to play something beautiful. MIT © modern-terminal-games

fastwc fastwc — a fast wc rewrite Table of Contents Quick Start Benchmarks Uninstall Usage Testing Conditions Quick Start # Install cargo install --git https://github.com/CallMeAlphabet/fastwc Note: Make sure ~/.cargo/bin is in your PATH. It's added automatically by rustup, but if fastwc isn't found, add this to your shell config file: # If you use Bash: export PATH="$HOME/.cargo/bin:$PATH" # If you use Fish: fish_add_path $HOME/.cargo/bin # If you use Zsh: export PATH="$PATH:$HOME/.cargo/bin" # Use it! fastwc /path/to/file Benchmarks Benchmark 1: 1.5 GiB file Tool Time Speed vs fastwc fastwc 0.16s 1x (baseline) wc 23s 141.6x slower The gains in speed are higher the bigger the file. Uninstall cargo uninstall fastwc Usage fastwc does not add any additional flags to the original wc. All flags are the same and behave the same. The --help message was changed though. Testing Conditions https://gist.github.com/CallMeAlphabet/4b7022c4b1a8849e6943526de6a23582
nixmac An AI-powered macOS configuration manager built on nix-darwin. Describe what you want in plain English. nixmac evolves your Nix config, builds it, and applies it. What is nixmac? nixmac is a native macOS app (Tauri + Rust) that puts an AI agent in front of your nix-darwin configuration. Instead of hand-editing .nix files, you chat with nixmac: "Install Tailscale and make it start at login" The agent reads your config, plans the changes, edits the Nix files, builds the system, and applies it — all while you watch. If something breaks, roll back in one click. Key Features Natural-language config evolution — an agentic loop with tool use (read, edit, search) that iterates until your system matches the prompt Multi-provider AI — OpenRouter (default), OpenAI-compatible endpoints, Ollama for fully local operation Tool-augmented agent — read_file, write_file, search_packages, search_docs, search_code tools give the model deep context about nix-darwin options and nixpkgs Chat memory — session context persists across turns for multi-step conversations Smart summarization — every changeset and commit gets an AI-generated summary with token-budgeted batching Git-native history — every evolution creates a branch, every apply is a commit; full diff-based change tracking One-click rollback — revert to any previous system generation Secret scanning — detects accidentally committed API keys and credentials Sentry integration — opt-in crash reporting with automatic PII scrubbing CLI + GUI — use the menu bar app or nixmac evolve "..." from the terminal Eval suite — reproducible benchmarks for measuring agent accuracy across models Architecture nixmac/ ├── apps/ │ ├── native/ # Tauri + Rust desktop app (core agent, tools, git, nix) │ ├── web/ # React + TanStack Router frontend (dashboard, onboarding) │ ├── server/ # Hono + tRPC API server │ ├── fumadocs/ # Documentation site (Next.js / Fumadocs) │ └── eval/ # Python eval harness for model benchmarking ├── packages/ │ ├── api/ # Shared business logic │ ├── auth/ # Better-Auth configuration │ ├── db/ # Drizzle ORM + PostgreSQL schema │ ├── ui/ # Shared UI components │ ├── config/ # Shared config utilities │ ├── env/ # Environment variable validation │ ├── hono-api/ # Hono middleware and API helpers │ └── znv/ # Zod + env parsing The Evolution Loop User prompt → agent receives the request Tool use → agent reads config files, searches nix-darwin docs, searches nixpkgs Edit → agent writes changes via semantic file edits Build → darwin-rebuild build validates the configuration Iterate → if the build fails, agent reads errors and tries again (up to N iterations) Apply → darwin-rebuild switch activates the new system generation Summarize → changeset and commit get AI-generated descriptions Getting Started Prerequisites macOS (Apple Silicon or Intel) Nix with flakes enabled (Determinate Nix Installer recommended) devenv — nix profile add github:cachix/devenv/latest A nix-darwin flake at ~/.darwin (see Setup Guide below) Install from Release Download the latest .dmg from Releases, open it, and drag nixmac.app into your Applications folder before launching it. Running nixmac directly from the DMG triggers macOS App Translocation, which prevents Full Disk Access from being granted. Build from Source git clone https://github.com/darkmatter/nixmac.git cd nixmac devenv shell bun install cd apps/native && bun run tauri build --bundles app Build Debug with Bundle cd apps/native bun run tauri build --debug ../../target/debug/nixmac Development devenv shell bun install # Start everything (web + server + native app in dev mode) devenv up # Or start individual pieces bun run dev:web # React frontend at http://localhost:3001 bun run dev:server # API server at http://localhost:3000 bun run dev:native # Tauri desktop app Profiling (Rust-side) You should have Xcode installed. cd apps/native bunx tauri build -- --profile profiling and run the app from /target via: cd ../.. open -a "Instruments" ./target/profiling/nixmac Or start ../../target/profiling/nixmac manually to get past the startup overhead, start Instruments, and attach to the process. Setting Up nix-darwin If you don't already have a nix-darwin configuration: mkdir -p ~/.darwin && cd ~/.darwin git init Copy one of the included templates: Template Description nix-darwin-determinate Minimal nix-darwin for Determinate Nix nixos-unified Cross-platform (macOS + NixOS) minimal Bare-bones starting point Then activate: sudo cp /etc/{bashrc,zshrc,zshenv} /etc/{bashrc,zshrc,zshenv}.before-nix-darwin sudo -i nix run nix-darwin/master#darwin-rebuild -- switch --flake ~/.darwin#$HOSTNAME Nixmac Template Placeholders When you import a nix repository from a zip file, nixmac will perform substitution on the following placeholder strings: Placeholder Value HOSTNAME_PLACEHOLDER Hostname of the Mac you're running on PLATFORM_PLACEHOLDER Platform architecture of the Mac you're running on USERNAME_PLACEHOLDER Current username e.g. $USER Determinate Nix note: darwin-rebuild isn't installed globally. Run it via sudo -i nix run nix-darwin/master#darwin-rebuild. AI Configuration nixmac uses separate models for evolution (config changes via tool use) and summarization (commit messages, UI labels). Variable Default Description EVOLVE_PROVIDER openrouter openrouter, openai, ollama, or openai_compatible EVOLVE_MODEL anthropic/claude-sonnet-4 Model for config evolution SUMMARY_AI_PROVIDER openrouter Provider for summarization SUMMARY_MODEL openai/gpt-4o-mini Model for summaries OLLAMA_API_BASE http://localhost:11434 Ollama endpoint VLLM_API_BASE unset OpenAI-compatible endpoint, for example http://localhost:8000/v1 VLLM_API_KEY unset Optional OpenAI-compatible API key For fully local operation: EVOLVE_PROVIDER=ollama SUMMARY_AI_PROVIDER=ollama devenv up Evolution calls request up to 32,768 output tokens by default. For self-hosted OpenAI-compatible servers, open Settings → AI Models → Evolution Limits and set Max output tokens low enough to leave room for the prompt inside your model's context window. For example, a model with a 65,536-token context window should use less than 65,536 output tokens; 32,768 is a safe starting point for typical prompts. The same value can be set for CLI runs with nixmac evolve --max-output-tokens <tokens>. Note: Models under ~70B parameters tend to struggle with the multi-tool evolution workflow. CLI # Basic evolution nixmac evolve "install ripgrep and fd" # With options nixmac evolve "enable Touch ID for sudo" \ --config ~/.darwin \ --max-token-budget 50000 \ --max-output-tokens 32768 \ --evolve-provider ollama \ --evolve-model qwen3-coder:30b # Dump results to JSON nixmac evolve "add Homebrew casks for Firefox and 1Password" --out result.json Eval Suite The apps/eval/ directory contains a reproducible benchmark harness for measuring evolution accuracy across models and providers, including support for OpenAI-compatible and Ollama backends. cd apps/eval uv sync python run_evals.py --provider ollama --model qwen3-coder:30b python calc_stats.py Deployment The web app deploys via Alchemy: cd apps/web && bun run deploy # deploy cd apps/web && bun run destroy # tear down Releases Tagged commits trigger CI to produce signed .dmg builds: npx release-it # interactive version bump + tag + GitHub release Database nixmac uses PostgreSQL with Drizzle ORM for the web app and server: bun run db:push # apply schema bun run db:studio # open Drizzle Studio bun run db:generate # generate migrations Logs darwin-rebuild logs: ~/Library/Logs/nixmac/ App logs: stdout/stderr (or set NIXMAC_LOGFILE for file output) Provider completion logs: set NIXMAC_RECORD_COMPLETIONS for full provider completions # Merged tail of everything tail -F ${NIXMAC_LOGFILE} ~/Library/Logs/nixmac/*
Skim A free AI email client for Windows that doesn't suck (that hard). Minimalist, native, fast. Bring your own AI key for the assistant and co-writer. No subscriptions, free forever. Free & open source · ~5 MB installer · no admin rights needed Grab Skim_x.y.z_x64-setup.exe from the latest release Website · Download · Report a bug · Contribute Why Skim Email clients usually come in two flavors: a browser cosplaying as an app, or a monstrous do-everything suite with ICQ-era vibes. Skim is neither: ⚡ Native, not Chromium. A Rust core with a system WebView2 UI (Tauri 2) — no bundled browser like Electron. The installer is a few megabytes, cold start is instant, idle memory is modest. No admin rights. ✂️ Half the features, cut on purpose. No calendar, no contacts manager, no rules, no filters, no snooze — none of the stuff you never actually use anyway. Fewer buttons, less cognitive load. Need a do-everything suite? Install Outlook. 🎯 Actions when you need them. Buttons appear only when they're useful; there's no menu bar at all. Skim's job is to surface the right action at the right moment. 🔒 Local and private by default. Your mail syncs over IMAP straight into a local SQLite cache. It works offline, search is instant, and nothing ever passes through anyone else's servers. Zero telemetry, zero anal probes. ✦ AI on your terms. Paste your own key — Anthropic (Claude), OpenRouter for models from any vendor (Claude, GPT, Gemini, Grok, …), or any OpenAI-compatible endpoint, including a local model (Ollama, LM Studio, vLLM) that never leaves your machine — and Skim drafts in your voice, summarizes threads, answers questions about a message, and chats across your whole mailbox with cited sources. No key? Skim is a great mail client without it. Requests go directly from your machine to the provider; the key lives in Windows Credential Manager. 🌍 11 languages, light & dark themes, keyboard-first. Features Mail Gmail, Outlook, Yahoo, iCloud, or any IMAP/SMTP server (autoconfig for the big ones) Google and Microsoft sign-in via OAuth (loopback + PKCE) or app password Multiple accounts side by side, plus a unified All inboxes view; compose from any of them with a per-message From picker Conversation threading (References/In-Reply-To with subject fallback) Archive, delete, star, read/unread — all optimistic with a durable offline queue: act instantly, Skim syncs when the network returns IMAP IDLE push + periodic polling; new-mail notifications with a mark-read quick action Lives in the tray: closing the window keeps mail syncing in the background; starts with Windows minimized (both optional) Compose, reply, reply-all, forward with proper threading headers Attachments: open, save; inline images served from the local cache Calendar invites get an RSVP card — Yes / No / Maybe answers the organizer the standard way, and Add to calendar opens the .ics in whatever calendar you already use (Skim itself has none, on purpose) One-click Unsubscribe for mailing lists — RFC 8058 one-click POST, unsubscribe e-mail, or the link in your browser, in that order Speed Instant full-text search (SQLite FTS5) over subject, sender, recipients, and bodies Ctrl+K command palette: search-as-you-type, jump to folders, every command Keyboard shortcuts: j/k move · e archive · # delete · s star · u unread · r reply · Ctrl+N compose · / search — press ? for the full list AI (bring your own key) There's no "Skim Pro" subscription and there never will be. Paste your own key and the ✦ violet buttons come alive: Drafts in your voice — tell it what to say and get a finished, first-person email. Skim can sift through your last 100 sent messages, pick the most representative ones, and match how you write — greetings, sentence length, punctuation. It replies in the sender's language, even one you don't speak Refine in dialogue — “shorter”, “add a deadline”, “drop the exclamation marks”. Each tweak lands on the current draft, keeping everything you didn't ask to change; your hand-edits are respected too Ask about an email — question one message or the whole thread (up to 25 emails in context), with follow-ups. Answers come only from the content — if it's not in the conversation, it says so Mailbox chat — ask “which invoices are still unpaid this month?” in the palette; Skim retrieves the relevant mail (FTS5/bm25) and answers with the source emails cited as clickable chips AI Recap — one click digests up to 20 unread emails, what-needs-a-reply first with deadlines and cited sources, and marks them read Context-aware — every prompt carries the current date, weekday, time, your timezone, your UI language, and the relevant thread. “Reply that I'll make it by Friday” becomes a concrete date Your writer profile — set your name, pick a style (formal / friendly / concise / witty / enthusiastic) or “write exactly like me”, and give standing instructions (“sign as Nick”, “my company is called…”) Three ways to bring a key — Anthropic directly (Claude Sonnet 5 default, Opus 4.8, Haiku 4.5), OpenRouter with one key for every vendor (Claude, GPT, Gemini, Grok, or any model slug you type in), or any OpenAI-compatible endpoint — Ollama, LM Studio, vLLM, a gateway, or OpenAI itself — including a local model that never leaves your machine Your key, your bill: Skim talks to the provider's API directly and adds no markup, no proxy, no accounts. The key is stored in Windows Credential Manager. Privacy & security HTML email is sanitized in Rust (ammonia) and rendered in a sandboxed iframe with a strict CSP — scripts never run Remote images blocked by default, with one-click per-sender allow Passwords, OAuth tokens, and your API key live in Windows Credential Manager — never in the database, never in a config file Install Download the latest installer from Releases — the .exe (NSIS) installs per-user without admin rights; an .msi is also published for managed environments. Requirements: Windows 10/11 with WebView2 (preinstalled on Windows 11). Skim keeps itself current: once a day it quietly asks GitHub for a new release and, if there is one, shows a small banner — one click downloads in the background, another restarts into the new version. Dismiss it and that version never nags again. No update, no banner, no background installer services. Connecting your mail Onboarding is email-first: type your address and Skim leads with the sign-in method that actually works best for your provider — no wall of buttons to pick from. Gmail — app password (recommended) Gmail's one-click OAuth needs a paid annual security assessment we don't do, so a Google-signed-in session gets logged out every few days. An app password has no such limit and is the reliable path: Enable 2-step verification on your Google account. Create a 16-character app password at myaccount.google.com/apppasswords. Paste your address and the app password into Skim — server settings fill themselves in. One-click Continue with Google is still offered as a secondary option (with an honest note about the weekly re-sign-in) when the build ships a Google client ID. Outlook / Office 365 — one click Press Continue with Microsoft. Skim opens your browser, you approve access, done — Skim never sees your password, and the OAuth tokens live in Credential Manager. This covers Outlook.com, Hotmail, and Office 365 / Exchange Online alike. Microsoft is retiring Basic Auth (app passwords) for Exchange Online in 2026, so OAuth is the way in. Yahoo / iCloud — app password Same three steps as Gmail, using each provider's app-password page (Yahoo · iCloud). Note for source builds: Google and Microsoft require each app distribution to register its own OAuth client. Official installers ship with the project's client IDs. Build from source without one and the OAuth buttons simply stay hidden — the app-password path still works. Any other server Enter your address and password; adjust the IMAP/SMTP hosts under “Server settings” if the guess is wrong. Implicit TLS (:993) for IMAP, STARTTLS (:587) or TLS (:465) for SMTP. Registering your own OAuth clients For forks and source builds (~15 minutes per provider, free). Google console.cloud.google.com → create a project. APIs & Services → Enable APIs → enable Gmail API. Google Auth Platform → configure the consent screen (External). Data access → add the scope https://mail.google.com/. Clients → create an OAuth client ID of type Desktop app. Bake the client ID (and secret) into your build via the SKIM_GOOGLE_CLIENT_ID / SKIM_GOOGLE_CLIENT_SECRET env vars at compile time. While your Google app is unverified it runs in testing mode: only listed test users can sign in and refresh tokens expire weekly. App passwords have no such limits — which is why Skim leads with them for Gmail and demotes one-click Google to a clearly-labelled secondary. Microsoft portal.azure.com → App registrations → New registration; allow personal Microsoft accounts and any organizational directory. Add a Mobile and desktop applications platform with the redirect URI http://localhost. Grant the delegated permissions IMAP.AccessAsUser.All and SMTP.Send (the Office 365 Exchange Online / outlook.office.com resource, not Microsoft Graph) plus offline_access, openid, email, profile. It's a public client — there is no secret. Bake the application (client) ID in via SKIM_MICROSOFT_CLIENT_ID at compile time. Until you verify a publisher, Microsoft's consent screen calls the app "unverified" and users in other organizations' tenants can be blocked from consenting. Publisher verification is free: join the Microsoft AI Cloud Partner Program (formerly MPN), verify a domain you control, then associate the Partner ID under App registrations → Branding & properties → Verify publisher. Clearing the in-app caveat. Skim shows an honest "may be unverified / limited sign-in" note next to each OAuth button until you tell the build the app is verified. Set SKIM_MICROSOFT_OAUTH_VERIFIED=1 (and SKIM_GOOGLE_OAUTH_VERIFIED=1, once you ever complete Google's CASA) at compile time to drop the respective note. Enabling AI Pick a provider and get a key (or point Skim at your own endpoint): Anthropic — console.anthropic.com (Claude, straight from the source) OpenRouter — openrouter.ai (one key for Claude, GPT, Gemini, Grok, and hundreds more — pick a suggested model or type any vendor/model slug) OpenAI-compatible — anything that speaks the OpenAI chat API: Ollama, LM Studio, vLLM, a gateway, or OpenAI itself. Give Skim the base URL, a model name, and a key if the endpoint needs one. Point it at a local model and your mail never leaves the machine (the mailbox chat wants a model with tool support). Paste it in onboarding (step 2) or later in Settings → Skim AI, on the provider's tab. That's it — the ✦ violet buttons light up. Your key, your bill: Skim talks to the provider's API directly and adds no markup, no proxy, no accounts. The key is stored in Windows Credential Manager and can be removed in one click. Keyboard shortcuts Key Action Ctrl K / / Command palette / search Ctrl N New message j / k Next / previous conversation e Archive # / Delete Delete ! Mark as spam s Star / unstar u Mark unread r / a / f Reply / reply all / forward q Ask AI about the email . Toggle sidebar ? Shortcut cheat sheet Esc Close / deselect Building from source Prerequisites:

yqr yqr ("YAML query in Rust") is a fidelity-first, jq-style command-line tool for YAML. It queries and edits YAML while preserving every byte it was not asked to change — comments, quoting, indentation, key order, and line endings all survive. Byte-exact reads, by default. yqr '.' file.yaml reproduces the input exactly — no flag, no reflow. Surgical edits. yqr -i '.spec.replicas = 5' deploy.yaml rewrites only the bytes the filter targets, or refuses — clean diffs, guaranteed. jq is JSON-only and cannot preserve YAML formatting at all; yq edits in place but its docs admit comment and whitespace issues. yqr changes nothing but the edit site, or errors. Native YAML, no JSON round-trip. Parsing and emission run through the noyalib engine — the lossless CST behind both the default read path and the --normalize pipeline; the CLI uses clap. Install / build Install the published crate from crates.io: cargo install yqr # binary at ~/.cargo/bin/yqr Or build from a source checkout (requires the Rust 1.97 toolchain, pinned via rust-toolchain.toml): cargo build --release # binary at target/release/yqr Usage yqr [OPTIONS] <FILTER> [FILE] Arguments: <FILTER> The jq-style filter to apply (e.g. '.foo.bar', '.items[]') [FILE] Input YAML file; reads stdin when omitted or '-' Options: -r, --raw-output Emit string results without YAML quoting -N, --normalize Re-serialize output (drop comments, canonicalize scalars) -i, --in-place Edit the input file in place (mutating filters only) --engine <ENGINE> Backend parser for byte-preserving reads (default: noyalib) -h, --help Print help -V, --version Print version Examples # Field access echo 'name: yqr version: 1' | yqr .name # => yqr # Nested access + array indexing echo 'authors: - name: ada - name: linus' | yqr -r '.authors[0].name' # => ada # Negative indexing (from the end) echo 'tags: [cli, yaml]' | yqr -r '.tags[-1]' # => yaml # Iterate a collection (one result per line) echo 'tags: [a, b, c]' | yqr -r '.tags[]' # => a # b # c # Pipe composition echo 'a: {b: {c: 42}}' | yqr '.a | .b | .c' # => 42 # Optional `?` suppresses errors echo 'name: yqr' | yqr '.name[]?' # prints nothing, exits 0 Byte-preserving reads (default) and --normalize yqr preserves formatting by default. Untouched nodes are emitted as their original source bytes, so the identity filter reproduces the input exactly — comments, quoting, indentation, and line endings all survive. Pass --normalize (-N) to re-serialize the output instead, which canonicalizes scalars and drops comments. --engine <name> selects which backend parser performs the byte-preserving read (default noyalib, the always-available lossless CST). Under --normalize the re-serializing pipeline runs and the engine choice has no observable effect (an unknown name is still rejected up front). # Identity reproduces the file byte-for-byte -- comments, blank lines, # quoting, block scalars, CRLF, BOM, and multi-document streams survive yqr '.' config.yaml | diff config.yaml - # no diff (no flag needed) # Projections keep the original spelling echo "zip: 007" | yqr '.zip' # => 007 (not 7) echo "s: 'hi'" | yqr '.s' # => 'hi' (quotes kept) # --normalize re-serializes (lossy: drops comments, canonicalizes scalars) echo "zip: 007" | yqr --normalize '.zip' # => 7 (re-typed) yqr --normalize '.' config.yaml # comments dropped, scalars canonicalized Results that are computed rather than selected (and nodes an engine cannot address faithfully — entries merged in via <<, alias references) fall back to the regular typed rendering. Multi-document inputs run the filter against every document. -r keeps its usual meaning and prints string values. Fidelity notes: Projected nested block collections are emitted at their original indentation (the slice is extended to the line start), so the output is uniformly indented and re-parses to the selected value. Empty input produces no output in the default (byte-preserving) mode (byte-identity with the empty file), where --normalize prints null. The noyalib backend's value model has string-only mapping keys: non-string keys (true:, 8080:) are matched by spelling; distinct keys that collide after string conversion (1 and "1") are refused with an error. Duplicate keys resolve last-wins and emit the last occurrence's real bytes. Keep-chomped (|+) block scalars retain their kept trailing blank lines, alias references project the anchor's real bytes, block-collection spans start at their first line's indent, and classic-Mac CR-only line endings are accepted. Surgical edits (=, +=, del, -i) yqr can also edit YAML, not just read it — and it changes only the bytes the filter targets, leaving every other byte (comments, indentation, quoting, key order) untouched, or refuses. Edits always run through the fidelity engine, so a mutating filter is byte-exact except at the edit site. The mutation surface: Filter Meaning <path> = <value> Replace the scalar at path (style-matched quoting) <path>.<newkey> = <value> Add a new mapping entry under an existing mapping <path> += <value> Append an item to the block sequence at path del(<path>) Remove the block entry at path (single- or multi-line) <value> is a scalar literal (5, 1.5, "web", true, false, null) or a .-rooted path that copies the value found at another location. # Replace a value; the comment and every other line are preserved verbatim echo 'spec: replicas: 3 # keep me image: web' | yqr '.spec.replicas = 5' # => spec: # replicas: 5 # keep me # image: web # Append to a block sequence at the right indent yqr '.spec.ports += 9090' deploy.yaml # Add a new key, delete an entry (a nested/multi-line block closes up cleanly) yqr '.metadata.env = "prod"' deploy.yaml yqr 'del(.metadata.labels)' deploy.yaml yqr 'del(.spec.template)' deploy.yaml # Edit the file in place (rewritten atomically: temp file + rename) yqr -i '.spec.replicas = 5' deploy.yaml git diff deploy.yaml # touches only that one line Guarantees and limits: Structural integrity. An edit whose result would re-parse to a different structure is refused (exit 5) rather than emitted; under -i the file is left unchanged. No-match is a no-op. A filter that matches no node succeeds and leaves the document unchanged (jq/yq semantics), so del(.x) across a batch of files does not fail the ones that lack .x. -i needs a file. Using --in-place with stdin, or with a read-only filter, is an error (diagnosed before any input is read). Writes are atomic (temp file + fsync + rename) and edit through a symlink to the real file; the original mode is preserved. Owner/group, SELinux context, ACLs, extended attributes, and hardlinks are not carried across the replace — the same temp-file+rename tradeoff sed -i makes. Multi-document. The edit applies to each document whose path resolves; the others are emitted byte-identically. Scalar RHS only. =, +=, and new-key values are scalars (number, string, bool, null) or a path copying a scalar; a collection RHS is refused. Structural delete. del removes multi-line and nested block entries too, not just single-line ones; it closes up the entry's lines and leaves every surviving byte identical. Deleting the only entry of a block (which would empty it) or an item of a flow collection ([a, b]) is refused with a clear message. Unsupported operations. Computed updates (|=), key rename, and sequence reorder / comment edits each fail with a clear message. Query filters Filter Meaning . Identity .foo Field access (.["foo"] for non-bareword keys) .a.b Nested field access .[n] Array index (.[-1] counts from the end) .[] Iterate sequence elements / mapping values a | b Pipe f? Suppress errors from f Planned: object/array construction, builtins (length, keys, select, map, …), arithmetic, multi-document/slurp mode, and more. See the spec. Using yqr in Kubernetes (and beyond) Install paths and recipes for running yqr against kubectl output, baking it into a container image, and reading CI configs, Compose files, Ansible playbooks, OpenAPI specs, alerting rules, and app config: zoosky.github.io/yqr/docs/content/home.html (source: docs/content/home.html). Architecture filter ──▶ lexer ──▶ parser ──▶ Ast ──▶ evaluator ──▶ Value(s) ──▶ YAML YAML ──▶ noyalib::from_str ──▶ Value ──┘ Module Responsibility src/lexer.rs Filter string → tokens src/parser.rs Tokens → Ast src/ast.rs Filter AST node definitions src/eval.rs Ast × Value → stream of Value src/value.rs yqr's Value model (converts to/from noyalib) src/fidelity/ Byte-preserving read engine (default reads) + write tier (src/fidelity/write.rs) src/error.rs YqrError + jq-style exit-code mapping src/cli.rs clap argument parsing src/lib.rs Public API (eval_str, render) src/main.rs Binary entry + exit-code mapping Testing cargo test # unit + integration + CLI tests cargo fmt --all -- --check cargo clippy --all-targets --all-features -- -D warnings Unit tests live alongside each module. tests/integration.rs exercises the public library API end-to-end. tests/cli.rs runs the compiled binary against piped input. Benchmarks Criterion benchmarks live in benches/ (cargo bench --bench eval). Every push to main runs them in CI and publishes the results to a tracked history: Live benchmark dashboard — performance over time, with alerts on >30% regressions.
Our AI finds products from public sources, then rotates exposure so useful newcomers have a fair chance to be seen.
Learn how discovery works