OpenMuse 0.4.0
Skills, triggers, contacts, and a sandbox. The agent has recipes it follows and can write new ones after a job went well; work starts from new mail, an upcoming event or a webhook, not only from the clock; it knows who is who before writing to anyone; and on Linux every command it runs is boxed in its own namespace with no way to your home directory and no network unless the command needs it.
Added
- Skills: how a job is done, written down once. A skill is a folder with a
SKILL.md— a name and a one-line description up top, the steps in Markdown below — in the Agent Skills format, so skills written for other agents work here and yours work there. Five ship with the app:weekly-review,trip-plan,inbox-triage,compare-options,meeting-prep. The model sees the index (name and description of every enabled skill) in its system prompt and reads the steps with theskillstool when a request fits;/trip-plan Kyoto, 5 days in Novemberat the start of a message runs one directly — type/in the composer and the skills come up,Tabcompletes. Yours live in<data_dir>/skills/<name>/and one with the same name as a built-in replaces it. Three ways to get one: write it in Skills → New (a template appears), paste a link — a rawSKILL.md, or a GitHub folder or file page — or, after a job went well, "save this as a skill": the agent writes down what it did as steps and asks first (skillssave and remove are sensitive calls, so they ask even inautomode). Switch any skill off; Make your own copy opens a built-in in the editor under your name. Skill folders are visible read-only inside the sandbox, so a skill's scripts and reference files can be used from there. A Skills entry in the avatar menu,openmuse skills list | show | add | new | remove | enable | disable,GET/PUT/DELETE /api/skills/{name},POST /api/skills/import,[skills]settings (dir,disabled);openmuse doctorlists what is loaded and any folder it could not read. - Triggers: work that starts when something happens. Reminders fire at a time; a trigger fires on an event in the world. Three kinds, set in chat ("when the landlord writes back, summarise it and draft a reply") or under Upcoming → When something happens: new mail — the inbox is looked at every five minutes while a mail trigger exists, by IMAP UID, so connecting a mailbox never replays old mail and nothing fires twice; before an event — N minutes before a calendar event whose title or place contains the words you named; webhook — a URL with a key that any program can
POSTto (/api/hooks/<id>?key=…, body ≤ 64 KB, JSON pretty-printed, 429 when deliveries come too close, a wrong key indistinguishable from a wrong URL). Each firing is a background run in the chat the trigger was set from, with the mail, event or request as context — marked as data, never instructions — and shows in the Feed as New mail: …, Coming up: … or Webhook: …, pushed once. Mail and events taint the session like any private data. Atriggerstool,openmuse triggers list | add | cancel,GET/POST /api/triggers,[triggers]settings (mail_poll_minutes,hook_min_seconds);openmuse doctorcounts them and flags ones whose connector is missing. - Contacts connector. The agent knows who is who. Import a
.vcfexport — Google Contacts, iCloud, Outlook, Nextcloud, the phone's own contacts app — from Connections → Contacts (upload from the phone, a path, or a link kept in the vault) oropenmuse contacts add-source; vCard 2.1, 3.0 and 4.0 are read, with Apple's label groups and quoted-printable names from old phones. Besides those there is My contacts, the book the agent fills from chat ("the landlord is Bob Li, bob@example.com") — the only one it writes to. Thecontactstool searches by name, nickname, company, email or phone (prefixes and single characters of a Chinese name count); the system prompt tells the agent to look people up before writing to them and never to guess an address. Thesend_emailapproval card names the recipient from the address book and warns when it does not know them (which asks even inautomode). A look-up is private data and taints the session.GET /api/contacts?q=,openmuse contacts search | list | add | sources | add-source | remove-source;openmuse doctorcounts the people it knows. - A sandbox for every command (Linux). With bubblewrap installed, each
shellandpython_executecall runs in its own namespace: the workspace (andagent.extra_roots) are the only writable places,/usrand friends are read-only,/tmpis private, and your home directory — vault, data directory, ssh keys, browser profiles — is not there at all (only the directory the running Python lives in is, read-only, so scripts run with the same interpreter and packages). There is no network unless the call needs it: a shell command that runscurl,pip,git,ssh… or names a URL, or saysnetwork=true; a script that imports a network module or starts programs. A command that fails for want of the network is told so in its result. That sharpens the Sentinel's egress rule forshell— a boxedlsafter reading mail is not egress, acurlstill is.[sandbox] mode = auto | bwrap | off; Settings → Safety andopenmuse doctorsay whether it is on and, if not, why (macOS, Windows and most Docker containers run commands as before, with the scrubbed environment). On Ubuntu 24.04, whose AppArmor restriction leaves an unprofiledbwrapunable to set up a network namespace, the box stays on for the file system, the status says the network is not blocked, shell commands count as egress again, and the doctor points to the profile to load (sentinel.md).
Fixed
- Calendar occurrences are given in the configured time zone everywhere — the Feed's Today block,
/api/calendarand event triggers had been showing a Google feed's UTC times as is (a 05:21 meeting appeared as 21:21). - Windows: a drive-letter path (
C:\…\contacts.vcf) counts as a path when a source is added from the app; drafted events name their file with forward slashes;tzdatais a dependency there, since Windows has no system time-zone database (the calendar and quiet hours need one).
pip install -U openmuse · uv tool upgrade openmuse · docker pull ghcr.io/openmuseagent/openmuse:0.4.0. Full list of changes: CHANGELOG.md.