Aster 0.4.0 is out. 62 commits since 0.3.0, six new crates, three new surfaces, and the biggest permission rewrite yet. Here's everything that shipped.
Aster is a self-hostable agent harness for software work. It reads your code, answers questions, edits files, runs commands, and reviews your changes. It runs in your terminal, your editor, your browser, and on your own hardware, against whichever model you point it at.
Install it in one line:
curl -fsSL https://aster.builders/install | sh
This release is about closing the distance between the agent and wherever you work. Five surfaces, one config, no setup tax.
The agent, served from localhost
aster serve
That opens the agent at localhost:4187. It's the full editor panel served as a page: streaming chat, approvals, @ mentions, slash commands, saved sessions, review, compaction.
There's nothing to deploy. The UI ships inside the binary, so the installer already has it. The port is guarded.
open_preview: turns now end with the thing they built
A turn that builds a page used to end by describing it. "I created a landing page at dist/index.html." Now the agent points at the dev server or the file it built, and the page opens in your browser.
Loopback URLs and in-repo files open on their own. Anything else asks first. You keep the keys to what leaves the sandbox.
VS Code and Cursor
The editor extension is published on both marketplaces:
- VS Code: marketplace.visualstudio.com
- Cursor, Windsurf, VSCodium: Open VSX
It is a chat panel, not a terminal wedged into a sidebar:
- Streaming replies with the reasoning shown as it arrives, and a thread that rebuilds itself when you reopen a session.
@mentions for files in the repo, and drag-and-drop or pasted screenshots.- A command menu holding everything the panel can do: model, provider, effort, mode, review, status, diff, memory, MCP servers, and every skill the session can see. Open it with
/in an empty composer. - Inline approvals. You see the edit before it lands, and a box under the buttons rejects it and tells the agent what to do instead, in one step.
- A compaction ring showing how much history budget is left, which compacts on click.
Review lives in the same panel. Point it at the working tree, a git range, or a GitHub PR, and it reports only the findings that survive verification. Hand one back and it writes the patch.
Keyboard shortcuts, drawn the way your own keyboard is labelled:
| Action | macOS | Windows and Linux |
|---|---|---|
| Open the panel | ⌘⇧A |
ctrl+shift+A |
| Show the command menu | ⌘⌥K |
ctrl+alt+K |
| New conversation | ⌘⌥N |
ctrl+alt+N |
| Reopen a session | ⌘⌥R |
ctrl+alt+R |
| Send the editor selection as a mention | ⌥A |
alt+A |
The panel's own tips now render ⌘ ⌥ ⇧ on macOS and spell out ctrl alt shift everywhere else, because a Mac keycap does not say alt.
The extension drives the aster binary, so install that first.
Telegram: the agent in your pocket
A new aster-remote crate and an aster remote command run the agent from a Telegram chat:
- Skills and a model picker live in the chat, so you can reconfigure without touching a terminal.
/commitworks from your phone.- Plan pinning and edit diffs are rendered inline, so you can see exactly what changed before you accept it.
- Chat settings persist, so the bot remembers how you like it between sessions.
Review a PR from the train. Kick off a fix while your build runs. Same agent, same config, different screen.
38 providers, local ones included
The binary ships with 38 providers. Three of them need no key at all, because they run on your own machine: Ollama, LM Studio, and llama.cpp.
Three changes make multi-provider setups sane:
- Per-provider keys. Each provider keeps its own key, so setting up a second one no longer overwrites the first. The var each endpoint reads comes from the shipped catalog, so
BASETEN_API_KEY,TOGETHER_API_KEY,CEREBRAS_API_KEYand the rest all work. - One-command switching.
aster provider use groqswitches endpoint and model in a single write, and every surface reads it. Terminal, editor, desktop, browser: all pointed at the same place. - A shipped catalog.
aster providerandaster modelare backed by a catalog compiled into the binary, so discovery works offline. The init wizard persists whatever you pick to the global config.
aster config: the config file, from the command line
Changing a setting used to mean finding aster.yaml and remembering how a key is spelled. There is a command for it now.
aster config # a form in your terminal
aster config get model # one value, so it pipes
aster config set model gpt-5
aster config path # which files Aster reads here
aster config edit # opens $EDITOR, tells you if it still parses
On its own it opens a form, the same one aster init uses. Settings are grouped by what they do rather than by the block they sit in, because the block is the part a key name gives away least. Each row carries a plain name, the value it currently resolves to, and the key it is spelled by, so anything you find in the form is something you can pass to get and set.
Numbers read as quantities: a timeout is 300s, a compaction budget is 192k chars, an empty include says "everything". A Save to row switches between the repo's config and the global one without leaving the form.
Nothing is saved that the next run would refuse to read. The edited file is parsed first, so a misspelled key or a value of the wrong type is an error naming the keys that do exist, rather than a config that breaks on your next turn. Comments and layout survive an edit, unset clears a key from every file that pins it, and a shell variable that outranks what you just wrote is said out loud.
Reasoning you can actually read
- Streaming reasoning. Thinking streams into the terminal, VS Code panel, and desktop app as it happens, not after the answer lands.
- Reasoning in transcripts. A turn's reasoning is recorded in the session file, so reopening a session brings the whole thread back: what the agent thought, not just what it said.
- Reasoning effort scoping.
--effortnow only applies to commands that actually run a model, so it can't silently change behavior elsewhere.
Web search with zero setup
Web search works out of the box with no API key and no server. It falls through to DuckDuckGo, so a fresh install can search and read a page without signing up for anything.
When you do have accounts, Context.dev leads, followed by Exa, Firecrawl, Browserbase, Perplexity, and Cloudflare, all picked up automatically once their key is set.
It is not just search. web/sitemap maps a site and web/screenshot captures a page, and all of it is on the CLI too:
aster web search "rust async traits"
aster web sitemap https://example.com
aster web screenshot https://example.com
For pages that need real JavaScript, aster init scaffolds a browser-use server and aster mcp enable browser turns it on, giving the agent navigate, click, type, scroll, read-state, and screenshot. It runs headless with vendor telemetry off, and its two LLM-dependent tools are denied by default because both want a second API key.
A tool can return an image now. An MCP image content part reaches the model as an actual image instead of [image content omitted], which is the change that makes taking a screenshot worth anything.
read_file reads documents. PDF, Word, PowerPoint, Excel, OpenDocument, EPUB, and RTF are converted to Markdown, and a document hiding behind the wrong extension is sniffed rather than mangled. web/extract does the same for document URLs.
A built-in web-research skill teaches the agent how to use all of it well.
Agent Plugins v1.0.0
Aster supports Agent Plugins v1.0.0, the portable plugin standard other AI tools have adopted. A plugin is just a directory: skills, MCP servers, a manifest. No lock-in, no proprietary format.
On top of that standard:
- 20 built-in skills: 10 core ones in every session's index, and 10 optional ones that ship in the binary and install with
aster skills bundled <name> - Cross-agent skill import: pull skills from other coding agents' skill directories instead of starting from zero
- Remote MCP over Streamable HTTP
- Per-tool on/off switches
- Capped skill descriptions in the prompt index, so a big skill library can't bloat every request
The core ten cover the work every session touches: git-workflow, gh-pr-workflow, verify-before-done, build-triage, batched-bash, cli-toolbox, context-economy, correction-protocol, security-hygiene, and web-research.
macos-harness
The optional tier includes a skill that drives an entire Mac. macos-harness runs a persistent Python session with screenshots, PID-targeted input, an animated virtual pointer, Apple Accessibility, Apple Events, Chrome DevTools Protocol, and filesystem access.
It works on native apps, Electron apps, browsers, and dialogs, without moving your physical cursor or dragging windows into the foreground. So the agent can drive an app while you keep working.
The skill ships with Aster; the CLI it drives does not. Install it once:
uv tool install macos-harness
macos-harness doctor
doctor checks the permissions it needs without prompting for them.
Apple Shortcuts
A new aster-shortcuts crate registers an in-process shortcuts server, so every Shortcut you have already built is a tool the agent can call. No configuration and no separate process: shortcuts/list names what this machine has, and shortcuts/run runs one by name and hands back its output.
It drives /usr/bin/shortcuts, so anything you can automate on a Mac (Home devices, Music, Notes, a shortcut you wrote yourself) is reachable from a turn.
Together with macos-harness, that is the macOS story for this release: the agent can drive the apps you already use, not just the files in your repo.
Sub-agent swarm
Big tasks fan out. The agent spawns sub-agents that work in parallel and reports back a synthesized result, and the desktop app renders the swarm live as each one works. A synthesizer builtin deduplicates and resolves conflicts across their findings.
Permissions collapsed into one rule language
Permission config used to be six keys across three matcher vocabularies. It's one language now:
Edit(<glob>)
Read(<glob>)
Bash(<cmd>:*)
Precedence is simple: deny beats ask beats allow.
This one breaks existing configs, so read this bit. permissions.protected, secret_read, allow_exec, deny_exec, and use_default_protected are gone, and bare globs in allow/deny are rejected. A retired key does not warn, it stops the run, so a config from 0.3.0 needs editing before your next turn:
| Old | New |
|---|---|
allow_exec: ["git"] |
allow: ["Bash(git:*)"] |
deny_exec: ["rm"] |
deny: ["Bash(rm:*)"] |
protected: ["src/**"] |
ask: ["Edit(src/**)"] |
secret_read: [".env"] |
deny: ["Read(.env)"] |
Headless runs changed too: anything a rule sends to a prompt now refuses rather than hanging, so a script that ran curl under mode: edit needs an explicit allow: ["Bash(curl:*)"].
The upside of one vocabulary is that a Bash rule now matches inside a shell invocation. deny: ["Bash(rm:*)"] never used to stop bash -lc "rm -rf x", because the matcher only ever saw the binary name. Rules now parse through quotes, leading environment assignments, and nested scripts.
The mode ladder also stopped inverting. plan < manual < auto < edit < yolo holds for every action now, where writes to .git/** and .github/workflows/** used to be refused outright by the looser edit mode. The only difference between auto and edit is that auto pauses on the built-in risky-command list and edit trusts commands.
Two additions round it out:
- Demotion. A turn can tighten its own permission mode mid-flight (
aster-policydemote), so an agent that realizes it's over-scoped can step itself down without waiting for you. - Plan-aware approvals. Approving a plan can switch the permission mode to match it, so execution doesn't stop to re-ask what the plan already settled.
Commands run sandboxed. A command that needs your gh or aws credentials asks instead of failing mysteriously.
Safety and correctness passes
The unglamorous work that makes the rest trustworthy:
- Secret redaction in tool output. Keys and tokens are stripped before anything reaches the transcript or the model.
- Repetition guard on character boundaries. The guard that cuts runaway generations no longer slices mid-character on multibyte text.
- System message folding. Mid-conversation system messages fold into the turn beside them instead of breaking provider caches.
- Rate-limit backoff fixes.
x-ratelimit-resetunits are normalized before computing retry delays, so retries don't fire too early or wait forever. - Fenced
ask_user. The agent won't ask a question the request already answers. - Loop guards. Barren rounds (no progress, no tool calls) stop the loop instead of burning tokens.
- Read caching. Repeat file reads hit a cache, and open-ended reads window their results, so long sessions stay fast and bounded.
The first turn already knows the repo
Before you ask anything, one walk of the repository builds a profile: name, what it does, languages, layout, docs. On Aster's own repo that's six lines and 24ms.
An environment note derived from your lockfiles joins the system prompt too, so the agent knows your package manager and toolchain before its first tool call. @-mention file search runs on demand rather than indexing upfront, so opening a huge repo costs nothing until you search it.
Sessions that travel
- XDG data dir. Session data moved to the platform-standard location.
- Session import. Bring a session in from outside Aster.
- Generated titles. Sessions name themselves from their content, shown in the CLI and desktop app.
- History restore. Desktop and VS Code rebuild a session's blocks on load, reasoning included.
Under the hood
- Six new crates:
aster-serve(the browser surface),aster-remote(Telegram),aster-plugins(Agent Plugins),aster-shortcuts(Apple Shortcuts),aster-eval(session grading for live evals against a repo root), andaster-telemetry(OTLP span export). - OpenRouter web plugin: native web search with URL citations when running through OpenRouter.
- Yolo mode in the desktop app, and review intent folded into the composer mode picker.
- TUI fixes: the transcript stays put when the pane resizes; Mac modifier keys render as glyphs in the VS Code tips; every command title is prefixed so the palette shows Aster.
Standing on the shoulders of
Aster is a harness, not a model. It works because these projects and companies built the pieces it plugs into:
Model providers
- OpenRouter , one API, hundreds of models, and the native web-search plugin
- OpenAI , the API shape the whole ecosystem speaks
- Anthropic , Claude, the Agent Skills and Agent Plugins standards, and MCP
- Google , Gemini
- Groq , fast inference
- Mistral, Cohere, Perplexity, xAI, DeepSeek, Qwen, and every other OpenAI-compatible provider in the catalog
Local inference
Search and the web
- DuckDuckGo , the zero-setup search fallback
- Exa, Firecrawl, Browserbase, Perplexity, Cloudflare , search, crawling, and browser automation when you have accounts
Standards and surfaces
- Model Context Protocol , the tool plug-in standard, local and remote
- Telegram , Bot API for the pocket surface
- Tauri , the desktop app
- ratatui , the terminal UI
If you maintain one of these and want your entry changed, open an issue.
Try it
Built solo, in the open, Apache-2.0. Binaries for macOS, Linux, and Windows, plus desktop installers.
curl -fsSL https://aster.builders/install | sh
In your editor, install Aster AI from the VS Code Marketplace, or from Open VSX if you are on Cursor, Windsurf, or VSCodium.