Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
a5c9413
Merge branch 'chore/standardize-readmes-2026-05' into main
DavidsonGomes May 6, 2026
31d000a
docs(org): update GitHub URLs from EvolutionAPI to evolution-foundation
DavidsonGomes May 6, 2026
7f5dd76
feat(licensing): headless auto-activation via EVOLUTION_OPERATOR_EMAIL
DavidsonGomes May 12, 2026
0b945c6
ci: add feature/hermes-runtime to CI and Docker publish triggers
hermes-agent May 23, 2026
5cb2320
ci: switch Docker publish from Docker Hub to GHCR (ghcr.io/pedrotecinf)
hermes-agent May 23, 2026
2fb353e
ci: trigger docker publish with push event
hermes-agent May 23, 2026
40df1ff
ci: use GHCR_PAT secret for registry login
hermes-agent May 23, 2026
ba05dd4
feat: add Hermes runtime support
hermes-agent May 23, 2026
fdc520d
feat: add Hermes runtime provider
May 23, 2026
86c9115
feat: integrate Hermes provider into terminal-server and dashboard
pedrotecinf May 23, 2026
e451d25
ci: use native arm64 runners instead of QEMU emulation
pedrotecinf May 23, 2026
9e87827
feat(providers): add CLI selector for OmniRouter (openclaude/hermes)
pedrotecinf May 23, 2026
3670f39
feat(docker): install Hermes Agent CLI in Swarm images
pedrotecinf May 23, 2026
5ee0f2d
feat: add secure Hermes UI proxy in dashboard
pedrotecinf May 23, 2026
172d273
fix(docker): add git and jq to dashboard runtime image
pedrotecinf May 23, 2026
db5b72e
fix(docker): replace Hermes install script with PyPI package
pedrotecinf May 23, 2026
5ff3a53
fix(dashboard): correct hermes command and make it non-critical
pedrotecinf May 23, 2026
42ca345
fix(dashboard): Hermes UI polish — i18n, CLI badges, error page
pedrotecinf May 23, 2026
32fbfaa
fix(terminal): use -z instead of --skills for Hermes agent persona
pedrotecinf May 23, 2026
caff748
fix(dashboard): remove unused ExternalLink import breaking CI build
pedrotecinf May 23, 2026
369b293
fix(hermes-proxy): strip X-Frame-Options and CSP headers for iframe
pedrotecinf May 23, 2026
84a40af
fix(terminal): reorder hermes -z flag before chat subcommand
pedrotecinf May 23, 2026
a6b5af7
feat(hermes): profiles for agent persona + proxy asset rewrite + volume
pedrotecinf May 23, 2026
88d5079
fix(hermes): copy base config to agent profiles on sync
pedrotecinf May 23, 2026
fbe4c09
fix(hermes): rewrite JS API paths in proxy + env vars with EVONEXUS p…
pedrotecinf May 23, 2026
0600414
fix(terminal): strip OSC 11 escape sequences from PTY output
pedrotecinf May 23, 2026
f517f2e
fix(hermes): also copy auth.json to agent profiles
pedrotecinf May 24, 2026
7947b3b
fix(providers): merge structural fields from example into live config
pedrotecinf May 24, 2026
576bdf3
feat(docker): add Composio CLI to container image
pedrotecinf May 24, 2026
81232b5
perf(hermes): persistent iframe host + drop double-fetch on Hermes UI
pedrotecinf Jun 8, 2026
fa9843b
feat(dashboard): floating chat widget global
pedrotecinf Jun 8, 2026
ccc768f
fix(hermes): proxy WebSocket + runtime URL shim so embedded chat conn…
pedrotecinf Jun 8, 2026
3a97406
feat(float-chat): resizable windows + continue external sessions
pedrotecinf Jun 8, 2026
d50a41d
fix(hermes): load agent as system prompt instead of --skills (CLA-27)
pedrotecinf Jun 8, 2026
c00bab9
fix(hermes): use pipes instead of pty for chat sessions (CLA-27)
pedrotecinf Jun 8, 2026
dd4b362
fix(hermes-proxy): don't tear down chat WebSocket on idle timeout
Jun 15, 2026
b7207de
fix(chat): load agent via hermes -p profile + fix @ search in picker
pedrotecinf Jun 15, 2026
bcd72b0
Merge pull request #1 from pedrotecinf/asiotech-hub/chat-flutuante-rj5ld
pedrotecinf Jun 21, 2026
29b8262
fix: WS-aware proxy para Hermes UI (event feed + Kanban)
Jun 21, 2026
d05f442
fix(hermes-proxy): remap dashboard-plugins <script>/<link> URLs in th…
Jun 21, 2026
016e827
fix(hermes-proxy): serialize simple_websocket frame writes to stop "I…
Jun 22, 2026
78ce5a1
fix(heartbeats): allow handler heartbeats (max_turns 0 / empty prompt…
Jun 22, 2026
00de3dd
feat(heartbeats): persist + dispatch in-process handler heartbeats
Jun 22, 2026
1d429bd
fix(hermes-proxy): disable permessage-deflate to stop "Invalid frame …
Jun 22, 2026
06dd2f3
feat(tailscale): VPN integration via Auth Key — TailscaleCard in Inte…
pedrotecinf Jul 14, 2026
562bc41
fix(tailscale): fix duplicate import causing TS compile error
pedrotecinf Jul 14, 2026
d929dbe
docs(.env.example): add Tailscale VPN section with usage notes
pedrotecinf Jul 14, 2026
05d6039
fix(tailscale): start tailscaled daemon in start-dashboard.sh
pedrotecinf Jul 14, 2026
e069e3f
fix(tailscale): use userspace-networking (no NET_ADMIN/tun needed und…
pedrotecinf Jul 14, 2026
934223f
feat(hermes): native Basic Auth for remote desktop via Tailscale
pedrotecinf Jul 15, 2026
df77b77
fix(hermes): use uv venv for bcrypt (system python3 lacks the module)
pedrotecinf Jul 15, 2026
867d96b
fix: configure Hermes auth in gateway wrapper
pedrotecinf Jul 15, 2026
4360bec
fix(hermes-auth): use native Hermes env vars + cookie-based proxy aut…
pedrotecinf Jul 15, 2026
d2b2fe5
feat(hermes): add profile registry and deterministic routing module
pedrotecinf Jul 17, 2026
21215b3
feat(hermes): propagate profile through runner→adapter chain
pedrotecinf Jul 17, 2026
895d6eb
feat(hermes): profile routing endpoint + task executor integration
pedrotecinf Jul 17, 2026
4b2ed71
feat(hermes): profile selector in Tasks + baseline preview in TicketD…
pedrotecinf Jul 17, 2026
e35abfe
test(hermes): profile routing unit/API tests + CI integration
pedrotecinf Jul 17, 2026
f36a78f
fix(hermes): enforce runtime timeout and protect profile overrides
pedrotecinf Jul 23, 2026
71ea738
feat(hermes): Control API, task-run lifecycle, ECC catalog, event bus…
pedrotecinf Jul 23, 2026
ace4bcb
feat(hermes): link scheduled tasks to their originating ticket
pedrotecinf Jul 24, 2026
35c10ed
fix(hermes): restore missing _ALLOWED_CLI_COMMANDS allowlist
pedrotecinf Jul 24, 2026
5fdfbec
feat(hermes): normalized runtime service and provider-native heartbea…
pedrotecinf Jul 25, 2026
da9e169
feat(hermes): heartbeat decision parsing, atomic checkout, nullable m…
pedrotecinf Jul 25, 2026
ab73945
fix(hermes): harden scheduled task execution
pedrotecinf Jul 25, 2026
b307bd9
feat(hermes): add goals ticket rollout observability
pedrotecinf Jul 25, 2026
f746bd2
feat(hermes): persist bounded chat replay and ticket control
pedrotecinf Jul 25, 2026
f893bc7
feat(hermes): Control API v1 endpoints for goals, heartbeats and sche…
pedrotecinf Jul 25, 2026
7a93697
feat(hermes): Control API v1 routines list, logs and safe manual run
pedrotecinf Jul 25, 2026
569a94a
fix(hermes): restore scheduled task lifecycle fields
pedrotecinf Jul 25, 2026
fa2bf17
fix(hermes): enforce heartbeat and task cancellation safety
pedrotecinf Jul 25, 2026
0143c91
fix(hermes): redact terminal stderr logs
pedrotecinf Jul 25, 2026
933dc6d
fix(hermes): preserve legacy routine metrics
pedrotecinf Jul 25, 2026
1e5bc66
fix(hermes): preserve activity log provenance
pedrotecinf Jul 25, 2026
671775e
fix(services): report container-aware scheduler health
pedrotecinf Jul 25, 2026
ef7402a
fix(deploy): align scheduler with immutable runtime image
pedrotecinf Jul 25, 2026
5ed0986
fix(hermes): keep scheduler health fresh during jobs
pedrotecinf Jul 25, 2026
2e17970
feat(tickets): add agent mention autocomplete
pedrotecinf Jul 26, 2026
dc9c08a
fix(tickets): correct mention composer layout
pedrotecinf Jul 26, 2026
5e5aa81
fix(tickets): preserve failed mention comments
pedrotecinf Jul 26, 2026
6157768
fix(tickets): clamp mention selection state
pedrotecinf Jul 26, 2026
faae0ad
fix(tickets): isolate mention geometry helpers
pedrotecinf Jul 26, 2026
0f66ad3
fix(tickets): compact agent mention suggestions
pedrotecinf Jul 26, 2026
4747090
Merge branch 'feature/hermes-runtime' into feat/hermes-tailscale-inte…
pedrotecinf Jul 26, 2026
de02f9e
fix(hermes): harden Tailscale controls and runtime envs
pedrotecinf Jul 26, 2026
4b8709a
fix(hermes): harden upstream integration and deployment
pedrotecinf Jul 26, 2026
466f0ad
fix(ci): make Hermes integration checks reproducible
pedrotecinf Jul 26, 2026
a72449b
chore(security): sanitize Tailscale key placeholder
pedrotecinf Jul 26, 2026
95cb231
fix(hermes): close upstream review findings
pedrotecinf Jul 26, 2026
d46e377
fix(heartbeats): persist configured ticket lease timeout
pedrotecinf Jul 26, 2026
db352ac
fix(runtime): harden scheduled task concurrency
pedrotecinf Jul 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ META_APP_SECRET=
LINKEDIN_CLIENT_ID=
LINKEDIN_CLIENT_SECRET=

# ── License — headless auto-activation ───────────────
# Set this to the email used in your first manual license registration.
# On startup, EvoNexus calls /v1/register/auto silently and skips the manual
# setup screen. Falls back to manual setup if the email isn't registered yet.
# Leave empty (or unset) to keep the default behavior.
# EVOLUTION_OPERATOR_EMAIL=operator@example.com

# ── Evolution API ────────────────────────────────────
# Your Evolution API instance URL and global API key
EVOLUTION_API_URL=
Expand Down Expand Up @@ -242,3 +249,52 @@ AI_IMG_CREATOR_GEMINI_KEY=
# DB_REDIS_1_ALLOW_WRITE=false
# DB_REDIS_1_QUERY_TIMEOUT=30
# DB_REDIS_1_MAX_ROWS=1000

# ── Tailscale VPN ─────────────────────────────────────────
# Managed via Dashboard → Integrations → Network tab.
# The Auth Key is entered transiently in the UI and is never stored by EvoNexus.
# Generate at: console.tailscale.com → Settings → Keys
# Optional hostname override (RFC 1123 label, max 63 characters):
# EVONEXUS_TAILSCALE_HOSTNAME=evonexus-hermes
#
# Persistence: /var/lib/tailscale is stored in the 'tailscale-state'
# Docker volume, so the node reconnects automatically after restarts.
#
# ── Hermes Runtime ──────────────────────────────────────────
# Configure provider credentials through Dashboard → Providers or hermes setup.
# These variables follow the native Hermes Agent environment contract.
# HERMES_MODEL=anthropic/claude-sonnet-4
# HERMES_MAX_ITERATIONS=30
# OPENROUTER_API_KEY=
# ANTHROPIC_API_KEY=
# DEEPSEEK_API_KEY=
# OPENAI_API_KEY=
# OPENAI_BASE_URL=
# Emergency fail-closed switch for all Hermes executions:
# HERMES_KILL_SWITCH=0
#
# ── Hermes Control API (optional, disabled without a token) ────────────
# Use independent, high-entropy bearer tokens. Scopes are comma-separated
# and fail closed when omitted. See dashboard/backend/routes/control_api.py.
# HERMES_CONTROL_API_TOKEN=
# HERMES_CONTROL_API_TOKEN_PREVIOUS=
# HERMES_CONTROL_API_SCOPES=health:read,projects:read,tickets:read
#
# ── Hermes Dashboard Auth (remote access via Tailscale) ───────────────────
# When set, Hermes binds 0.0.0.0 (enabling remote access) and requires
# Basic Auth. The proxy injects credentials automatically for the iframe.
# Use a strong plaintext password here; Hermes hashes/validates it internally.
# Leave both values empty to bind Hermes to 127.0.0.1 without direct remote access.
# EVONEXUS_HERMES_USERNAME=hermes-admin
# EVONEXUS_HERMES_PASSWORD=
# Optional native Hermes API server. Disabled by default; enabling it requires a key.
# EVONEXUS_HERMES_API_ENABLED=false
# EVONEXUS_HERMES_API_KEY=
# HERMES_UI_PORT=9119
# HERMES_API_PORT=8642
#
# ── Immutable deployment images ─────────────────────────────
# Required by docker-compose.hub.yml, docker-compose.proxy.yml and the Swarm stack.
# EVONEXUS_IMAGE_TAG=sha-abcdef0
# Optional registry override; official images default to Docker Hub/evoapicloud.
# EVONEXUS_IMAGE_REGISTRY=evoapicloud
42 changes: 37 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,27 @@ on:
branches: [develop, main]
paths:
- "dashboard/**"
- "ADWs/**"
- "config/**"
- "tests/**"
- "Dockerfile*"
- "docker-compose*.yml"
- "evonexus.stack.yml"
- "start-dashboard.sh"
- "pyproject.toml"
- "uv.lock"
- ".github/workflows/ci.yml"
push:
branches: [develop, main]
paths:
- "dashboard/**"
- "ADWs/**"
- "config/**"
- "tests/**"
- "Dockerfile*"
- "docker-compose*.yml"
- "evonexus.stack.yml"
- "start-dashboard.sh"
- "pyproject.toml"
- "uv.lock"
- ".github/workflows/ci.yml"
Expand Down Expand Up @@ -43,7 +55,23 @@ jobs:
run: uv sync --frozen --dev

- name: Run backend tests
run: uv run python -m pytest tests/backend/test_auth_security.py tests/backend/test_health_routes.py
run: >-
uv run python -m pytest -q
tests/backend
tests/db
tests/heartbeats
tests/test_deployment_images.py
ADWs/test_hermes_integration.py
ADWs/test_runtime_policy.py

- name: Validate deployment manifests
env:
EVONEXUS_IMAGE_TAG: sha-ci
run: |
bash -n start-dashboard.sh
docker compose -f docker-compose.hub.yml config >/dev/null
docker compose -f docker-compose.proxy.yml config >/dev/null
docker stack config -c evonexus.stack.yml >/dev/null

terminal-server:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -81,12 +109,16 @@ jobs:
with:
node-version: "22"
cache: npm
cache-dependency-path: dashboard/frontend/package-lock.json
cache-dependency-path: dashboard/package-lock.json

- name: Install frontend dependencies
working-directory: dashboard/frontend
working-directory: dashboard
run: npm ci

- name: Run frontend tests
working-directory: dashboard
run: npm run test --workspace frontend

- name: Build frontend
working-directory: dashboard/frontend
run: npm run build
working-directory: dashboard
run: npm run build --workspace frontend
128 changes: 101 additions & 27 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ name: Build & Publish Docker Images (Swarm)

# Builds evo-nexus-runtime and evo-nexus-dashboard images using the
# Swarm-specific Dockerfiles (Dockerfile.swarm and Dockerfile.swarm.dashboard)
# and pushes them to Docker Hub under the `evoapicloud` namespace. The
# upstream Dockerfile and Dockerfile.dashboard are intentionally NOT used
# here: they are for local `docker compose up`, while these variants carry
# the Swarm-specific bootstrap (entrypoint.sh, start-dashboard.sh, terminal-
# server native build, both CLIs on PATH).
# and pushes them to Docker Hub. Uses native arm64 runners instead of QEMU
# emulation to avoid 6h+ build times on the dashboard image.
#
# Strategy: build each platform natively in parallel, then merge into
# a single multi-arch manifest via docker buildx imagetools.
#
# Triggers:
# * push to main -> builds + publishes :latest
# * push of a version tag -> builds + publishes :vX.Y.Z and :latest
# * push to main -> builds + publishes immutable :sha-<revision>
# * push of a version tag -> builds + publishes :vX.Y.Z and :sha-<revision>
# * manual dispatch -> builds without pushing (dry-run)
#
# Required repository secrets:
# * DOCKERHUB_USERNAME — Docker Hub account with push rights to evoapicloud
# * DOCKERHUB_TOKEN access token (Settings → Security → New Access Token)
# * DOCKERHUB_USERNAME — Docker Hub account name
# * DOCKERHUB_TOKEN — Docker Hub access token with write access
on:
push:
branches: [main]
Expand All @@ -28,29 +28,37 @@ env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'

jobs:
build-and-push:
name: Build & push ${{ matrix.image }}
runs-on: ubuntu-latest
build:
name: Build ${{ matrix.image }} (${{ matrix.platform }})
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- image: evo-nexus-runtime
dockerfile: Dockerfile.swarm
platform: linux/amd64
runner: ubuntu-latest
- image: evo-nexus-runtime
dockerfile: Dockerfile.swarm
platform: linux/arm64
runner: ubuntu-24.04-arm
- image: evo-nexus-dashboard
dockerfile: Dockerfile.swarm.dashboard
platform: linux/amd64
runner: ubuntu-latest
- image: evo-nexus-dashboard
dockerfile: Dockerfile.swarm.dashboard
platform: linux/arm64
runner: ubuntu-24.04-arm

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up QEMU (for arm64 emulation on amd64 runners)
uses: docker/setup-qemu-action@v3
with:
platforms: arm64

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

Expand All @@ -67,26 +75,92 @@ jobs:
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.NAMESPACE }}/${{ matrix.image }}
# Boa prática: publicar :latest junto com a tag versionada sempre
# que um release (tag v*) for empurrado. Push para a branch main
# sem tag também atualiza :latest.
flavor: |
latest=${{ github.ref_type == 'tag' || github.ref == 'refs/heads/main' }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=sha-,format=short

- name: Build and push
- name: Build and push by digest
id: build
uses: docker/build-push-action@v5
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64,linux/arm64
platforms: ${{ matrix.platform }}
push: ${{ github.event_name != 'workflow_dispatch' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.image }}
cache-to: type=gha,scope=${{ matrix.image }},mode=max
outputs: type=image,name=${{ env.REGISTRY }}/${{ env.NAMESPACE }}/${{ matrix.image }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'workflow_dispatch' }}
cache-from: type=gha,scope=${{ matrix.image }}-${{ matrix.platform }}
cache-to: type=gha,scope=${{ matrix.image }}-${{ matrix.platform }},mode=max

- name: Export digest
if: github.event_name != 'workflow_dispatch'
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"

- name: Upload digest
if: github.event_name != 'workflow_dispatch'
uses: actions/upload-artifact@v4
with:
name: digests-${{ matrix.image }}-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1

merge:
name: Merge manifests (${{ matrix.image }})
runs-on: ubuntu-latest
if: github.event_name != 'workflow_dispatch'
needs: build
permissions:
contents: read
packages: write
strategy:
matrix:
image:
- evo-nexus-runtime
- evo-nexus-dashboard

steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-${{ matrix.image }}-*
merge-multiple: true

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.NAMESPACE }}/${{ matrix.image }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=sha-,format=short

- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY }}/${{ env.NAMESPACE }}/${{ matrix.image }}@sha256:%s ' *)

- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.NAMESPACE }}/${{ matrix.image }}:${{ steps.meta.outputs.version }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ ADWs/routines/custom/

# ── Provider config (user-specific, has API keys) ─
config/providers.json
config/hermes_profiles.json

# ── Runtime data & logs ───────────────────
backups/
Expand Down Expand Up @@ -90,6 +91,7 @@ config/routines.yaml
config/triggers.yaml
config/heartbeats.yaml
config/smart-router.json
config/runtime_policy.json

# ── Claude Code session data ─────────────
.claude/projects/
Expand Down
Loading