openmuse 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. openmuse-0.1.0/.gitignore +42 -0
  2. openmuse-0.1.0/LICENSE +21 -0
  3. openmuse-0.1.0/PKG-INFO +295 -0
  4. openmuse-0.1.0/README.md +245 -0
  5. openmuse-0.1.0/README_zh.md +245 -0
  6. openmuse-0.1.0/config/config.example.toml +155 -0
  7. openmuse-0.1.0/openmuse/__init__.py +10 -0
  8. openmuse-0.1.0/openmuse/__main__.py +4 -0
  9. openmuse-0.1.0/openmuse/agent/__init__.py +3 -0
  10. openmuse-0.1.0/openmuse/agent/core.py +257 -0
  11. openmuse-0.1.0/openmuse/app.py +150 -0
  12. openmuse-0.1.0/openmuse/cli.py +563 -0
  13. openmuse-0.1.0/openmuse/config.py +308 -0
  14. openmuse-0.1.0/openmuse/console.py +136 -0
  15. openmuse-0.1.0/openmuse/goals/__init__.py +3 -0
  16. openmuse-0.1.0/openmuse/goals/store.py +233 -0
  17. openmuse-0.1.0/openmuse/llm/__init__.py +15 -0
  18. openmuse-0.1.0/openmuse/llm/base.py +119 -0
  19. openmuse-0.1.0/openmuse/llm/factory.py +24 -0
  20. openmuse-0.1.0/openmuse/llm/mock.py +39 -0
  21. openmuse-0.1.0/openmuse/llm/openai_chat.py +188 -0
  22. openmuse-0.1.0/openmuse/llm/openai_responses.py +213 -0
  23. openmuse-0.1.0/openmuse/llm/prompt_tools.py +187 -0
  24. openmuse-0.1.0/openmuse/logger.py +41 -0
  25. openmuse-0.1.0/openmuse/memory/__init__.py +3 -0
  26. openmuse-0.1.0/openmuse/memory/store.py +158 -0
  27. openmuse-0.1.0/openmuse/prompts.py +116 -0
  28. openmuse-0.1.0/openmuse/schema.py +185 -0
  29. openmuse-0.1.0/openmuse/sentinel/__init__.py +5 -0
  30. openmuse-0.1.0/openmuse/sentinel/audit.py +63 -0
  31. openmuse-0.1.0/openmuse/sentinel/gate.py +191 -0
  32. openmuse-0.1.0/openmuse/sentinel/policy.py +137 -0
  33. openmuse-0.1.0/openmuse/server/__init__.py +86 -0
  34. openmuse-0.1.0/openmuse/server/api.py +436 -0
  35. openmuse-0.1.0/openmuse/server/events.py +142 -0
  36. openmuse-0.1.0/openmuse/server/service.py +685 -0
  37. openmuse-0.1.0/openmuse/server/static/assets/index-C0fjpYij.js +299 -0
  38. openmuse-0.1.0/openmuse/server/static/assets/index-D2k1_9-v.css +1 -0
  39. openmuse-0.1.0/openmuse/server/static/icon-192.png +0 -0
  40. openmuse-0.1.0/openmuse/server/static/icon-512.png +0 -0
  41. openmuse-0.1.0/openmuse/server/static/icon.svg +11 -0
  42. openmuse-0.1.0/openmuse/server/static/index.html +25 -0
  43. openmuse-0.1.0/openmuse/server/static/manifest.webmanifest +16 -0
  44. openmuse-0.1.0/openmuse/server/webui.py +301 -0
  45. openmuse-0.1.0/openmuse/tools/__init__.py +34 -0
  46. openmuse-0.1.0/openmuse/tools/base.py +159 -0
  47. openmuse-0.1.0/openmuse/tools/browser.py +238 -0
  48. openmuse-0.1.0/openmuse/tools/email_tool.py +256 -0
  49. openmuse-0.1.0/openmuse/tools/files.py +144 -0
  50. openmuse-0.1.0/openmuse/tools/goal_tools.py +137 -0
  51. openmuse-0.1.0/openmuse/tools/mcp_tools.py +157 -0
  52. openmuse-0.1.0/openmuse/tools/memory_tools.py +110 -0
  53. openmuse-0.1.0/openmuse/tools/shell.py +154 -0
  54. openmuse-0.1.0/openmuse/tools/terminate.py +58 -0
  55. openmuse-0.1.0/openmuse/tools/web.py +196 -0
  56. openmuse-0.1.0/openmuse/ui.py +90 -0
  57. openmuse-0.1.0/openmuse/vault/__init__.py +3 -0
  58. openmuse-0.1.0/openmuse/vault/vault.py +144 -0
  59. openmuse-0.1.0/pyproject.toml +75 -0
@@ -0,0 +1,42 @@
1
+ # local configuration & secrets
2
+ config/config.toml
3
+ config/*.local.toml
4
+ .env
5
+ .env.*
6
+ !.env.example
7
+
8
+ # runtime data
9
+ workspace/
10
+ *.db
11
+ *.enc
12
+ *.key
13
+ audit.jsonl
14
+ sessions/
15
+ logs/
16
+
17
+ # python
18
+ __pycache__/
19
+ *.py[cod]
20
+ *.egg-info/
21
+ .eggs/
22
+ build/
23
+ dist/
24
+ .venv/
25
+ venv/
26
+ .pytest_cache/
27
+ .ruff_cache/
28
+ .mypy_cache/
29
+ .coverage
30
+ htmlcov/
31
+
32
+ # web app sources (the production build in openmuse/server/static IS committed)
33
+ web/node_modules/
34
+ web/dist/
35
+ web/.vite/
36
+ npm-debug.log*
37
+
38
+ # editors / OS
39
+ .vscode/
40
+ .idea/
41
+ .DS_Store
42
+ *.swp
openmuse-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpenMuse Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,295 @@
1
+ Metadata-Version: 2.5
2
+ Name: openmuse
3
+ Version: 0.1.0
4
+ Summary: Open-source version of Meta's Muse: a personal agent with a phone app, a Sentinel gatekeeper, a credential vault, memory and goals. Bring your own model.
5
+ Project-URL: Homepage, https://github.com/OpenMuseAgent/OpenMuse
6
+ Project-URL: Repository, https://github.com/OpenMuseAgent/OpenMuse
7
+ Project-URL: Issues, https://github.com/OpenMuseAgent/OpenMuse/issues
8
+ Author: OpenMuse Contributors
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,ai,deepseek,llm,mcp,meta-muse,muse,personal-assistant
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: beautifulsoup4>=4.12
22
+ Requires-Dist: cryptography>=42
23
+ Requires-Dist: ddgs>=9.0
24
+ Requires-Dist: fastapi>=0.110
25
+ Requires-Dist: html2text>=2024.2.26
26
+ Requires-Dist: httpx>=0.27
27
+ Requires-Dist: loguru>=0.7
28
+ Requires-Dist: mcp>=1.2
29
+ Requires-Dist: openai>=1.60
30
+ Requires-Dist: pydantic>=2.7
31
+ Requires-Dist: qrcode>=7.4
32
+ Requires-Dist: rich>=13.7
33
+ Requires-Dist: tenacity>=8.3
34
+ Requires-Dist: typer>=0.12
35
+ Requires-Dist: uvicorn[standard]>=0.29
36
+ Provides-Extra: all
37
+ Requires-Dist: httpx>=0.27; extra == 'all'
38
+ Requires-Dist: playwright>=1.45; extra == 'all'
39
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'all'
40
+ Requires-Dist: pytest>=8; extra == 'all'
41
+ Requires-Dist: ruff>=0.5; extra == 'all'
42
+ Provides-Extra: browser
43
+ Requires-Dist: playwright>=1.45; extra == 'browser'
44
+ Provides-Extra: dev
45
+ Requires-Dist: httpx>=0.27; extra == 'dev'
46
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
47
+ Requires-Dist: pytest>=8; extra == 'dev'
48
+ Requires-Dist: ruff>=0.5; extra == 'dev'
49
+ Description-Content-Type: text/markdown
50
+
51
+ <p align="center">
52
+ <img src="web/public/icon.svg" width="88" alt="OpenMuse">
53
+ </p>
54
+
55
+ <h1 align="center">OpenMuse</h1>
56
+
57
+ <p align="center">
58
+ An open-source version of Meta's <a href="https://about.fb.com/news/2026/09/introducing-muse-personal-ai-agent/">Muse</a>: a personal agent that works for you from your phone, keeps going while the app is closed, and asks before it does anything you can't undo. Self-hosted, any model.
59
+ </p>
60
+
61
+ <p align="center">
62
+ <a href="https://github.com/OpenMuseAgent/OpenMuse/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/OpenMuseAgent/OpenMuse/actions/workflows/ci.yml/badge.svg"></a>
63
+ <a href="LICENSE"><img alt="MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
64
+ <img alt="Python 3.11+" src="https://img.shields.io/badge/python-3.11%2B-blue.svg">
65
+ <br>
66
+ English · <a href="README_zh.md">简体中文</a>
67
+ </p>
68
+
69
+ <p align="center">
70
+ <img src="docs/screenshots/chat-approval.png" width="24%" alt="Chat with an approval card">
71
+ <img src="docs/screenshots/goal-detail.png" width="24%" alt="A goal with its plan">
72
+ <img src="docs/screenshots/ideas.png" width="24%" alt="Ideas tab">
73
+ <img src="docs/screenshots/settings.png" width="24%" alt="Sentinel settings">
74
+ </p>
75
+
76
+ ## Start here
77
+
78
+ | You want to... | Go to |
79
+ |---|---|
80
+ | Install and open the app on your phone | [Install](#install) → [Quick start](#quick-start) |
81
+ | Use it from the terminal instead | [CLI](docs/cli.md) |
82
+ | Point it at DeepSeek, OpenAI, Ollama, or an internal gateway | [Models](#models) · [Configuration](docs/configuration.md) |
83
+ | Understand what it will and won't do without asking | [Sentinel](#sentinel) · [docs/sentinel.md](docs/sentinel.md) |
84
+ | Connect email, a browser, or MCP servers | [Configuration → Connectors](docs/configuration.md#connectors) |
85
+ | Read the code | [Architecture](#architecture) · [docs/architecture.md](docs/architecture.md) |
86
+ | Run it in Docker | [Deployment](docs/deployment.md) |
87
+
88
+ ## What it does
89
+
90
+ Meta's Muse is an agent that does things rather than answering questions: it researches, plans, writes files, sends mail, works on goals over weeks, and every risky action passes through a separate gatekeeper. OpenMuse rebuilds that shape in the open:
91
+
92
+ - One long conversation with your agent, plus side chats for separate tasks. Tool calls show up inline as chips you can expand.
93
+ - Approval cards. Anything hard to undo (a shell command, an email, a network call after reading private data) stops and waits for a tap: deny, allow once, allow for the session, always allow.
94
+ - Goals that outlive the chat. The agent breaks a goal into steps, updates them as it works, and can keep advancing goals on a timer while the app is closed, posting updates to the main chat.
95
+ - Ideas: suggested next actions based on your goals, memory and recent conversations.
96
+ - Memory you can read and edit. Durable facts about you are saved by the agent and shown in a tab; anything can be forgotten with one tap.
97
+ - A Sentinel, a credential vault, taint tracking and an append-only audit log. See [Sentinel](#sentinel).
98
+ - Tools: files, shell, Python, web search and fetch, email (with one-time codes scrubbed before the model sees them), an optional Playwright browser, and any [MCP](https://modelcontextprotocol.io) server.
99
+ - Runs on any OpenAI-compatible model. DeepSeek, OpenAI, OpenRouter, Ollama, vLLM, or a company gateway with custom headers.
100
+
101
+ ## Why OpenMuse
102
+
103
+ - **It is a Muse, not a bot framework.** One agent with a name and a face, a phone app with Chat / Goals / Ideas / Memory tabs, approval cards, background work. If you want a bot in Telegram or Discord, see [Related projects](#related-projects).
104
+ - **Safety is the architecture, not a setting.** The agent never touches tools directly. A separate `Sentinel` decides allow / ask / deny per call, resolves `{{vault:NAME}}` placeholders so secrets never reach the model, tracks taint (private data read → new destinations need approval), and logs everything.
105
+ - **Bring your own model.** Chat Completions or Responses API, streaming, `<think>` handling, native or prompt-based tool calling.
106
+ - **Small enough to read.** About 7k lines of typed Python and 3k lines of TypeScript. No orchestration framework underneath.
107
+
108
+ ## Install
109
+
110
+ Python 3.11 or newer. The phone app is pre-built and included in the package; Node is only needed if you change `web/`.
111
+
112
+ ```bash
113
+ uv tool install git+https://github.com/OpenMuseAgent/OpenMuse.git
114
+ # or: pip install git+https://github.com/OpenMuseAgent/OpenMuse.git
115
+ ```
116
+
117
+ From a checkout, for development:
118
+
119
+ ```bash
120
+ git clone https://github.com/OpenMuseAgent/OpenMuse.git && cd OpenMuse
121
+ uv venv && source .venv/bin/activate
122
+ uv pip install -e ".[dev]"
123
+ ```
124
+
125
+ Optional: `openmuse[browser]` adds the Playwright browser tool (then `playwright install chromium`). A PyPI release follows the first tagged version.
126
+
127
+ ## Quick start
128
+
129
+ ```bash
130
+ openmuse config init # writes config/config.toml
131
+ export DEEPSEEK_API_KEY=sk-... # the default config uses DeepSeek; see Models below
132
+ openmuse serve --host 0.0.0.0 # prints a URL and a QR code
133
+ ```
134
+
135
+ Scan the QR code with your phone (same Wi-Fi), or open the URL on this machine. The link carries a one-time access token; add the page to your home screen and it behaves like an app. Then try:
136
+
137
+ - *"Compare the Sony WH-1000XM6 and Bose QuietComfort Ultra for long flights and save a short comparison to headphones.md"*
138
+ - *"Check how much free disk space this machine has"* — this one produces an approval card.
139
+ - *"Set up a goal: conversational Japanese before my Kyoto trip in December, 30 minutes a day"* — then open the Goals tab.
140
+
141
+ Prefer a terminal? `openmuse chat` gives you the same agent with approvals in the console, and `openmuse run "task"` runs one task and exits. See [docs/cli.md](docs/cli.md).
142
+
143
+ ## The app
144
+
145
+ `openmuse serve` starts an always-on agent and serves a mobile-first web app from the same process (FastAPI + a WebSocket for live events; React on the client, bundled into the Python package).
146
+
147
+ <p align="center">
148
+ <img src="docs/screenshots/chat-research.png" width="24%" alt="Research with tool chips and a file artifact">
149
+ <img src="docs/screenshots/chat-approval.png" width="24%" alt="Approval card">
150
+ <img src="docs/screenshots/memory.png" width="24%" alt="Memory tab">
151
+ <img src="docs/screenshots/goal-detail.png" width="24%" alt="Goal plan">
152
+ </p>
153
+
154
+ | Screen | What you get |
155
+ |---|---|
156
+ | Chat | Message-style conversation, streaming replies, tool chips with output, file artifacts, approval and question cards, side chats. You can keep typing while the agent works; new messages are folded into the running turn. |
157
+ | Goals | Active / paused / done goals, a plan with step status and notes, "work on it now", and a switch to keep working on goals every N minutes while you are away. |
158
+ | Ideas | Five suggested actions, regenerated on demand. Tap one to send it as a message. |
159
+ | Memory | Everything the agent remembers about you, by category. Add or forget entries. |
160
+ | You | Name, avatar, colour and personality of your agent; the Sentinel mode; background work; reply language. |
161
+ | Avatar | Tap it for the activity log: every tool call, decision and approval from the audit trail. |
162
+
163
+ The app talks to a small REST + WebSocket API, documented in [docs/app.md](docs/app.md), so other front-ends can be built on the same server.
164
+
165
+ ## Sentinel
166
+
167
+ Every tool call goes through `Sentinel` before it runs. Tools declare a risk level (`safe` / `moderate` / `sensitive`) and can escalate a specific call (`shell` on `rm -rf`, `web_fetch` on a private IP). Evaluation order, first match wins:
168
+
169
+ 1. `deny_tools` → deny
170
+ 2. `[[sentinel.rules]]` matching glob patterns on the arguments → the rule's action
171
+ 3. `always_allow_tools` / `always_ask_tools`
172
+ 4. Taint: the session has read private data (email, memories, files outside the workspace) **and** this call sends data to a host outside `egress_allowlist` → ask
173
+ 5. Risk × mode: `ask` asks for sensitive calls, `strict` also for moderate ones, `auto` allows everything not denied
174
+
175
+ ```toml
176
+ [sentinel]
177
+ mode = "ask" # ask | strict | auto
178
+ always_ask_tools = ["send_email", "shell"]
179
+ egress_allowlist = ["*.wikipedia.org", "github.com", "*.github.com"]
180
+
181
+ [[sentinel.rules]]
182
+ tool = "shell"
183
+ match = { command = "*rm -rf*" }
184
+ action = "deny"
185
+ ```
186
+
187
+ Secrets live in a Fernet-encrypted vault (`openmuse vault set EMAIL_PASSWORD`). Config and tool arguments reference them as `{{vault:EMAIL_PASSWORD}}`; Sentinel substitutes the value right before execution and redacts it from tool output, so the model never sees it. Every decision is appended to `~/.openmuse/audit.jsonl`. Details in [docs/sentinel.md](docs/sentinel.md).
188
+
189
+ ## Models
190
+
191
+ Edit `[llm]` in `config/config.toml`. Any OpenAI-compatible endpoint works:
192
+
193
+ ```toml
194
+ [llm]
195
+ provider = "openai" # Chat Completions; "openai_responses" for the Responses API
196
+ model = "deepseek-flash"
197
+ base_url = "https://api.deepseek.com"
198
+ api_key = "${DEEPSEEK_API_KEY}"
199
+
200
+ # OpenAI: model = "gpt-5.6-sol" base_url = "https://api.openai.com/v1" api_key = "${OPENAI_API_KEY}"
201
+ # Ollama: model = "qwen3:32b" base_url = "http://localhost:11434/v1" api_key = "ollama"
202
+ # OpenRouter: model = "deepseek/deepseek-flash" base_url = "https://openrouter.ai/api/v1"
203
+ # A gateway that needs headers: extra_headers = { "X-End-User-Id" = "openmuse" }
204
+ # A model that ignores `tools`: tool_mode = "prompt"
205
+ ```
206
+
207
+ The same settings can be set with `OPENMUSE_LLM_MODEL`, `OPENMUSE_LLM_BASE_URL`, `OPENMUSE_LLM_API_KEY`, `OPENMUSE_LLM_PROVIDER`. Full reference: [docs/configuration.md](docs/configuration.md).
208
+
209
+ ## Architecture
210
+
211
+ ```mermaid
212
+ flowchart LR
213
+ P([Phone / browser]) <-- WebSocket + REST --> S[MuseService<br/>threads, scheduler, ideas]
214
+ C([Terminal]) <--> A
215
+ S <--> A[MuseAgent loop]
216
+ A <--> LLM[(any OpenAI-compatible model)]
217
+ A --> G{{Sentinel}}
218
+ G -- allow --> T[Tools]
219
+ G -- ask --> P
220
+ G --> AU[(audit.jsonl)]
221
+ G <--> V[(vault.enc)]
222
+ T --> F[files · shell · python]
223
+ T --> W[web_search · web_fetch · browser]
224
+ T --> E[email]
225
+ T --> MCP[MCP servers]
226
+ T <--> M[(memory.db)]
227
+ T <--> GO[(goals.db)]
228
+ ```
229
+
230
+ | Area | Files |
231
+ |---|---|
232
+ | Agent loop, system prompt, context window | `openmuse/agent/core.py`, `openmuse/prompts.py` |
233
+ | Sentinel: policy, approvals, taint, audit | `openmuse/sentinel/` |
234
+ | Credential vault | `openmuse/vault/` |
235
+ | Tools and MCP adapter | `openmuse/tools/` |
236
+ | LLM providers, `<think>` filter, prompt-based tool calling | `openmuse/llm/` |
237
+ | Memory and goals (SQLite) | `openmuse/memory/`, `openmuse/goals/` |
238
+ | App server: service, REST/WebSocket API, timeline | `openmuse/server/` |
239
+ | Phone app (React, Vite, Tailwind) | `web/` → built into `openmuse/server/static/` |
240
+ | Terminal UI and CLI | `openmuse/console.py`, `openmuse/cli.py` |
241
+
242
+ More in [docs/architecture.md](docs/architecture.md).
243
+
244
+ ## OpenMuse and Meta Muse
245
+
246
+ | Meta Muse | OpenMuse |
247
+ |---|---|
248
+ | Runs in a per-user Secure VM | Runs on your machine or in Docker; the workspace and data directory are the boundary |
249
+ | Sentinel approves sensitive actions | `Sentinel` policy engine: allow / ask / deny, rules, taint tracking, egress allowlist |
250
+ | Credentials never reach the model | Encrypted vault with `{{vault:NAME}}` placeholders and output redaction |
251
+ | Remembers you | SQLite memory the agent maintains and you can edit |
252
+ | Works on goals in the background | Goals with steps; scheduler advances them and reports to the chat |
253
+ | Mobile app with chat, goals, approvals | Mobile-first web app served by `openmuse serve`, installable to the home screen |
254
+ | Meta's models | Any OpenAI-compatible model |
255
+ | Closed | MIT |
256
+
257
+ ## Docs
258
+
259
+ - [Configuration](docs/configuration.md): every setting, environment overrides, connectors, MCP
260
+ - [Sentinel](docs/sentinel.md): policy order, rules, taint tracking, vault, audit
261
+ - [The app and its API](docs/app.md): phone access, tokens, threads, approvals, endpoints
262
+ - [CLI](docs/cli.md): `chat`, `run`, `serve`, `daemon`, `goals`, `memory`, `vault`, `audit`, `config`
263
+ - [Architecture](docs/architecture.md): source map and extension points
264
+ - [Deployment](docs/deployment.md): Docker, Compose, keeping it running
265
+ - [Troubleshooting](docs/troubleshooting.md)
266
+
267
+ ## Roadmap
268
+
269
+ - [x] Agent loop, Sentinel, vault, audit, memory, goals, tools, MCP, CLI
270
+ - [x] Mobile-first app: chat, approval cards, side chats, Goals / Ideas / Memory, background goal work
271
+ - [ ] Push notifications when an approval is waiting or a goal posts an update
272
+ - [ ] Triggers for goals: cron, webhooks, new mail
273
+ - [ ] Calendar and contacts connectors (via MCP)
274
+ - [ ] Better memory recall (embeddings) and periodic consolidation
275
+ - [ ] Per-tool sandboxes for `shell` and `python_execute`
276
+ - [ ] Skills: reusable task recipes
277
+
278
+ ## Contributing
279
+
280
+ Use it for a real task, report what broke, then pick something focused. [CONTRIBUTING.md](CONTRIBUTING.md) has the development setup; CI runs `ruff`, `pytest` and the web build.
281
+
282
+ ## Related projects
283
+
284
+ - [nanobot](https://github.com/HKUDS/nanobot): a lightweight personal assistant framework that lives in chat apps (Telegram, Discord, Slack, WeChat...). Pick it if you want a bot in the channels you already use. OpenMuse is one agent with Muse's product shape and safety model; it does not try to be a channel framework.
285
+ - [OpenClaw](https://github.com/openclaw/openclaw): the always-on gateway approach many assistant projects follow.
286
+ - [browser-use](https://github.com/browser-use/browser-use): the element-annotation idea behind the browser tool.
287
+ - [Model Context Protocol](https://modelcontextprotocol.io): how OpenMuse gets connectors without writing each one.
288
+
289
+ ## Disclaimer
290
+
291
+ OpenMuse is an independent community project. It is not affiliated with, endorsed by, or derived from Meta Platforms, Inc. or its Muse product.
292
+
293
+ ## License
294
+
295
+ [MIT](LICENSE)
@@ -0,0 +1,245 @@
1
+ <p align="center">
2
+ <img src="web/public/icon.svg" width="88" alt="OpenMuse">
3
+ </p>
4
+
5
+ <h1 align="center">OpenMuse</h1>
6
+
7
+ <p align="center">
8
+ An open-source version of Meta's <a href="https://about.fb.com/news/2026/09/introducing-muse-personal-ai-agent/">Muse</a>: a personal agent that works for you from your phone, keeps going while the app is closed, and asks before it does anything you can't undo. Self-hosted, any model.
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://github.com/OpenMuseAgent/OpenMuse/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/OpenMuseAgent/OpenMuse/actions/workflows/ci.yml/badge.svg"></a>
13
+ <a href="LICENSE"><img alt="MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
14
+ <img alt="Python 3.11+" src="https://img.shields.io/badge/python-3.11%2B-blue.svg">
15
+ <br>
16
+ English · <a href="README_zh.md">简体中文</a>
17
+ </p>
18
+
19
+ <p align="center">
20
+ <img src="docs/screenshots/chat-approval.png" width="24%" alt="Chat with an approval card">
21
+ <img src="docs/screenshots/goal-detail.png" width="24%" alt="A goal with its plan">
22
+ <img src="docs/screenshots/ideas.png" width="24%" alt="Ideas tab">
23
+ <img src="docs/screenshots/settings.png" width="24%" alt="Sentinel settings">
24
+ </p>
25
+
26
+ ## Start here
27
+
28
+ | You want to... | Go to |
29
+ |---|---|
30
+ | Install and open the app on your phone | [Install](#install) → [Quick start](#quick-start) |
31
+ | Use it from the terminal instead | [CLI](docs/cli.md) |
32
+ | Point it at DeepSeek, OpenAI, Ollama, or an internal gateway | [Models](#models) · [Configuration](docs/configuration.md) |
33
+ | Understand what it will and won't do without asking | [Sentinel](#sentinel) · [docs/sentinel.md](docs/sentinel.md) |
34
+ | Connect email, a browser, or MCP servers | [Configuration → Connectors](docs/configuration.md#connectors) |
35
+ | Read the code | [Architecture](#architecture) · [docs/architecture.md](docs/architecture.md) |
36
+ | Run it in Docker | [Deployment](docs/deployment.md) |
37
+
38
+ ## What it does
39
+
40
+ Meta's Muse is an agent that does things rather than answering questions: it researches, plans, writes files, sends mail, works on goals over weeks, and every risky action passes through a separate gatekeeper. OpenMuse rebuilds that shape in the open:
41
+
42
+ - One long conversation with your agent, plus side chats for separate tasks. Tool calls show up inline as chips you can expand.
43
+ - Approval cards. Anything hard to undo (a shell command, an email, a network call after reading private data) stops and waits for a tap: deny, allow once, allow for the session, always allow.
44
+ - Goals that outlive the chat. The agent breaks a goal into steps, updates them as it works, and can keep advancing goals on a timer while the app is closed, posting updates to the main chat.
45
+ - Ideas: suggested next actions based on your goals, memory and recent conversations.
46
+ - Memory you can read and edit. Durable facts about you are saved by the agent and shown in a tab; anything can be forgotten with one tap.
47
+ - A Sentinel, a credential vault, taint tracking and an append-only audit log. See [Sentinel](#sentinel).
48
+ - Tools: files, shell, Python, web search and fetch, email (with one-time codes scrubbed before the model sees them), an optional Playwright browser, and any [MCP](https://modelcontextprotocol.io) server.
49
+ - Runs on any OpenAI-compatible model. DeepSeek, OpenAI, OpenRouter, Ollama, vLLM, or a company gateway with custom headers.
50
+
51
+ ## Why OpenMuse
52
+
53
+ - **It is a Muse, not a bot framework.** One agent with a name and a face, a phone app with Chat / Goals / Ideas / Memory tabs, approval cards, background work. If you want a bot in Telegram or Discord, see [Related projects](#related-projects).
54
+ - **Safety is the architecture, not a setting.** The agent never touches tools directly. A separate `Sentinel` decides allow / ask / deny per call, resolves `{{vault:NAME}}` placeholders so secrets never reach the model, tracks taint (private data read → new destinations need approval), and logs everything.
55
+ - **Bring your own model.** Chat Completions or Responses API, streaming, `<think>` handling, native or prompt-based tool calling.
56
+ - **Small enough to read.** About 7k lines of typed Python and 3k lines of TypeScript. No orchestration framework underneath.
57
+
58
+ ## Install
59
+
60
+ Python 3.11 or newer. The phone app is pre-built and included in the package; Node is only needed if you change `web/`.
61
+
62
+ ```bash
63
+ uv tool install git+https://github.com/OpenMuseAgent/OpenMuse.git
64
+ # or: pip install git+https://github.com/OpenMuseAgent/OpenMuse.git
65
+ ```
66
+
67
+ From a checkout, for development:
68
+
69
+ ```bash
70
+ git clone https://github.com/OpenMuseAgent/OpenMuse.git && cd OpenMuse
71
+ uv venv && source .venv/bin/activate
72
+ uv pip install -e ".[dev]"
73
+ ```
74
+
75
+ Optional: `openmuse[browser]` adds the Playwright browser tool (then `playwright install chromium`). A PyPI release follows the first tagged version.
76
+
77
+ ## Quick start
78
+
79
+ ```bash
80
+ openmuse config init # writes config/config.toml
81
+ export DEEPSEEK_API_KEY=sk-... # the default config uses DeepSeek; see Models below
82
+ openmuse serve --host 0.0.0.0 # prints a URL and a QR code
83
+ ```
84
+
85
+ Scan the QR code with your phone (same Wi-Fi), or open the URL on this machine. The link carries a one-time access token; add the page to your home screen and it behaves like an app. Then try:
86
+
87
+ - *"Compare the Sony WH-1000XM6 and Bose QuietComfort Ultra for long flights and save a short comparison to headphones.md"*
88
+ - *"Check how much free disk space this machine has"* — this one produces an approval card.
89
+ - *"Set up a goal: conversational Japanese before my Kyoto trip in December, 30 minutes a day"* — then open the Goals tab.
90
+
91
+ Prefer a terminal? `openmuse chat` gives you the same agent with approvals in the console, and `openmuse run "task"` runs one task and exits. See [docs/cli.md](docs/cli.md).
92
+
93
+ ## The app
94
+
95
+ `openmuse serve` starts an always-on agent and serves a mobile-first web app from the same process (FastAPI + a WebSocket for live events; React on the client, bundled into the Python package).
96
+
97
+ <p align="center">
98
+ <img src="docs/screenshots/chat-research.png" width="24%" alt="Research with tool chips and a file artifact">
99
+ <img src="docs/screenshots/chat-approval.png" width="24%" alt="Approval card">
100
+ <img src="docs/screenshots/memory.png" width="24%" alt="Memory tab">
101
+ <img src="docs/screenshots/goal-detail.png" width="24%" alt="Goal plan">
102
+ </p>
103
+
104
+ | Screen | What you get |
105
+ |---|---|
106
+ | Chat | Message-style conversation, streaming replies, tool chips with output, file artifacts, approval and question cards, side chats. You can keep typing while the agent works; new messages are folded into the running turn. |
107
+ | Goals | Active / paused / done goals, a plan with step status and notes, "work on it now", and a switch to keep working on goals every N minutes while you are away. |
108
+ | Ideas | Five suggested actions, regenerated on demand. Tap one to send it as a message. |
109
+ | Memory | Everything the agent remembers about you, by category. Add or forget entries. |
110
+ | You | Name, avatar, colour and personality of your agent; the Sentinel mode; background work; reply language. |
111
+ | Avatar | Tap it for the activity log: every tool call, decision and approval from the audit trail. |
112
+
113
+ The app talks to a small REST + WebSocket API, documented in [docs/app.md](docs/app.md), so other front-ends can be built on the same server.
114
+
115
+ ## Sentinel
116
+
117
+ Every tool call goes through `Sentinel` before it runs. Tools declare a risk level (`safe` / `moderate` / `sensitive`) and can escalate a specific call (`shell` on `rm -rf`, `web_fetch` on a private IP). Evaluation order, first match wins:
118
+
119
+ 1. `deny_tools` → deny
120
+ 2. `[[sentinel.rules]]` matching glob patterns on the arguments → the rule's action
121
+ 3. `always_allow_tools` / `always_ask_tools`
122
+ 4. Taint: the session has read private data (email, memories, files outside the workspace) **and** this call sends data to a host outside `egress_allowlist` → ask
123
+ 5. Risk × mode: `ask` asks for sensitive calls, `strict` also for moderate ones, `auto` allows everything not denied
124
+
125
+ ```toml
126
+ [sentinel]
127
+ mode = "ask" # ask | strict | auto
128
+ always_ask_tools = ["send_email", "shell"]
129
+ egress_allowlist = ["*.wikipedia.org", "github.com", "*.github.com"]
130
+
131
+ [[sentinel.rules]]
132
+ tool = "shell"
133
+ match = { command = "*rm -rf*" }
134
+ action = "deny"
135
+ ```
136
+
137
+ Secrets live in a Fernet-encrypted vault (`openmuse vault set EMAIL_PASSWORD`). Config and tool arguments reference them as `{{vault:EMAIL_PASSWORD}}`; Sentinel substitutes the value right before execution and redacts it from tool output, so the model never sees it. Every decision is appended to `~/.openmuse/audit.jsonl`. Details in [docs/sentinel.md](docs/sentinel.md).
138
+
139
+ ## Models
140
+
141
+ Edit `[llm]` in `config/config.toml`. Any OpenAI-compatible endpoint works:
142
+
143
+ ```toml
144
+ [llm]
145
+ provider = "openai" # Chat Completions; "openai_responses" for the Responses API
146
+ model = "deepseek-flash"
147
+ base_url = "https://api.deepseek.com"
148
+ api_key = "${DEEPSEEK_API_KEY}"
149
+
150
+ # OpenAI: model = "gpt-5.6-sol" base_url = "https://api.openai.com/v1" api_key = "${OPENAI_API_KEY}"
151
+ # Ollama: model = "qwen3:32b" base_url = "http://localhost:11434/v1" api_key = "ollama"
152
+ # OpenRouter: model = "deepseek/deepseek-flash" base_url = "https://openrouter.ai/api/v1"
153
+ # A gateway that needs headers: extra_headers = { "X-End-User-Id" = "openmuse" }
154
+ # A model that ignores `tools`: tool_mode = "prompt"
155
+ ```
156
+
157
+ The same settings can be set with `OPENMUSE_LLM_MODEL`, `OPENMUSE_LLM_BASE_URL`, `OPENMUSE_LLM_API_KEY`, `OPENMUSE_LLM_PROVIDER`. Full reference: [docs/configuration.md](docs/configuration.md).
158
+
159
+ ## Architecture
160
+
161
+ ```mermaid
162
+ flowchart LR
163
+ P([Phone / browser]) <-- WebSocket + REST --> S[MuseService<br/>threads, scheduler, ideas]
164
+ C([Terminal]) <--> A
165
+ S <--> A[MuseAgent loop]
166
+ A <--> LLM[(any OpenAI-compatible model)]
167
+ A --> G{{Sentinel}}
168
+ G -- allow --> T[Tools]
169
+ G -- ask --> P
170
+ G --> AU[(audit.jsonl)]
171
+ G <--> V[(vault.enc)]
172
+ T --> F[files · shell · python]
173
+ T --> W[web_search · web_fetch · browser]
174
+ T --> E[email]
175
+ T --> MCP[MCP servers]
176
+ T <--> M[(memory.db)]
177
+ T <--> GO[(goals.db)]
178
+ ```
179
+
180
+ | Area | Files |
181
+ |---|---|
182
+ | Agent loop, system prompt, context window | `openmuse/agent/core.py`, `openmuse/prompts.py` |
183
+ | Sentinel: policy, approvals, taint, audit | `openmuse/sentinel/` |
184
+ | Credential vault | `openmuse/vault/` |
185
+ | Tools and MCP adapter | `openmuse/tools/` |
186
+ | LLM providers, `<think>` filter, prompt-based tool calling | `openmuse/llm/` |
187
+ | Memory and goals (SQLite) | `openmuse/memory/`, `openmuse/goals/` |
188
+ | App server: service, REST/WebSocket API, timeline | `openmuse/server/` |
189
+ | Phone app (React, Vite, Tailwind) | `web/` → built into `openmuse/server/static/` |
190
+ | Terminal UI and CLI | `openmuse/console.py`, `openmuse/cli.py` |
191
+
192
+ More in [docs/architecture.md](docs/architecture.md).
193
+
194
+ ## OpenMuse and Meta Muse
195
+
196
+ | Meta Muse | OpenMuse |
197
+ |---|---|
198
+ | Runs in a per-user Secure VM | Runs on your machine or in Docker; the workspace and data directory are the boundary |
199
+ | Sentinel approves sensitive actions | `Sentinel` policy engine: allow / ask / deny, rules, taint tracking, egress allowlist |
200
+ | Credentials never reach the model | Encrypted vault with `{{vault:NAME}}` placeholders and output redaction |
201
+ | Remembers you | SQLite memory the agent maintains and you can edit |
202
+ | Works on goals in the background | Goals with steps; scheduler advances them and reports to the chat |
203
+ | Mobile app with chat, goals, approvals | Mobile-first web app served by `openmuse serve`, installable to the home screen |
204
+ | Meta's models | Any OpenAI-compatible model |
205
+ | Closed | MIT |
206
+
207
+ ## Docs
208
+
209
+ - [Configuration](docs/configuration.md): every setting, environment overrides, connectors, MCP
210
+ - [Sentinel](docs/sentinel.md): policy order, rules, taint tracking, vault, audit
211
+ - [The app and its API](docs/app.md): phone access, tokens, threads, approvals, endpoints
212
+ - [CLI](docs/cli.md): `chat`, `run`, `serve`, `daemon`, `goals`, `memory`, `vault`, `audit`, `config`
213
+ - [Architecture](docs/architecture.md): source map and extension points
214
+ - [Deployment](docs/deployment.md): Docker, Compose, keeping it running
215
+ - [Troubleshooting](docs/troubleshooting.md)
216
+
217
+ ## Roadmap
218
+
219
+ - [x] Agent loop, Sentinel, vault, audit, memory, goals, tools, MCP, CLI
220
+ - [x] Mobile-first app: chat, approval cards, side chats, Goals / Ideas / Memory, background goal work
221
+ - [ ] Push notifications when an approval is waiting or a goal posts an update
222
+ - [ ] Triggers for goals: cron, webhooks, new mail
223
+ - [ ] Calendar and contacts connectors (via MCP)
224
+ - [ ] Better memory recall (embeddings) and periodic consolidation
225
+ - [ ] Per-tool sandboxes for `shell` and `python_execute`
226
+ - [ ] Skills: reusable task recipes
227
+
228
+ ## Contributing
229
+
230
+ Use it for a real task, report what broke, then pick something focused. [CONTRIBUTING.md](CONTRIBUTING.md) has the development setup; CI runs `ruff`, `pytest` and the web build.
231
+
232
+ ## Related projects
233
+
234
+ - [nanobot](https://github.com/HKUDS/nanobot): a lightweight personal assistant framework that lives in chat apps (Telegram, Discord, Slack, WeChat...). Pick it if you want a bot in the channels you already use. OpenMuse is one agent with Muse's product shape and safety model; it does not try to be a channel framework.
235
+ - [OpenClaw](https://github.com/openclaw/openclaw): the always-on gateway approach many assistant projects follow.
236
+ - [browser-use](https://github.com/browser-use/browser-use): the element-annotation idea behind the browser tool.
237
+ - [Model Context Protocol](https://modelcontextprotocol.io): how OpenMuse gets connectors without writing each one.
238
+
239
+ ## Disclaimer
240
+
241
+ OpenMuse is an independent community project. It is not affiliated with, endorsed by, or derived from Meta Platforms, Inc. or its Muse product.
242
+
243
+ ## License
244
+
245
+ [MIT](LICENSE)