Skip to content

Commit f957fdd

Browse files
DavidsonGomesclaude
andcommitted
release: v0.32.0 — Plugin System v1 + security hardening + community fixes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f43736f commit f957fdd

6 files changed

Lines changed: 152 additions & 3 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ config/providers.json
4949
# ── Runtime data & logs ───────────────────
5050
backups/
5151
ADWs/logs/
52+
.claude/scheduled_tasks.lock
5253
# Runtime DBs may be created in repo root, dashboard/data/ or dashboard/backend/
5354
*.db
5455
*.db-shm

CHANGELOG.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,62 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.32.0] - 2026-04-24
9+
10+
Minor release introducing the **Plugin System v1** — a full extensibility layer with 15 capabilities, pre-install security scanning, per-capability toggles, update diff previews, and a reference plugin (`pm-essentials`). Ships alongside a security-hardening pass (PRD #37) and a batch of community-reported fixes.
11+
12+
### Added
13+
14+
- **Plugin System v1 — 15 capabilities, security gate, reference plugin (#41)** — end-to-end extensibility: Pydantic-validated manifests, git/zip/local install with SHA-256 integrity check, semver-aware migration runner with rollback, atomic file ops, Claude Code hooks dispatcher (PreToolUse / PostToolUse / Stop / SubagentStop) with per-plugin SQLite circuit breaker, and crash recovery for orphaned installs. Capabilities include agents, skills, commands, rules, routines, heartbeats, widgets, readonly_data, writable_data, claude_hooks, goals, tasks, triggers, MCP servers and custom UI pages. Plugin-contributed rows are tagged with `source_plugin` across `tickets`, `projects`, `goals`, `missions`, `goal_tasks` and `triggers` so uninstall cleans them without touching user data.
15+
- **Plugins REST API + dashboard UI** — full CRUD (`GET/POST/PATCH/DELETE /api/plugins`), curated marketplace listing, upload endpoint (ZIP / tar.gz, 20 MB cap, zip-slip guard), preview-before-install flow, audit log, and per-plugin widget limits per tier (essential / standard / power). New `/plugins` page with marketplace grid, install wizard (source → security scan → config → confirm), plugin detail with widgets, capabilities toggles, MCP banner, and Update button with diff preview (Wave 1.2). New `/mcp-servers` system page aggregating `~/.claude.json` entries grouped by plugin / native with masked env values.
16+
- **Plugins CLI (`cli/src/commands/plugin.mjs`)**`plugin init` (scaffold from template), `plugin install <source>`, `plugin list`, `plugin uninstall <slug>`, `plugin update <slug>`. Starter template under `cli/templates/plugin-skeleton/` ships with a pre-filled `plugin.yaml`, sample agent, and README.
17+
- **Plugin security scan (Wave 2.5)** — hybrid regex + LLM scanner with 13 pattern categories, 57-domain whitelist, anti-hallucination guard, 7-day cache in `plugin_scan_cache`, and an APPROVE / WARN / BLOCK adaptive button with admin BLOCK override. New `plugin-security-scan` skill exposes the semantic scanner.
18+
- **Plugin MCP servers (Wave 2.3)** — plugins can declare MCP servers with command whitelist and shell-metachar block; 6-layer atomic write to `~/.claude.json` with flock, timestamped backups (retention 10) and drift detection (name + args_hash match). UI shows a restart-Claude-CLI callout on install and an MCP diff section in update preview.
19+
- **Plugin integrations (Wave 2.2r)** — plugins can declare env-var-based integrations with optional HTTP health checks running as in-process heartbeats (zero Claude CLI overhead). New Plugin Integrations section on `/integrations` with schema-driven configure modal and secret masking.
20+
- **Plugin custom UI (Wave 2.1)** — plugins can contribute React pages mounted at `/plugins-ui/:slug/*`, sidebar groups, and writable SQLite resources with column allowlist + jsonschema validation. `window.EvoNexus` SDK injected post-login for plugin frontends.
21+
- **Plugin per-capability toggles (Wave 1.1)** — granular ON/OFF per capability without uninstalling the plugin. Disable cascades to `.claude/{agents,skills,commands}/plugin-{slug}-*` (rename to `.disabled`), routines skipped by the scheduler, hooks and heartbeats skipped by their dispatchers.
22+
- **Plugin management skills**`plugin-install`, `plugin-list`, `plugin-uninstall`, `plugin-update`, `plugin-marketplace`, `plugin-health` expose plugin operations to all agents.
23+
- **`agent_meta_seed.py`** — 38-agent seed served via `GET /api/agent-meta` (in-process cache + invalidation). Plugin agents contribute metadata via `manifest.metadata.icon` + per-agent avatars; frontend registry (`agent-meta.ts`) is hydrated once post-login and plugin cards render custom icons with img fallback.
24+
- **Merged routines listing**`/api/routines` now merges declared routines (via `discover_routines()`) with execution metrics so newly installed plugin routines and unrun core routines show up in `/routines` with zeroed metrics.
25+
- **`EVONEXUS_DEV=1`** — toggles Flask's auto-reloader (`debug=True`, `use_reloader=True`) for backend development. Default remains off; production uses systemd/docker.
26+
- **`docker-compose.proxy.yml` (#45)** — sibling compose file for reverse-proxy hosts (Coolify, Dokploy, Traefik, Caddy): uses `expose:` instead of `ports:` so the proxy owns external traffic while containers stay reachable by name inside the Docker network. Volumes named identically to `hub.yml` for no-loss migration.
27+
- **`docs/knowledge-database.md` (#46)** — provider cheat-sheet for Supabase / Neon / Railway PgBouncer gotchas (port 5432 vs 6543, Supabase IPv6-only edge case, error reference table). Inline hint added under the Knowledge connections wizard input.
28+
- **`scripts/clean-history.sh` (#26)** — safe-by-default dry-run helper that clones the remote as `--mirror` and previews removal of ~283 MB of orphaned PNG avatar blobs via `git filter-repo --path-regex`. Verifies develop/main HEAD trees are byte-identical and all tags preserved before the maintainer force-pushes. `CONTRIBUTING.md` gains the partial-clone recipe (`git clone --filter=blob:none`) so contributors download ~10 MB instead of ~290 MB in the interim.
29+
30+
### Changed
31+
32+
- **`/api/health/deep` now requires an authenticated admin session** (PRD security hardening, #37) — previously leaked filesystem paths, provider identity, secret-key source, and error details to unauthenticated callers. `/api/health` is now a minimal public liveness probe returning status only. Tooling scraping `/api/health/deep` for internals must authenticate.
33+
- **Frontend route splitting (#37)** — top-level route bundles are code-split so the main chunk size drops substantially on first load.
34+
- **Plugin install sources restricted (hardening)**`resolve_source` now rejects local filesystem paths, `file://`, `ssh://` and non-HTTPS schemes with a clear `ValueError`. Only `github:`, `https://` tarballs, or uploaded ZIP / tar.gz archives are accepted. Closes the doc/code mismatch where the skill promised rejection but the code accepted anything via `Path(s)`.
35+
- **Plugin triggers ship disabled by default** — regardless of YAML value, unless explicitly `"true"`, so a malicious plugin cannot auto-fire hooks on install.
36+
- **Telegram notifications moved from skills to routines**`run_skill(notify_telegram=True)` appends a one-shot send instruction at the end of the prompt, guaranteeing exactly one send per execution (was duplicated when skills embedded the instruction themselves). Skills cleaned: `prod-end-of-day`, `prod-good-morning`, `pulse-faq-sync`, `pulse-daily`.
37+
- **Integration status verifies all declared env keys (#49)**`list_integrations` previously checked only a single key per entry, so Evolution API / Evolution Go / Evo CRM showed as "configured" with only the token set (URL missing) or vice-versa. Schema is now `keys: list[str]`; an integration is considered configured only when every declared key is non-empty.
38+
- **Bling integration keys corrected (#49)**`BLING_ACCESS_TOKEN` (which existed nowhere in the repo) replaced with `BLING_CLIENT_ID` / `BLING_CLIENT_SECRET` used by the real OAuth2 flow. **Migration:** users who set `BLING_ACCESS_TOKEN` manually must run `make bling-auth` to obtain the OAuth credentials.
39+
- **Omie integration now requires both `OMIE_APP_KEY` and `OMIE_APP_SECRET`** — backend was only checking the key, so a half-configured Omie appeared green (#49).
40+
41+
### Fixed
42+
43+
- **`scripts/start-services.sh` no longer kills unrelated processes (#18)**`pkill -f 'python.*app.py'` matched every `app.py` on the host, killing unrelated services. Replaced with an explicit pinned match on the venv interpreter + absolute script path, and TCP 8080 (or `EVONEXUS_PORT`) is now freed directly via `fuser` / `lsof` before restart — falls back to `lsof -ti tcp:$PORT | kill` when `fuser` is absent (BSD-ish / macOS).
44+
- **Terminal client detects RFC1918 + CGNAT hostnames as local (#35)** — previously only `localhost` / `127.0.0.1` were treated as local, so bare-metal installs behind no reverse proxy fell back to `/terminal` on the same origin, which didn't exist. Heuristic widened to RFC1918 (`10/8`, `172.16/12`, `192.168/16`), RFC6598 CGNAT (`100.64.0.0/10`, common on Brazilian VPS), link-local (`169.254/16`), IPv6 loopback (`::1`), and IPv6 link-local (`fe80:`). New `VITE_TERMINAL_URL` explicit override for edge cases (reverse proxy on a private IP). `deriveWsBase` rewritten to use `URL()` instead of a regex that silently dropped the `https` branch and mangled uppercase schemes.
45+
- **Plugin uninstall sweeps leftover `plugin-{slug}-*` files**`reverse_remove_from_manifest` walks `.install-manifest.json`, but if that manifest is missing / corrupt / predates the name-rewrite change, files in `.claude/{agents,skills,rules,commands}/` stayed behind and the next install hit 409. An unconditional sweep runs after the manifest pass.
46+
- **Plugin install seeds an anchor mission per plugin** — plugins seeding projects without `mission_id` left them orphaned and invisible in `/goals`. Installer now synthesizes one mission per plugin (`plugin-{slug}-root`) when the YAML doesn't declare one and links all orphan projects to it. Missions get `source_plugin` too so uninstall cleans them.
47+
- **Plugin widget listing reads `ui_entry_points.widgets`** — was reading a non-existent `manifest.manifest.widgets` key and returning `[]` regardless of mount point.
48+
- **Plugin install falls back to first `migrations/*.sql`** when `migrations/install.sql` is missing, so plugin authors using the `NNN_description.sql` convention don't have to rename.
49+
- **Plugin skills install as directory trees**`copy_with_manifest` now copies `skills/<name>/` as a whole directory and rewrites the `name:` field inside `SKILL.md` to match the prefixed dirname, enforcing the Claude Code contract that `name` == filename. Agents / commands / rules similarly get their `name:` frontmatter rewritten.
50+
- **Plugin `GET /api/plugins/<slug>/audit` endpoint** — was missing, so `PluginDetail.tsx` hit the SPA catch-all, got `index.html` back, and threw `Unexpected token '<'` on JSON parse.
51+
- **Plugin heartbeat agent references get auto-prefixed** — plugins can declare `assignee_agent: pm-nova` instead of the full `plugin-pm-essentials-pm-nova`; the installer rewrites bare references to match the prefixed file.
52+
- **Plugin update endpoint now uses `resolve_source`** — works from `github:` / `https://` / uploaded path (was local-only).
53+
- **`PATCH /api/triggers/<id>`** — the endpoint was simply missing.
54+
- **Brain Repo sync no longer blocks HTTP requests** — new `brain_repo/job_runner.py` background executor serialises sync / milestone / bootstrap ops. `POST /sync/force`, `/sync/cancel`, `/tag/milestone` now enqueue jobs and return immediately; `GET /status` exposes job state. `/backups` and `/brain-repo` pages poll state and expose a Cancel button (cooperative `cancel_requested` flag checked between git steps).
55+
- **`ticket_janitor.py`** — guards against `IsADirectoryError` on the health-check path that crashed on certain setups.
56+
57+
### Security
58+
59+
- **Pre-install plugin security scanning** — every plugin installed from an external source runs through a hybrid regex + LLM scanner before any file lands on disk. APPROVE / WARN / BLOCK with admin override + audit trail.
60+
- **`/api/health/deep` requires admin** — see Changed.
61+
- **Plugin install sources restricted to HTTPS / github / upload** — see Changed.
62+
- **Plugin triggers disabled by default** — see Changed.
63+
864
## [0.31.0] - 2026-04-24
965

1066
Minor release introducing the **Brain Repo** — automatic GitHub versioning of workspace memory and customizations — plus a full onboarding wizard and a unified `/backups` page covering Local, S3 and Brain Repo destinations.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ It turns a single CLI installation into a team of **38 specialized agents** orga
3333

3434
### Why EvoNexus?
3535

36-
- **Markdown-first agents** — agents are `.md` files with system prompts, not code. No SDK, no plugin runtime, no compile step. Add an agent by dropping a file in `.claude/agents/`
36+
- **Markdown-first agents** — agents are `.md` files with system prompts, not code. No SDK, no compile step. Add an agent by dropping a file in `.claude/agents/`, or package reusable bundles via the plugin system (see [`docs/introduction.md`](docs/introduction.md))
3737
- **Skills as instructions** — reusable capabilities are markdown too. 190+ skills covering finance, community, social, engineering, data, legal, HR, ops, product, CS
3838
- **Multi-provider by design** — default runs on Anthropic's native `claude` CLI, but can switch to OpenRouter, OpenAI, Gemini, AWS Bedrock, Google Vertex, or Codex Auth via [OpenClaude](https://www.npmjs.com/package/@gitlawb/openclaude) without touching a line of code. Your keys, your model choice, no vendor lock-in
3939
- **MCP integrations** — first-class support for Google Calendar, Gmail, GitHub, Linear, Telegram, Canva, Notion, and more via the Model Context Protocol

cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@evoapi/evo-nexus",
3-
"version": "0.31.0",
3+
"version": "0.32.0",
44
"description": "Unofficial open source toolkit for Claude Code — AI-powered business operating system",
55
"keywords": [
66
"claude-code",

docs/llms-full.txt

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6706,6 +6706,98 @@ EvoNexus is MIT-licensed, built by [Evolution Foundation](https://evolutionfound
67066706
It's designed to be forked and adapted. Add your own agents, skills, routines, and integrations. The architecture is markdown-first — no complex plugin systems, just files that Claude Code reads.
67076707

67086708

6709+
---
6710+
6711+
# Knowledge — database setup
6712+
6713+
The Knowledge base stores chunked documents with vector embeddings in
6714+
PostgreSQL + pgvector. This page collects the gotchas you need to know
6715+
before pointing it at a managed database.
6716+
6717+
## Requirements
6718+
6719+
- **PostgreSQL 14+** with the `pgvector` extension available.
6720+
- **Session mode** connections. Transaction pooling (PgBouncer in
6721+
transaction-pooling mode) is **not supported**, see below.
6722+
- Privileges sufficient to run `CREATE EXTENSION IF NOT EXISTS vector`,
6723+
`CREATE INDEX ... USING hnsw`, and Alembic migrations on first connect.
6724+
6725+
## Provider cheat-sheet
6726+
6727+
### Supabase
6728+
6729+
Supabase exposes **two** Postgres endpoints per project:
6730+
6731+
| Endpoint | Port | Mode | Use here? |
6732+
|--------------------------------------------------|------|-------------------|-----------|
6733+
| Direct connection (`db.<ref>.supabase.co`) | 5432 | Session | **Yes** |
6734+
| Pooler (`aws-*-*.pooler.supabase.com`) | 6543 | Transaction pool | **No** |
6735+
| Session pooler (`aws-*-*.pooler.supabase.com`) | 5432 | Session | Yes |
6736+
6737+
Use the direct connection string Supabase shows in
6738+
*Project Settings → Database → Connection string → URI*. It looks like:
6739+
6740+
```
6741+
postgresql://postgres:<password>@db.<ref>.supabase.co:5432/postgres
6742+
```
6743+
6744+
If you pasted the pooler URL (port `6543` or hostname containing `pooler`)
6745+
the wizard fails fast with a `Knowledge is not compatible with PgBouncer
6746+
in transaction pooling mode` error. That's by design — the Alembic
6747+
migrations and `CREATE INDEX ... USING hnsw` statements rely on prepared
6748+
statements and session-scoped state that PgBouncer's transaction pooling
6749+
silently drops.
6750+
6751+
If you genuinely need pooling (for example, your Supabase project is on
6752+
a plan with a connection limit), use the **session pooler** endpoint
6753+
Supabase exposes on port `5432`. It keeps prepared statements working
6754+
while still bounding the number of backend connections.
6755+
6756+
#### IPv6-only direct connection
6757+
6758+
New Supabase projects default to IPv6-only on the direct endpoint. If
6759+
your host does not have IPv6 connectivity the connection will fail with
6760+
6761+
```
6762+
connection to server at "db.<ref>.supabase.co" failed: Network is unreachable
6763+
```
6764+
6765+
Workarounds:
6766+
6767+
1. Enable the IPv4 add-on in Supabase (paid feature).
6768+
2. Use the session pooler URL on port `5432` — it is dual-stack.
6769+
3. Run Knowledge on a host with native IPv6 (most cloud providers do).
6770+
6771+
### Neon, Railway, Render, Fly, Heroku
6772+
6773+
Same rule: give Knowledge the **session-mode** connection string. Neon
6774+
and Railway both expose a pooler; pick the non-pooler URL from the
6775+
dashboard. The fast-fail check triggers on port `6543` and on hostnames
6776+
containing `pooler`.
6777+
6778+
### Self-hosted Postgres
6779+
6780+
Nothing special — just make sure `pgvector` is installed
6781+
(`CREATE EXTENSION vector` runs as superuser or owner of the target
6782+
database) and that the user in your connection string can create
6783+
extensions and indexes.
6784+
6785+
## Error reference
6786+
6787+
| Message snippet | Cause | Fix |
6788+
|--------------------------------------------------|-------------------------------------------------------|-----|
6789+
| `hostname contains 'pooler'` | You pasted the Supabase/Neon transaction-pool URL | Swap for the direct (`5432`) connection string |
6790+
| `port 6543 (Supabase transaction pooler)` | Same as above, detected by port | Same |
6791+
| `Network is unreachable` + IPv6 address | Host has no IPv6, direct endpoint is IPv6-only | Session pooler URL or IPv4 add-on |
6792+
| `could not load extension "vector"` | pgvector not installed on the cluster | `CREATE EXTENSION vector;` as a role with privileges |
6793+
| `permission denied to create extension "vector"` | Role lacks `CREATE` on the database | Grant it, or run the `CREATE EXTENSION` yourself |
6794+
6795+
## Related
6796+
6797+
- Wizard: **Knowledge → Connections → New** in the dashboard.
6798+
- Source for the validation: `dashboard/backend/knowledge/auto_migrator.py`.
6799+
6800+
67096801
---
67106802

67116803
# OpenAI Codex (OAuth) — Provider Guide

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "evo-nexus"
3-
version = "0.31.0"
3+
version = "0.32.0"
44
description = "Unofficial open source toolkit for Claude Code — AI-powered business operating system"
55
requires-python = ">=3.10"
66
dependencies = [

0 commit comments

Comments
 (0)