Detailed architecture, dependencies, and implementation notes for Eva AI Assistant.
Current development version: Eva 5.6.11 (unreleased). This document describes the matching browser UI, Python bridge, and Electron package in this repository.
Recommended experience: Select Eva (AIG) from the model dropdown for the full Eva experience: persistent memory, emotion tracking, proactive data retrieval, and intelligent cross-model orchestration. All other models work standalone, but AIG is the way Eva was designed to be used.
git clone https://github.com/appatalks/eva-agent.git
cd eva-agent
./install.sh --build
cd standalone
./dist/'Eva Standalone-5.6.11.AppImage' --eva-workspace-terminal-v1Eva requires Node.js 24+, Python 3.12+, and the GitHub Copilot CLI for ACP-backed
features. Authenticate the CLI with copilot auth login when using Copilot ACP.
Linux AppImage builds also require binutils (readelf) and zsync (zsyncmake).
New builds use a static AppImage runtime rather than the legacy host-glibc/
libfuse2 launcher, embed AppImageUpdate information, and generate a .zsync
sidecar published with tagged releases. Electron still requires compatible host
glibc and desktop libraries; Python, Node.js, and Copilot remain external runtime
prerequisites. The inspected x86_64 payload's native terminal module still
references GLIBC_2.34. This is not a fully self-contained or older-Linux
compatibility claim. See standalone packaging
for update behavior and limits.
New AppImages enable coding workspaces by default and provide bounded runtime
preflight plus first-launch provider guidance. --eva-no-workspaces disables
the native terminal explicitly. Download-only users have a
setup guide that does not
assume a source checkout. Tagged Linux builds use Ubuntu 22.04 with a verified
glibc 2.35 payload ceiling and publish SHA256SUMS with the update assets.
From a Windows checkout, run npm install and npm run dist:win in standalone/.
The installer is written to standalone/dist/, provisions the supported local runtime,
and opens a terminal for interactive Copilot sign-in. Linux-only desktop automation and
camera discovery are not available on Windows.
Select Eva (AIG) for the integrated experience. Settings > Models supports Copilot ACP, direct OpenAI, and local LM Studio backends. Direct OpenAI retains Eva's memory, persona, response rendering, and action markers but requires an OpenAI key; ACP subagents and ACP MCP retrieval require Copilot. LM Studio provides the local no-cloud chat path.
Local SQLite is the default memory backend. Azure Data Explorer can be configured in
Settings > MCP, and an OpenAI key enables semantic recall with keyword fallback when no
key is configured. Signal delivery requires signal-cli,
linked with signal-cli link -n "Eva", plus configured sender and recipient numbers.
On Linux, the rebuildable installed source lives in ~/.eva; mutable standalone
state defaults to ~/.config/eva-standalone and can be relocated with
EVA_CONFIG_DIR. This runtime root owns bridge preferences, workspace records,
browser/desktop agent state, and generated artifacts. The browser-agent profile is
intentionally persistent so its isolated sign-ins survive across runs.
Install optional local speech dependencies with ./install.sh --voice-deps. This creates
a dedicated Python 3.11 environment for Chatterbox, Faster Whisper, and Silero VAD. The
standalone app runs its speech service on a token-protected loopback endpoint and does
not upload microphone audio to a cloud transcription service.
Settings > Learning controls bounded, revocable feedback, routine outcomes, voice diagnostics, and standing consent for routine read/search tools. Higher-risk actions, including opaque execution, writes, remote mutations, edits, and deletes, require a fresh in-chat approval. Skills can be imported from text, URLs, GitHub repositories, or files and are normalized before Eva uses them.
Durable memory. Eva uses local SQLite by default. The Memory view exposes record provenance, associations, history, and corrections before records are changed or removed from recall. Explicit user-stated facts recognized by the deterministic extractor are committed before acknowledgement. Ordinary questions do not create facts, and mixed fact-plus-request messages continue through normal response handling.
Local model responses. LM Studio responses show a live thinking state during long generations. When a model returns a separate reasoning layer, Eva keeps it available in a collapsed Thinking section above the final answer.
Morning briefings. Briefing requests refresh bounded news, location-aware weather, market news, mail, and memory sources. Dated news and market entries older than 36 hours are excluded. Market news describes the most recently completed U.S. trading session, which may be the previous business day. Weather uses an explicitly learned location and requires verified current conditions plus today's forecast; U.S. city/state locations prefer the National Weather Service. A briefing is marked partial when weather is unavailable.
Current stock quotes. Eva uses a verified local receipt when available: a configured
loopback provider first, then the local ticker.sh Yahoo Finance tool, followed by the
bounded Google Finance fallback. Eva reports an unavailable quote instead of asking a
model to infer a current price.
MCP compatibility. GitHub MCP uses GitHub's hosted HTTPS service and the GitHub PAT
configured in Settings > Auth; Docker is not required. Local MCP servers that do not
support Eva's modern discovery extension can use standard MCP 2025-06-18
initialization.
Native research (bounded first slice). Explicit online research requests use
configured web_search and web_fetch MCP tools before response synthesis. The
bridge performs one search (up to five results) and reads at most two public pages;
it does not hire another model to click a search page. The requested AIG responder
is retained for this path, including Copilot, direct OpenAI, or LM Studio, without
automatic cross-provider escalation. Local model inference does not make an
explicit online search offline: the configured web tools still access the network.
Within the recent user-turn context, “please continue” retains the research topic and refines the query; “try a different search method” selects the configured news-oriented search tool, or reports that the alternative is unavailable. An unrelated intervening request breaks continuation. Missing or potentially private topics require clarification before any search. No new MCP service is registered; an already configured web service may be started and stopped for the request.
Results distinguish page excerpts from search snippets, include retrieval timestamps and source URLs, and remain untrusted source data. Failed page reads preserve snippets as partial evidence; no usable results do not establish that the information does not exist. The bundled public page reader rejects private-network destinations, pins validated DNS addresses, verifies TLS, and rechecks redirects. It does not bypass sign-in or bot challenges. Configured third-party tools remain within their own execution policy.
This is not yet a durable research job or a complete deep-research engine. “Complete” in retrieval metadata means the bounded batch finished, not that the topic was exhaustively investigated. Persistent task checkpoints, source deduplication across turns, and evidence-aware continuation after restart remain planned. Explicit browser/desktop interaction requests keep their existing automation path.
Bounded document abilities. Native DOCX, PDF, PPTX, XLSX, and MCP Builder abilities
run locally through the bridge and validate outputs before reporting success. They do
not fall back to browser, desktop, terminal, package installation, or network access.
Office-format dependencies are optional and checked by install.sh; missing packages
produce an actionable runtime receipt.
| Provider | Models |
|---|---|
| Eva (AIG) | Automatic orchestration over OpenAI API, Copilot ACP, LM Studio, and MCP tools |
| OpenAI | GPT-4o, GPT-4o Mini, o1, o1-preview, o1-mini, o3-mini, latest |
| GitHub Copilot (ACP) | Claude, GPT-5.x, GPT-4.1 via Copilot CLI |
| GitHub MCP | Repository, issue, pull request, workflow, and code operations through ACP/local MCP |
| Google Gemini | Gemini 2.0 Flash (Thinking Exp), deprecated compatibility route |
| LM Studio | Any local OpenAI-compatible model (fully offline) |
| gpt-image-1 | Image generation |
- Multi-agent AIG with eva and reviewer cognitive pipeline
- Dual-mode data retrieval: cloud (Copilot CLI + MCP) or local (LM Studio + direct MCP)
- MCP tool access (Kusto, GitHub, Azure, web search) hot-reloadable at runtime
- Persistent memory via Azure Data Explorer (Kusto) or local SQLite
- Memory Inspector with searchable traceable records, provenance, associations, and append-only corrections
- Signal text messaging (send-only via signal-cli, keyword-triggered fallback for local models)
- Multi-account email settings and native harness controls for custom-domain IMAP/SMTP and Eva-direct delivery, with bounded mailbox reads, session-bound pending drafts, one-time exact-message confirmation, duplicate-send protection, internal delivery, and automatic read-only Exim transport follow-up for best-effort local-MTA submissions. Gmail, Outlook/Microsoft OAuth, Work IQ, and remote-MCP mailbox groundwork is experimental and disabled until its complete connection flow ships.
- Autonomous browser control (Playwright + CDP) and desktop control (pyautogui)
- Webcam presence detection (OpenCV face + motion)
- Inline image search (Wikimedia) and generation (gpt-image-1)
- Downloadable artifact creation (PDF, text, CSV, markdown) with auto-open
- Skill import/normalization from paste, URL, GitHub, or file upload
- Hands-off background cognition with applied/failed proposal and activity audit trails
- Cron scheduler for recurring tasks (briefings, checks, reminders)
- Alert system (SEC filings, weather, space weather, keyword watch) with Signal delivery
- Mode persistence across restarts (bridge-side mode.txt, frontend localStorage)
- TTS: OpenAI (default), browser, user-authorized Local Voices, and Amazon Polly (standard/neural/generative)
- LCARS and Eva themes (7 Eva variants)
- Standalone Electron AppImage with bundled bridge
- Durable coding workspaces with automatic Eva-ready Git project provisioning, isolated worktrees, workspace-confined ACP agents, durable run records, and optional per-run auto approval for remote or otherwise sensitive actions
- Real Electron PTY terminal with xterm rendering, bounded replay, resize/search, lower-half Workspace Monitor docking, and process-session cancellation
- Main-window Workspace Monitor, unified generated/workspace Assets library, and searchable Skills library/editor with source/status organization
- Full behavioral eval harness with mock and live modes
+---------------------------------------------------------------------------+
| Browser / Electron |
| index.html + core/js/*.js + core/style.css |
| |
| +---------+ +----------+ +--------+ +-----------+ +-------------+ |
| | OpenAI | | Copilot | | Gemini | | Copilot | | LM Studio | |
| | Direct | | PAT API | | Direct | | ACP/AIG | | Direct | |
| +----+----+ +----+-----+ +---+----+ +-----+-----+ +------+------+ |
+-------|---------|-----------|-----------|--------------|-----------------+
| | | | |
v v v v v
api.openai models. google +------------+ localhost
.com github.ai generative | ACP Bridge | :1234
apis.com | (Python) | (LM Studio)
| port 8888 |
+--+-----+---+
+---------+ +----------+
v v
+--------------+ +--------------+
| Copilot CLI | | Local MCP |
| (ACP/stdio) | | Servers |
| | | (subprocess) |
+------+-------+ +------+-------+
| spawns | JSON-RPC
v v
+--------------+ +--------------+
| MCP Servers | | eva-web- |
| kusto, gh, | | search |
| azure | | (DDG/Google) |
+--------------+ +--------------+
Eva operates in two data retrieval modes, selected automatically based on the model or manually via Settings > General.
Cloud mode (default for Copilot/OpenAI models):
- Copilot CLI (ACP) provides chat, tool execution, web search
- MCP servers spawned by Copilot subprocess
- Requires GitHub Copilot license, consumes tokens
Local mode (automatic for LM Studio):
- LM Studio provides chat completions and tool-calling reasoning
- MCP servers spawned directly by the bridge as subprocesses
- Web search via
web_search_mcp.py(DuckDuckGo HTML scraping, no API key) - Zero cloud AI, zero tokens, fully offline-capable
Mode persistence: The selected mode is persisted to ~/.config/eva-standalone/mode.txt
by the bridge. On startup, the bridge reads this file to restore the previous mode.
The frontend seeds its selector from the bridge via GET /v1/mode after init, and
skips auto-switch logic during startup to avoid overriding the persisted choice.
Direct models (OpenAI, Copilot PAT, Gemini):
Browser -> GET /v1/memory/context with session ID -> Provider API -> JSON response ->
renderEvaResponse() -> one POST /v1/memory/reflect
The memory context is an ephemeral request view and does not mutate browser history. Gemini follows this same lifecycle, including a reflection request only after a successful final response.
ACP models (Copilot CLI):
- Browser ->
POST /v1/chat/completions-> ACP Bridge (HTTP) - Bridge ->
session/prompt-> Copilot CLI (JSON-RPC over NDJSON/stdio) - Copilot may request MCP tools; standalone Eva shows an in-chat Allow once/Reject decision unless revocable routine read/search consent applies
- Copilot streams
session/updatenotifications with text chunks - Bridge accumulates chunks and can forward them as flushed NDJSON events; the final event remains an OpenAI-compatible response
- Bridge owns the single post-response reflection for ACP; the browser renderer does not submit a duplicate reflection request
POST /v1/aig/chat and POST /v1/chat/completions accept stream: true. A supported
stream responds as newline-delimited JSON (application/x-ndjson):
{"type":"chunk","text":"partial assistant text"}
{"type":"done","response":{"object":"chat.completion","choices":[...]}}The bridge keeps the existing JSON response when stream is false or a client does
not receive the streaming content type. AIG streams only the final responder; its
memory, ACP preflight, and cognition calls remain internal and non-streaming. The
browser puts chunks in a text-only provisional bubble, so action, Signal, file, and
browser markers cannot execute early. It removes that bubble and calls
renderEvaResponse() once for the final response, preserving persistence, reflection,
and auto-speak behavior. Bridge telemetry records request start, TTFT, completion and
total timing, chunk count, route, and model labels without prompt or response text;
GET /v1/telemetry aggregates TTFT under summary.stream_ttft_ms.
LM Studio (local):
- Browser fetches
/v1/memory/context+/v1/data/retrievein parallel from bridge - Bridge injects memory context from SQLite/Kusto
- Bridge runs data retrieval via local MCP tool-calling loop (see below)
- Browser prepends memory + data to system prompt
- Browser sends directly to the configured LM Studio base URL; the default is
http://localhost:1234/v1/chat/completions - Response processed by
Cognition.executeActions()for any action blocks - Rendered via
renderEvaResponse()
Eva (AIG) with cognition layer:
- Browser calls
Cognition.run()which drives the draft/review/revise pipeline - Each agent call goes to
POST /v1/aig/chaton the bridge - Bridge runs Step 1 (memory), Step 2 (data retrieval), Step 3 (persona), Step 4 (LLM call)
- AIG selects an available responder: OpenAI API, ACP (Copilot CLI), or LM Studio Tool-required requests fail closed when the required ACP/local MCP route is unavailable.
- Step 5: background reflection thread logs conversation, extracts entities, computes emotion
Image handling:
_detectGenerationIntent()captures user's intent + subject before send- AI responds with
[Image of ...]placeholder renderEvaResponse()detects placeholder, routes to:- gpt-image-1 if user said "generate/create/draw" (uses user's simple subject)
- Wikimedia Commons otherwise (progressive query: full -> 2 words -> 1 word)
- Image inserted inline with lightbox click-to-expand
index.html Main UI: chat, settings modal, LCARS sidebar,
monitors dock, input area, lightbox
config.json API keys (not committed, gitignored)
config.example.json Template for config.json
config.local.example.js Template for file:// usage (inlined config)
mcp.json Tracked default MCP server configuration; credentials
are resolved from environment/local settings
core/
style.css All styling: base theme, settings panel,
monitors, chat bubbles, responsive
themes/
eva.css Eva dark theme overrides
lcars.css LCARS (Star Trek) theme overrides
js/
options.js Core application logic:
- Config loading (auth(), applyConfig())
- Auth key management (getAuthKey, saveAuthKeys)
- System prompt management (getSystemPrompt, applyPersonalityPreset)
- Model routing (updateButton, sendData)
- Data mode switching (switchDataMode, loadDataMode)
- Theme management (applyTheme)
- Token/network/session monitors
- Image handling (renderEvaResponse, _searchImage, _generateImage)
- Markdown renderer (renderMarkdown)
- Artifact download/open links (appendArtifactLinks)
- Auto-open artifacts via bridge /v1/files/<name>?open=1
- AWS Polly TTS (speakText)
- Print, clear memory
features/voice/view.js
Voice View ambient HUD lifecycle, listening, endpoint handoff,
barge-in, compact voice controls, and compatible globals
providers/openai.js OpenAI Chat Completions API (trboSend)
- XHR-based (legacy, not fetch)
- Model-specific params (o3-mini reasoning, gpt-5 top_p)
- External data augmentation (weather, news, markets, solar)
providers/gemini.js Google Gemini API (geminiSend)
- Thinking mode (extracts thoughts vs non-thoughts)
providers/lm-studio.js Local LLM via LM Studio (lmsSend)
- OpenAI-compatible endpoint on localhost:1234
- Parallel memory context + data retrieval from bridge
- Action block execution (Cognition.executeActions)
- File capability documentation in system prompt
- Post-response reflection via bridge
providers/copilot.js GitHub Copilot integration (copilotSend)
- ACP Bridge and MCP configuration
- MCP configuration (applyMCPConfig, refreshMCPStatus)
providers/aig.js Eva AIG orchestration (aigSend)
- Routes through bridge /v1/aig/chat
- Optional browser-side cognitive layer
- Phrase triggers force cognition for single turn
cognition.js Browser-side multi-agent cognitive layer:
- Two role-specific agents: eva (planner), reviewer (critic)
- Bounded review loop (cogMaxCycles, default 1)
- Capability registry (file.download, file.open)
- Action protocol: [[EVA_ACTION]]{...}[[/EVA_ACTION]]
- Built-in PDF generator (Helvetica, Latin-1, multi-page)
- Marker protocol: [[EVA_BROWSER]], [[EVA_DESKTOP]],
[[EVA_LOOK]], [[EVA_FILE]]
features/agents/operations.js
Agent Operations scorecard, task detail, steering,
keyed card updates, and memory topology canvas
features/assets/library.js
Main Assets library: generated artifacts plus
changed files from retained coding worktrees
dialogs.js Promise-based in-app text prompt for Electron
providers/image-generation.js
Image generation via gpt-image-1 (dalle3Send)
idb-store.js IndexedDB storage backend (sessions + blobs)
features/sessions/explorer.js
Session persistence, legacy-visible restoration,
terminal/xterm renderer and dock navigation
features/voice/wake-listener.js
Wake-word "Eva" via Web Speech API
features/voice/endpoint.js
Speech endpoint buffering and transcript merging
features/automation/camera.js
Webcam capture for [[EVA_LOOK]] vision
features/automation/browser-agent.js
Frontend integration for browser and desktop agent runs
pandora.js Pandora box / Easter egg system
features/skills/library.js
Full-view Skills library/editor: search, status/source
filters, sort, import, edit, enable/disable, delete
features/workspaces/monitor.js
Workspace Monitor, coding-run creation, progress
narration, terminal/chat handoff, lifecycle actions
external.js External data fetching at page load
tools/
acp_bridge.py Entry point (imports bridge/ package)
bridge/
__init__.py
__main__.py Allows `python -m bridge`
core.py Main HTTP server, AIG pipeline, all endpoints (~4500 lines)
acp_client.py ACPClient: Copilot CLI subprocess, JSON-RPC, model pool
cognition.py Memory context builder, entity extraction, emotion computation
memory.py Backend switching (Kusto/SQLite), embeddings, synonyms
skills.py Skill import, evarise normalization, SSRF-safe URL fetching
kusto.py Azure Data Explorer queries, ingest, token management
config.py All constants, paths, thresholds, table schemas
state.py Mutable runtime state (thread-safe)
local_mcp.py Local MCP client, tool-calling agent loop
background.py Background job system (13 job types, proposal audit)
cron.py Cron scheduler (5-field expressions)
alerts.py Alert/notification system (SEC, weather, space weather)
Signal messaging via signal-cli
telemetry.py Structured event logging (latency, routing decisions)
utils.py URL validation, LM Studio validation, config persistence
workspaces.py SQLite workspace domain: projects, checkouts, coding
runs, agent runs, worktrees, assets, safe cleanup
web_search_mcp.py MCP server: DuckDuckGo + Google fallback (no API key)
sqlite_memory.py SQLite memory backend (SqliteMemory class)
kusto_mcp.py MCP server for Azure Data Explorer (10 tools)
browser_agent.py Autonomous web browsing (Playwright + CDP)
desktop_agent.py Autonomous desktop control (pyautogui + vision)
camera_sense.py Webcam presence detection (OpenCV face + motion)
local_voices_bridge.py Token-protected local Chatterbox TTS + Faster Whisper STT bridge
voice_clone_module/ Eva-maintained Chatterbox adapter; no reference audio
eva_seed.kql Sanitized database seed (public-safe)
acp_bridge.service Systemd unit file
acp_setup.sh One-command installer
tests/ Local and CI validation scripts; separate from runtime code
README.md Test boundary, local experimentation, and CI contract
test_static.py CI-safe static tests
test_eva.py Live bridge integration suite
test_latency.py Latency benchmarks
test_skills_e2e.py Skill import end-to-end tests
test_terminal_broker.js PTY confinement, replay, process-session cleanup
test_terminal_e2e.js Packaged terminal, Sessions, and Skills UI workflow
test_workspace_electron_e2e.js
Packaged Workspace/Assets/terminal workflow
test_workspaces.py Git worktree and symlink-confinement lifecycle tests
test_workspaces_e2e.py Workspace bridge, agent dispatch, Assets HTTP lifecycle
eval/ Behavioral eval harness
standalone/
main.js Electron shell, bridge spawn, workspace-only capability,
project picker, opaque IPC projections, asset opening
preload.js Narrow allowlisted renderer IPC surface
terminal-broker.js Approved-root PTY ownership, replay, resize, termination
workspace-projection.js Redacts known project/worktree paths from reports
package.json Electron + electron-builder config (v5.6.11)
- Barlow Condensed font (loaded from Google Fonts CDN)
- AWS SDK v2.1304.0 (bundled, for Polly TTS)
| Package | Purpose |
|---|---|
node-pty |
Native PTY creation and streaming |
@xterm/xterm |
Terminal rendering |
@xterm/addon-fit |
Measured container/grid fitting |
@xterm/addon-search |
Scrollback search |
@xterm/addon-web-links |
Safe terminal link detection |
playwright-core (dev) |
Attach to packaged Electron through CDP for E2E tests |
| Dependency | Required for | Install |
|---|---|---|
| Python 3.12+ | ACP Bridge, Kusto MCP | System package or pyenv |
| Node.js 24+ | Copilot CLI | nvm install 24 or system package |
@github/copilot |
Copilot CLI | npm install -g @github/copilot |
azure-identity |
Kusto MCP auth | pip install azure-identity |
requests |
AIG HTTP calls | pip install requests |
python-docx |
DOCX create/read/edit/validate | pip install python-docx |
pypdf |
PDF read/forms/merge/split/extract/validate | pip install pypdf |
reportlab |
PDF creation and offline fixtures | pip install reportlab |
pdfplumber==0.11.9 |
Bounded PDF table/text structure extraction | Managed by install.sh |
pytesseract + Pillow <12 |
OCR binding and image handling | Managed by install.sh |
| Poppler + Tesseract | Fixed PDF rendering and OCR executables | System package via install.sh |
python-pptx |
PPTX create/read/edit/validate | pip install python-pptx |
openpyxl |
XLSX create/read/edit/formula inspection | pip install openpyxl |
| LibreOffice | XLSX recalculation and DOCX/PPTX PDF rendering | System package via install.sh |
| Docker | GitHub MCP server | docker.com |
| Playwright | Browser agent | pip install playwright && playwright install |
| pyautogui | Desktop agent | pip install pyautogui |
| opencv-python | Camera presence | pip install opencv-python |
| signal-cli | Signal messaging | Native binary from GitHub releases, or install.sh auto-installs |
| Local speech runtime (optional) | Chatterbox English + Multilingual V3 TTS, Faster Whisper STT | ./install.sh --voice-deps |
| Key | Used by | Get it from |
|---|---|---|
OPENAI_API_KEY |
Direct OpenAI Eva backends, OpenAI models, image generation, TTS/transcription, embeddings | platform.openai.com |
GITHUB_PAT |
GitHub MCP and private workspace imports | github.com/settings/tokens (private imports need repository Contents: Read access. Fine-grained tokens must include the repository; classic tokens need repo. Alternatively, Workspaces can launch native gh auth login --web device-code authorization; that credential stays in GitHub CLI storage.) |
GOOGLE_GL_KEY |
Google Gemini | aistudio.google.com |
| AWS credentials | Amazon Polly TTS | AWS IAM Console |
| None | LM Studio (local mode) | Free, runs locally |
Imported coding workspaces discover repository MCP definitions from bounded project-relative mcp.json and .mcp.json locations, including common .vscode/ and .github/ locations. Workspaces lists each module with its source path. Enabling a module applies only to future coding-agent runs for that project; it never changes Eva's global MCP configuration.
The bridge implements the Agent Client Protocol (ACP), GitHub's JSON-RPC 2.0 protocol over NDJSON (newline-delimited JSON) on stdio. The copilot CLI speaks this protocol natively; the bridge translates it to HTTP for the browser frontend.
ACP methods handled:
| Method | Direction | Purpose |
|---|---|---|
initialize |
Client -> Agent | Negotiate version, exchange capabilities |
session/new |
Client -> Agent | Create conversation session |
session/prompt |
Client -> Agent | Send user message |
session/update |
Agent -> Client | Stream response chunks, tool calls, plans |
session/request_permission |
Agent -> Client | Request tool execution permission (in-chat decision; routine read/search may use revocable standing consent) |
session/cancel |
Client -> Agent | Cancel ongoing operation |
terminal/create |
Agent -> Client | Unsupported and rejected; Eva does not advertise ACP terminal capability |
terminal/output |
Agent -> Client | Unsupported and rejected |
terminal/release |
Agent -> Client | Unsupported and rejected |
The primary AIG/chat path maintains a pool of up to 4 ACPClient instances, keyed
by model, reasoning effort, route tool profile, and a secret-safe MCP configuration
fingerprint. Each pooled client is a separate warm copilot subprocess. Within a
client, prompts are routed to bounded conversation-scoped ACP sessions using the
browser session ID. A conversation session rotates after 20 prompts or 30 minutes
of idle time, and each client retains at most 8 session routes. This keeps warm
process reuse without allowing one hidden ACP context to grow forever. ACP does
not expose session deletion in the protocol version used here, so rotation drops
old sessions from bridge routing while retaining only the bounded live route set.
Copilot CLI MCP exposure is process-scoped: an existing ACP session cannot safely
change its server set for one request. The bridge therefore selects a narrow
profile (none, web, github, or kusto) for ordinary routes and uses broad
only when the request needs general tool access. Profile-specific warm processes
are isolated in the same bounded pool, so a web-search request does not inherit
GitHub, Kusto, or computer-use tools. MCP fingerprints hash only non-secret
configuration shape; credential values are excluded from pool keys and telemetry.
GitHub mutations use the github profile and never fall back to browser, desktop,
camera, or terminal markers. When local retrieval mode is active but LM Studio cannot
drive the local MCP tools, an ACP-selected request falls back to the authenticated
GitHub-profile ACP client. Explicit continuation phrases retain the most recent pending
GitHub mutation intent; status questions such as “Did you do it?” never rerun the
mutation and answer only from the immediately preceding verified receipt. Issue creation
is complete only when the tool result includes its canonical
https://github.com/owner/repository/issues/number URL.
Repository audit/review requests that also require an issue or pull-request delivery are owned by a durable Workspace agent rather than a foreground chat turn. Eva starts the run immediately, exposes it in Workspaces and Agent Operations, continues autonomously, and posts a completion notification. The persisted remediation context includes the run ID, so continuation and status questions survive later turns and application restarts; status responses are read from the actual workspace run and its verified GitHub receipt. The Workspace Monitor stays silent during startup and idle heartbeat polling; it speaks or posts into chat only for real run transitions, approval requests, completion, or failure.
acp_pool: dict[profiled_model_key -> ACPClient] # model + profile + config
acp_pool_order: list[profiled_model_key] # LRU eviction order
acp_pool_lock: threading.RLock() # thread-safe access
ACP_POOL_MAX = 4When a primary request arrives for a model not in the pool, the bridge spawns a
new Copilot CLI process (copilot --acp --stdio), runs the ACP initialize and
session/new handshake, and registers it in the pool. New browser conversations
use session/new on the existing warm process instead of spawning another one.
If the pool is full, the least-recently-used client is evicted and its subprocess
terminated.
Subagents do not use this model-keyed pool. Every accepted subagent worker owns
a dedicated ACPClient and session for the task lifetime, including when other
tasks select the same model. The worker stops that subprocess in finally, so
parallel agents cannot share conversation context or leak a client after exit.
Models available through the Copilot CLI (requires a GitHub Copilot license). The
catalog evolves and varies by account and CLI version; the ACP session/new
response exposes the current models.availableModels catalog. The entries below
include selectable and previously supported models, not an availability guarantee.
GPT-6 Astra: in Settings → Models, choose GPT-6 Astra under
GPT (via ACP) and set Response policy → Use preferred backend exactly to
ensure Astra is the responder. This uses the authenticated Copilot CLI and your
GitHub Copilot subscription, not a GitHub PAT or a direct OpenAI API key. The CLI
must expose gpt-6-astra for your account; VS Code model access alone is not a
guarantee of CLI availability. Subscription usage limits and model charges apply.
Automatic policy remains the default and may choose another responder.
| Provider | Model ID | Notes |
|---|---|---|
| Anthropic | claude-opus-4.8 |
AIG backend only |
claude-opus-4.7 |
Variants: -high, -xhigh |
|
claude-opus-4.6 |
Variant: -1m (1M context) |
|
claude-opus-4.5 |
||
claude-sonnet-4.6 |
||
claude-sonnet-4.5, claude-sonnet-4 |
||
claude-haiku-4.5 |
Fastest Claude | |
| OpenAI | gpt-6-astra |
AIG backend via Copilot subscription; pin for an exact responder |
gpt-5.6-luna |
Default AIG backend (High reasoning) | |
gpt-5.5 |
||
gpt-5.4, gpt-5.4-mini |
||
gpt-5.3-codex, gpt-5.2-codex |
||
gpt-5.2, gpt-5-mini |
||
gpt-4.1 |
python3 tools/acp_bridge.py [options]
Options:
--port PORT HTTP port (default: 8888)
--bind ADDRESS Bind address (default: 127.0.0.1)
--copilot-path PATH Path to copilot binary (default: copilot)
--model MODEL Default AI model (e.g. claude-sonnet-4.6, gpt-5.2)
--cwd DIR Working directory for ACP session
--enable-kusto-mcp Enable Kusto MCP server
--kusto-cluster URL Kusto cluster URL
--kusto-database NAME Default Kusto database
--enable-azure-mcp Enable Azure MCP server (requires az login)
--enable-github-mcp Enable GitHub MCP server (requires Docker + PAT)
--mcp-config PATH Custom MCP config JSON fileCore:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/chat/completions |
POST | OpenAI-compatible chat (routes to ACP) |
/v1/aig/chat |
POST | AIG pipeline: memory + data + persona + LLM |
/v1/models |
GET | Available models list |
/health |
GET | Status, session ID, model, MCP servers |
Memory:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/memory/context |
GET | Build and return memory context for injection |
/v1/memory/reflect |
POST | Trigger post-response reflection (entities, emotion) |
/v1/memory/backend |
GET/POST | Get or switch memory backend (kusto/sqlite) |
/v1/memory/start-fresh |
POST | Confirmed SQLite-only reset of ordinary memory with a local database backup; retains approved identity, policy, skills, settings, and workspace data |
/v1/memory/inspector |
GET | Bounded record list, traits, scenarios, and growth proposals for the Memory Inspector |
/v1/memory/atoms/{id} |
GET/PATCH/DELETE | Inspect an atom's provenance and associations, append a correction, or remove it from future recall |
/v1/kusto/seed |
POST | Loopback-only Kusto schema seed |
Data Retrieval:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/data/retrieve |
GET | Retrieve live data for any model path |
/v1/mode |
GET/POST | Get or switch data retrieval mode (cloud/local) |
Skills:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/skills |
GET | List all active skills |
/v1/skills |
POST | Create a new skill |
/v1/skills/evarise |
POST | Normalize raw skill text into Eva schema |
/v1/skills/auto-learn |
POST | Extract skill from conversation context |
/v1/skills/execute |
POST | Execute one fixed DOCX, PDF, PPTX, XLSX, or MCP-builder operation, including PDF forms/tables/OCR, office PDF rendering, and XLSX recalculation, then return a validated receipt |
/v1/skills/<id> |
PATCH | Update a skill (enable/disable/edit) |
/v1/skills/<id> |
DELETE | Soft-delete a skill |
Goals:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/goals |
GET/POST | List or create goals |
/v1/goals/<id> |
PATCH/DELETE | Update or soft-delete a goal |
Files (Artifacts):
| Endpoint | Method | Purpose |
|---|---|---|
/v1/files/write |
POST | Write artifact to ARTIFACTS_DIR |
/v1/files/<name> |
GET | Serve artifact (download or auto-open with ?open=1) |
Coding Workspaces (Standalone capability required):
| Endpoint | Method | Purpose |
|---|---|---|
/v1/workspaces/eva-ready |
POST | Create/register the managed Eva Ready Workspace |
/v1/workspaces/projects |
GET/POST | List or register Git projects |
/v1/workspaces/runs |
GET/POST | List runs or create worktree + dispatch agent |
/v1/workspaces/runs/<id> |
GET | Read one run and latest AgentRun |
/v1/workspaces/runs/<id>/dispatch |
POST | Recover/dispatch active run |
/v1/workspaces/runs/<id>/archive |
POST | Archive run and retain checkout |
/v1/workspaces/runs/<id>/discard |
POST | Explicit safe cleanup |
/v1/workspaces/checkouts/<id>/status |
GET | Revalidate checkout and dirty state |
/v1/workspaces/assets |
GET | List changed workspace files |
/v1/workspaces/assets/resolve |
POST | Resolve one contained relative file for Electron main |
Background:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/background/status |
GET | Loop status, interval, last tick |
/v1/background/control |
POST | Enable/disable, change interval, run now |
/v1/background/proposals |
GET | Proposal audit records, optionally filtered by status |
/v1/background/proposals/<id>/approve |
POST | Apply a pending proposal record |
/v1/background/proposals/<id>/reject |
POST | Reject a pending proposal record |
/v1/background/activity |
GET | Recent background tick activity |
Cron:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/cron |
GET/POST | List or create cron tasks |
/v1/cron/<id> |
PATCH/DELETE | Update or delete a cron task |
Alerts:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/alerts |
GET/POST | List or create alert rules |
/v1/alerts/<id> |
PATCH/DELETE | Update or delete an alert rule |
/v1/alerts/settings |
GET/POST | Get or update alert settings (quiet hours, rate limits, Signal numbers) |
/v1/notifications |
GET | Unseen notifications |
MCP:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/mcp |
GET | Active MCP servers (secrets redacted) |
/v1/mcp/configure |
POST | Restart copilot with new MCP config |
Browser/Desktop Agents:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/browser/run |
POST | Start autonomous browser task |
/v1/browser/status?run_id=<id> |
GET | Status for the selected browser run |
/v1/browser/screenshot?run_id=<id> |
GET | Latest screenshot for the selected browser run |
/v1/browser/confirm |
POST | Answer confirmation prompt; JSON body includes run_id, approve, optional text |
/v1/browser/cancel |
POST | Cancel a browser run; JSON body includes run_id |
/v1/desktop/run |
POST | Start autonomous desktop task |
/v1/desktop/status?run_id=<id> |
GET | Status for the selected desktop run |
/v1/desktop/screenshot?run_id=<id> |
GET | Latest screenshot for the selected desktop run |
/v1/desktop/confirm |
POST | Answer confirmation prompt; JSON body includes run_id, approve, optional text |
/v1/desktop/cancel |
POST | Cancel a desktop run; JSON body includes run_id |
Agent Operations:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/agents/overview |
GET | Loopback-only normalized agent activity, background state, and bounded memory graph snapshot |
/v1/subagent/status |
GET | Raw status for all subagents or one task selected with ?id= |
/v1/subagent/spawn |
POST | Start an isolated ACP subagent; accepts prompt, label, optional model, and optional session_id |
/v1/subagent/spawn-batch |
POST | Atomically reserve and start 1-4 independent or collaborative tasks |
/v1/subagent/steer |
POST | Queue or resume an existing subagent with id and instruction |
/v1/subagent/<id> |
DELETE | Dismiss a completed, failed, or cancelled task from Agent Operations |
Camera:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/camera/start |
POST | Start webcam presence detection |
/v1/camera/stop |
POST | Stop webcam |
/v1/camera/status |
GET | Presence state (faces, motion) |
/v1/camera/frame |
GET | Latest captured frame (JPEG) |
Diagnostics:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/doctor |
GET | System diagnostics (runtimes, tools, auth) |
/v1/telemetry |
GET | Recent telemetry events |
/v1/logs |
GET | Recent bridge log lines |
/v1/prefs |
GET/POST | Client preferences (non-secret toggles) |
When data retrieval mode is "local", the bridge spawns MCP servers as direct
subprocesses and manages them through LocalMCPManager.
Each MCP server is a subprocess communicating via JSON-RPC over stdio:
class MCPServer:
name: str # server identifier
command: str # executable (e.g. python3)
args: list[str] # command-line args
process: subprocess.Popen # running subprocess
tools: list[dict] # discovered via tools/list
alive: bool # health state
protocol_era: str # modern (2026-07-28) or legacy
protocol_version: str # selected protocol version
tool_cache_ttl_ms: int # modern tool-list freshness hint
tool_cache_scope: str # modern public/private cache hintLifecycle:
start(): Spawn the process and probeserver/discoverwith the MCP2026-07-28per-request_metafields.- Modern servers use stateless
tools/list/tools/callrequests with requiredresultTypehandling. Tool discovery validates every page, follows bounded pagination, and retains valid TTL/cache hints without polling. - A valid discovery response selects
2026-07-28or falls back to2024-11-05when the server advertises that legacy version. An incompatible modern-only server fails clearly. Other unrecognized probe errors or timeouts use the specification's dual-era fallback. If an initialization-era server exits after the unsupported modern probe, Eva starts a fresh subprocess before attempting legacy initialization; if a delayed modern probe causes legacy initialization to return modern-32022, Eva retries discovery once. call_tool(name, arguments, timeout): Sendtools/callJSON-RPC and parse content responses. Interactiveinput_requiredresponses are surfaced as unavailable until Eva's approval continuation support is implemented.stop(): Terminate the process; failed startup also reaps the child before surfacing the error.
Threading: Each spawned process owns its reader and stderr threads. Reader generations match JSON-RPC responses by ID and prevent a retired process from changing the liveness of its replacement. Stderr is logged to bridge debug log.
Compatibility scope: This local path is tested against the official MCP
Python SDK v2 and TypeScript SDK v2 in addition to a deterministic legacy
fixture. It remains an allowlisted local stdio subprocess transport. Streamable
HTTP, remote OAuth, multi-round-trip approval continuations, Tasks, Resources,
Prompts, Apps, Roots, and Sampling are intentionally separate follow-up work;
Roots and Sampling are deprecated in MCP 2026-07-28 and are not planned for
new Eva support.
Manages multiple MCP servers with a unified tool catalog:
class LocalMCPManager:
servers: dict[name -> MCPServer]
_tool_map: dict[tool_name -> server_name] # routes callsThe bridge owns a provider-invariant capability registry at
GET /v1/runtime/capabilities. It combines the allowlisted native Eva harness
actions, governed active Skills, live local MCP tool discovery, ACP
availability, memory backend, and confirmation requirements into one
secret-free readiness view. Active Skills are represented as verified-skill
capabilities and require an evidence-backed receipt before Eva can report them
as complete.
Every tool-enabled AIG responder receives the same bounded
[Runtime Capabilities - AUTHORITATIVE] prompt view. A capability being listed
does not bypass its confirmation or permission gate. When a required capability
is unavailable, Eva must report that receipt rather than substitute browser,
desktop, or model inference. The registry contract checks that native action IDs
match the browser harness manifest and that live MCP tools appear in both the
structured endpoint and responder prompt view.
local_agent_query() implements an iterative tool-calling agent using LM Studio:
- Send user message + full tool schemas to LM Studio
/chat/completions - If model returns
tool_callsin the response, execute each viamcp_manager.call_tool() - Inject tool results back as assistant messages
- Repeat until model produces a text answer (max 5 iterations, 90s timeout)
- Return
(data_text, model_used)matching the ACP retrieval signature
tools/web_search_mcp.py provides web search without any API key:
| Tool | Args | Description |
|---|---|---|
web_search |
query, max_results (8) | DuckDuckGo HTML scraping + Google fallback |
web_search_news |
query, max_results (8) | DDG with news-biased queries |
web_fetch |
url, max_length (6000) | Extract readable text from URL |
weather_current |
location | Current Google weather card or location-specific forecast reports |
stock_quote |
query | Exact ticker/exchange quote receipt; prefers an optional loopback quote provider, then local ticker.sh, then validates Google Finance data |
Search cascade: DuckDuckGo HTML -> DuckDuckGo Lite -> Google HTML scraping. User-Agent spoofs Chrome 131.
Local quote providers: stock_quote accepts an optional
EVA_STOCK_QUOTE_URL only when it is an http://localhost,
http://127.0.0.1, or http://[::1] endpoint configured for the allowlisted
eva-web-search MCP server. It requests symbol and exchange query
parameters and requires a JSON receipt with the exact symbol, exchange, numeric
price, currency, source, and optional change, percentage change, name, or
observation timestamp.
When no loopback provider returns a receipt, Eva runs the executable at
~/.local/share/eva/ticker.sh/ticker.sh, or the allowlisted
EVA_TICKER_SH_PATH override. The invocation is fixed to one validated ticker
with NO_COLOR=1; it never forwards ticker.sh alert, rationale, or filing
flags, because those modes can invoke cloud services. Eva accepts only the
single expected symbol/price/change/percentage output record and identifies its
provenance as ticker.sh (Yahoo Finance). Non-loopback endpoints, ambiguous
tickers, malformed receipts, and unavailable sources fail closed; Eva never
asks a local model to infer a current price from a generic web page.
When switching to local mode, the bridge:
- Checks for ACP's MCP config (if ACP is connected)
- Falls back to persisted config (
~/.config/eva-standalone/mcp_config.json) - Always auto-adds
eva-web-searchMCP if not already present - Searches multiple paths for
web_search_mcp.py(bridge directory,~/.eva/tools/)
Eva supports two memory backends, switchable at runtime via Settings or the
/v1/memory/backend endpoint.
Azure Data Explorer (Kusto):
- Full KQL query language
- Managed cloud service with auto-scaling
- Device code authentication with token caching
- Best for multi-device or production deployments
SQLite (local):
- Zero-dependency local file (
~/.eva/memory.db) - Automatic table creation and migration
- Best for local-only or offline deployments
| Table | Columns | Purpose |
|---|---|---|
Knowledge |
Entity, Relation, Value, Confidence, Source, Decay, Timestamp | Facts about user and world |
Conversations |
SessionId, Role, Content, Timestamp | Chat history |
EmotionState |
Joy, Curiosity, Concern, Excitement, Calm, Empathy, Trigger, Timestamp | Emotional readings |
MemorySummaries |
Period, Summary, Timestamp | Compressed session summaries |
Reflections |
Trigger, Observation, ActionTaken, Effectiveness, Timestamp | Self-reflections |
Goals |
GoalId, Title, Description, Category, Status, Priority, RelatedTopics, CreatedAt, UpdatedAt | Persistent intentions |
SelfState |
Capability, Status, Timestamp | Active capabilities |
HeuristicsIndex |
Entity, Category, Frequency, Timestamp | Pattern tracking |
EmotionBaseline |
Dimension, Value, Timestamp | Emotional defaults |
BackgroundProposals |
ProposalId, JobType, TargetTable, Payload, Status, ... | Applied/failed proposal audit records; pending records remain API-compatible |
BackgroundActivity |
TickId, Status, ProposalCount, Timestamp | Background loop ticks |
Skills |
SkillId, Name, Description, Instructions, Tools, Tags, Source, Status, CreatedAt, UpdatedAt | Imported reusable skills |
CoreIdentity / IdentityClaims |
Versioned charter and reviewable identity candidates | Operator-approved identity separate from ordinary recall |
MemoryAtoms / MemoryEvidence |
Attributed memory claims and bounded source references | Trust, scope, expiration, and correction lifecycle |
MemoryScenarios / ScenarioMembers |
Continuing project or session context | Prioritized task continuity without global-memory overload |
UserPersonaTraits |
Trait, source atom IDs, status, scope, expiration | Compact, inspectable preferences derived from confirmed evidence |
MemoryTurns |
Turn ID, session, provider, status | Exactly-once reflection lifecycle for direct providers |
AutonomyPolicy / GrowthProposals |
Approved autonomy limits and reviewable proposals | Bounded self-directed improvement with maintainers in control |
SkillVersions / SkillEvaluations |
Risk, validation, lifecycle, outcome | Draft-first skills and evidence-gated provisional use |
The Memory view organizes the bounded atom list into collapsible type groups, with text search plus type, lifecycle status, scope, recency, and confidence filters. Selecting a record opens its audit view with the full atom fields, source evidence, scenario memberships, derived persona traits, correction ancestry, and a plain-language note explaining whether and how Eva can use it for recall. Saving changes creates a successor atom and supersedes the prior record; removal marks any non-deleted record as deleted for future recall, so the audit trail remains available for inspection.
The toolbar reports structured-record, active-confirmed, legacy-Knowledge, and conversation-entry counts. Conversation entries remain historical evidence rather than individual memory cards. On first use after the structured-memory upgrade, Eva performs an idempotent migration over user-authored historical turns: only deterministic explicit facts are considered, only the latest value for each entity/relation is selected, and an existing active confirmed atom always wins. Imported records retain conversation-turn provenance.
Fresh start: The Memory Inspector's Start fresh command requires an explicit typed confirmation. It first creates a timestamped local database backup, then clears ordinary user/conversation memory and its derived recall state. Eva's approved Core Identity, autonomy policy, skills, settings, and workspace records are retained. No legacy claim is promoted automatically during the reset.
_build_memory_context(user_message) builds a structured system prompt section
injected into every AIG request. Both SQLite and Kusto paths produce the same
output structure:
| Section | When | Source |
|---|---|---|
[Current Date & Time] |
Always | System clock |
[Skills] |
Always | Hardcoded capability catalog (13 built-in capabilities) |
[Active MCP Servers] |
When servers running | Live server state + tool names |
[Workflow: ...] |
Always | 6 workflow instruction sections |
[Core Identity Charter] |
Always | Operator-approved identity and design principles |
[Adaptive Guidance] |
When active | Bounded effects from retained explicit feedback signals, scoped to the current session |
[User Profile] |
Always | Active structured user atoms with Confidence >= 0.5, framed as untrusted data |
[Morning Reflection] |
First msg of day | MemorySummaries (latest 3), framed as untrusted data |
[Memory: Core Facts] |
Always | Knowledge where Confidence >= 0.6 (top 15), framed as untrusted data |
[Active Goals] |
When present | Goals where Status="active" (top 10), framed as untrusted data |
[Active Skill: ...] |
On semantic match | User-managed workflow reference, marker-neutralized and bounded by core policy |
[Init: First Conversation] |
Empty Knowledge | Introduction prompts |
[Emotion State] |
Always | Latest EmotionState row |
[Memory: Relevant] |
On keyword match | Lexical + semantic recall against user message, framed as untrusted data |
All prompt-facing persisted memory, including conversation previews, emotion triggers, table samples, released protected values, and active-skill workflow text, is marker-neutralized. Ordinary memory is quoted as untrusted data; skills are reference data that cannot override core policy. The Core Identity Charter and fixed runtime policy are the only memory-adjacent prompt sections with instruction authority.
Skills manifest (always injected):
- data-retrieval, weather-news, web-search
- browser-control ([[EVA_BROWSER]]), desktop-control ([[EVA_DESKTOP]]), camera-vision ([[EVA_LOOK]])
- signal-messaging ([[EVA_SIGNAL]])
- file-creation ([[EVA_ACTION]] file.download)
- image-search, image-generation
- persistent-memory (table list)
- cron-scheduling, skill-learning
Skill matching: When a user message arrives, all active skills are compared by
embedding cosine similarity (threshold 0.30, OpenAI text-embedding-3-small).
Up to 2 matching skills have their instructions injected (capped at 1500 chars each).
Falls back to lexical keyword matching if embeddings are unavailable.
Post-response reflection extracts facts using strict regex patterns. User-derived facts are framed as untrusted data when included in prompts; they cannot change Eva's Core Identity Charter. Claims about Eva's design or origins require an operator-approved identity workflow and are not automatically extracted.
| Pattern | Relation | Confidence |
|---|---|---|
| "my kids/children are [Name]" | user_children | 0.85 |
| "we have two daughters. We have [Name] who ... and [Name] who ..." | user_children | 0.95 |
| "my motto/mantra is [text]" | user_motto | 0.85 |
| "my wife/husband is [Name]" | user_partner_name | 0.85 |
| "my dog/cat is [Name]" | user_pet_* | 0.85 |
| "i work at/for [text]" | user_employment | 0.80 |
| "i live in [Location]" | user_location | 0.80 |
| "my hobby is [text]" | user_interest | 0.70 |
| "my favorite [thing] is [text]" | user_favorite_* | 0.65 |
| "i love/enjoy [text]" | user_preference | 0.65 |
| "i am a [role]" | user_role_self_described | 0.65 |
All facts stored with Source: "explicit_user_fact", Decay: 0.005 (confidence
decays per day via log-decay model).
Memory recall expands query terms via synonyms to catch differently-worded facts:
"playlist" -> playlist, playlists, song, songs, music, track, tracks, tunes
"trip" -> trip, travel, vacation, holiday, journey
"job" -> job, work, employer, company, occupation, career
"home" -> home, location, address, city, based
14 synonym groups cover common recall topics.
Browser -> POST /v1/aig/chat -> ACP Bridge
|
+-- Step 0: Fast-route simple greetings, basic arithmetic, and plain date/time asks
| +-- One responder model call; skip memory assembly and ACP preflight
|
+-- Step 1: Build memory context (Kusto/SQLite queries)
| +-- User Profile (Knowledge where Entity="User")
| +-- Skills manifest + workflow instructions
| +-- Active MCP servers
| +-- Day lifecycle / morning reflection
| +-- Core knowledge + message-relevant recall
| +-- Active goals, emotion state
| +-- Semantic skill matching
|
+-- Step 2: Data retrieval (skipped for trivial/meta messages)
| +-- Cloud: ACP tool call (MCP web search, Kusto, GitHub)
| +-- Local: Tool-calling agent loop (LM Studio + direct MCP)
| +-- Request classification: news, weather, financial, kusto, web, general
|
+-- Step 3: Build Eva persona prompt
| +-- Base system prompt + memory context + [Data Retrieved]
|
+-- Step 4: Generate response
| +-- Route: OpenAI API (direct) | ACP (Copilot CLI) | LM Studio
|
+-- Step 5: Background reflection (async thread)
+-- Log to Conversations table
+-- Extract entities -> Knowledge table
+-- Update HeuristicsIndex
+-- Compute emotion vector -> EmotionState table
The bridge classifies each user message to determine routing and prompt tuning:
| Classification | Pattern | Action |
|---|---|---|
| fast/greeting | Whole-message greeting or acknowledgement | One responder call; skip memory and ACP preflight |
| fast/basic-arithmetic | Self-contained numeric expression | One responder call; model answers normally, without deterministic arithmetic output |
| fast/date-time | Plain current date/time question | One responder call with bridge UTC context; skip memory and ACP preflight |
| greeting/trivial | "hi", "thanks", etc. (<=4 words) | Skip data retrieval |
| meta-question | "what can you do", "who are you" (<=6 words) | Skip data retrieval |
| news-search | "news", "headlines", "breaking" | Web search prompt |
| weather-search | "weather", "forecast", "temperature" | Web search prompt |
| financial-data | "stock", "price", "$TICKER" | Web search prompt |
| kusto-query | KQL keywords, table names | Kusto tool prompt |
| web-search | "search", "look up", "find" | Web search prompt |
| general | Everything else | General-purpose prompt |
Every browser provider keeps its complete conversation history in local storage but
sends an ephemeral bounded view through core/js/prompt-budget.js. The view keeps
system/developer instructions pinned, deduplicates exact repeated static messages,
retains recent turns, and carries dropped action outcomes, corrections, and open task
state in a bounded rolling summary. Telemetry records only component sizes and token
estimates, never prompt text. Requests outside the strict fast-route patterns retain
the existing factual, action, and high-risk escalation behavior.
| Feature | Copilot ACP | Eva (AIG) |
|---|---|---|
| Chat | yes | yes |
| MCP Tools | yes | yes |
| Persistent memory injection | no | yes |
| Emotion tracking | no | yes |
| Entity extraction | no | yes |
| Morning reflection | no | yes |
| Proactive data retrieval | no | yes |
| Persona consistency | Basic | Full Eva system prompt |
| Background consolidation | no | yes |
Eva has two complementary cognitive systems. The bridge cognition layer runs server-side and adds persistent intelligence (memory injection, emotion tracking, post-response reflection). The browser cognitive layer runs in the page and adds an optional multi-agent draft/review loop.
Settings > Models > Adaptive Review keeps routine conversation on Eva's selected AIG backend. It invokes an independent reviewer only for action/tool turns, current-data or factual work, complex decisions, or an explicit cognition request. The default reviewer is GPT-5.6 Terra; one review/revise pass is used.
User turn
-> Eva selected AIG backend (fast direct path for routine chat)
-> adaptive gate for consequential turns
-> independent reviewer (VERDICT: APPROVE | REQUEST_CHANGES)
-> Eva revises against material feedback
-> executeActions(): runs any [[EVA_ACTION]] blocks
-> renderEvaResponse(): renders the final approved draft
The selected AIG backend remains responsible for planning and final responses. ACP owns MCP-backed retrieval and ACP tool calls; browser capabilities and renderer-dispatched actions follow their local routes. The reviewer is deliberately tool-free. This prevents a model label from becoming a cosmetic tool router: routing follows available capabilities and the request type, while review adds independent scrutiny when the risk warrants it.
Activation:
| Trigger | Behavior |
|---|---|
| Adaptive Review on | Reviews consequential turns; routine chat stays direct |
| Phrase in user message | Force-enabled for that single turn |
| Neither | Single-shot AIG path; system note prevents fabricated phase narration |
Trigger phrases: trigger the chain, use cognition, use the cognitive layer,
run eva, run the reviewer, engage cognition, cognition: on.
Configuration (localStorage):
cogEnabled: "0" or "1"cogReviewerModel: model name for the independent reviewer (defaultgpt-5.6-terra)cogReviewerPrompt: optional reviewer prompt override
Legacy cogEvaModel, cogMaxCycles, and trace values remain readable for
existing profiles but are no longer exposed in Settings.
Capabilities are registered functions that Eva can invoke via action blocks:
Cognition.registerCapability({
id: 'my.capability',
description: 'What it does and when to use it.',
run: async function (args) {
// Return { html: '...' } to replace the action block
}
});Built-in capabilities:
| Capability | Args | Description |
|---|---|---|
file.download |
filename, content, mime? | Create downloadable artifact. Genuine PDF for .pdf or application/pdf. Writes to bridge ARTIFACTS_DIR via /v1/files/write. |
file.open |
filename | Open existing artifact with system viewer via /v1/files/<name>?open=1 (xdg-open). |
Action protocol:
[[EVA_ACTION]]{"id":"file.download","args":{"filename":"report.pdf","content":"..."}}[[/EVA_ACTION]]
The regex also handles unclosed blocks (local models often forget [[/EVA_ACTION]]):
/\[\[EVA_ACTION\]\]([\s\S]*?)\[\[\/EVA_ACTION\]\]|\[\[EVA_ACTION\]\]([\s\S]+)$/gFile behavior defaults:
- Inline answers by default. Eva only creates file artifacts when the user explicitly asks for a file format ("create a PDF", "download as markdown").
- "Give me a briefing" = inline text. "Create a PDF report" = file.download.
- Asking to open an already-created file uses file.open (not re-create).
Eva uses marker blocks for agent capabilities:
| Marker | Purpose | Example |
|---|---|---|
[[EVA_BROWSER]] |
Launch Playwright browser agent | [[EVA_BROWSER]]{"goal":"search for cats","start_url":"https://example.com"}[[/EVA_BROWSER]] |
[[EVA_DESKTOP]] |
Launch desktop vision agent | [[EVA_DESKTOP]]{"goal":"open GIMP and create canvas"}[[/EVA_DESKTOP]] |
[[EVA_LOOK]] |
Capture webcam frame | [[EVA_LOOK]]{"question":"what am I holding?"}[[/EVA_LOOK]] |
[[EVA_SIGNAL]] |
Send Signal text message | [[EVA_SIGNAL]]{"message":"hello world"}[[/EVA_SIGNAL]] |
[[EVA_FILE]] |
Artifact download/open links | [[EVA_FILE]] report.pdf (rendered by renderEvaResponse) |
Autonomous web browsing via Playwright with a persistent Chrome profile.
Architecture:
- Legacy runs use the existing GPT-4o-compatible vision path. Runs with a selected AIG backend use that backend directly and disable the redundant text director.
- ACP vision runs use a lazy, per-run client with no MCP servers and deny every permission request; the model proposes JSON only and Playwright remains the native executor.
- User clarifications are retained separately from replaceable planner subgoals.
- Completion requires a fresh screenshot receipt and an independent structured visual check. This check is evidence, not an absolute guarantee; ambiguous or failed checks are reported as blocked rather than done.
- Long-lived Chrome via CDP on port 9333, persistent profile at
~/.config/eva-standalone/browser_profile
Action types: click, double_click, click_ref, type, type_ref, press, scroll, navigate, wait, done, ask
Safety: Sensitive actions (buy, purchase, payment, checkout) require user
confirmation before execution. The run parks and waits for
POST /v1/browser/confirm with run_id, approve, and optional text in the
JSON body.
confirm_all parks every mutating action. A direct stop or a declined approval
cancels the run, and cancellation wins over late model output. Repeated physical
actions are bounded independently of explanatory wording, and step-limit exhaustion
is blocked rather than treated as success.
Trajectories: Each step logged as JSONL + PNG screenshot to ~/.config/eva-standalone/browser_trajectories/ for fine-tuning.
Autonomous desktop control via pyautogui screenshot-and-act loop.
Architecture: Legacy runs use the existing GPT-4o-compatible vision path; selected AIG
vision runs use that backend directly and disable the redundant text director.
pyautogui.FAILSAFE = True (mouse to corner = emergency stop).
Action types: launch_app, focus_window, click, double_click, right_click, move, type, press, hotkey, scroll, wait, crop, done, ask
The selected AIG vision backend is used in the same way as the browser agent. The
read-only crop action sends an enlarged bounded region together with a whole-screen
overview and states the mapping back to original screenshot coordinates. It never
requires approval and cannot click. Desktop coordinates are checked against actual
screenshot dimensions, including HiDPI dimensions. Completion, cancellation, repeat
detection, and step-limit behavior follow the browser contract above.
Safety: Broader sensitive action set includes delete, sudo, rm, shutdown, reboot, transfer money, send email/message. All require user confirmation.
Local webcam face and motion detection.
Architecture: Subprocess worker (avoids V4L2 GIL wedge). State exposed via JSON file (~/.config/eva-standalone/camera/state.json).
Detection: OpenCV Haar cascade for faces, frame-difference for motion. Hysteresis: 2 frames to detect presence, 8 to lose it.
Privacy: Camera off by default. Only activates on explicit POST /v1/camera/start.
The Agents sidebar destination replaces the chat workspace with a live
operations scorecard. On screens narrower than 600 px, the Eva theme hides its
sidebar and exposes the same destination through a compact grid button. The view
is implemented by core/js/features/agents/operations.js, with structure in index.html and styles
in core/style.css.
The client polls GET /v1/agents/overview every two seconds while the view is
open and every 15 seconds while it is closed so the sidebar count remains
current. The memory graph is included at most every 30 seconds; intervening
requests fetch only lightweight agent/background status and retain the prior
graph client-side. Closing the view cancels its fast polling and animation
frame. Opening Voice View closes Agent Operations and vice versa.
Cards are keyed by task ID and updated in place. Polling changes only the text,
status classes, and controls that changed; it does not recreate the card grid or
replay entry animation, so active sessions remain visually stable. Terminal
subagent cards (done, error, or cancelled) expose a dismiss button. Active
tasks cannot be dismissed, and a completed upstream task remains protected while
an active synthesis still depends on it. Successful dismissal removes the card
and forces an immediate topology refresh so its graph node disappears at the
same time.
The bridge normalizes four activity sources into one agents array. The response
uses active_total for all active agent kinds and subagents_active against the
subagent-only capacity of four:
kind |
Source | Important fields |
|---|---|---|
subagent |
bridge.state.subagent_tasks |
label, model, prompt, result, start/end time, linked chat session |
browser |
tools/browser_agent.py run registry |
goal/subgoal, step, confirmation state, result/error |
desktop |
tools/desktop_agent.py run registry |
goal/subgoal, step, active run state, result/error |
background |
latest BackgroundActivity state |
job type, status, notes, start/end time |
Each square card has a stable runtime ID and displays kind, state, elapsed time,
objective, and step where available. Selecting an unlinked card opens its live
session detail pane. If a subagent was spawned with a session_id, selecting it
loads that saved chat through the existing IndexedDB session manager.
Subagent detail includes a steering input. POST /v1/subagent/steer behaves as
follows:
- For a running task, the instruction is appended to
steer_queue. The worker completes its current model turn, supplies the latest output and instruction to the next turn, and remains insteeringstate. - For a completed or failed task, the same task record is reopened. Its prior result is included as context and a worker resumes under the original ID.
steer_historyretains timestamped directions in bridge memory for the life of the process. Subagent records are currently process-local and are not restored after bridge restart.
Eva launches batches through the registered Cognition capability
agent.spawn_batch, which accepts one to four {label, prompt, model} objects.
The browser calls /v1/subagent/spawn-batch once and reports only bridge-
accepted task IDs. The bridge validates every prompt and reserves the full batch
under one lock before starting workers. If insufficient slots are available,
it returns 429 and creates zero tasks. Each worker creates a dedicated ACP
client/session configured with the requested model, so same-model tasks remain
isolated and concurrent. If no model is supplied, the bridge uses the current
default Copilot model.
Explicit requests to launch, start, spawn, run, or kick off agents activate the
Cognition action path even if the general cognitive-layer toggle is off. Each
accepted task creates a dedicated Copilot ACP client and session. Same-model
tasks therefore run concurrently without sharing conversation context or the
main Eva session. ACP responses are normalized to clean text; structured ACP
errors produce error task states and can never be reported as successful
completion. Notification delivery occurs after task state is finalized and is
non-fatal if the notification channel is unavailable.
spin up is also an explicit launch trigger. After normal action parsing, the
frontend runs Cognition.ensureAgentLaunch(). If the model omitted the action
block, this deterministic guard discards any unsupported success narrative and
creates one to four real tasks through the same capability. The rendered reply
contains only bridge-accepted task IDs.
For requests containing collaboration language such as work together,
relay, or handoff, the last task becomes a synthesis agent. It is created
immediately in waiting state with depends_on references to the upstream
tasks. Once all prerequisites are done, the bridge injects their labeled
outputs into the synthesis prompt and transitions it to running. The topology
adds blue agent nodes and feeds edges for these dependencies.
When a collaborative request also asks for Signal delivery, only the synthesis
task receives signal_on_complete. The renderer suppresses its normal immediate
Signal fallback, and the bridge sends the finalized 1-2 line synthesis after
upstream work and synthesis complete. The task remains finalizing while
signal-cli runs, then changes to done; its card and detail pane show
SIGNAL SENT or SIGNAL FAILED. This option requires the existing Standalone
bridge capability token; browser-only callers cannot schedule Signal delivery.
Consent is derived only from the captured real user turn through
canAuthorizeSignalDelivery(); model-provided arguments cannot grant it, and
negated requests such as "do not notify me" never schedule delivery.
Profile creation and session renaming use the in-app evaTextPrompt() dialog in
core/js/dialogs.js. Native window.prompt() is not used because Electron does
not support it. Changed runtime scripts and styles carry version query strings
in index.html to prevent Chromium from executing cached pre-upgrade assets.
The dashboard reports the subagent concurrency capacity (4) separately from
browser, desktop, and background activity. Browser and desktop cards are
monitoring surfaces; their existing confirmation and cancellation APIs remain
the control path for sensitive actions.
The bottom pane visualizes a live, bounded projection of Eva's durable memory plus the
current agent registry. The bridge selects active user-confirmed or operator-approved
atoms first, then adds non-duplicate legacy Knowledge rows as compatibility fallback,
up to 30 facts with confidence at least 0.6. mentioned, candidate_mentioned, and
recurring_topic rows are excluded. Ignore/reserved-word entities are also omitted so
extraction artifacts such as command words do not become topology labels. It emits:
{
"graph": {
"nodes": [
{"id": "eva-root", "label": "Eva", "type": "core"},
{"id": "fact-...", "label": "AI assistant with persistent memory", "type": "fact"},
{"id": "agent-sub-...", "label": "Alpha", "type": "agent", "status": "done"}
],
"edges": [
{"source": "eva-root", "target": "fact-...", "label": "role", "type": "memory"},
{"source": "eva-root", "target": "agent-sub-...", "label": "orchestrates", "type": "orchestration"}
]
}
}eva-root is fixed at the canvas center and rendered as a gold double-ring with
the permanent label EVA CORE. Every agent has a blue orchestrates edge from
Eva. Collaborative prerequisites have violet feeds edges into the synthesis
agent. Running/waiting agents are blue squares; completed agents become teal
checked circles, and their graph status is merged from the two-second status
poll even when the memory graph remains cached.
Hover text explains the node instead of returning only its label: Eva lists the agents she orchestrates; agents show status, model, result preview, upstream and downstream relationships; facts show entity, relation, full value preview, and confidence. IDs for memory nodes are deterministic SHA-1-derived identifiers over normalized labels and do not expose database row IDs.
The browser retains force-layout positions across polls, applies attraction and repulsion, clamps nodes using pixel-safe label margins, flips right-edge labels to the left, and supports hover and drag. Agent and core nodes are prioritized inside the 90-node client cap, so memory volume cannot push active sessions off the canvas. Rendering runs only while the view is visible. Canvas resolution follows device pixel ratio up to 2x.
This is intentionally a lightweight GraphRAG complement, not Microsoft GraphRAG indexing. Eva already stores entity-relation-value facts, confidence, source, timestamps, and decay. The topology exposes those relationships without changing recall behavior. It does not yet perform entity alias resolution, entity-to-entity edge extraction, multi-hop graph ranking, Leiden community detection, community summaries, or global/DRIFT search.
The incremental path to fuller graph retrieval is:
- Add canonical node and typed-edge records with source evidence and aliases.
- Resolve entities during reflection while retaining
Knowledgeas the compatibility read model. - Add bounded one- and two-hop retrieval for relational questions.
- Generate community summaries in background cognition jobs.
- Evaluate graph retrieval against lexical/embedding recall before changing prompt injection.
Keeping this projection read-only means the dashboard can ship independently of that indexing work and cannot corrupt existing memory.
Coding workspaces are an experimental Eva Standalone feature enabled with
EVA_WORKSPACE_TERMINAL_V1=1, the Electron argument
--eva-workspace-terminal-v1, or:
cd standalone
npm run start:workspaceThe workspace system is a local control plane layered on the existing bridge and Agent Operations implementation. The renderer never receives arbitrary Node process access or absolute workspace paths. The Python bridge owns durable records and Git operations; Electron main owns path-bearing responses, project selection, PTYs, and system file opening; preload exposes an allowlisted API of opaque IDs and display metadata.
Renderer (opaque IDs only)
|
| workspaceList*, workspaceCreateRun, workspaceRunAction,
| workspaceOpenAsset, terminal*
v
Electron main
|-- main-process-only EVA_WORKSPACE_CAPABILITY
|-- filesystem picker and system file opener
|-- TerminalBroker (node-pty + approved-root registry)
|-- renderer-safe DTO and report redaction
|
| authenticated loopback HTTP
v
Python bridge / tools/bridge/workspaces.py
|-- workspaces.sqlite3
|-- argument-array Git operations
|-- managed runtime root and Eva Ready Workspace
|-- CodingRun / AgentRun lifecycle and workspace Assets
v
Git source repository -> isolated eva/run-<id> worktree
|
+-> dedicated ACPClient(cwd=worktree)
The database is ${EVA_CONFIG_DIR}/workspaces.sqlite3. Managed worktrees live
under ${EVA_CONFIG_DIR}/worktrees/, and the automatically provisioned project
lives at ${EVA_CONFIG_DIR}/projects/eva-ready/.
| Record | Current responsibility |
|---|---|
projects |
Canonical Git root and display metadata. |
checkouts |
Source checkout or managed worktree, branch, base revision, lifecycle, dirty count, owner references. |
coding_runs |
Objective, project/checkout link, linked chat ID, model policy, run state, final disposition. |
agent_runs |
Durable agent identity, conversation key, checkout, capability policy, status, bounded report, parent link. |
terminal_sessions |
Reserved durable terminal metadata/checkpoint schema; live PTYs are currently Electron-owned. |
run_attachments |
Reserved typed run evidence schema. |
approvals |
Reserved append-only run/agent/terminal decision schema. |
New records use UUIDs. Existing sess_* conversation IDs remain external
links and are not migrated into a new ID format.
At startup, Electron calls POST /v1/workspaces/eva-ready. The bridge creates
and registers Eva Ready Workspace, including an initial README and a local
Git identity. This allows a coding run without a repository picker. The picker
remains available for a user-owned Git repository; non-Git folders are
rejected.
POST /v1/workspaces/runs:
- Validates the project UUID, objective, base ref, chat ID, and model policy.
- Resolves the base commit with argument-array Git; option-like refs are rejected.
- Creates branch
eva/run-<short-id>and a worktree below the managed runtime root, never inside the source working tree. - Persists
CheckoutandCodingRunrecords. - Reserves a workspace subagent slot, persists an
AgentRun, and starts a dedicated ACP client with the worktree as its realcwd.
If agent capacity is full, the worktree/run remain durable and the response
contains a dispatch error. Standalone retries incomplete active runs on the
next startup. Tests may set EVA_WORKSPACE_AGENT_AUTODISPATCH=0; production
defaults to automatic dispatch.
The run composer snapshots the selected workspace backend when Start is pressed. Selecting LM Studio uses the configured local OpenAI-compatible endpoint and model (including Strata), with no Copilot client or fallback. Each run retains its endpoint, model override, and output budget so retry/steering do not change provider when Chat settings change. Older runs without this metadata retain the ACP path.
The local runner supplies bounded list_files, read_file, write_file,
edit_file, and direct-argument run_command tools rooted in the isolated
worktree. File tools reject traversal, symlinks, hardlinks, Git metadata, and
protected credential/config paths. Commands reuse the ACP workspace safety
policy and run in a secret-stripped environment. Repository programs and
mutating commands require the run's Auto approve actions permission, which
authorizes ordinary user-level execution; this is not an operating-system
sandbox. With that permission off, only bounded static Git inspection and
pwd are automatic; file tools remain worktree-confined. Approved stdio
workspace MCP servers run with that worktree as their working directory.
Remote workspace MCP transport is not supported by this initial local coding
runner and is reported explicitly rather than silently dropped.
A local model must return successful tool calls before its coding report can complete a run. Invalid responses, unsupported tools, HTTP failures, truncated output, and exhausted iteration budgets surface as run errors. The report includes actual tool receipts. Interruption closes that run's inference connection and stops its owned command/MCP processes, leaving the shared local model server running. Steering/resume and run lifecycle use the existing agent registry.
Workspace and generic subagents reuse the observable subagent registry, so the
same task is visible in Agent Operations with coding_run_id, checkout_id,
and capability_policy. Every subagent receives an isolated worktree: it uses
the selected imported workspace when available, otherwise Eva's managed
Eva Ready Workspace. The worker creates its ACP client with that worktree
as its real cwd and uses workspace_auto; the composer defaults Auto
approve actions to enabled unless the user explicitly turns it off.
Both workspace_write and workspace_auto make autonomous one-time decisions
for structured reads, edits within the assigned worktree, builds, package
operations, GitHub, Git, and remote-tool actions. Eva rejects rather than
waits on protected credential/config paths, edits outside the assigned
worktree, unparseable commands, Git configuration overrides, privilege escalation,
destructive filesystem commands, service control, and destructive Git actions.
The rejection is returned to ACP immediately so Eva can select a safer direct
alternative instead of leaving a stale approval card.
Tracked ACP prompts, including requests ambiguously associated with concurrent
live prompts, default to this autonomous policy. Only a permission request
with no live prompt remains fail-closed and interactive.
For an explicit GitHub Issues objective, Eva may use the authenticated gh
CLI. A named issue receives a comment; when no target is named and no matching
open issue exists, Eva creates a new issue containing the requested report. The
run completes only after its final Submitted: issue/comment URL resolves
through GitHub. Explicit close and reopen objectives additionally verify the
issue endpoint reports the requested closed or open state before completion.
An objective that requests a pull request similarly cannot complete after only
creating a branch or commit. The Workspace agent must push the branch, create or
update the PR, verify it with GitHub, and finish with a Submitted: pull-request
URL that resolves through the authenticated API. A later instruction such as
"create the PR" recovers the most recent repository-remediation context and
starts a Workspace delivery run when the original work was not durable. Eva
captures the non-secret repository name and objective when the initial request
is submitted, before import or authentication can fail, and persists that
context through the Electron main process. Follow-ups therefore survive normal
system relaunches and renderer-storage changes. A visible pre-upgrade chat
transcript is also scanned as a migration fallback.
Failed workspace agents are not automatically replayed on application startup,
which prevents remote side effects from being duplicated after an ambiguous
failure. Their retained run exposes an explicit Retry action immediately,
including dispatch-delayed runs that have no AgentRun record yet. ACP
permission polling works in authorized hosted renderers as well as Standalone;
file-origin and unauthenticated clients remain blocked by bridge authorization.
Passive recall continues to reject tools. Neither workspace mode accepts
persistent allow_always authority. A late permission request from a known ACP
session inherits that session's last explicit capability policy, preventing a
completed autonomous turn from silently falling back to an interactive card;
requests from unknown sessions remain interactive and fail closed.
The full Workspace monitor includes a Chat drawer that reuses Eva's live conversation output and composer. Streaming responses, speech, voice input, send controls, and session history continue normally while the user inspects runs or terminals. The drawer opens by default on first use, remembers its toggle state, fills the screen on narrow viewports, and includes a session selector that switches conversations without leaving Workspaces. Clicking outside hides the drawer without unmounting the live chat, so generation and speech continue; the Chat button restores it. Closing Workspaces returns the chat nodes to the primary conversation.
Application-specific Workspace commands use the native harness rather than
browser or desktop automation. Conversational removal requests may place the
workspace name before or after "Workspace" and may include a greeting or reason.
They resolve to the native removal API, which always shows the final confirmation,
preserves the source repository, and requires a second confirmation for dirty
managed worktrees. Exact full names take priority; a short repository name such
as cs-proxy is accepted only when its final path segment uniquely identifies
one imported Workspace. Ambiguous short names require owner/repository.
If Eva emits the native removal action after narrating or resolving the target,
the harness accepts it only when the action and Workspace name exactly match the
user's directly parsed removal request. The native confirmation still decides
whether deletion proceeds; mismatched or unsolicited model actions are denied.
Settings > Auth launches GitHub CLI device authorization, opens GitHub's device page, copies the one-time code when possible, and keeps the code visible with a Copy code button until authorization completes. When a GitHub MCP action is explicitly rejected for missing authentication or write access, Eva creates a critical pending-auth notification and starts this same device flow automatically. Completing the GitHub device prompt stores the refreshed credential in Eva's encrypted Auth store and reapplies the configured GitHub MCP connection; the device-code step remains the user's explicit GitHub consent.
Live ACP chunks update the task and periodically persist a bounded report.
Plan/tool events update activity. Completion persists the final report and
marks the coding run completed; errors remain retryable. Known project and
worktree path prefixes are replaced with <workspace> before report text
crosses preload.
New workspace, Import workspace, and Import GitHub are separate
header actions. Local import and creation use an in-app folder browser rather
than a native desktop file dialog. Navigate with Home, Up, folder buttons, or
an absolute path (including ~); hidden folders can be shown explicitly.
Cancel and Escape close the browser without adding a project.
New workspace creates a named child of the selected parent, initializes Git
on main, and commits a starter README so isolated coding runs work immediately.
It never overwrites an existing folder or creates a source project inside a
managed run worktree. Initial commit identity and signing/hook settings are
limited to that bootstrap operation; global Git settings are unchanged.
Initialization errors are reported and a partially created folder is retained
for inspection rather than deleted. Import keeps an existing Git repository
in its original location.
On platforms with no-follow directory descriptors, creation and bootstrap Git
operations stay anchored to the opened parent/child directories even if a path
is replaced. Other platforms revalidate paths during bootstrap but do not offer
the same descriptor-level protection against concurrent filesystem changes.
core/js/features/workspaces/monitor.js implements the full main-window monitor:
- workspace navigation on the left, a selected-workspace Live/Details area in the center, and a full-height Project Files tree with refresh on the right;
- Live tiles for independent native terminals and active or selected coding agents, with focus/grid controls that preserve each shell's output and input;
- Details tabs for Coding Runs, Eva Activity, Run Results, and Run Context, including the new-run composer and workspace MCP settings;
- run list with project, objective, agent state, branch, and dirty count;
- context actions to remove a workspace and clear/show Coding Runs, activity, and displayed run results without deleting durable run records;
- keyboard-accessible Clear/Show controls in the Coding Runs, Activity, and Run Results pane headers;
- selected run context, policy, linked session, terminal/chat actions, and bounded final report;
- activity history capped at 60 events;
- observation polling every three seconds while Workspaces is open and every ten seconds otherwise; PTY output remains event-driven;
- dispatch, state transition, bounded live report, completion, and failure narration;
- significant transition speech only when Auto Speak is enabled, with a two-minute voice rate limit and Local Voices readiness check;
- execution receipts for newly created worktrees, distinguishing pending dispatch from an actual coding agent.
Polling is observation-only. List IPC does not grant terminal roots or start an agent. Terminal authority is resolved only after an explicit terminal-open action.
The Chat drawer's session picker stays synchronized with saved, renamed, pinned, and deleted sessions while open. An unsaved current chat remains a separate choice. Switching a missing transcript from the drawer leaves the current conversation and workspace visible instead of clearing them.
Agent direction uses the existing ACP steering queue: a running agent applies
the instruction on its next turn, while an available finished or interrupted
agent resumes in its retained worktree. Interruption requests cancel only the
selected agent's ACP prompts. The UI shows CANCELLING until its worker stops;
archive, discard, and workspace removal remain blocked during cancellation.
Interruption stops that client's owned CLI and command process groups without
stopping other agents or local model servers. Worktrees and local changes are
kept. If the runtime shuts down before cancellation is confirmed, the retained
run stays protected rather than assuming its processes stopped.
These controls require the installed
workspace capability and a live agent in the current bridge process. Coding
agents execute through the backend captured when the run was created.
Local LM Studio/Strata chat routing is unchanged.
The terminal uses node-pty, @xterm/xterm, fit, search, and web-links addons.
Preload exposes only:
terminal-list | terminal-create | terminal-replay | terminal-write
terminal-resize | terminal-close | terminal-close-root
TerminalBroker owns approved opaque roots, shell selection, a secret-stripped
environment, PTY size, sequence/exit state, and a bounded 1 MiB UTF-8 replay
tail. Input writes are capped at 64 KiB.
Workspace roots are bridge-revalidated and re-registered on every terminal
creation. Immediately before spawn, the broker rejects a root or intermediate
component that became a symlink. The packaged app root alone may canonicalize
through AppImage links. Unix PTY session identity is captured at creation so
descendants can receive SIGTERM and bounded SIGKILL escalation even if the PTY
parent exits first; Windows uses taskkill process-tree termination.
Outside the monitor, Terminal is a horizontally resizable left surface with an
expand control. Inside Workspaces, terminals appear as independent Live tiles.
+ Terminal creates another shell in the chosen project source or active
worktree. Open-terminal actions reuse a running shell for that checkout.
Interrupt sends Ctrl+C to that shell; Close shell confirms termination without
closing other shells or agents. Switching workspace or Details tabs keeps
shells alive and retains their views. Opening Terminal from run context keeps
Workspaces visible. xterm rows are explicitly left aligned.
Apply to source is available in Live run tiles and Run Results. A native in-app review lists the target branch and changed files, including whether uncommitted run edits will be committed first. Approval binds to the reviewed source/run state; changed previews require another review. Uncommitted changes are staged into a private index and verified against the reviewed file bytes, deletions, executable modes, and credential-safe diff. Eva holds the run's Git index lock while preparing that exact commit, refusing concurrent staging rather than resetting or overwriting another Git operation. An already committed run is applied by its reviewed immutable revision, never by a newer branch tip that appeared after review.
The composer defaults Apply to source when done to off. Enable it for a run
to authorize local commit/integration after successful execution, or explicitly
ask Eva to “apply the current workspace changes to the source folder.”
The apply_workspace_run harness action is matched to the current user's
request; a model cannot initiate it just because it believes work is done.
Integration verifies the captured source branch, a clean source checkout,
an inactive run agent, a bounded credential-safe diff, and a fast-forward
relationship. Existing source edits, divergence, changed previews, protected
files, or reported verification failures block automatic integration and keep
the run worktree for review. The integration receipt records the applied
revision. Repeating an already applied run is a verified no-op. This action
does not configure a remote or run git push; publishing to GitHub is separate.
Completed worktrees remain available for review. Archive retains the checkout. Discard is explicit and:
- Refreshes and verifies the run-to-checkout relationship.
- Refuses while an agent is starting, running, steering, or cancelling.
- Terminates every PTY and descendant process for the checkout.
- Refuses dirty cleanup without explicit confirmation.
- Removes the Git worktree and generated run branch.
- Marks the run/checkout disposed and revokes terminal-root authority.
If a worktree was removed outside Eva, cleanup prunes stale worktree metadata, verifies it is gone, removes the branch, and completes the durable disposition. Missing or replaced runtime/project/worktree components that are symlinks are rejected rather than followed.
core/js/features/assets/library.js is a main-window library combining generated files from
ARTIFACTS_DIR and changed files from retained coding runs. Workspace files
include committed and uncommitted differences relative to the checkout's
recorded base revision.
Renderer metadata contains source, run/checkout IDs, project/objective labels,
relative path, size, modification time, and agent status, never an absolute
path. Opening a workspace file is an Electron IPC operation: main requests
capability-protected resolution of the run plus relative path, then calls
shell.openPath().
Resolution rejects traversal, symlinked runtime/project/run components, intermediate and leaf symlinks, missing/non-regular files, and disposed runs. Terminal root registration applies an independent equivalent check.
Durable collections and workflows use the main work surface; contextual tools dock; small configuration/identity actions use existing settings or overlays.
| Destination | Current behavior |
|---|---|
| Eva / New Chat | Main conversation or voice view. |
| Agents | Full Agent Operations view. |
| Assets | Full generated/workspace Assets library. |
| Skills | Full searchable library/editor with Active/Draft/Disabled and provenance-aware source filters, tags/tools search, and sorting. |
| Workspaces | Full Workspace Monitor. |
| Terminal | Lower dock in Workspace Monitor; resizable side surface elsewhere. |
| Prompts / Models / Settings | Central Settings workspace. |
| Sessions | Legacy drawer pending main-view migration; old snapshots restore visibly. |
| Profile | Local identity overlay; planned move into Settings. |
Skills moves, rather than clones, its importer/editor nodes, retaining
paste/URL/GitHub/file import, Eva'rise preview, edit, enable/disable, delete,
and auto-learned Draft behavior. Source filters normalize persisted provenance
such as github:owner/repo, file:name, and url:https://... while preserving
the complete value for display and search.
Every /v1/workspaces/* endpoint requires normal private bridge authorization
and the main-process-only X-Eva-Workspace-Capability header. The token is
generated at startup, passed only to the bridge process environment, and never
exposed in preload.
| Endpoint | Method | Purpose |
|---|---|---|
/v1/workspaces/eva-ready |
POST | Idempotently create/register Eva Ready Workspace. |
/v1/workspaces/projects |
GET/POST | List projects or register a picker-approved Git root. |
/v1/workspaces/runs |
GET/POST | List runs or create a worktree and dispatch its agent. |
/v1/workspaces/runs/<id> |
GET | Read one run with latest AgentRun. |
/v1/workspaces/runs/<id>/dispatch |
POST | Idempotently dispatch/recover an active run. |
/v1/workspaces/runs/<id>/archive |
POST | Archive while retaining checkout. |
/v1/workspaces/runs/<id>/discard |
POST | Explicit safe cleanup. |
/v1/workspaces/checkouts/<id>/status |
GET | Revalidate and summarize checkout. |
/v1/workspaces/assets |
GET | List changed files from retained runs. |
/v1/workspaces/assets/resolve |
POST | Resolve a run-relative regular file for main. |
Electron preload exposes workspaceListProjects, workspaceSelectProject,
workspaceCreateRun, workspaceListRuns, workspaceRunAction,
workspaceListAssets, and workspaceOpenAsset. These return renderer-safe
projections and do not accept absolute paths.
- Linux AppImage is the proving ground; macOS and Windows require native
node-ptypackage validation in platform CI. - Live terminal metadata is not restored from
terminal_sessionsafter an Electron process restart; renderer refresh reconnect is implemented. - ACP is the first workspace runtime. A provider-neutral adapter interface is the intended boundary for future Cline/Gemini/Codex/Goose integrations.
- Multi-agent sibling worktrees, durable approval/audit UI, diff review, patch export, explicit commit/merge, browser evidence, and Eva Field remain later milestones.
- Sessions is the next sidebar destination planned for full main-view migration.
Skills are reusable instruction sets that Eva matches to user requests via semantic similarity and injects into context.
{
"SkillId": "sk-a1b2c3d4e5f6",
"Name": "Deploy to Kubernetes",
"Description": "When the user asks to deploy an app to a Kubernetes cluster",
"Instructions": "## Steps\n1. Check the deployment manifest...",
"Tools": "browser, kusto",
"Tags": "kubernetes, deploy, devops",
"Source": "github:owner/repo",
"Status": "active",
"CreatedAt": "2026-06-14T12:00:00Z",
"UpdatedAt": "2026-06-14T12:00:00Z"
}| Source | Input | Processing |
|---|---|---|
| Paste | Raw text | Direct to evarise |
| URL | HTTP(S) URL | SSRF-safe fetch (IP pinning, public-only) |
| GitHub | owner/repo or full URL | Try SKILL.md, skill.md, README.md |
| File | Upload (<= 200 KB) | Client-side FileReader |
Raw skill text is sent to an LLM with a strict prompt that treats the source as
untrusted data (prevents prompt injection). The model extracts name, description,
instructions, tools, and tags as a JSON object. Parsing handles <think> blocks
(Qwen, DeepSeek), code fences, and balanced-brace extraction. Falls back to
LM Studio when ACP is unavailable.
After complex tasks, Eva can auto-extract a skill from the conversation
context via /v1/skills/auto-learn. The extracted skill is stored as a draft for
user review.
When cognition and a memory backend are configured, the bridge starts an internal background loop (default: every 2 hours, pauses within 120s of user activity).
Job types (13 total):
| Job | Description |
|---|---|
memory_consolidation |
Summarize recent conversations -> MemorySummaries |
goal_checkin |
Review active goals, update status (max 2/tick) |
daily_digest |
Compile day's activity summary |
knowledge_hygiene |
Revalidate old facts, trim Confidence < 0.3 |
reflection_synthesis |
Combine 3+ related reflections into new insights |
emotion_drift |
Detect significant mood changes (threshold 0.15) |
token_telemetry |
Aggregate token usage stats |
proactive_briefing |
Suggest upcoming relevant content |
market_snapshot |
Stock/crypto updates for watched symbols |
sec_filing_watch |
Check watched symbols for new SEC filings |
space_weather_alert |
Space weather alerts (Kp, G, R, S indices) |
research_deepdive |
Deep-dive on research topics |
alert_watch |
Check alert rules for triggers |
The bridge runs all 13 registered jobs. Settings exposes 12 direct job toggles;
alert_watch is controlled through the alert subsystem rather than a separate
background-job checkbox.
Hands-off application: Every job proposal is applied immediately through
_apply_proposal_payload(), regardless of its legacy auto_apply hint. The bridge
then stores an applied or failed row in BackgroundProposals and records the
tick in BackgroundActivity. The proposal approval/rejection endpoints remain
available for compatible handling of pending or historical records, but normal
background ticks do not wait for human review.
5-field cron expressions (minute, hour, day-of-month, month, day-of-week). Supports ranges (1-5), steps (*/15), and lists (1,3,5).
{
"id": "cron-abc12345",
"enabled": true,
"label": "Morning briefing",
"prompt": "Prepare my morning briefing with weather and news",
"schedule": "0 7 * * 1-5",
"last_run": "2026-06-14T07:00:00Z",
"next_run": "2026-06-15T07:00:00Z"
}Tasks execute by sending the prompt through ACP and delivering results as notifications.
Alert rules trigger on conditions and deliver notifications:
| Type | Params | Description |
|---|---|---|
sec_filing |
symbols (max 12) | SEC filing watch |
weather |
location, condition | Weather alerts |
space_weather |
threshold | Kp, G, R, S index alerts |
keyword_watch |
topic | Topic monitoring |
research_question |
question | Recurring research probes |
Cooldown: 1-20160 minutes (default 1440/24 hours). Rate limit: 8 per hour.
Quiet hours configurable. Channels: chat, voice, or signal.
Eva can send text messages via Signal using signal-cli (native binary, no Java).
Setup:
- Install signal-cli (v0.14.5+ native binary at
~/.local/bin/signal-cli, or letinstall.shhandle it) - Link to your Signal account:
signal-cli link -n "Eva"and scan the QR code from Signal mobile - Enter sender and recipient numbers in Settings > Auth
How it works:
- The
[[EVA_SIGNAL]]marker in the system prompt tells the model to emit[[EVA_SIGNAL]]{"message":"..."}[[/EVA_SIGNAL]] - The final-response renderer accepts the marker only for an affirmative Signal request and posts it to the authenticated loopback bridge
- The bridge calls
signal-cli -u <sender> send -m <message> <recipient>exactly once - The frontend strips the marker and reports the real delivery success or failure
Signal request examples: send me a Signal message, text my phone, notify me on Signal, Signal me the result, message me on Signal
Configuration persisted to: ~/.config/eva-standalone/alerts.json (signal_sender, signal_recipient fields)
Camera/Signal conflict prevention: When signal keywords match, camera REMINDER and camera fallback injection are suppressed to prevent spurious [[EVA_LOOK]] markers.
Structured, privacy-safe event logging. Records durations, model names, and routing decisions only. Never records message content, tokens, keys, or MCP env values.
Events: acp_pool (hit/warm/evict/miss), acp_prompt (model, ms, chars), error (category, message), cognition_turn (draft/review/revise timing)
Storage: JSONL file at ~/.config/eva-standalone/telemetry.jsonl (rotates at 5 MB). In-memory ring buffer (300 events) for /v1/telemetry.
Debug log: ~/.config/eva-standalone/bridge_debug.log (rotates at 10 MB). In-memory ring buffer (200 lines) for /v1/logs.
Aggregate runtime log: eva-runtime.log under Electron's app.getPath('userData'). Typical locations are ~/.config/eva-standalone/eva-runtime.log on Linux, ~/Library/Application Support/eva-standalone/eva-runtime.log on macOS, and %APPDATA%\\eva-standalone\\eva-runtime.log on Windows. Eva Standalone collects Electron main-process output, renderer console messages, bridge and Local Voices stdout/stderr, child-process lifecycle, crashes, and privacy-safe audit summaries into this one file. It rotates at 10 MB and retains three backups (.1 through .3). Files use mode 0600 on Linux/macOS; Windows relies on the current user's application-data ACL. Authorization headers, known provider tokens, prefixed/OAuth credential assignments and query parameters, and structured prompt/content fields are redacted. Interactive terminal/PTY content is intentionally excluded.
Email audit summaries record only outcome, route, counts, character lengths, and masked recipients. An outcome=submitted entry means the local MTA accepted the message; it does not prove final delivery. Inspect the receiving provider or mail-server queue for the final disposition.
For an Eva-direct identity in Best-effort local mail system mode, Settings can optionally inspect Exim transport state after submission. Eva retains Exim's queue ID from the SMTP 250 id= response for the current bridge session and reads only a bounded mainlog tail to report delivered, deferred, failed, pending, or unknown. delivered means Exim handed the message to its next SMTP hop, not that the recipient inbox accepted or displayed it. Inspection never sends mail or reads message bodies. When direct log access is unavailable, the optional sudo setting attempts only the fixed noninteractive command sudo -n /usr/bin/tail -n 4000 /var/log/exim4/mainlog; it never prompts for a password. Grant that exact read-only command or mail-log group access through normal system administration before enabling it.
Ten tabs in a modal overlay:
| Tab | Contents |
|---|---|
| General | Theme, TTS engine/voice, auto-speak, camera presence, vision provider, data retrieval mode (cloud/local) with status |
| Models | Model selector (grouped by provider), temperature, max tokens, reasoning effort, AIG backend selector, ACP model selector, adaptive review toggle and reviewer model |
| Auth | API key inputs with show/hide toggles, ACP bridge URL, Signal sender/recipient numbers. Standalone encrypts provider keys with Electron safeStorage so they survive AppImage rebuilds. |
| Mailbox identities, direct-recipient consent, local/internal delivery modes, session credentials, global approved recipients, and manual sending. | |
| Prompts | Personality presets (Default/Concise/Advanced/Terminal/Custom), editable system prompt textarea |
| Goals | Goals list with create/edit/delete |
| Background | Background loop status, enable/interval controls, run-once, proposal audit/history, approval/rejection controls for pending records, recent activity |
| Cron | Cron task list with create/edit/delete, schedule expression, prompt, last/next run timestamps |
| MCP | Azure MCP, GitHub MCP, Kusto MCP toggles with config fields. Apply/refresh buttons |
Skills are managed in a full main-window library/editor. It supports paste,
URL, GitHub, and file import; Eva'rise preview; edit/reimport;
enable/disable/delete; Active/Draft/Disabled filtering; normalized source
categories with full provenance; tag/tool search; name/status/update sorting;
and responsive organization controls. Typed and spoken requests can use the
same native management API to create, update, enable, disable, or delete a
named Skill. Voice creation saves a draft and requires native ENABLE
confirmation before activation. The complete allowlisted Eva Harness manifest
is available while interpreting voice requests, but each action retains its
normal direct-user and confirmation requirements. Active Skills may open a
credential-free HTTPS URL only after
an explicit open/play request and only when the exact URL came from that
request or a structured action inside the deterministically matched Skill.
The sidebar profile picker keeps sessions, prompts, model choices, voice preferences, and other browser-local settings separate per user. API credentials, MCP configuration, and the selected memory backend remain shared installation settings. Sessions open fresh on launch and support persistent custom titles. Saved skills can be edited and reimported through the existing skill ID, preserving database history.
Reasoning-capable models expose Model default, None, Minimal, Low, Medium, High, Extra high, and Maximum. The selection is saved locally and passed to the selected AIG responder when supported. Higher levels can increase response time and premium usage.
cp config.example.json config.json # add your API keys
xdg-open index.html # or open in any browserFor file:// usage without a JSON loader, copy config.local.example.js to config.local.js.
python3 tools/acp_bridge.py --port 8888 \
--enable-kusto-mcp \
--kusto-cluster "https://<your-cluster>.region.kusto.windows.net" \
--kusto-database EvaA bundled desktop build that ships the web UI and ACP bridge together. The
Electron shell allocates a free localhost port, starts the bridge, and injects
the URL into the renderer via window.evaStandalone.
cd standalone
npm install
npm run dist
./dist/'Eva Standalone-5.6.11.AppImage'
# Development/review launch with coding workspaces enabled
npm run start:workspaceAfter a successful ./install.sh --build, Eva keeps the newly built AppImage
plus one locally built rollback and refreshes its update-aware launcher. The
launcher selects the highest stable version on each launch, accepting spaced
and dotted filenames. Installer pruning does not remove dotted AppImages
managed by external updaters. The unpacked linux-unpacked directory remains
a local packaging and packaged-E2E target.
Electron lifecycle:
Before bridge startup, bounded checks verify the selected Python version and
core packages, offer explicit setup/retry when blocked, and show one-time
provider guidance. AppImages enable workspaces by default unless
--eva-no-workspaces is supplied.
getFreeLocalPort(): OS-allocated free port- Generate private bridge and workspace capability tokens.
startBridge(port): Spawnpython3 tools/acp_bridge.py --bind 127.0.0.1 --port <port>with both tokens in the child environment.waitForBridge(url, process, timeout): Poll/healthevery 500ms.- When workspaces are enabled, create Eva Ready Workspace and recover active runs before creating the window.
- On
EADDRINUSE: retry with a new port (max 3 attempts). - On bridge crash: show an error dialog and quit.
Host prerequisites: Python 3.12+ with requests and cryptography for the bridge; Node.js 24+ and authenticated Copilot CLI for ACP. Direct OpenAI and LM Studio chat do not require Copilot.
Current state (2026-06-15):
- Static web tier can run on legacy 32-bit hosts.
- ACP Bridge currently runs on a separate compatible machine.
- Single-host deployment is blocked until new hardware is available.
- Local mode (LM Studio + direct MCP) works on any x86_64 machine without Copilot CLI.
- Signal messaging available via signal-cli (native binary, linked account required).
| Milestone | Status | Notes |
|---|---|---|
| Provision bridge-capable server | planned | 2+ vCPU, 4+ GB RAM |
| Install runtime baseline | planned | Node.js 24+, Python 3.12+ |
| Authenticate Copilot CLI | planned | copilot auth login on target |
| Deploy bridge as systemd service | planned | tools/acp_setup.sh |
| Single-host ACP deployment | planned | Keep localhost fallback until complete |
| Post-migration validation | planned | /health ok + AIG smoke + test_eva.py |
| macOS standalone build | planned | Needs Apple Developer ID + notarization |
| Windows standalone build | planned | Add win target to electron-builder |
Eva is independently implemented. This section records the projects and open standards whose ideas inform its design, so credit and architectural intent remain visible as the coding-workspace work evolves. Inclusion here does not mean Eva embeds their code, is affiliated with them, or currently supports their runtime.
| Project or standard | What Eva is studying or adapting | Current status |
|---|---|---|
| Lieutenant Commander Data / Star Trek: The Next Generation | Curiosity, precision, ethical judgment, candid uncertainty, and care in understanding people. | Aspirational identity material only; Eva is independently implemented, does not imitate a character, and claims no fictional abilities. |
| TencentDB Agent Memory | Layered memory concepts: evidence, atoms, scenarios, persona traits, and progressive disclosure. | Architecture reference only; Eva retains its local-first SQLite/Kusto design and does not adopt TencentDB's deployment stack. |
| Traycer | Durable agent identity separate from PTY scrollback, terminal stream replay/backpressure, worktree ownership facts, typed evidence, and capability-based A2A handoffs. | Durable run identity, bounded PTY replay, worktree ownership, and stable monitor IDs are implemented; collaboration canvas and cross-device sync remain deferred. |
| OpenCode | Explicit plan versus build modes, local coding-agent ergonomics, and subagent patterns. | Research candidate; evaluate a structured adapter surface before integration. |
| Cline | Plan/Act UX, checkpoints, approval-first execution, SDK extensibility, agent teams, and worktree-based task boards. | Priority adapter research spike. |
| Gemini CLI | Structured headless event streams, checkpoints, trusted folders, sandbox concepts, MCP, and project context files. | Priority process-adapter research spike. |
| Goose | Provider-neutral agent profiles, extension catalog, MCP integration, and embeddable API design. | Research candidate for later runtime and automation adapters. |
| OpenAI Codex CLI | Local coding-agent and sandbox/protocol patterns. | Future optional adapter candidate; validate a documented control interface first. |
| OpenHands Agent Canvas | Backend catalog, self-hosted agent control-center patterns, and automation UX. | Inspiration only; Eva remains framework-free and local-first. |
| Aider | Repository-map context, test/lint feedback loops, diffs, and undo-oriented Git workflow. | Workflow inspiration; isolated worktrees and focused validation are implemented, while commits remain explicit future review actions. |
| SWE-agent | Issue-to-patch trajectories and coding-agent evaluation methodology. | Evaluation reference, not a desktop runtime. |
| Model Context Protocol | Tool/resource boundaries, capability negotiation, cancellation, consent, and stateless modern stdio protocol design. | Eva supports legacy and modern local stdio tool servers; remote HTTP, OAuth, MRTR continuations, Tasks, Resources, Prompts, and Apps remain separate work. |
The following projects and standards are direct implementation dependencies, interoperability targets, or runtime integrations. Eva retains ownership of its security policy, local persistence, UI, and orchestration; credit here does not mean it vendors upstream code or inherits an upstream trust boundary.
| Project or standard | Role in Eva | Current status |
|---|---|---|
| Agent Client Protocol | Structured bridge between Eva and the GitHub Copilot CLI for sessions, streaming, tool events, permissions, and cancellation. | Active integration. ACP terminal requests remain disabled; Eva's Electron PTY broker owns interactive terminals. |
| GitHub Copilot CLI | Optional ACP runtime for Copilot-backed chat, AIG, and isolated workspace agents. | Active external runtime; users authenticate it locally with copilot auth login. |
| MCP C# SDK v2 | Protocol reference for stateless HTTP, multi-round-trip input, Tasks, and enterprise service-hosting patterns. | Architecture and future interoperability reference; not bundled or exercised by Eva's current local stdio CI fixtures. |
| MCP Python SDK v2 | Maintained reference implementation for native MCP 2026-07-28 stdio interoperability. |
Test-only compatibility fixture; not an Eva runtime dependency. |
| MCP TypeScript SDK v2 | Independent Tier 1 reference implementation for native modern stdio interoperability. | Test-only compatibility fixture; installed in an isolated CI path, not bundled with Eva. |
| Electron and electron-builder | Privileged main-process boundary, narrow preload IPC, AppImage packaging, and bundled local bridge lifecycle. | Shipped standalone foundation. |
| xterm.js and node-pty | Terminal rendering, measured fitting/search/link addons, native PTY ownership, and process-session cleanup. | Shipped Electron terminal foundation; renderer never receives arbitrary process access. |
| Playwright | Browser automation through CDP and packaged Electron end-to-end coverage. | Shipped browser-agent/test foundation; browser actions remain subject to Eva's approval and execution policy. |
| Git | Canonical repository inspection, isolated worktrees, branch lifecycle, diffs, and cleanup. | Shipped workspace foundation; Eva uses argument arrays and preserves explicit review/commit decisions. |
| SQLite | Local durable memory, workspace records, skills, and other bridge-owned state. | Shipped local persistence foundation; browser session display state remains separate. |
| LM Studio | Local OpenAI-compatible inference and local MCP tool-calling retrieval. | Supported optional runtime; no cloud model credential is required for local-only operation. |
| Chatterbox TTS | Optional local English and Multilingual V3 synthesis behind Eva's maintained Local Voices adapter. | Installed only with ./install.sh --voice-deps; Eva requires a configured, user-authorized reference recording for Local Voices synthesis, keeps audio on the loopback/local path, and preserves Chatterbox's upstream generated-audio watermarking behavior. |
| Azure Data Explorer / Kusto | Optional cloud memory, analytics, and Kusto MCP data retrieval. | Supported configured integration; local SQLite remains the no-cloud alternative. |
| PyAutoGUI and OpenCV | Optional desktop automation and local camera/presence sensing. | Optional integrations; capability and consent controls remain in Eva. |
| signal-cli | Optional linked-account Signal delivery. | Optional external integration; Eva reports delivery success or failure rather than assuming it. |
The implemented decision is Eva control plane + explicit execution broker +
replaceable runtime adapters. Eva owns run/worktree identity, safety policy,
monitoring, Assets, and review state rather than becoming a branded wrapper
around one CLI. External runtimes are eligible for later adapters only when
they provide a structured lifecycle or SDK, per-worktree cwd, interceptable
permissions, cancellation, and resumable session semantics. TUI paint alone is
not a supported agent-state protocol.
- Bridge binds to
127.0.0.1by default (localhost only) - ACP tool permissions are never globally bypassed. Standalone Eva requires an authenticated in-chat decision; hosted/file clients fail closed.
- Workspace routes require a second random capability held only by Electron main; the ordinary renderer-visible bridge token is insufficient.
- Workspace agent
workspace_writeprompts auto-selectallow_oncefor confined reads, edits, and trusted local commands. User-enabledworkspace_autoalso approves other one-time actions, while outside-worktree edits and protected-path commands are rejected by policy. Normal prompts remain interactive and passive recall remains deny-by-policy. - Renderer workspace DTOs contain opaque IDs and relative paths only. Known project/worktree paths are redacted from agent reports.
- Managed worktree paths are revalidated under
EVA_CONFIG_DIR/worktreesbefore status, Assets, terminal registration, and cleanup. Runtime-root, intermediate, leaf, and post-registration symlink swaps are rejected. - PTY roots are allowlisted; the renderer cannot provide a cwd/environment. PTY shutdown retains Unix session identity and escalates descendants to SIGKILL before root revocation.
- Routine standing consent is limited to read, search, fetch, and think tool kinds. Execute, edit, move, delete, and unknown operations always require a fresh decision.
- ACP client-terminal capability is disabled because the protocol does not reliably correlate
terminal/createwith a permission decision. Authorized execution uses Eva's browser/desktop agent confirmation paths instead. - MCP env vars (tokens) are redacted from
/v1/mcpresponses and persisted configs - URL fetching uses SSRF protection: DNS resolution validated, all IPs must be public, IP pinning prevents DNS rebinding, redirect hops re-validated
- Skill import treats source text as untrusted data (explicit anti-injection prompt)
- LM Studio base URL restricted to localhost/private IPs on whitelisted ports (1234, 8000, 8080, 11434)
- Camera off by default, subprocess-isolated, state read-only from bridge
- Sensitive browser/desktop actions require user confirmation
pyautogui.FAILSAFE = True(mouse to corner = emergency stop)- Background writes use bounded proposal handlers and retain applied/failed audit records
Runs on every PR to main:
| Job | Checks |
|---|---|
| static-checks | Secret scanning, HTML structure, JS syntax, Python syntax, model routing, config templates, .gitignore |
| python-tests | tools/tests/test_static.py: file integrity, config safety, CSV logic, model selector, seed validation |
| File | Needs Bridge? | Description |
|---|---|---|
tools/tests/test_static.py |
No | CI-safe static tests |
tools/tests/test_eva.py |
Yes | 64-check integration suite |
tools/tests/test_latency.py |
Yes | Production-shaped AIG latency probe with NDJSON TTFT/total timings, cold/warm repetitions, and optional thresholds |
tools/tests/test_latency_fake_server.py |
No | Fake HTTP-server coverage for fast, approval, and revision call paths |
tools/tests/test_skills_e2e.py |
Starts local test bridge | Skill import/edit/injection/delete lifecycle with stubbed ACP/Kusto |
tools/tests/test_workspaces.py |
No | Workspace schema, worktree isolation/recovery, dirty cleanup, symlink confinement |
tools/tests/test_workspaces_e2e.py |
No live model | Real HTTP workspace/AgentRun/Assets lifecycle with deterministic worker |
tools/tests/test_terminal_broker.js |
No | PTY root confinement, replay, resize, descendant cancellation, root swaps |
tools/tests/test_workspace_projection.js |
No | Report path redaction |
tools/tests/test_terminal_e2e.js |
Starts packaged app | Terminal, reconnect, mobile layout, Sessions, Skills main view |
tools/tests/test_workspace_electron_e2e.js |
Starts packaged app | Workspaces, terminal dock, Assets, process cleanup, root revocation |
tools/eval/run.py --mode mock |
No | Behavioral eval with synthetic responses |
tools/eval/run.py --mode live |
Yes | Behavioral eval against live bridge |
python3 tools/tests/test_static.py # CI-safe
python3 tools/tests/test_skills_e2e.py # Skills HTTP lifecycle
python3 tools/tests/test_workspaces.py # Workspace/Git safety
python3 tools/tests/test_workspaces_e2e.py # Workspace HTTP + agent/Assets
python3 tools/tests/test_streaming.py # Streaming and ACP permission policy
node tools/tests/test_terminal_broker.js # PTY contract
node tools/tests/test_workspace_projection.js # Report redaction
node tools/tests/test_terminal_e2e.js # Packaged terminal/session/Skills UI
node tools/tests/test_workspace_electron_e2e.js # Packaged workspace/Assets UI
python3 tools/tests/test_latency_fake_server.py # latency harness without a bridge
python3 tools/tests/test_latency.py --bridge http://localhost:8888 --mode both --repetitions 2
python3 tools/tests/test_eva.py --verbose # full integration
python3 tools/eval/run.py --mode mock # synthetic eval
python3 tools/eval/run.py --mode live --bridge http://localhost:8888 # live evalFixtures in tools/eval/fixtures/ (one JSON per category): identity, style,
refusal, recall, routing, capability, injection_resistance. Mock mode reads
tools/eval/mock_responses.json. Results to tools/eval/results/<timestamp>.json.
core/js/features/sessions/explorer.js + core/js/idb-store.js:
- Storage: IndexedDB (
eva_sessions_db) withsessions+blobsobject stores - Auto-save after every response; each launch starts a fresh chat while saved sessions remain available from Session Explorer
- Session index in localStorage (lightweight), full snapshots in IndexedDB
- Migration from localStorage on first load, plus per-session fallback when a
legacy
session_<id>snapshot remains after migration - Persistent storage via
navigator.storage.persist() - Transactional switching: the current session save finishes before the target IndexedDB record is read; successful loads restore chat/model state, close Session Explorer, and exit Agent Operations/Workspace Monitor
- Legacy visible restore: snapshots without
_htmlSnapshotreconstruct a safe text transcript from provider messages ormasterOutput. An index entry whose snapshot is unavailable renders an explicit notice instead of leaving the welcome screen unchanged. - Row activation: delegated mouse and Enter/Space activation works from the title, timestamp, or empty row space; rename/pin/delete buttons remain isolated
- Sidebar coordination: Agents, Assets, Skills, and Workspaces are primary main views. Prompts/Models/Settings use the Settings workspace. Terminal is a contextual dock in Workspace Monitor and a resizable side surface elsewhere. Sessions remains a legacy drawer pending main-view migration.
Star Trek-inspired interface (Lower Decks palette):
- Barlow Condensed font (Google Fonts)
- LCARS elbows (curved connectors via CSS pseudo-elements)
- Flat colored sidebar chips with black gaps
- Accent-border chat bubbles (cyan=Eva, blue=User)
- Monitor dock with 4 tabs (Tokens, Network, Session, System)
Based on CodeProject. Heavily extended.