nemoris 0.1.0
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.
- package/.env.example +49 -0
- package/LICENSE +21 -0
- package/README.md +209 -0
- package/SECURITY.md +119 -0
- package/bin/nemoris +46 -0
- package/config/agents/agent.toml.example +28 -0
- package/config/agents/default.toml +22 -0
- package/config/agents/orchestrator.toml +18 -0
- package/config/delivery.toml +73 -0
- package/config/embeddings.toml +5 -0
- package/config/identity/default-purpose.md +1 -0
- package/config/identity/default-soul.md +3 -0
- package/config/identity/orchestrator-purpose.md +1 -0
- package/config/identity/orchestrator-soul.md +1 -0
- package/config/improvement-targets.toml +15 -0
- package/config/jobs/heartbeat-check.toml +30 -0
- package/config/jobs/memory-rollup.toml +46 -0
- package/config/jobs/workspace-health.toml +63 -0
- package/config/mcp.toml +16 -0
- package/config/output-contracts.toml +17 -0
- package/config/peers.toml +32 -0
- package/config/peers.toml.example +32 -0
- package/config/policies/memory-default.toml +10 -0
- package/config/policies/memory-heartbeat.toml +5 -0
- package/config/policies/memory-ops.toml +10 -0
- package/config/policies/tools-heartbeat-minimal.toml +8 -0
- package/config/policies/tools-interactive-safe.toml +8 -0
- package/config/policies/tools-ops-bounded.toml +8 -0
- package/config/policies/tools-orchestrator.toml +7 -0
- package/config/providers/anthropic.toml +15 -0
- package/config/providers/ollama.toml +5 -0
- package/config/providers/openai-codex.toml +9 -0
- package/config/providers/openrouter.toml +5 -0
- package/config/router.toml +22 -0
- package/config/runtime.toml +114 -0
- package/config/skills/self-improvement.toml +15 -0
- package/config/skills/telegram-onboarding-spec.md +240 -0
- package/config/skills/workspace-monitor.toml +15 -0
- package/config/task-router.toml +42 -0
- package/install.sh +50 -0
- package/package.json +90 -0
- package/src/auth/auth-profiles.js +169 -0
- package/src/auth/openai-codex-oauth.js +285 -0
- package/src/battle.js +449 -0
- package/src/cli/help.js +265 -0
- package/src/cli/output-filter.js +49 -0
- package/src/cli/runtime-control.js +704 -0
- package/src/cli-main.js +2763 -0
- package/src/cli.js +78 -0
- package/src/config/loader.js +332 -0
- package/src/config/schema-validator.js +214 -0
- package/src/config/toml-lite.js +8 -0
- package/src/daemon/action-handlers.js +71 -0
- package/src/daemon/healing-tick.js +87 -0
- package/src/daemon/health-probes.js +90 -0
- package/src/daemon/notifier.js +57 -0
- package/src/daemon/nurse.js +218 -0
- package/src/daemon/repair-log.js +106 -0
- package/src/daemon/rule-staging.js +90 -0
- package/src/daemon/rules.js +29 -0
- package/src/daemon/telegram-commands.js +54 -0
- package/src/daemon/updater.js +85 -0
- package/src/jobs/job-runner.js +78 -0
- package/src/mcp/consumer.js +129 -0
- package/src/memory/active-recall.js +171 -0
- package/src/memory/backend-manager.js +97 -0
- package/src/memory/backends/file-backend.js +38 -0
- package/src/memory/backends/qmd-backend.js +219 -0
- package/src/memory/embedding-guards.js +24 -0
- package/src/memory/embedding-index.js +118 -0
- package/src/memory/embedding-service.js +179 -0
- package/src/memory/file-index.js +177 -0
- package/src/memory/memory-signature.js +5 -0
- package/src/memory/memory-store.js +648 -0
- package/src/memory/retrieval-planner.js +66 -0
- package/src/memory/scoring.js +145 -0
- package/src/memory/simhash.js +78 -0
- package/src/memory/sqlite-active-store.js +824 -0
- package/src/memory/write-policy.js +36 -0
- package/src/onboarding/aliases.js +33 -0
- package/src/onboarding/auth/api-key.js +224 -0
- package/src/onboarding/auth/ollama-detect.js +42 -0
- package/src/onboarding/clack-prompter.js +77 -0
- package/src/onboarding/doctor.js +530 -0
- package/src/onboarding/lock.js +42 -0
- package/src/onboarding/model-catalog.js +344 -0
- package/src/onboarding/phases/auth.js +589 -0
- package/src/onboarding/phases/build.js +130 -0
- package/src/onboarding/phases/choose.js +82 -0
- package/src/onboarding/phases/detect.js +98 -0
- package/src/onboarding/phases/hatch.js +216 -0
- package/src/onboarding/phases/identity.js +79 -0
- package/src/onboarding/phases/ollama.js +345 -0
- package/src/onboarding/phases/scaffold.js +99 -0
- package/src/onboarding/phases/telegram.js +377 -0
- package/src/onboarding/phases/validate.js +204 -0
- package/src/onboarding/phases/verify.js +206 -0
- package/src/onboarding/platform.js +482 -0
- package/src/onboarding/status-bar.js +95 -0
- package/src/onboarding/templates.js +794 -0
- package/src/onboarding/toml-writer.js +38 -0
- package/src/onboarding/tui.js +250 -0
- package/src/onboarding/uninstall.js +153 -0
- package/src/onboarding/wizard.js +499 -0
- package/src/providers/anthropic.js +168 -0
- package/src/providers/base.js +247 -0
- package/src/providers/circuit-breaker.js +136 -0
- package/src/providers/ollama.js +163 -0
- package/src/providers/openai-codex.js +149 -0
- package/src/providers/openrouter.js +136 -0
- package/src/providers/registry.js +36 -0
- package/src/providers/router.js +16 -0
- package/src/runtime/bootstrap-cache.js +47 -0
- package/src/runtime/capabilities-prompt.js +25 -0
- package/src/runtime/completion-ping.js +99 -0
- package/src/runtime/config-validator.js +121 -0
- package/src/runtime/context-ledger.js +360 -0
- package/src/runtime/cutover-readiness.js +42 -0
- package/src/runtime/daemon.js +729 -0
- package/src/runtime/delivery-ack.js +195 -0
- package/src/runtime/delivery-adapters/local-file.js +41 -0
- package/src/runtime/delivery-adapters/openclaw-cli.js +94 -0
- package/src/runtime/delivery-adapters/openclaw-peer.js +98 -0
- package/src/runtime/delivery-adapters/shadow.js +13 -0
- package/src/runtime/delivery-adapters/standalone-http.js +98 -0
- package/src/runtime/delivery-adapters/telegram.js +104 -0
- package/src/runtime/delivery-adapters/tui.js +128 -0
- package/src/runtime/delivery-manager.js +807 -0
- package/src/runtime/delivery-store.js +168 -0
- package/src/runtime/dependency-health.js +118 -0
- package/src/runtime/envelope.js +114 -0
- package/src/runtime/evaluation.js +1089 -0
- package/src/runtime/exec-approvals.js +216 -0
- package/src/runtime/executor.js +500 -0
- package/src/runtime/failure-ping.js +67 -0
- package/src/runtime/flows.js +83 -0
- package/src/runtime/guards.js +45 -0
- package/src/runtime/handoff.js +51 -0
- package/src/runtime/identity-cache.js +28 -0
- package/src/runtime/improvement-engine.js +109 -0
- package/src/runtime/improvement-harness.js +581 -0
- package/src/runtime/input-sanitiser.js +72 -0
- package/src/runtime/interaction-contract.js +347 -0
- package/src/runtime/lane-readiness.js +226 -0
- package/src/runtime/migration.js +323 -0
- package/src/runtime/model-resolution.js +78 -0
- package/src/runtime/network.js +64 -0
- package/src/runtime/notification-store.js +97 -0
- package/src/runtime/notifier.js +256 -0
- package/src/runtime/orchestrator.js +53 -0
- package/src/runtime/orphan-reaper.js +41 -0
- package/src/runtime/output-contract-schema.js +139 -0
- package/src/runtime/output-contract-validator.js +439 -0
- package/src/runtime/peer-readiness.js +69 -0
- package/src/runtime/peer-registry.js +133 -0
- package/src/runtime/pilot-status.js +108 -0
- package/src/runtime/prompt-builder.js +261 -0
- package/src/runtime/provider-attempt.js +582 -0
- package/src/runtime/report-fallback.js +71 -0
- package/src/runtime/result-normalizer.js +183 -0
- package/src/runtime/retention.js +74 -0
- package/src/runtime/review.js +244 -0
- package/src/runtime/route-job.js +15 -0
- package/src/runtime/run-store.js +38 -0
- package/src/runtime/schedule.js +88 -0
- package/src/runtime/scheduler-state.js +434 -0
- package/src/runtime/scheduler.js +656 -0
- package/src/runtime/session-compactor.js +182 -0
- package/src/runtime/session-search.js +155 -0
- package/src/runtime/slack-inbound.js +249 -0
- package/src/runtime/ssrf.js +102 -0
- package/src/runtime/status-aggregator.js +330 -0
- package/src/runtime/task-contract.js +140 -0
- package/src/runtime/task-packet.js +107 -0
- package/src/runtime/task-router.js +140 -0
- package/src/runtime/telegram-inbound.js +1565 -0
- package/src/runtime/token-counter.js +134 -0
- package/src/runtime/token-estimator.js +59 -0
- package/src/runtime/tool-loop.js +200 -0
- package/src/runtime/transport-server.js +311 -0
- package/src/runtime/tui-server.js +411 -0
- package/src/runtime/ulid.js +44 -0
- package/src/security/ssrf-check.js +197 -0
- package/src/setup.js +369 -0
- package/src/shadow/bridge.js +303 -0
- package/src/skills/loader.js +84 -0
- package/src/tools/catalog.json +49 -0
- package/src/tools/cli-delegate.js +44 -0
- package/src/tools/mcp-client.js +106 -0
- package/src/tools/micro/cancel-task.js +6 -0
- package/src/tools/micro/complete-task.js +6 -0
- package/src/tools/micro/fail-task.js +6 -0
- package/src/tools/micro/http-fetch.js +74 -0
- package/src/tools/micro/index.js +36 -0
- package/src/tools/micro/lcm-recall.js +60 -0
- package/src/tools/micro/list-dir.js +17 -0
- package/src/tools/micro/list-skills.js +46 -0
- package/src/tools/micro/load-skill.js +38 -0
- package/src/tools/micro/memory-search.js +45 -0
- package/src/tools/micro/read-file.js +11 -0
- package/src/tools/micro/session-search.js +54 -0
- package/src/tools/micro/shell-exec.js +43 -0
- package/src/tools/micro/trigger-job.js +79 -0
- package/src/tools/micro/web-search.js +58 -0
- package/src/tools/micro/workspace-paths.js +39 -0
- package/src/tools/micro/write-file.js +14 -0
- package/src/tools/micro/write-memory.js +41 -0
- package/src/tools/registry.js +348 -0
- package/src/tools/tool-result-contract.js +36 -0
- package/src/tui/chat.js +835 -0
- package/src/tui/renderer.js +175 -0
- package/src/tui/socket-client.js +217 -0
- package/src/utils/canonical-json.js +29 -0
- package/src/utils/compaction.js +30 -0
- package/src/utils/env-loader.js +5 -0
- package/src/utils/errors.js +80 -0
- package/src/utils/fs.js +101 -0
- package/src/utils/ids.js +5 -0
- package/src/utils/model-context-limits.js +30 -0
- package/src/utils/token-budget.js +74 -0
- package/src/utils/usage-cost.js +25 -0
- package/src/utils/usage-metrics.js +14 -0
- package/vendor/smol-toml-1.5.2.tgz +0 -0
package/.env.example
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# ============================================================
|
|
2
|
+
# Nemoris — Environment Variables
|
|
3
|
+
# Copy this file to .env and fill in your values
|
|
4
|
+
# Run: nemoris setup (walks you through the essentials)
|
|
5
|
+
# ============================================================
|
|
6
|
+
|
|
7
|
+
# ---- Anthropic (required for cloud AI) --------------------
|
|
8
|
+
NEMORIS_ANTHROPIC_API_KEY= # Get from console.anthropic.com
|
|
9
|
+
|
|
10
|
+
# ---- OpenRouter (optional — fallback + Perplexity search) --
|
|
11
|
+
OPENROUTER_API_KEY= # Get from openrouter.ai
|
|
12
|
+
|
|
13
|
+
# ---- Telegram (required for Telegram channel) -------------
|
|
14
|
+
NEMORIS_TELEGRAM_BOT_TOKEN= # From @BotFather on Telegram
|
|
15
|
+
NEMORIS_TELEGRAM_CHAT_ID= # Your Telegram user/chat ID
|
|
16
|
+
NEMORIS_ALLOW_ANY_CHAT=false # true = accept messages from any chat (dev only)
|
|
17
|
+
NEMORIS_ALLOW_TELEGRAM_DELIVERY=true # false = suppress outbound Telegram messages
|
|
18
|
+
|
|
19
|
+
# ---- Slack (optional) -------------------------------------
|
|
20
|
+
SLACK_BOT_TOKEN= # xoxb-... from Slack App dashboard
|
|
21
|
+
SLACK_SIGNING_SECRET= # From Slack App dashboard → Basic Info
|
|
22
|
+
|
|
23
|
+
# ---- Ollama (optional — local inference) ------------------
|
|
24
|
+
# Install from https://ollama.com then run: nemoris setup ollama
|
|
25
|
+
OLLAMA_BASE_URL=http://localhost:11434 # Override if Ollama runs on a different port
|
|
26
|
+
NEMORIS_OLLAMA_MODEL=kimi-k2.5 # Default local model
|
|
27
|
+
|
|
28
|
+
# ---- Runtime tuning (optional) ----------------------------
|
|
29
|
+
NEMORIS_RATE_LIMIT_MAX=10 # Max messages per window (default: 10)
|
|
30
|
+
NEMORIS_RATE_LIMIT_WINDOW_MS=60000 # Rate limit window in ms (default: 60000)
|
|
31
|
+
NEMORIS_IDENTITY_CACHE_TTL_MS=300000 # Identity cache TTL in ms (default: 5 min)
|
|
32
|
+
|
|
33
|
+
# ---- Provider mode (required at startup) ------------------
|
|
34
|
+
NEMORIS_ALLOW_PROVIDER_MODE=remote # "remote" or "local"
|
|
35
|
+
NEMORIS_ALLOW_REMOTE_PROVIDER_MODE=true
|
|
36
|
+
|
|
37
|
+
# ---- Advanced / internal ----------------------------------
|
|
38
|
+
NEMORIS_AGENT_NAME= # Override default agent name
|
|
39
|
+
NEMORIS_LIVE_ROOT= # Override live root path
|
|
40
|
+
NEMORIS_INIT_MODE= # "fresh" forces re-initialisation
|
|
41
|
+
NEMORIS_QUIET=false # Suppress startup logs
|
|
42
|
+
ANTHROPIC_THINKING_ENABLED=false # Enable /think extended thinking mode
|
|
43
|
+
|
|
44
|
+
# ---- Semantic embeddings (local via Ollama nomic-embed-text) --
|
|
45
|
+
# NEMORIS_ALLOW_EMBEDDINGS=1
|
|
46
|
+
# NEMORIS_ALLOW_REMOTE_EMBEDDINGS=0
|
|
47
|
+
|
|
48
|
+
# ---- Feature flags ----------------------------------------
|
|
49
|
+
NEMORIS_WEBHOOK_SECRET= # Optional — validates Telegram webhook payloads
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lee Anderson
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
<p align="left">
|
|
2
|
+
<img src="assets/logo.svg" alt="Nemoris" width="600">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
[](https://npmjs.com/package/nemoris)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://github.com/amzer24/nemoris/actions/workflows/main.yml)
|
|
8
|
+
[](https://nodejs.org)
|
|
9
|
+
|
|
10
|
+
A personal AI agent runtime. Runs locally. Persistent memory, delivery guarantees, scheduled jobs, and self-healing — no cloud, no lock-in.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install -g nemoris
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Most agent frameworks give you a chatbot that forgets everything between sessions and silently drops messages when something breaks.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Why Nemoris
|
|
21
|
+
|
|
22
|
+
Nemoris fixes this with three things that actually work:
|
|
23
|
+
|
|
24
|
+
### Active Memory
|
|
25
|
+
SQLite-backed semantic memory with embeddings, salience scoring, deduplication, and compaction. Your agents remember what matters across sessions — not just within them.
|
|
26
|
+
|
|
27
|
+
### Delivery Guarantees
|
|
28
|
+
Criticality-classified message delivery with retry pipelines, ack tracking, and pending decision management. Messages don't get lost. Decisions don't fall through cracks.
|
|
29
|
+
|
|
30
|
+
### Task Contracts
|
|
31
|
+
Structured task lifecycle with state machines, escalation chains, and explicit completion signals. When an agent starts something, it finishes it — or tells you why it didn't.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Install globally
|
|
39
|
+
npm install -g nemoris
|
|
40
|
+
|
|
41
|
+
# Interactive setup (~2 minutes)
|
|
42
|
+
nemoris setup
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
You'll need an API key from Anthropic or OpenRouter — or just use Ollama for free local models.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Start the daemon
|
|
49
|
+
nemoris start
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The setup wizard connects a provider, optionally wires up Telegram, and starts your first agent. Coming from OpenClaw? Run `nemoris migrate` — agents, jobs, and memory import in under 2 minutes.
|
|
53
|
+
|
|
54
|
+
### Requirements
|
|
55
|
+
|
|
56
|
+
- **Node.js >= 22**
|
|
57
|
+
- **Ollama** (optional — free local models via [ollama.ai](https://ollama.ai))
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Providers
|
|
62
|
+
|
|
63
|
+
- **Anthropic** (Claude) — direct API with prompt caching
|
|
64
|
+
- **OpenRouter** — access to 100+ models
|
|
65
|
+
- **Ollama** — free local models, zero cloud dependency
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## What You Get
|
|
70
|
+
|
|
71
|
+
| Feature | What it does |
|
|
72
|
+
|---------|-------------|
|
|
73
|
+
| **Active Memory** | Semantic search, embeddings, salience scoring, dedup, compaction — all in SQLite |
|
|
74
|
+
| **Self-Healing** | Nurse system with health probes, automatic repair, rule promotion, severity-tiered notifications |
|
|
75
|
+
| **Exec Approval** | Side-effect gating — approve or deny shell commands from Telegram before they run |
|
|
76
|
+
| **Task Contracts** | State machine lifecycle, escalation chains, completion pings, multi-agent coordination |
|
|
77
|
+
| **Context Compaction** | DAG-based session summarisation — long conversations stay fast and relevant |
|
|
78
|
+
| **Runtime Resilience** | Circuit breaker, near-duplicate detection, idempotent retries |
|
|
79
|
+
| **Session Search** | FTS5 full-text search over conversation history via `/search` and `session_search` tool |
|
|
80
|
+
| **MCP Consumer** | Connect external MCP servers as native tools — filesystem, GitHub, databases, anything |
|
|
81
|
+
| **Vision** | Telegram photos processed by vision-capable models |
|
|
82
|
+
| **Scheduled Jobs** | Cron-triggered and ad-hoc jobs land in the same unified queue as interactive messages |
|
|
83
|
+
| **Multi-Agent** | Agents trigger each other via task contracts and completion pings |
|
|
84
|
+
| **Telegram** | Chat with agents from your phone — slash commands, photos, reactions |
|
|
85
|
+
| **OpenClaw Migration** | Full import of agents, jobs, and memory |
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## CLI Commands
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
nemoris setup # Interactive setup wizard
|
|
93
|
+
nemoris start # Start the daemon
|
|
94
|
+
nemoris stop # Stop the daemon
|
|
95
|
+
nemoris status # Show running agents, jobs, providers
|
|
96
|
+
nemoris doctor # Health check and dependency report
|
|
97
|
+
nemoris migrate # Import from OpenClaw
|
|
98
|
+
nemoris mcp list # Show connected MCP servers and tools
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Telegram Commands
|
|
102
|
+
|
|
103
|
+
| Command | Description |
|
|
104
|
+
|---------|-------------|
|
|
105
|
+
| `/switch` | Switch who you're talking to |
|
|
106
|
+
| `/who` | Show current agent |
|
|
107
|
+
| `/status` | System status and usage |
|
|
108
|
+
| `/cost` | Today / week / month spending totals |
|
|
109
|
+
| `/search` | Search conversation history |
|
|
110
|
+
| `/logs` | Tail recent daemon logs |
|
|
111
|
+
| `/model` | Change AI model — `/model sonnet \| haiku \| opus` |
|
|
112
|
+
| `/clear` | Start a fresh conversation |
|
|
113
|
+
| `/stop` | Cancel current task |
|
|
114
|
+
| `/compact` | Free up memory (keeps recent turns) |
|
|
115
|
+
| `/exec_approve <id>` | Approve a pending exec command |
|
|
116
|
+
| `/exec_deny <id>` | Deny a pending exec command |
|
|
117
|
+
| `/agents` | List available agents |
|
|
118
|
+
| `/help` | Show all commands |
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Architecture
|
|
123
|
+
|
|
124
|
+
Nemoris runs as a single background daemon on your machine — no Docker, no cloud. Inbound messages enter a unified queue alongside scheduled jobs. The drain loop hydrates context (memory, history, tools), calls the LLM, executes tool calls with approval gating, writes to memory, and delivers responses. The Nurse watches everything and repairs what breaks.
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
Telegram / MCP / CLI
|
|
128
|
+
│
|
|
129
|
+
┌─────▼──────┐
|
|
130
|
+
│ Inbound │
|
|
131
|
+
│ Handler │
|
|
132
|
+
└─────┬──────┘
|
|
133
|
+
│
|
|
134
|
+
┌─────▼──────┐ ┌────────────┐
|
|
135
|
+
│ Unified │◄────│ Scheduled │
|
|
136
|
+
│ Queue │ │ Jobs │
|
|
137
|
+
└─────┬──────┘ └────────────┘
|
|
138
|
+
│
|
|
139
|
+
┌─────▼──────┐
|
|
140
|
+
│ Drain │
|
|
141
|
+
│ Loop │
|
|
142
|
+
└─────┬──────┘
|
|
143
|
+
│
|
|
144
|
+
┌─────▼──────────────────────────────────┐
|
|
145
|
+
│ Executor │
|
|
146
|
+
│ ┌──────┐ ┌───────┐ ┌──────────────┐ │
|
|
147
|
+
│ │ LLM ├──► Tools ├──► Memory Write │ │
|
|
148
|
+
│ └──────┘ └───┬───┘ └──────────────┘ │
|
|
149
|
+
│ │ │
|
|
150
|
+
│ ┌──────▼──────┐ │
|
|
151
|
+
│ │ Exec Approve│ │
|
|
152
|
+
│ └─────────────┘ │
|
|
153
|
+
└─────┬──────────────────────────────────┘
|
|
154
|
+
│
|
|
155
|
+
┌─────▼──────┐ ┌────────────┐
|
|
156
|
+
│ Delivery │ │ Nurse │
|
|
157
|
+
│ Pipeline │ │ (healing) │
|
|
158
|
+
└─────┬──────┘ └──────┬─────┘
|
|
159
|
+
│ │
|
|
160
|
+
┌─────▼───┐ ┌────▼─────┐
|
|
161
|
+
│Telegram │ │ Probes & │
|
|
162
|
+
│Agent │ │ Repair │
|
|
163
|
+
│Webhook │ └──────────┘
|
|
164
|
+
└─────────┘
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Platform Support
|
|
170
|
+
|
|
171
|
+
| Platform | Service Manager | Status |
|
|
172
|
+
|----------|----------------|--------|
|
|
173
|
+
| macOS | launchd | Full support |
|
|
174
|
+
| Linux | systemd (user) | Full support |
|
|
175
|
+
| Windows | PM2 | Supported (WSL2 recommended) |
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Development
|
|
180
|
+
|
|
181
|
+
Requires Node.js >= 22.
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
git clone https://github.com/amzer24/nemoris.git
|
|
185
|
+
cd nemoris
|
|
186
|
+
npm install
|
|
187
|
+
npm test # 1179 tests
|
|
188
|
+
npm run test:e2e # End-to-end tests
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Agents are configured in TOML with their own identity files, memory, tool access, and workspace context. See `docs/` for specs and architecture decisions.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Contributing
|
|
196
|
+
|
|
197
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
|
|
198
|
+
|
|
199
|
+
Please read our [Code of Conduct](CODE_OF_CONDUCT.md) before participating.
|
|
200
|
+
|
|
201
|
+
## Security
|
|
202
|
+
|
|
203
|
+
See [SECURITY.md](SECURITY.md) for our security policy and how to report vulnerabilities.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
[MIT](LICENSE)
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
Nemoris is a local-first agent runtime for a single operator on a machine they control. It is powerful software: it can execute tools, talk to remote model providers, store local state, and deliver messages through channels like Telegram and Slack. Please read this file before deploying it on a machine that holds sensitive data.
|
|
4
|
+
|
|
5
|
+
## Supported Versions
|
|
6
|
+
|
|
7
|
+
Security fixes are currently targeted at:
|
|
8
|
+
|
|
9
|
+
- the latest `main` branch
|
|
10
|
+
- the latest published npm release
|
|
11
|
+
|
|
12
|
+
Older versions may not receive backported fixes.
|
|
13
|
+
|
|
14
|
+
## Reporting a Vulnerability
|
|
15
|
+
|
|
16
|
+
Please do not open public GitHub issues for security vulnerabilities.
|
|
17
|
+
|
|
18
|
+
Use one of these private channels instead:
|
|
19
|
+
|
|
20
|
+
- GitHub Security Advisories: [Report a vulnerability](https://github.com/amzer24/nemoris/security/advisories/new)
|
|
21
|
+
- Email fallback: `amzer24@gmail.com`
|
|
22
|
+
|
|
23
|
+
Please include:
|
|
24
|
+
|
|
25
|
+
- what you observed
|
|
26
|
+
- affected version or commit
|
|
27
|
+
- the smallest reliable reproduction
|
|
28
|
+
- impact assessment
|
|
29
|
+
- any mitigations you already tested
|
|
30
|
+
|
|
31
|
+
I will acknowledge a good-faith report as quickly as possible and work toward a coordinated fix before public disclosure.
|
|
32
|
+
|
|
33
|
+
## Threat Model
|
|
34
|
+
|
|
35
|
+
Nemoris is designed for:
|
|
36
|
+
|
|
37
|
+
- a single user
|
|
38
|
+
- a machine or account they control
|
|
39
|
+
- explicitly configured workspaces and delivery channels
|
|
40
|
+
- operator-reviewed tool use and provider configuration
|
|
41
|
+
|
|
42
|
+
Nemoris is not designed to be:
|
|
43
|
+
|
|
44
|
+
- a hardened multi-tenant sandbox
|
|
45
|
+
- a safe environment for arbitrary untrusted users
|
|
46
|
+
- a drop-in remote execution service for strangers
|
|
47
|
+
|
|
48
|
+
If you need those guarantees, isolate Nemoris at the OS, VM, or container level rather than relying on prompt rules alone.
|
|
49
|
+
|
|
50
|
+
## What Stays Local vs What Leaves the Machine
|
|
51
|
+
|
|
52
|
+
By default, Nemoris stores its runtime state locally under the install root, including:
|
|
53
|
+
|
|
54
|
+
- config manifests
|
|
55
|
+
- local state and SQLite databases
|
|
56
|
+
- auth profiles in `state/auth-profiles.json`
|
|
57
|
+
- daemon logs
|
|
58
|
+
|
|
59
|
+
Data leaves the machine when you enable external integrations, including:
|
|
60
|
+
|
|
61
|
+
- LLM provider calls to Anthropic, OpenRouter, OpenAI Codex, or other configured providers
|
|
62
|
+
- Telegram or Slack delivery and inbound messaging
|
|
63
|
+
- MCP servers or other network-capable tools
|
|
64
|
+
|
|
65
|
+
Treat those integrations as trust boundaries. Only enable the ones you intend to use.
|
|
66
|
+
|
|
67
|
+
## Security Expectations and Non-Goals
|
|
68
|
+
|
|
69
|
+
Nemoris aims to be secure by default for a personal local runtime, but there are important limits:
|
|
70
|
+
|
|
71
|
+
- tool access is policy-bounded, but the runtime is still operating on your machine
|
|
72
|
+
- remote providers can receive prompt content, tool output, and uploaded content needed to complete a turn
|
|
73
|
+
- delivery adapters can send content to third-party services once enabled
|
|
74
|
+
- local state files should be treated as sensitive operator data
|
|
75
|
+
|
|
76
|
+
This means Nemoris should be run with the least privilege that still lets it do useful work.
|
|
77
|
+
|
|
78
|
+
## Safe Deployment Guidance
|
|
79
|
+
|
|
80
|
+
Recommended:
|
|
81
|
+
|
|
82
|
+
- run Nemoris as your own user account, not a shared account
|
|
83
|
+
- keep workspaces narrow and intentional
|
|
84
|
+
- use least-privilege provider tokens
|
|
85
|
+
- leave delivery gates disabled until you are ready for live sends
|
|
86
|
+
- keep `.env` and `state/auth-profiles.json` private
|
|
87
|
+
- use explicit allowlists for Telegram/Slack users rather than broad access
|
|
88
|
+
- keep the runtime updated
|
|
89
|
+
|
|
90
|
+
Not recommended:
|
|
91
|
+
|
|
92
|
+
- pointing it at your whole home directory as a workspace
|
|
93
|
+
- running it as root
|
|
94
|
+
- sharing one install across untrusted users
|
|
95
|
+
- enabling remote delivery channels before validating auth and allowlists
|
|
96
|
+
|
|
97
|
+
## Sensitive Files
|
|
98
|
+
|
|
99
|
+
Handle these as secrets:
|
|
100
|
+
|
|
101
|
+
- `.env`
|
|
102
|
+
- `state/auth-profiles.json`
|
|
103
|
+
- any provider or delivery tokens
|
|
104
|
+
- daemon logs that may contain identifiers or operational details
|
|
105
|
+
|
|
106
|
+
Do not paste those files into public issues.
|
|
107
|
+
|
|
108
|
+
## Security-Focused Operations
|
|
109
|
+
|
|
110
|
+
Useful commands when validating a setup:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
nemoris doctor
|
|
114
|
+
nemoris status
|
|
115
|
+
nemoris logs
|
|
116
|
+
npm run publish:check
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
If you are recovering from a token, install, or daemon problem, see [`docs/RECOVERY-FLOWS.md`](docs/RECOVERY-FLOWS.md).
|
package/bin/nemoris
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
SCRIPT_PATH=$0
|
|
5
|
+
while [ -L "$SCRIPT_PATH" ]; do
|
|
6
|
+
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$SCRIPT_PATH")" && pwd)
|
|
7
|
+
LINK_TARGET=$(readlink "$SCRIPT_PATH")
|
|
8
|
+
case "$LINK_TARGET" in
|
|
9
|
+
/*) SCRIPT_PATH="$LINK_TARGET" ;;
|
|
10
|
+
*) SCRIPT_PATH="$SCRIPT_DIR/$LINK_TARGET" ;;
|
|
11
|
+
esac
|
|
12
|
+
done
|
|
13
|
+
|
|
14
|
+
ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$SCRIPT_PATH")/.." && pwd)
|
|
15
|
+
FILTERED_NODE_OPTIONS=""
|
|
16
|
+
SKIP_NEXT=0
|
|
17
|
+
|
|
18
|
+
for ARG in ${NODE_OPTIONS-}; do
|
|
19
|
+
if [ "$SKIP_NEXT" = "1" ]; then
|
|
20
|
+
SKIP_NEXT=0
|
|
21
|
+
case "$ARG" in
|
|
22
|
+
*disable_autoselectfamily.js*) continue ;;
|
|
23
|
+
*) FILTERED_NODE_OPTIONS="$FILTERED_NODE_OPTIONS $ARG"; continue ;;
|
|
24
|
+
esac
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
case "$ARG" in
|
|
28
|
+
--require)
|
|
29
|
+
SKIP_NEXT=1
|
|
30
|
+
;;
|
|
31
|
+
--require=*disable_autoselectfamily.js*)
|
|
32
|
+
;;
|
|
33
|
+
*)
|
|
34
|
+
FILTERED_NODE_OPTIONS="$FILTERED_NODE_OPTIONS $ARG"
|
|
35
|
+
;;
|
|
36
|
+
esac
|
|
37
|
+
done
|
|
38
|
+
|
|
39
|
+
FILTERED_NODE_OPTIONS=$(printf "%s" "$FILTERED_NODE_OPTIONS" | sed 's/^ //')
|
|
40
|
+
if [ -n "$FILTERED_NODE_OPTIONS" ]; then
|
|
41
|
+
export NODE_OPTIONS="$FILTERED_NODE_OPTIONS"
|
|
42
|
+
else
|
|
43
|
+
unset NODE_OPTIONS
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
exec node "$ROOT_DIR/src/cli.js" "$@"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Example agent configuration — copy this to create your own agent.
|
|
2
|
+
#
|
|
3
|
+
# cp agent.example.toml myagent.toml
|
|
4
|
+
# Then edit the values below.
|
|
5
|
+
|
|
6
|
+
id = "myagent"
|
|
7
|
+
primary_lane = "interactive_primary"
|
|
8
|
+
memory_policy = "default"
|
|
9
|
+
tool_policy = "interactive_safe"
|
|
10
|
+
soul_ref = "config/identity/myagent-soul.md"
|
|
11
|
+
purpose_ref = "config/identity/myagent-purpose.md"
|
|
12
|
+
|
|
13
|
+
# Where this agent reads/writes workspace files.
|
|
14
|
+
# Relative to the Nemoris install directory.
|
|
15
|
+
workspace_root = "workspace"
|
|
16
|
+
|
|
17
|
+
# Files loaded into context at the start of each turn (optional).
|
|
18
|
+
# workspace_context_files = ["MEMORY.md"]
|
|
19
|
+
# workspace_context_cap = 8000
|
|
20
|
+
|
|
21
|
+
[limits]
|
|
22
|
+
max_tokens_per_turn = 16000
|
|
23
|
+
max_tool_calls_per_turn = 6
|
|
24
|
+
max_runtime_seconds = 120
|
|
25
|
+
|
|
26
|
+
[access]
|
|
27
|
+
workspace = "rw"
|
|
28
|
+
network = "restricted"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id = "assistant"
|
|
2
|
+
primary_lane = "interactive_primary"
|
|
3
|
+
memory_policy = "default"
|
|
4
|
+
tool_policy = "interactive_safe"
|
|
5
|
+
soul_ref = "config/identity/default-soul.md"
|
|
6
|
+
purpose_ref = "config/identity/default-purpose.md"
|
|
7
|
+
workspace_root = "~/.nemoris/workspace"
|
|
8
|
+
|
|
9
|
+
[interaction_contract]
|
|
10
|
+
ack_mode = "immediate"
|
|
11
|
+
progress_mode = "milestone"
|
|
12
|
+
notify_on_done = true
|
|
13
|
+
notify_on_error = true
|
|
14
|
+
|
|
15
|
+
[limits]
|
|
16
|
+
max_tokens_per_turn = 16000
|
|
17
|
+
max_tool_calls_per_turn = 6
|
|
18
|
+
max_runtime_seconds = 120
|
|
19
|
+
|
|
20
|
+
[access]
|
|
21
|
+
workspace = "rw"
|
|
22
|
+
network = "restricted"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
id = "orchestrator"
|
|
2
|
+
soul_ref = "config/identity/orchestrator-soul.md"
|
|
3
|
+
purpose_ref = "config/identity/orchestrator-purpose.md"
|
|
4
|
+
primary_lane = "local_cheap"
|
|
5
|
+
fallback_lane = "interactive_fallback"
|
|
6
|
+
tool_policy = "orchestrator"
|
|
7
|
+
memory_policy = "orchestrator"
|
|
8
|
+
|
|
9
|
+
[limits]
|
|
10
|
+
max_tokens_per_turn = 2700
|
|
11
|
+
|
|
12
|
+
[routing.static]
|
|
13
|
+
"heartbeat-check" = "heartbeat"
|
|
14
|
+
|
|
15
|
+
[routing.dynamic]
|
|
16
|
+
enabled = true
|
|
17
|
+
model_lane = "local_cheap"
|
|
18
|
+
max_routing_tokens = 500
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
default_interactive_profile = "gateway_telegram_main"
|
|
2
|
+
default_scheduler_profile = "shadow_scheduler"
|
|
3
|
+
default_interactive_profile_standalone = "standalone_operator"
|
|
4
|
+
default_peer_profile_standalone = "standalone_peer"
|
|
5
|
+
|
|
6
|
+
[profiles.shadow_scheduler]
|
|
7
|
+
adapter = "shadow"
|
|
8
|
+
enabled = true
|
|
9
|
+
target = "scheduler_log"
|
|
10
|
+
|
|
11
|
+
[profiles.gateway_preview_main]
|
|
12
|
+
adapter = "openclaw_cli"
|
|
13
|
+
enabled = true
|
|
14
|
+
channel = "telegram"
|
|
15
|
+
account_id = "default"
|
|
16
|
+
chat_id = "7781763328"
|
|
17
|
+
silent = true
|
|
18
|
+
dry_run = true
|
|
19
|
+
|
|
20
|
+
[profiles.gateway_telegram_main]
|
|
21
|
+
adapter = "openclaw_cli"
|
|
22
|
+
enabled = false
|
|
23
|
+
channel = "telegram"
|
|
24
|
+
account_id = "default"
|
|
25
|
+
chat_id = "7781763328"
|
|
26
|
+
silent = true
|
|
27
|
+
dry_run = false
|
|
28
|
+
|
|
29
|
+
[profiles.peer_preview]
|
|
30
|
+
adapter = "openclaw_peer"
|
|
31
|
+
enabled = true
|
|
32
|
+
dry_run = true
|
|
33
|
+
timeout_ms = 15000
|
|
34
|
+
|
|
35
|
+
[profiles.peer_live]
|
|
36
|
+
adapter = "openclaw_peer"
|
|
37
|
+
enabled = false
|
|
38
|
+
dry_run = false
|
|
39
|
+
timeout_ms = 15000
|
|
40
|
+
|
|
41
|
+
[profiles.telegram_main]
|
|
42
|
+
adapter = "telegram"
|
|
43
|
+
enabled = false
|
|
44
|
+
channel = "telegram"
|
|
45
|
+
account_id = "default"
|
|
46
|
+
chat_id = "7781763328"
|
|
47
|
+
bot_token_env = "NEMORIS_TELEGRAM_BOT_TOKEN"
|
|
48
|
+
|
|
49
|
+
[profiles.standalone_operator]
|
|
50
|
+
adapter = "local_file"
|
|
51
|
+
enabled = true
|
|
52
|
+
target = "operator"
|
|
53
|
+
|
|
54
|
+
[profiles.standalone_peer]
|
|
55
|
+
adapter = "local_file"
|
|
56
|
+
enabled = true
|
|
57
|
+
target = "peer_queue"
|
|
58
|
+
|
|
59
|
+
[profiles.standalone_http_operator]
|
|
60
|
+
adapter = "standalone_http"
|
|
61
|
+
enabled = false
|
|
62
|
+
dry_run = false
|
|
63
|
+
base_url = "${NEMORIS_TRANSPORT_URL}"
|
|
64
|
+
auth_token_env = "NEMORIS_TRANSPORT_TOKEN"
|
|
65
|
+
timeout_ms = 5000
|
|
66
|
+
|
|
67
|
+
[profiles.standalone_http_peer]
|
|
68
|
+
adapter = "standalone_http"
|
|
69
|
+
enabled = false
|
|
70
|
+
dry_run = false
|
|
71
|
+
base_url = "${NEMORIS_TRANSPORT_URL}"
|
|
72
|
+
auth_token_env = "NEMORIS_TRANSPORT_TOKEN"
|
|
73
|
+
timeout_ms = 5000
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Help the user accomplish their goals efficiently.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Route incoming jobs to the most appropriate agent based on job type, agent capabilities, and current load.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
You are the Nemoris orchestrator — a routing and coordination agent that decides which agent handles each job.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[targets.workspace_health]
|
|
2
|
+
job_id = "workspace-health"
|
|
3
|
+
default_mode = "provider"
|
|
4
|
+
default_model_override = "ollama/qwen3:8b"
|
|
5
|
+
default_timeout_ms = 60000
|
|
6
|
+
allowed_knobs = ["report_guidance", "retrieval_blend", "model_override"]
|
|
7
|
+
recommended_variants = ["baseline", "focus_concrete", "retrieval_lexical_heavy", "retrieval_embedding_heavy", "report_model_bump"]
|
|
8
|
+
|
|
9
|
+
[targets.memory_rollup]
|
|
10
|
+
job_id = "memory-rollup"
|
|
11
|
+
default_mode = "provider"
|
|
12
|
+
default_model_override = "ollama/qwen3:8b"
|
|
13
|
+
default_timeout_ms = 75000
|
|
14
|
+
allowed_knobs = ["report_guidance", "retrieval_blend", "model_override"]
|
|
15
|
+
recommended_variants = ["baseline", "focus_concrete", "retrieval_lexical_heavy", "retrieval_embedding_heavy", "report_model_bump"]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
id = "heartbeat-check"
|
|
2
|
+
trigger = "every:30m"
|
|
3
|
+
task_type = "heartbeat"
|
|
4
|
+
agent_id = "assistant"
|
|
5
|
+
model_lane = "local_cheap"
|
|
6
|
+
output_target = "inbox"
|
|
7
|
+
idempotency_key = "heartbeat-check"
|
|
8
|
+
|
|
9
|
+
[budget]
|
|
10
|
+
max_tokens = 3000
|
|
11
|
+
max_runtime_seconds = 20
|
|
12
|
+
|
|
13
|
+
[retry]
|
|
14
|
+
max_attempts = 1
|
|
15
|
+
|
|
16
|
+
[stop]
|
|
17
|
+
halt_on_policy_error = true
|
|
18
|
+
halt_on_budget_exceeded = true
|
|
19
|
+
|
|
20
|
+
[interaction_contract]
|
|
21
|
+
ack_mode = "silent"
|
|
22
|
+
progress_mode = "none"
|
|
23
|
+
notify_on_done = false
|
|
24
|
+
notify_on_error = true
|
|
25
|
+
requires_pingback = false
|
|
26
|
+
pingback_target = "scheduler_log"
|
|
27
|
+
completion_signal = "heartbeat_ok"
|
|
28
|
+
failure_signal = "heartbeat_error"
|
|
29
|
+
handoff_format = "concise_status"
|
|
30
|
+
completion_sections = ["status"]
|