Skip to content

feat: add Context Engine plugin for hybrid code search and RAG#10

Open
TerminallyLazy wants to merge 514 commits intomainfrom
context-engine-a0-plugin
Open

feat: add Context Engine plugin for hybrid code search and RAG#10
TerminallyLazy wants to merge 514 commits intomainfrom
context-engine-a0-plugin

Conversation

@TerminallyLazy
Copy link
Copy Markdown
Owner

@TerminallyLazy TerminallyLazy commented Feb 28, 2026

User description

Summary

  • Adds a complete Agent Zero plugin (usr/plugins/context-engine/) integrating Context Engine for hybrid code search and RAG
  • 8 agent tools for semantic code search, AI-powered Q&A, symbol graph analysis, developer memory, and specialized searches
  • Auto-context injection via lifecycle extensions that proactively inject relevant code into agent prompts
  • WebUI dashboard with service status, search testing, and index management
  • Docker Compose overlay for one-command deployment of all Context Engine services (Qdrant, Redis, Indexer MCP, Memory MCP)

What's included

Component Files Description
Scaffold 5 Plugin manifest, config, settings UI, HTTP client
Agent Tools 8 + 2 prompts code_search, context_answer, symbol_graph, context_index, ce_memory_store, ce_memory_find, search_tests, search_callers
Extensions 4 + 1 prompt Init health check, auto-context injection, system prompt behavior
API + Dashboard 3 API + 4 UI Status/search/index endpoints, tabbed dashboard
Deployment 2 Docker Compose overlay, comprehensive README

Test plan

  • Plugin appears in Agent Zero plugin list when enabled
  • Settings UI renders correctly with all configuration fields
  • Dashboard loads and shows connection status
  • Tools are available to the agent when plugin is active
  • Docker Compose overlay starts all Context Engine services
  • Agent can perform code search when Context Engine services are running

🤖 Generated with Claude Code


PR Type

Enhancement, Tests


Description

  • Major infrastructure refactoring with thread-safe context management, WebSocket event routing, and extensible agent lifecycle hooks

  • Migrated UI server from Flask/Werkzeug to Uvicorn/Starlette ASGI stack with Socket.IO integration and comprehensive WebSocket namespace isolation

  • Refactored settings system with environment variable support (A0_SET_ prefix), dynamic UI generation, and persistent storage in usr/settings.json

  • New plugin management system with discovery, configuration, and per-project/per-agent toggle support

  • New skills management module with YAML frontmatter parsing, discovery, and CLI tool for skill lifecycle management

  • Enhanced project management with git repository cloning, subagent configuration, and hierarchical agent discovery

  • Improved task scheduler with cancellation support, running task tracking, and state monitor integration

  • Thread-safe logging with timestamp tracking, agent numbering, and state synchronization

  • New file utilities with binary detection, conditional text evaluation, and glob-based path discovery

  • WebSocket security hardening with origin validation (RFC 6455), CSRF/auth enforcement, and namespace-scoped event broadcasting

  • Chat branching API for creating conversation branches at specific message points

  • Work directory file operations API for renaming and folder creation

  • Comprehensive test coverage for WebSocket manager, namespace isolation, security validation, and integration scenarios

  • Bug fix in memory consolidation plugin import paths


Diagram Walkthrough

flowchart LR
  A["Settings Refactoring<br/>Environment Variables"] --> B["Plugin Management<br/>Discovery & Config"]
  C["WebSocket Manager<br/>Event Routing"] --> D["ASGI Migration<br/>Uvicorn/Starlette"]
  E["Skills System<br/>YAML Discovery"] --> F["Skills CLI<br/>Management Tool"]
  G["Agent Lifecycle<br/>Extensible Hooks"] --> H["Thread-Safe Context<br/>RLock Protection"]
  I["Project Management<br/>Git Cloning"] --> J["Subagent System<br/>Hierarchical Discovery"]
  K["Task Scheduler<br/>Cancellation Support"] --> L["State Monitor<br/>Integration"]
  D --> M["WebSocket Security<br/>Origin Validation"]
  M --> N["Namespace Isolation<br/>CSRF/Auth"]
  O["File Utilities<br/>Binary Detection"] --> P["Chat Branching<br/>API"]
Loading

File Walkthrough

Relevant files
Enhancement
15 files
settings.py
Major settings refactoring with environment variable support

python/helpers/settings.py

  • Refactored settings output structure from section-based to flat
    settings + additional metadata format
  • Added get_default_value() function to load settings from environment
    variables with A0_SET_ prefix
  • Removed 1000+ lines of hardcoded settings UI field definitions,
    replacing with dynamic generation
  • Added new settings fields: workdir_* (path, show, max_depth,
    max_files, max_folders, max_lines, gitignore),
    websocket_server_restart_enabled, uvicorn_access_logs_enabled,
    chat_inherit_project
  • Removed deprecated memory-related settings (memory_recall_*,
    memory_memorize_*, agent_memory_subdir)
  • Changed settings file location from tmp/settings.json to
    usr/settings.json
  • Simplified convert_out() to return flat settings dict with provider
    lists and options instead of nested sections
  • Added _load_sensitive_settings() to centralize loading of auth, API
    keys, and secrets from environment
+288/-1240
websocket_manager.py
New WebSocket manager with event routing and buffering     

python/helpers/websocket_manager.py

  • New comprehensive WebSocket connection manager with 1150+ lines of
    implementation
  • Supports handler registration, event routing, buffering, and lifecycle
    management
  • Includes diagnostic/debug capabilities for monitoring WebSocket
    traffic and connections
  • Implements fan-out request patterns (route_event_all) and
    per-connection request handling
  • Features automatic event buffering for disconnected clients with
    TTL-based expiration
  • Provides session tracking for single and multi-user scenarios
+1152/-0
skills_cli.py
New CLI tool for Agent Zero skill management                         

python/helpers/skills_cli.py

  • New CLI tool for managing Agent Zero skills with 360+ lines of
    implementation
  • Supports listing, creating, validating, and searching skills from YAML
    frontmatter
  • Includes skill template generation with directory structure (scripts,
    docs)
  • Validates skill metadata (name format, description length, content
    requirements)
  • Provides formatted table output and detailed skill information display
+364/-0 
agent.py
Thread-safe context management and extensible agent lifecycle hooks

agent.py

  • Added thread-safe context management with threading.RLock() for
    concurrent access to _contexts dictionary
  • Introduced @extensible decorator to multiple methods enabling
    plugin/extension hooks throughout agent lifecycle
  • Enhanced error handling with retry_critical_exception() method for
    resilient error recovery with configurable retries
  • Refactored prompt loading to use new subagents.get_paths() helper for
    better plugin/agent hierarchy support
  • Added is_running() method to check task execution status and improved
    intervention handling
  • Changed error logging from "error" to "warning" type for non-critical
    tool execution failures
+214/-92
run_ui.py
WebSocket infrastructure and ASGI migration                           

run_ui.py

  • Migrated from Flask/Werkzeug to Uvicorn/Starlette ASGI stack with
    Socket.IO integration
  • Implemented WebSocketManager for managing WebSocket connections and
    event routing across namespaces
  • Added comprehensive WebSocket origin validation and CSRF/auth security
    checks during handshake
  • Refactored API handler registration to use new register_api_route()
    helper function
  • Introduced plugin asset serving endpoints with security checks for
    /plugins/ and /usr/plugins/ routes
  • Added support for server restart broadcasts and connection lifecycle
    events
+361/-170
websocket.py
WebSocket handler base class and origin validation             

python/helpers/websocket.py

  • New WebSocketHandler abstract base class for declarative event handler
    definition with singleton pattern
  • WebSocketResult helper class for standardized success/error response
    payloads
  • Origin validation function validate_ws_origin() implementing RFC 6455
    and OWASP CSWSH mitigation
  • Event type validation enforcing lowercase_snake_case naming and
    preventing Socket.IO reserved event collisions
  • Handler lifecycle hooks (on_connect, on_disconnect) and convenience
    methods for emit/broadcast/request operations
+568/-0 
branch_chat.py
Chat branching API endpoint implementation                             

plugins/chat_branching/api/branch_chat.py

  • New API handler for creating branched chats from existing chat
    contexts at specific log message points
  • Implements chat serialization/deserialization with log trimming to
    preserve conversation history up to branch point
  • Auto-generates new context ID and marks state as dirty for UI
    synchronization across tabs
+75/-0   
skills.py
New skills management helper module with discovery and validation

python/helpers/skills.py

  • New module for managing skills with discovery, validation, and loading
    functionality
  • Implements Skill dataclass with metadata fields (name, description,
    version, author, tags, triggers, allowed_tools)
  • Provides skill discovery from SKILL.md files with YAML frontmatter
    parsing and fallback parser
  • Includes skill listing, searching, finding, and deletion operations
    with deduplication by normalized name
+527/-0 
plugins.py
New plugin management system with configuration and discovery

python/helpers/plugins.py

  • New comprehensive plugin management module with discovery and
    configuration handling
  • Implements PluginMetadata and PluginListItem models for plugin
    information
  • Provides plugin listing, enabling/disabling, configuration management,
    and WebUI extension discovery
  • Supports per-project and per-agent plugin configuration with toggle
    state tracking
+541/-0 
projects.py
Enhanced project management with git cloning and subagent support

python/helpers/projects.py

  • Renamed get_project_meta_folder() to get_project_meta() for
    consistency
  • Added clone_git_project() function for cloning git repositories as A0
    projects with token support
  • Added SubAgentSettings and GitStatusData TypedDict classes for project
    configuration
  • Added subagent and git status management with load_project_subagents()
    and save_project_subagents()
  • Enhanced project activation/deactivation with mark_dirty parameter for
    state monitoring
  • Removed memory isolation logic (get_context_memory_subdir()) and
    memory folder creation
+182/-70
task_scheduler.py
Task scheduler improvements with cancellation and state monitoring

python/helpers/task_scheduler.py

  • Changed scheduler folder from tmp/scheduler to usr/scheduler for
    persistence
  • Added task UUID generation using guids.generate_id() instead of
    uuid.uuid4()
  • Implemented task cancellation with cancel_running_task() and
    cancel_tasks_by_context() methods
  • Added running task tracking with _running_deferred_tasks dictionary
    and thread-safe registration
  • Integrated state monitor notifications via mark_dirty_all() for task
    changes
  • Enhanced error handling with asyncio.CancelledError and
    asyncio.shield() for graceful cleanup
+98/-31 
subagents.py
New subagent management system with hierarchical discovery

python/helpers/subagents.py

  • New module for managing subagents with discovery across default,
    plugin, user, and project directories
  • Implements SubAgentListItem and SubAgent models with validation and
    merging logic
  • Provides agent listing, loading, saving, and deletion with
    hierarchical configuration merging
  • Supports per-project agent filtering and availability management
+414/-0 
log.py
Thread-safe logging with state monitoring integration       

python/helpers/log.py

  • Added thread-safe logging with threading.RLock() for concurrent access
    protection
  • Introduced timestamp and agent number tracking for log items
  • Removed temp field from LogItem and added agentno field
  • Implemented state monitor integration with lazy imports to avoid
    circular dependencies
  • Refactored _update_item() to perform masking/truncation outside lock
    for better concurrency
  • Added progress tracking with progress_active flag and state monitor
    notifications
+181/-91
files.py
Enhanced file utilities with binary detection and conditional
evaluation

python/helpers/files.py

  • Added directory constants (AGENTS_DIR, PLUGINS_DIR, PROJECTS_DIR,
    USER_DIR)
  • Implemented conditional text evaluation with
    evaluate_text_conditions() supporting {{if}}...{{endif}} blocks
  • Added binary file detection with is_probably_binary_file() and
    is_probably_binary_bytes()
  • Added JSON and YAML file readers (read_file_json(), read_file_yaml())
  • Enhanced path utilities: get_abs_path_dockerized(),
    get_abs_path_development(), is_file(), is_dir(), is_in_dir()
  • Added find_existing_paths_by_pattern() for glob-based path discovery
  • Improved file operations with fallback copy-delete for
    cross-filesystem moves
+183/-18
rename_work_dir_file.py
New work directory file rename and folder creation API     

python/api/rename_work_dir_file.py

  • New API handler for renaming files and creating folders in work
    directory
  • Supports both rename and create-folder actions with validation
  • Integrates with FileBrowser for file system operations
  • Returns updated file listing after successful operations
+54/-0   
Bug fix
1 files
memory_consolidation.py
Fixed imports and updated memory consolidation references

plugins/memory/helpers/memory_consolidation.py

  • Fixed import path for Memory class from relative import (.memory)
  • Added plugin-relative import path handling for DEFAULT_THRESHOLD from
    tools
  • Updated docstring to remove reference to deprecated INSTRUMENTS memory
    area
+10/-8   
Tests
3 files
test_websocket_manager.py
Complete WebSocket manager test coverage                                 

tests/test_websocket_manager.py

  • Comprehensive test suite for WebSocketManager covering connection
    lifecycle, event routing, and error handling
  • Tests for buffer management, timeout handling, and correlation ID
    preservation across requests
  • Validation of handler registration, duplicate detection, and namespace
    isolation
  • Performance smoke tests and diagnostic event emission verification
+853/-0 
test_websocket_namespaces.py
WebSocket namespace isolation and integration tests           

tests/test_websocket_namespaces.py

  • Integration tests validating namespace isolation and cross-namespace
    event prevention
  • Tests for lifecycle event broadcasting scoped to individual namespaces
  • Validation of handler discovery and registration without
    cross-namespace contamination
  • Request semantics tests for timeout handling and error responses
    within namespace boundaries
+497/-0 
test_websocket_namespace_security.py
New WebSocket namespace security test suite                           

tests/test_websocket_namespace_security.py

  • New comprehensive test suite for WebSocket namespace security
    validation
  • Tests authentication and CSRF token enforcement across different
    namespace configurations
  • Validates connection security, unknown namespace rejection, and
    missing auth/CSRF scenarios
  • Uses async context managers and mock handlers to test security
    policies
+464/-0 
Additional files
101 files
.dockerignore +3/-10   
AGENTS.md +217/-0 
AGENTS.plugins.md +189/-0 
README.md +92/-60 
_context.md +0/-4     
agent.yaml +3/-0     
agent.system.tool.response.md +2/-1     
_context.md +0/-3     
agent.yaml +4/-0     
_context.md +0/-2     
agent.yaml +4/-0     
_context.md +0/-2     
agent.yaml +4/-0     
_context.md +0/-2     
agent.yaml +4/-0     
model_providers.yaml +22/-2   
limiter.toml +2/-2     
settings.yml +9/-1     
install_python.sh +1/-1     
install_searxng2.sh +3/-2     
Dockerfile +1/-0     
limiter.toml +2/-2     
settings.yml +9/-1     
README.md +114/-60
AGENTS.components.md +648/-0 
AGENTS.modals.md +307/-0 
backup-specification-backend.md +0/-1708
backup-specification-frontend.md +0/-1663
architecture.md +91/-57 
connectivity.md +108/-4 
contributing-skills.md +395/-0 
extensions.md +10/-3   
mcp-configuration.md +404/-0 
notifications.md +3/-0     
plugins.md +196/-0 
websockets.md +727/-0 
a2a-setup.md +153/-0 
api-integration.md +231/-0 
contribution.md +3/-2     
mcp-setup.md +117/-0 
projects.md +490/-0 
troubleshooting.md +61/-0   
usage.md +1105/-0
installation.md +0/-380 
mcp_setup.md +0/-146 
quickstart.md +76/-29 
dev-setup.md +31/-11 
installation.md +585/-0 
vps-deployment.md +771/-0 
troubleshooting.md +0/-44   
tunnel.md +0/-57   
usage.md +0/-364 
initialize.py +16/-3   
.DS_Store [link]   
download_video.py +0/-12   
yt_download.md +0/-11   
yt_download.sh +0/-10   
jsconfig.json +10/-2   
github_readme.md +0/-65   
installation.md +0/-554 
.gitkeep [link]   
github_readme.md +392/-0 
installation.md +585/-0 
.gitkeep [link]   
.gitkeep [link]   
models.py +23/-8   
README.md +67/-0   
inject-branch-buttons.js +32/-0   
plugin.yaml +3/-0     
agent.yaml +4/-0     
agent.system.plugin_example.md +3/-0     
plugin.yaml +7/-0     
import_knowledge.py +8/-5     
knowledge_path_get.py +5/-6     
knowledge_reindex.py +2/-4     
memory_dashboard.py +8/-1     
default_config.yaml +16/-0   
_10_memory_reload.py +10/-0   
_50_recall_memories.py +24/-13 
_91_recall_wait.py +6/-11   
_50_memorize_fragments.py +203/-0 
_51_memorize_solutions.py +208/-0 
_10_memory_init.py +3/-5     
_20_behaviour_prompt.py +8/-5     
memory-entry.html +12/-0   
memory-entry.html +7/-0     
knowledge_import.py [link]   
memory.py +36/-39 
plugin.yaml +7/-0     
agent.system.memories.md [link]   
agent.system.solutions.md [link]   
agent.system.tool.memory.md [link]   
fw.memory.hist_suc.sys.md [link]   
fw.memory.hist_sum.sys.md [link]   
fw.memory_saved.md [link]   
memory.consolidation.msg.md [link]   
memory.consolidation.sys.md [link]   
memory.keyword_extraction.msg.md [link]   
memory.keyword_extraction.sys.md [link]   
memory.memories_filter.msg.md [link]   
Additional files not shown

frdel and others added 30 commits January 30, 2026 16:31
Accept upstream's architectural refactors:
- Settings UI sections moved from Python to frontend components
- User data consolidated under /usr directory
- Inline settings modal replaced by stacked modal system
- settings.js removed (moved to component stores)

Conflicts resolved by accepting upstream for all 5 files.
Our skills/backup features will be re-implemented using the new architecture.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…dating skill search functionality. Adjusted skills tool to utilize project context for skill discovery and refined the skills loading process. Updated documentation to reflect changes in skill operations and removed deprecated script execution methods. Uses code_execution_tool for skill scripts instead of execute_scripts from the skills_tool.
The merge in 95de41a inadvertently accepted upstream's change from
agent0ai to frdel. This forward-fixes the file without rewriting
merge history.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Empty or whitespace-only AI messages cause API validation errors with strict
providers (OpenAI, Z.ai, GLM):
  "Assistant messages must have either content or tool_calls"

This is a companion fix to PR agent0ai#927 (response.py KeyError fix). When that fix
returns an empty string instead of crashing, the empty string can become an
empty AIMessage that fails API validation.

Changes:
- Pre-compute content before creating message objects
- Skip AI messages where content is None, empty, or whitespace-only
- Human messages are not filtered (they can be empty per spec)

Tested on 4 production A0 instances.
…ages

fix: Skip empty AI messages in output_langchain to prevent API rejection
single scrollbar in modals
linuztx and others added 3 commits February 28, 2026 19:11
Adds a complete Agent Zero plugin integrating Context Engine — an
open-source hybrid code search and RAG system — as a first-class
agent capability.

Plugin includes:
- 8 agent tools: code_search, context_answer, symbol_graph,
  context_index, ce_memory_store, ce_memory_find, search_tests,
  search_callers
- Async HTTP client wrapping Context Engine's MCP endpoints
- Auto-context injection via lifecycle extensions
- WebUI dashboard with status, search, and index panels
- Settings UI with per-project and per-agent config
- Docker Compose overlay for Context Engine services
- Sidebar entry and system prompt behavior extension

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cursor
Copy link
Copy Markdown

cursor bot commented Feb 28, 2026

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on March 3.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 28, 2026

Important

Review skipped

Too many files!

This PR contains 154 files, which is 4 over the limit of 150.

📥 Commits

Reviewing files that changed from the base of the PR and between a54768c and 9ae2dca.

⛔ Files ignored due to path filters (146)
  • docs/res/081_vid.png is excluded by !**/*.png
  • docs/res/arch-01.svg is excluded by !**/*.svg
  • docs/res/banner.png is excluded by !**/*.png
  • docs/res/banner_high.png is excluded by !**/*.png
  • docs/res/code_exec_jailbreak.png is excluded by !**/*.png
  • docs/res/david_vid.jpg is excluded by !**/*.jpg
  • docs/res/dev/devinst-1.png is excluded by !**/*.png
  • docs/res/dev/devinst-10.png is excluded by !**/*.png
  • docs/res/dev/devinst-11.png is excluded by !**/*.png
  • docs/res/dev/devinst-12.png is excluded by !**/*.png
  • docs/res/dev/devinst-13.png is excluded by !**/*.png
  • docs/res/dev/devinst-14.png is excluded by !**/*.png
  • docs/res/dev/devinst-2.png is excluded by !**/*.png
  • docs/res/dev/devinst-3.png is excluded by !**/*.png
  • docs/res/dev/devinst-4.png is excluded by !**/*.png
  • docs/res/dev/devinst-5.png is excluded by !**/*.png
  • docs/res/dev/devinst-6.png is excluded by !**/*.png
  • docs/res/dev/devinst-7.png is excluded by !**/*.png
  • docs/res/dev/devinst-8.png is excluded by !**/*.png
  • docs/res/dev/devinst-9.png is excluded by !**/*.png
  • docs/res/devguide_vid.png is excluded by !**/*.png
  • docs/res/easy_ins_vid.png is excluded by !**/*.png
  • docs/res/favicon.png is excluded by !**/*.png
  • docs/res/favicon_round.png is excluded by !**/*.png
  • docs/res/flask_link.png is excluded by !**/*.png
  • docs/res/flow-01.svg is excluded by !**/*.svg
  • docs/res/header.png is excluded by !**/*.png
  • docs/res/image-24.png is excluded by !**/*.png
  • docs/res/joke.png is excluded by !**/*.png
  • docs/res/memory-man.png is excluded by !**/*.png
  • docs/res/new_vid.jpg is excluded by !**/*.jpg
  • docs/res/physics-2.png is excluded by !**/*.png
  • docs/res/physics.png is excluded by !**/*.png
  • docs/res/profiles.png is excluded by !**/*.png
  • docs/res/prompts.png is excluded by !**/*.png
  • docs/res/quickstart/image-24.png is excluded by !**/*.png
  • docs/res/quickstart/ui_chat_management.png is excluded by !**/*.png
  • docs/res/quickstart/ui_newchat1.png is excluded by !**/*.png
  • docs/res/settings-page-ui.png is excluded by !**/*.png
  • docs/res/settings-page-ui1.png is excluded by !**/*.png
  • docs/res/setup/1-docker-image-search.png is excluded by !**/*.png
  • docs/res/setup/2-docker-image-run-3.png is excluded by !**/*.png
  • docs/res/setup/2-docker-image-run.png is excluded by !**/*.png
  • docs/res/setup/2-docker-image-run2.png is excluded by !**/*.png
  • docs/res/setup/3-docker-port-mapping.png is excluded by !**/*.png
  • docs/res/setup/4-docker-container-started.png is excluded by !**/*.png
  • docs/res/setup/5-docker-click-to-open.png is excluded by !**/*.png
  • docs/res/setup/6-docker-a0-running-new.png is excluded by !**/*.png
  • docs/res/setup/6-docker-a0-running.png is excluded by !**/*.png
  • docs/res/setup/9-rfc-devpage-on-docker-instance-1.png is excluded by !**/*.png
  • docs/res/setup/9-rfc-devpage-on-local-sbs-1.png is excluded by !**/*.png
  • docs/res/setup/a2a/a2a-conn.png is excluded by !**/*.png
  • docs/res/setup/a2a/a2a2.png is excluded by !**/*.png
  • docs/res/setup/docker-delete-image-1.png is excluded by !**/*.png
  • docs/res/setup/image-1.png is excluded by !**/*.png
  • docs/res/setup/image-10.png is excluded by !**/*.png
  • docs/res/setup/image-11.png is excluded by !**/*.png
  • docs/res/setup/image-12.png is excluded by !**/*.png
  • docs/res/setup/image-13.png is excluded by !**/*.png
  • docs/res/setup/image-14-u.png is excluded by !**/*.png
  • docs/res/setup/image-14.png is excluded by !**/*.png
  • docs/res/setup/image-15.png is excluded by !**/*.png
  • docs/res/setup/image-16.png is excluded by !**/*.png
  • docs/res/setup/image-17.png is excluded by !**/*.png
  • docs/res/setup/image-18.png is excluded by !**/*.png
  • docs/res/setup/image-19.png is excluded by !**/*.png
  • docs/res/setup/image-2.png is excluded by !**/*.png
  • docs/res/setup/image-20.png is excluded by !**/*.png
  • docs/res/setup/image-21.png is excluded by !**/*.png
  • docs/res/setup/image-22-1.png is excluded by !**/*.png
  • docs/res/setup/image-23-1.png is excluded by !**/*.png
  • docs/res/setup/image-3.png is excluded by !**/*.png
  • docs/res/setup/image-4.png is excluded by !**/*.png
  • docs/res/setup/image-5.png is excluded by !**/*.png
  • docs/res/setup/image-6.png is excluded by !**/*.png
  • docs/res/setup/image-7.png is excluded by !**/*.png
  • docs/res/setup/image-8.png is excluded by !**/*.png
  • docs/res/setup/image-9.png is excluded by !**/*.png
  • docs/res/setup/image.png is excluded by !**/*.png
  • docs/res/setup/macsocket.png is excluded by !**/*.png
  • docs/res/setup/mcp/mcp-example-config.png is excluded by !**/*.png
  • docs/res/setup/mcp/mcp-open-config.png is excluded by !**/*.png
  • docs/res/setup/oses/apple.png is excluded by !**/*.png
  • docs/res/setup/oses/linux.png is excluded by !**/*.png
  • docs/res/setup/oses/windows.png is excluded by !**/*.png
  • docs/res/setup/settings/1-agentConfig.png is excluded by !**/*.png
  • docs/res/setup/settings/2-chat-model.png is excluded by !**/*.png
  • docs/res/setup/settings/3-auth.png is excluded by !**/*.png
  • docs/res/setup/settings/4-local-models.png is excluded by !**/*.png
  • docs/res/setup/thumb_play.png is excluded by !**/*.png
  • docs/res/setup/thumb_setup.png is excluded by !**/*.png
  • docs/res/setup/update-initialize.png is excluded by !**/*.png
  • docs/res/showcase-thumb.png is excluded by !**/*.png
  • docs/res/splash_wide.png is excluded by !**/*.png
  • docs/res/ui-actions.png is excluded by !**/*.png
  • docs/res/ui-attachments-2.png is excluded by !**/*.png
  • docs/res/ui-attachments.png is excluded by !**/*.png
  • docs/res/ui-behavior-change-chat.png is excluded by !**/*.png
  • docs/res/ui-context.png is excluded by !**/*.png
  • docs/res/ui-file-browser.png is excluded by !**/*.png
  • docs/res/ui-history.png is excluded by !**/*.png
  • docs/res/ui-katex-1.png is excluded by !**/*.png
  • docs/res/ui-katex-2.png is excluded by !**/*.png
  • docs/res/ui-nudge.png is excluded by !**/*.png
  • docs/res/ui-restarting.png is excluded by !**/*.png
  • docs/res/ui-screen-2.png is excluded by !**/*.png
  • docs/res/ui-screen.png is excluded by !**/*.png
  • docs/res/ui-settings-5-speech-to-text.png is excluded by !**/*.png
  • docs/res/ui-tts-stop-speech.png is excluded by !**/*.png
  • docs/res/ui_chat_management.png is excluded by !**/*.png
  • docs/res/ui_newchat1.png is excluded by !**/*.png
  • docs/res/ui_screen.png is excluded by !**/*.png
  • docs/res/ui_screen2.png is excluded by !**/*.png
  • docs/res/usage/action-btns.png is excluded by !**/*.png
  • docs/res/usage/api-int/api-int-1.png is excluded by !**/*.png
  • docs/res/usage/api-int/api-int-2image-gen-api2.png is excluded by !**/*.png
  • docs/res/usage/api-int/api-int-3-api-key-missing-secrets.png is excluded by !**/*.png
  • docs/res/usage/api-int/api-int-4-secrets-setting.png is excluded by !**/*.png
  • docs/res/usage/api-int/api-int-5-finish.png is excluded by !**/*.png
  • docs/res/usage/attachments-1.png is excluded by !**/*.png
  • docs/res/usage/attachments-2.png is excluded by !**/*.png
  • docs/res/usage/file-browser.png is excluded by !**/*.png
  • docs/res/usage/file-edit.png is excluded by !**/*.png
  • docs/res/usage/first-task.png is excluded by !**/*.png
  • docs/res/usage/memory-dashboard.png is excluded by !**/*.png
  • docs/res/usage/memory-editing.png is excluded by !**/*.png
  • docs/res/usage/multi-agent.png is excluded by !**/*.png
  • docs/res/usage/nudge.png is excluded by !**/*.png
  • docs/res/usage/projects/projects-activate-project.png is excluded by !**/*.png
  • docs/res/usage/projects/projects-creation.png is excluded by !**/*.png
  • docs/res/usage/projects/projects-desc-and-instructions.png is excluded by !**/*.png
  • docs/res/usage/projects/projects-first-ops.png is excluded by !**/*.png
  • docs/res/usage/projects/projects-git-projects-tree.png is excluded by !**/*.png
  • docs/res/usage/projects/projects-gitprojects-clone.png is excluded by !**/*.png
  • docs/res/usage/restart.png is excluded by !**/*.png
  • docs/res/usage/tasks/edit-task.png is excluded by !**/*.png
  • docs/res/usage/tasks/scheduler-1.png is excluded by !**/*.png
  • docs/res/usage/ui-context1.png is excluded by !**/*.png
  • docs/res/usage/ui-history1.png is excluded by !**/*.png
  • docs/res/usage/ui-katex-2.png is excluded by !**/*.png
  • docs/res/usage/ui-settings-5-speech-to-text.png is excluded by !**/*.png
  • docs/res/usage/ui-tts-stop-speech1.png is excluded by !**/*.png
  • docs/res/web-ui.mp4 is excluded by !**/*.mp4
  • docs/res/web_screenshot.jpg is excluded by !**/*.jpg
  • docs/res/win_webui2.gif is excluded by !**/*.gif
  • instruments/default/.DS_Store is excluded by !**/.DS_Store
📒 Files selected for processing (154)
  • .dockerignore
  • .gitignore
  • AGENTS.md
  • AGENTS.plugins.md
  • README.md
  • agent.py
  • agents/agent0/_context.md
  • agents/agent0/agent.yaml
  • agents/agent0/prompts/agent.system.tool.response.md
  • agents/default/_context.md
  • agents/default/agent.yaml
  • agents/developer/_context.md
  • agents/developer/agent.yaml
  • agents/hacker/_context.md
  • agents/hacker/agent.yaml
  • agents/researcher/_context.md
  • agents/researcher/agent.yaml
  • conf/model_providers.yaml
  • conf/projects.default.gitignore
  • conf/skill.default.gitignore
  • conf/workdir.gitignore
  • docker/base/fs/etc/searxng/limiter.toml
  • docker/base/fs/etc/searxng/settings.yml
  • docker/base/fs/ins/install_python.sh
  • docker/base/fs/ins/install_searxng2.sh
  • docker/run/Dockerfile
  • docker/run/fs/etc/searxng/limiter.toml
  • docker/run/fs/etc/searxng/settings.yml
  • docs/README.md
  • docs/agents/AGENTS.components.md
  • docs/agents/AGENTS.modals.md
  • docs/designs/backup-specification-backend.md
  • docs/designs/backup-specification-frontend.md
  • docs/developer/architecture.md
  • docs/developer/connectivity.md
  • docs/developer/contributing-skills.md
  • docs/developer/extensions.md
  • docs/developer/mcp-configuration.md
  • docs/developer/notifications.md
  • docs/developer/plugins.md
  • docs/developer/websockets.md
  • docs/guides/a2a-setup.md
  • docs/guides/api-integration.md
  • docs/guides/contribution.md
  • docs/guides/mcp-setup.md
  • docs/guides/projects.md
  • docs/guides/troubleshooting.md
  • docs/guides/usage.md
  • docs/installation.md
  • docs/mcp_setup.md
  • docs/plans/2026-02-28-docker-auto-clone-design.md
  • docs/plans/2026-02-28-docker-services-ui-design.md
  • docs/quickstart.md
  • docs/setup/dev-setup.md
  • docs/setup/installation.md
  • docs/setup/vps-deployment.md
  • docs/troubleshooting.md
  • docs/tunnel.md
  • docs/usage.md
  • initialize.py
  • instruments/default/yt_download/download_video.py
  • instruments/default/yt_download/yt_download.md
  • instruments/default/yt_download/yt_download.sh
  • jsconfig.json
  • knowledge/default/main/about/github_readme.md
  • knowledge/default/main/about/installation.md
  • knowledge/main/.gitkeep
  • knowledge/main/about/github_readme.md
  • knowledge/main/about/installation.md
  • knowledge/solutions/.gitkeep
  • models.py
  • plugins/README.md
  • plugins/chat_branching/api/branch_chat.py
  • plugins/chat_branching/extensions/webui/set_messages_after_loop/inject-branch-buttons.js
  • plugins/chat_branching/plugin.yaml
  • plugins/example_agent/agents/plugin_example/agent.yaml
  • plugins/example_agent/agents/plugin_example/prompts/agent.system.plugin_example.md
  • plugins/example_agent/plugin.yaml
  • plugins/memory/api/import_knowledge.py
  • plugins/memory/api/knowledge_path_get.py
  • plugins/memory/api/knowledge_reindex.py
  • plugins/memory/api/memory_dashboard.py
  • plugins/memory/default_config.yaml
  • plugins/memory/extensions/python/embedding_model_changed/_10_memory_reload.py
  • plugins/memory/extensions/python/message_loop_prompts_after/_50_recall_memories.py
  • plugins/memory/extensions/python/message_loop_prompts_after/_91_recall_wait.py
  • plugins/memory/extensions/python/monologue_end/_50_memorize_fragments.py
  • plugins/memory/extensions/python/monologue_end/_51_memorize_solutions.py
  • plugins/memory/extensions/python/monologue_start/_10_memory_init.py
  • plugins/memory/extensions/python/system_prompt/_20_behaviour_prompt.py
  • plugins/memory/extensions/webui/sidebar-quick-actions-dropdown-start/memory-entry.html
  • plugins/memory/extensions/webui/sidebar-quick-actions-main-start/memory-entry.html
  • plugins/memory/helpers/knowledge_import.py
  • plugins/memory/helpers/memory.py
  • plugins/memory/helpers/memory_consolidation.py
  • plugins/memory/plugin.yaml
  • plugins/memory/prompts/agent.system.memories.md
  • plugins/memory/prompts/agent.system.solutions.md
  • plugins/memory/prompts/agent.system.tool.memory.md
  • plugins/memory/prompts/fw.memory.hist_suc.sys.md
  • plugins/memory/prompts/fw.memory.hist_sum.sys.md
  • plugins/memory/prompts/fw.memory_saved.md
  • plugins/memory/prompts/memory.consolidation.msg.md
  • plugins/memory/prompts/memory.consolidation.sys.md
  • plugins/memory/prompts/memory.keyword_extraction.msg.md
  • plugins/memory/prompts/memory.keyword_extraction.sys.md
  • plugins/memory/prompts/memory.memories_filter.msg.md
  • plugins/memory/prompts/memory.memories_filter.sys.md
  • plugins/memory/prompts/memory.memories_query.msg.md
  • plugins/memory/prompts/memory.memories_query.sys.md
  • plugins/memory/prompts/memory.memories_sum.sys.md
  • plugins/memory/prompts/memory.recall_delay_msg.md
  • plugins/memory/prompts/memory.solutions_query.sys.md
  • plugins/memory/prompts/memory.solutions_sum.sys.md
  • plugins/memory/tools/behaviour_adjustment.py
  • plugins/memory/tools/memory_delete.py
  • plugins/memory/tools/memory_forget.py
  • plugins/memory/tools/memory_load.py
  • plugins/memory/tools/memory_save.py
  • plugins/memory/webui/config.html
  • plugins/memory/webui/main.html
  • plugins/memory/webui/memory-dashboard-store.js
  • plugins/memory/webui/memory-dashboard.html
  • plugins/memory/webui/memory-detail-modal.html
  • plugins/tests/test_webui_extension_surfaces.py
  • plugins/text_editor/default_config.yaml
  • plugins/text_editor/extensions/.gitkeep
  • plugins/text_editor/extensions/python/system_prompt/_15_text_editor_prompt.py
  • plugins/text_editor/helpers/__init__.py
  • plugins/text_editor/helpers/file_ops.py
  • plugins/text_editor/plugin.yaml
  • plugins/text_editor/prompts/agent.system.tool.text_editor.md
  • plugins/text_editor/prompts/fw.text_editor.patch_error.md
  • plugins/text_editor/prompts/fw.text_editor.patch_need_read.md
  • plugins/text_editor/prompts/fw.text_editor.patch_ok.md
  • plugins/text_editor/prompts/fw.text_editor.patch_stale_read.md
  • plugins/text_editor/prompts/fw.text_editor.read_error.md
  • plugins/text_editor/prompts/fw.text_editor.read_ok.md
  • plugins/text_editor/prompts/fw.text_editor.write_error.md
  • plugins/text_editor/prompts/fw.text_editor.write_ok.md
  • plugins/text_editor/tools/text_editor.py
  • plugins/text_editor/webui/config.html
  • preload.py
  • prompts/agent.extras.agent_info.md
  • prompts/agent.extras.workdir_structure.md
  • prompts/agent.system.instruments.md
  • prompts/agent.system.main.solving.md
  • prompts/agent.system.main.tips.md
  • prompts/agent.system.main.tips.py
  • prompts/agent.system.projects.active.md
  • prompts/agent.system.skills.loaded.md
  • prompts/agent.system.skills.md
  • prompts/agent.system.tool.call_sub.md
  • prompts/agent.system.tool.call_sub.py

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch context-engine-a0-plugin

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Feb 28, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Arbitrary code loading

Description: The tool loader uses an LLM-provided tool_name (from tool_request) to build candidate
Python file paths (name + ".py") and then dynamically imports classes from the first
matching path, which could enable path traversal / arbitrary local file import and code
execution if name is not strictly validated/sanitized by subagents.get_paths() and/or
extract_tools.load_classes_from_file().
agent.py [885-1039]

Referred Code
@extensible
async def process_tools(self, msg: str):
    # search for tool usage requests in agent message
    tool_request = extract_tools.json_parse_dirty(msg)

    if tool_request is not None:
        raw_tool_name = tool_request.get("tool_name", tool_request.get("tool",""))  # Get the raw tool name
        tool_args = tool_request.get("tool_args", tool_request.get("args", {}))

        tool_name = raw_tool_name  # Initialize tool_name with raw_tool_name
        tool_method = None  # Initialize tool_method

        # Split raw_tool_name into tool_name and tool_method if applicable
        if ":" in raw_tool_name:
            tool_name, tool_method = raw_tool_name.split(":", 1)

        tool = None  # Initialize tool to None

        # Try getting tool from MCP first
        try:
            import python.helpers.mcp_handler as mcp_helper


 ... (clipped 134 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Missing import: get_default_value() calls json.loads() for dict defaults but the new imports shown in the
diff do not include import json, which can cause a runtime NameError when parsing
env-provided dict settings.

Referred Code
def get_default_value(name: str, value: T) -> T:
    """
    Load setting value from .env with A0_SET_ prefix, falling back to default.

    Args:
        name: Setting name (will be prefixed with A0_SET_)
        value: Default value to use if env var not set

    Returns:
        Environment variable value (type-normalized) or default value
    """
    env_value = dotenv.get_dotenv_value(f"A0_SET_{name}", dotenv.get_dotenv_value(f"A0_SET_{name.upper()}", None))

    if env_value is None:
        return value

    # Normalize type to match value param type
    try:
        if isinstance(value, bool):
            return env_value.strip().lower() in ('true', '1', 'yes', 'on')  # type: ignore
        elif isinstance(value, dict):



 ... (clipped 6 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
UI error leakage: On MCP update failure, the notification includes detail=str(e) which may expose internal
error details to end-users instead of keeping specifics in internal logs only.

Referred Code
NotificationManager.send_notification(
    type=NotificationType.INFO,
    priority=NotificationPriority.NORMAL,
    message="Updating MCP settings...",
    display_time=999,
    group="settings-mcp"
)

mcp_config = MCPConfig.get_instance()
try:
    MCPConfig.update(mcp_servers)
except Exception as e:

    NotificationManager.send_notification(
        type=NotificationType.ERROR,
        priority=NotificationPriority.HIGH,
        message="Failed to update MCP settings",
        detail=str(e),                        
    )

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Secret in logs: The warning log in get_default_value() prints the raw environment variable value, which
can leak secrets if sensitive settings are provided via A0_SET_*.

Referred Code
try:
    if isinstance(value, bool):
        return env_value.strip().lower() in ('true', '1', 'yes', 'on')  # type: ignore
    elif isinstance(value, dict):
        return json.loads(env_value.strip())  # type: ignore
    elif isinstance(value, str):
        return str(env_value).strip()  # type: ignore
    else:
        return type(value)(env_value.strip())  # type: ignore
except (ValueError, TypeError, json.JSONDecodeError) as e:
    PrintStyle(background_color="yellow", font_color="black").print(
        f"Warning: Invalid value for A0_SET_{name}='{env_value}': {e}. Using default: {value}"
    )
    return value

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit context: The PR changes sensitive configuration flows (API keys/auth/secrets/MCP settings) but the
diff does not show structured audit logging with user identity and outcome for these
critical actions.

Referred Code
def _write_sensitive_settings(settings: Settings):
    for key, val in settings["api_keys"].items():
        if val != API_KEY_PLACEHOLDER:
            dotenv.save_dotenv_value(f"API_KEY_{key.upper()}", val)

    dotenv.save_dotenv_value(dotenv.KEY_AUTH_LOGIN, settings["auth_login"])
    if settings["auth_password"] != PASSWORD_PLACEHOLDER:
        dotenv.save_dotenv_value(dotenv.KEY_AUTH_PASSWORD, settings["auth_password"])
    if settings["rfc_password"] != PASSWORD_PLACEHOLDER:
        dotenv.save_dotenv_value(dotenv.KEY_RFC_PASSWORD, settings["rfc_password"])
    if settings["root_password"] != PASSWORD_PLACEHOLDER:
        if runtime.is_dockerized():
            dotenv.save_dotenv_value(dotenv.KEY_ROOT_PASSWORD, settings["root_password"])
            set_root_password(settings["root_password"])

    # Handle secrets separately - merge with existing preserving comments/order and support deletions
    secrets_manager = get_default_secrets_manager()



 ... (clipped 165 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Hidden files exposure: The backup preview now defaults include_hidden to True, which may unintentionally expose
sensitive hidden files unless access controls and path allowlisting are enforced
elsewhere.

Referred Code
# Get input parameters
include_patterns = input.get("include_patterns", [])
exclude_patterns = input.get("exclude_patterns", [])
include_hidden = input.get("include_hidden", True)
max_depth = input.get("max_depth", 3)
search_filter = input.get("search_filter", "")

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Feb 28, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
PR scope mismatches its goal

The PR's description, which claims to add a "Context Engine" plugin, is
inaccurate. The actual changes consist of a massive, unrelated refactoring of
the core framework, and the plugin code itself is missing.

Examples:

run_ui.py [1-478]
python/helpers/settings.py [1-663]

Solution Walkthrough:

Before:

// PR #123: "feat: Add Context Engine plugin"
// Contains changes to:
// - run_ui.py (Web server migration from Flask to Starlette/Uvicorn)
// - python/helpers/websocket_manager.py (New WebSocket management system)
// - python/helpers/settings.py (Complete settings system refactor)
// - python/helpers/plugins.py (New plugin management system)
// - python/helpers/skills.py (New skill management system)
// - agent.py (Core agent lifecycle refactoring)
// - ... and many other core files.
// - No files from `usr/plugins/context-engine/` are present.

After:

// PR #1: "refactor: Migrate web server to ASGI stack"
// Contains changes to run_ui.py, websocket_manager.py, etc.

// PR #2: "refactor: Overhaul settings system"
// Contains changes to python/helpers/settings.py.

// PR #3: "feat: Add new plugin management system"
// Contains changes to python/helpers/plugins.py.

// ... other focused refactoring PRs ...

// PR #N: "feat: Add Context Engine plugin"
// Contains changes to `usr/plugins/context-engine/`.
Suggestion importance[1-10]: 10

__

Why: The suggestion correctly identifies a critical and fundamental flaw: the PR's description is completely disconnected from its code changes, making it unreviewable and misleading.

High
Possible issue
Fix incorrect session lookup logic

Fix type mismatches in get_sids_for_user and get_user_for_sid to correctly
handle ConnectionIdentity tuples for lookups and return values, preventing
runtime errors.

python/helpers/websocket_manager.py [1138-1147]

 def get_sids_for_user(self, user: str | None = None) -> list[str]:
     """Return SIDs for a user; single-user default returns all active SIDs."""
     with self.lock:
         bucket = self._ALL_USERS_BUCKET if user is None else user
-        return list(self.user_to_sids.get(bucket, set())) # type: ignore
+        identities = self.user_to_sids.get(bucket, set())
+        return [sid for _, sid in identities]
 
-def get_user_for_sid(self, sid: str) -> str | None:
+def get_user_for_sid(self, namespace: str, sid: str) -> str | None:
     """Return user identifier for a SID or None."""
+    identity: ConnectionIdentity = (namespace, sid)
     with self.lock:
-        return self.sid_to_user.get(sid) # type: ignore
+        return self.sid_to_user.get(identity)

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical bug where session tracking methods would fail at runtime due to incorrect key types and return types, and provides a correct fix.

High
Fix race condition in logging method

Fix a race condition in the log method by fully constructing the LogItem and
appending it to the logs list within a single atomic lock to prevent data
corruption.

python/helpers/log.py [225-266]

 def log(
     self,
     type: Type,
     heading: str | None = None,
     content: str | None = None,
     kvps: dict | None = None,
     update_progress: ProgressUpdate | None = None,
     id: Optional[str] = None,
     **kwargs,
 ) -> LogItem:
+    # Determine agent number from streaming agent
+    agentno = 0
+    if self.context and self.context.streaming_agent:
+        agentno = self.context.streaming_agent.number
+
+    # Prepare all data outside the lock to minimize lock duration
+    final_kvps = OrderedDict(copy.deepcopy(kvps or {}))
+    if kwargs:
+        final_kvps.update(copy.deepcopy(kwargs))
+
+    masked_heading = _truncate_heading(self._mask_recursive(heading))
+    masked_content = _truncate_content(self._mask_recursive(content), type)
+    masked_kvps = _truncate_value(self._mask_recursive(final_kvps))
+
     with self._lock:
-        # add a minimal item to the log
-        # Determine agent number from streaming agent
-        agentno = 0
-        if self.context and self.context.streaming_agent:
-            agentno = self.context.streaming_agent.number
-
         item = LogItem(
             log=self,
             no=len(self.logs),
             type=type,
+            heading=masked_heading,
+            content=masked_content,
+            kvps=masked_kvps,
+            update_progress=update_progress,
+            id=id,
             agentno=agentno,
         )
+        self.logs.append(item)
+        self.updates.append(item.no)
 
-        self.logs.append(item)
-
-    # Update outside the lock - the heavy masking/truncation work should not hold
-    # the lock; we only need locking while mutating shared arrays/fields.
-    self._update_item(
-        no=item.no,
-        type=type,
-        heading=heading,
-        content=content,
-        kvps=kvps,
-        update_progress=update_progress,
-        id=id,
-        notify_state_monitor=False,
-        **kwargs,
-    )
+        if item.heading and item.update_progress != "none":
+            if item.no >= self.progress_no:
+                self.progress = item.heading
+                self.progress_no = (
+                    item.no if item.update_progress == "persistent" else -1
+                )
+                self.progress_active = True
 
     self._notify_state_monitor()
     return item

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical race condition that could lead to log corruption and proposes a valid fix by moving the item creation and update logic into a single atomic block.

High
Prevent race condition in context re-initialization

Move the existing.task.kill() call inside the _contexts_lock block in the
AgentContext constructor to prevent a race condition.

agent.py [67-77]

 def __init__(
     self,
     config: "AgentConfig",
     ...
 ):
     # initialize context
     self.id = id or AgentContext.generate_id()
     existing = None
     with AgentContext._contexts_lock:
         existing = AgentContext._contexts.get(self.id, None)
         if existing:
             AgentContext._contexts.pop(self.id, None)
+            if existing.task:
+                existing.task.kill()
         AgentContext._contexts[self.id] = self
-    if existing and existing.task:
-        existing.task.kill()
+
     if set_current:
         AgentContext.set_current(self.id)
     ...

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a race condition where a task could be accessed after its context is removed but before it's killed, and proposes moving the kill() call inside the lock to ensure atomicity.

Medium
Fix race condition in task cancellation

Fix a race condition in cancel_running_task by removing the cancelled task from
the _running_deferred_tasks dictionary under a lock to prevent memory leaks.

python/helpers/task_scheduler.py [648-655]

 def cancel_running_task(self, task_uuid: str, terminate_thread: bool = False) -> bool:
     with self._running_tasks_lock:
         deferred_task = self._running_deferred_tasks.get(task_uuid)
-    if not deferred_task:
-        return False
-    PrintStyle.info(f"Scheduler cancelling task {task_uuid}")
-    deferred_task.kill(terminate_thread=terminate_thread)
+        if not deferred_task:
+            return False
+        PrintStyle.info(f"Scheduler cancelling task {task_uuid}")
+        deferred_task.kill(terminate_thread=terminate_thread)
+        self._running_deferred_tasks.pop(task_uuid, None)
     return True

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a race condition and memory leak bug where a cancelled task is not removed from the tracking dictionary, and the proposed fix resolves the issue.

Medium
Allow clearing sensitive settings from UI

Modify _write_sensitive_settings to handle clearing sensitive values by checking
for empty strings and removing the corresponding key from the .env file, instead
of just saving an empty value.

python/helpers/settings.py [475-488]

 def _write_sensitive_settings(settings: Settings):
     for key, val in settings["api_keys"].items():
         if val != API_KEY_PLACEHOLDER:
-            dotenv.save_dotenv_value(f"API_KEY_{key.upper()}", val)
+            if val:
+                dotenv.save_dotenv_value(f"API_KEY_{key.upper()}", val)
+            else:
+                dotenv.remove_dotenv_key(f"API_KEY_{key.upper()}")
 
     dotenv.save_dotenv_value(dotenv.KEY_AUTH_LOGIN, settings["auth_login"])
     if settings["auth_password"] != PASSWORD_PLACEHOLDER:
-        dotenv.save_dotenv_value(dotenv.KEY_AUTH_PASSWORD, settings["auth_password"])
+        if settings["auth_password"]:
+            dotenv.save_dotenv_value(dotenv.KEY_AUTH_PASSWORD, settings["auth_password"])
+        else:
+            dotenv.remove_dotenv_key(dotenv.KEY_AUTH_PASSWORD)
     if settings["rfc_password"] != PASSWORD_PLACEHOLDER:
-        dotenv.save_dotenv_value(dotenv.KEY_RFC_PASSWORD, settings["rfc_password"])
+        if settings["rfc_password"]:
+            dotenv.save_dotenv_value(dotenv.KEY_RFC_PASSWORD, settings["rfc_password"])
+        else:
+            dotenv.remove_dotenv_key(dotenv.KEY_RFC_PASSWORD)
     if settings["root_password"] != PASSWORD_PLACEHOLDER:
         if runtime.is_dockerized():
-            dotenv.save_dotenv_value(dotenv.KEY_ROOT_PASSWORD, settings["root_password"])
-            set_root_password(settings["root_password"])
+            if settings["root_password"]:
+                dotenv.save_dotenv_value(dotenv.KEY_ROOT_PASSWORD, settings["root_password"])
+                set_root_password(settings["root_password"])
+            else:
+                dotenv.remove_dotenv_key(dotenv.KEY_ROOT_PASSWORD)

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a potential issue where clearing sensitive settings via the UI might not work as expected, and proposes a robust solution to handle empty values by removing the corresponding key from the environment file.

Low
Prevent data loss in parser

In the fallback frontmatter parser, only append list items to a key if its value
is already a list to avoid overwriting scalar values.

python/helpers/skills.py [193-203]

 m_list = re.match(r"^\s*-\s*(.*)$", line)
 if m_list and current_key:
     item = m_list.group(1).strip()
     if (item.startswith('"') and item.endswith('"')) or (
         item.startswith("'") and item.endswith("'")
     ):
         item = item[1:-1]
-    if not isinstance(data.get(current_key), list):
-        data[current_key] = []
-    data[current_key].append(item)
+    # Only append to an existing list to prevent overwriting scalar values.
+    if isinstance(data.get(current_key), list):
+        data[current_key].append(item)
     continue

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a potential data loss issue in the fallback parser where a scalar value could be overwritten by a list, and the proposed fix correctly prevents this.

Low
Security
Sanitize plugin name to prevent path traversal

Sanitize the plugin_name parameter from the URL to prevent potential path
traversal vulnerabilities before using it in file path operations.

run_ui.py [149-180]

 @extension.extensible
 async def _serve_plugin_asset(plugin_name, asset_path):
     """
     Serve static assets from plugin directories.
     Resolves using the plugin system (with overrides).
     """
     from python.helpers import plugins
     from flask import send_file
     
+    # Security: Sanitize plugin_name to prevent path traversal.
+    if ".." in plugin_name or "/" in plugin_name or "\\" in plugin_name:
+        return Response("Invalid plugin name", 400)
+
     # Use the new find_plugin helper
     plugin_dir = plugins.find_plugin_dir(plugin_name)
     if not plugin_dir:
         return Response("Plugin not found", 404)
     
     # Resolve the plugin asset path with security checks
     try:
         # Construct path using plugin root
         asset_file = files.get_abs_path(plugin_dir, asset_path)
         webui_dir = files.get_abs_path(plugin_dir, "webui")
         webui_extensions_dir = files.get_abs_path(plugin_dir, "extensions/webui")
         
         # Security: ensure the resolved path is within the plugin webui directory
         if not files.is_in_dir(str(asset_file), str(webui_dir)) and not files.is_in_dir(str(asset_file), str(webui_extensions_dir)):
             return Response("Access denied", 403)
             
         if not files.is_file(asset_file):
             return Response("Asset not found", 404)
             
         return send_file(str(asset_file))
     except Exception as e:
         PrintStyle.error(f"Error serving plugin asset: {e}")
         return Response("Error serving asset", 500)

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a potential path traversal vulnerability by using an unsanitized plugin_name from the URL to construct file paths, which is a critical security risk.

High
General
Parallelize broadcast emits

Refactor the broadcast method to send messages to all clients in parallel using
asyncio.gather instead of sequentially awaiting each emit_to call.

python/helpers/websocket_manager.py [982-1013]

-async def broadcast(
-    self,
-    namespace: str,
-    event_type: str,
-    data: dict[str, Any],
-    *,
-    exclude_sids: str | Iterable[str] | None = None,
-    handler_id: str | None = None,
-    correlation_id: str | None = None,
-    diagnostic: bool = False,
-) -> None:
+async def broadcast(...):
     excluded = self._normalize_sid_filter(exclude_sids)
 
-    targets: list[str] = []
     with self.lock:
-        current_identities = list(self.connections.keys())
-    for conn_identity in current_identities:
-        if conn_identity[0] != namespace:
-            continue
-        sid = conn_identity[1]
-        if sid in excluded:
-            continue
-        targets.append(sid)
-        await self.emit_to(
+        targets = [
+            sid
+            for (ns, sid) in self.connections.keys()
+            if ns == namespace and sid not in excluded
+        ]
+    # fire all emits in parallel
+    tasks = [
+        self.emit_to(
             namespace,
             sid,
             event_type,
             data,
             handler_id=handler_id,
             correlation_id=correlation_id,
             diagnostic=diagnostic,
         )
+        for sid in targets
+    ]
+    await asyncio.gather(*tasks)

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out a performance bottleneck in the broadcast method and proposes using asyncio.gather to send messages in parallel, which significantly improves efficiency for a large number of connections.

Medium
Make notification manager threadsafe

Make the NotificationManager instantiation thread-safe by guarding its creation
with the _contexts_lock.

agent.py [146-152]

 @classmethod
 def get_notification_manager(cls):
-    if cls._notification_manager is None:
-        from python.helpers.notification import NotificationManager  # type: ignore
-        cls._notification_manager = NotificationManager()
+    with AgentContext._contexts_lock:
+        if cls._notification_manager is None:
+            from python.helpers.notification import NotificationManager  # type: ignore
+            cls._notification_manager = NotificationManager()
     return cls._notification_manager
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential race condition in the lazy initialization of the singleton _notification_manager and proposes a valid fix using the existing lock to ensure thread safety.

Medium
Create toggle directory before writing

Before writing plugin toggle files, ensure their parent directory exists to
prevent files.write_file from failing.

python/helpers/plugins.py [333-339]

 files.delete_file(enabled_file)
 files.delete_file(disabled_file)
+
+# Ensure directory exists before writing toggle files
+parent_dir = str(Path(enabled_file).parent)
+files.create_dir(parent_dir)
 
 if enabled:
     files.write_file(enabled_file, "")
 else:
     files.write_file(disabled_file, "")

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that writing a toggle file could fail if its parent directory doesn't exist and provides a robust fix by ensuring the directory is created.

Medium
  • Update

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances Agent Zero's modularity, extensibility, and user experience by integrating a new Context Engine plugin for advanced code search and RAG. It introduces a comprehensive plugin system and a standardized 'Skills' framework, replacing older 'Instruments' for more dynamic agent capabilities. The changes also include a major overhaul of the project's documentation, a shift to a centralized /usr directory for user data, and expanded support for various LLM providers, making the framework more robust and adaptable.

Highlights

  • Context Engine Plugin Integration: Introduced a comprehensive Agent Zero plugin for Context Engine, enabling hybrid code search and RAG capabilities with 8 specialized agent tools for semantic code search, AI-powered Q&A, symbol graph analysis, and developer memory.
  • Modular Plugin Architecture: Implemented a robust plugin system with detailed documentation, allowing for extensible backend APIs, tools, helpers, Python lifecycle extensions, and WebUI contributions, alongside scoped settings and activation controls.
  • Skills System Adoption: Replaced the legacy 'Instruments' with a new 'Skills' system based on the open SKILL.md standard, enhancing contextual expertise and cross-platform compatibility with tools like Claude Code and GitHub Copilot.
  • Extensive Documentation Overhaul: Completely restructured and expanded the project documentation, introducing new guides for quick start, installation, development setup, usage, projects, API integration, MCP/A2A setup, and developer-focused topics like WebSockets and plugins.
  • Enhanced Agent Context Management: Refactored core agent methods to be extensible, improved thread-safe context handling, added robust error retry mechanisms for critical exceptions, and refined prompt parsing for dynamic agent behavior.
  • User Data Centralization: Migrated user-specific data directories (e.g., uploads, knowledge, memory) to a new /usr directory for cleaner separation from core framework files and improved persistence across updates.
  • Expanded LLM Provider Support: Added support for several new LLM providers including Moonshot AI, AWS Bedrock, Z.AI, and Z.AI Coding, alongside updates to existing providers like Agent Zero API and GitHub Copilot.
  • Chat Branching Feature: Introduced a new chat branching plugin that allows users to create new chat contexts from any point in an existing conversation's history, facilitating iterative development and exploration.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • .dockerignore
    • Removed obsolete exclusions for memory, instruments, and knowledge directories.
    • Added exclusion for 'knowledge/custom/**' to align with new user data structure.
  • .gitignore
    • Updated ignored folders to reflect new user data structure, specifically ignoring '/memory/', '/knowledge/custom/', and '/instruments/'.
    • Added explicit tracking for the new 'usr/plugins/context-engine/**' directory.
    • Included new ignore patterns for '.agent/' and '.claude/' directories.
  • AGENTS.md
    • Added a new comprehensive guide detailing Agent Zero's architecture, core commands, Docker environment, project structure, development patterns, safety guidelines, and code examples.
  • AGENTS.plugins.md
    • Added a new detailed guide outlining the full-stack plugin architecture, including manifest format, file structure, settings resolution, activation model, API surface, and community sharing process.
  • README.md
    • Updated documentation links to reflect the new structured documentation paths.
    • Revised the 'Projects' section to highlight the new 'Skills System' and 'Git-based Projects'.
    • Added a quick start Docker command for easier setup.
    • Updated the changelog to include details for version v0.9.8, focusing on Skills, UI Redesign, and Git projects.
  • agent.py
    • Refactored core Agent and AgentContext methods with @extensible decorators for enhanced modularity.
    • Implemented thread-safe context management using _contexts_lock.
    • Introduced error retry logic for critical exceptions within the agent's monologue loop.
    • Updated prompt parsing to leverage subagents.get_paths and files.is_full_json_template for dynamic loading.
    • Modified tool argument parsing to support both 'tool_name'/'tool_args' and 'tool'/'args' keys for broader compatibility.
  • agents/agent0/agent.yaml
    • Added a YAML-based agent profile for 'Agent 0', replacing the previous Markdown context file.
  • agents/agent0/prompts/agent.system.tool.response.md
    • Updated image path guidance and emphasized showing relevant images with full paths.
  • agents/default/agent.yaml
    • Added a YAML-based agent profile for the 'Default' agent, replacing the previous Markdown context file.
  • agents/developer/agent.yaml
    • Added a YAML-based agent profile for the 'Developer' agent, replacing the previous Markdown context file.
  • agents/hacker/agent.yaml
    • Added a YAML-based agent profile for the 'Hacker' agent, replacing the previous Markdown context file.
  • agents/researcher/agent.yaml
    • Added a YAML-based agent profile for the 'Researcher' agent, replacing the previous Markdown context file.
  • conf/model_providers.yaml
    • Updated the 'a0_venice' chat provider name to 'Agent Zero API' and its API base URL.
    • Added 'Copilot-Vision-Request' header for the 'github_copilot' provider.
    • Introduced new chat model providers: 'moonshot', 'bedrock', 'zai', and 'zai_coding'.
    • Added 'bedrock' as a new embedding model provider.
  • conf/projects.default.gitignore
    • Simplified gitignore patterns for Python and Node.js environments.
    • Removed explicit exclusion for '.a0proj/' as it's now handled differently.
  • conf/skill.default.gitignore
    • Added a new default gitignore file specifically for skill directories.
  • conf/workdir.gitignore
    • Added a new gitignore file for the working directory.
  • docker/base/fs/etc/searxng/limiter.toml
    • Updated SearXNG limiter configuration from 'real_ip' to 'botdetection' and 'x_for' to 'trusted_proxies'.
  • docker/base/fs/etc/searxng/settings.yml
    • Commented out 'Ahmia blacklist' plugin and disabled 'ahmia' and 'torch' search engines.
  • docker/base/fs/ins/install_python.sh
    • Added 'pipx' to the list of Python packages installed in the execution runtime.
  • docker/base/fs/ins/install_searxng2.sh
    • Changed SearXNG installation command from editable mode to standard install.
    • Added 'msgspec' and 'typing_extensions' to the pip install list.
  • docker/run/Dockerfile
    • Added a commented-out line for 'agent0ai/agent-zero-base:testing' image, indicating potential testing configurations.
  • docker/run/fs/etc/searxng/limiter.toml
    • Updated SearXNG limiter configuration from 'real_ip' to 'botdetection' and 'x_for' to 'trusted_proxies'.
  • docker/run/fs/etc/searxng/settings.yml
    • Commented out 'Ahmia blacklist' plugin and disabled 'ahmia' and 'torch' search engines.
  • docs/README.md
    • Updated documentation links to new structured paths for setup, guides, and developer sections.
    • Revised the 'Projects' section to introduce 'Agent Zero Skills' and 'Git-based Projects'.
    • Added a quick start Docker command for easier installation.
    • Updated the changelog to reflect version v0.9.8, detailing new Skills, UI Redesign, and Git projects.
  • docs/agents/AGENTS.components.md
    • Added new documentation detailing the Alpine.js component system, including architecture, structure, store patterns, lifecycle management, and best practices.
  • docs/agents/AGENTS.modals.md
    • Added new documentation explaining the frontend's stacked modal system, covering its core API, DOM structure, footer support, and conventions for modal components.
  • docs/developer/architecture.md
    • Renamed from 'docs/architecture.md'.
    • Updated content to reflect the new 'Skills' system, replacing 'Instruments'.
    • Revised Docker persistence notes and updated prompt organization details.
  • docs/developer/connectivity.md
    • Renamed from 'docs/connectivity.md'.
    • Added support for specifying a 'project' parameter in the API message endpoint.
    • Included project support in MCP and A2A connection URLs for isolated contexts.
  • docs/developer/contributing-skills.md
    • Added new comprehensive guide for contributing skills, detailing the SKILL.md standard, creation process, best practices, and sharing mechanisms.
  • docs/developer/extensions.md
    • Renamed from 'docs/extensibility.md'.
    • Updated content to refer to 'skills' instead of 'instruments'.
    • Revised custom prompt location guidance and highlighted project support for tasks.
  • docs/developer/mcp-configuration.md
    • Added new detailed documentation for advanced Model Context Protocol (MCP) configuration, covering server types, tool consumption, and troubleshooting.
  • docs/developer/notifications.md
    • Renamed from 'docs/notifications.md'.
    • Added a tip highlighting the synergy between notifications and scheduled tasks.
  • docs/developer/plugins.md
    • Added new documentation detailing the Agent Zero plugin system, including manifest format, settings resolution, activation model, and publishing to the Plugin Index.
  • docs/developer/websockets.md
    • Added new comprehensive guide for the WebSocket infrastructure, covering architecture, terminology, connection lifecycle, and producer/consumer patterns.
  • docs/guides/a2a-setup.md
    • Added new guide for setting up Agent-to-Agent (A2A) communication, including enabling the server, connection URL formats, and use cases.
  • docs/guides/api-integration.md
    • Added new guide demonstrating how to integrate external APIs without writing code, using Google AI Studio as an example.
  • docs/guides/contribution.md
    • Renamed from 'docs/contribution.md'.
    • Updated 'Getting Started' section with links to new developer documentation.
  • docs/guides/mcp-setup.md
    • Added new guide for setting up Model Context Protocol (MCP) servers, including adding servers and common examples.
  • docs/guides/projects.md
    • Added new comprehensive guide for working with projects, detailing creation, configuration, memory isolation, and advanced use cases.
  • docs/guides/troubleshooting.md
    • Added new troubleshooting and FAQ guide, addressing common issues and providing solutions.
  • docs/guides/usage.md
    • Added new comprehensive usage guide, covering basic operations, tool usage, multi-agent cooperation, projects, tasks, and memory management.
  • docs/quickstart.md
    • Updated the quick start guide to reflect new installation steps, API key configuration, dashboard overview, and skill interaction examples.
  • docs/setup/dev-setup.md
    • Renamed from 'docs/development.md'.
    • Updated run_ui.py host configuration and added RFC notes for host IDE + Docker execution.
    • Included guidance on configuring settings via environment variables.
  • docs/setup/installation.md
    • Added new detailed installation guide with OS-specific instructions for Docker Desktop, image pulling, container running, and initial configuration.
  • docs/setup/vps-deployment.md
    • Added new comprehensive guide for deploying Agent Zero on VPS/dedicated servers, covering Docker installation, Apache reverse proxy, SSL, and authentication.
  • initialize.py
    • Decorated several initialization functions with @extension.extensible to allow plugin hooks.
    • Removed memory_subdir from AgentConfig initialization, centralizing memory configuration within the memory plugin.
    • Added initialize_migration() to handle startup migrations and .env file reloading.
  • jsconfig.json
    • Updated JavaScript compiler options to enable stricter checks and ESNext features.
    • Expanded path mappings and include directives to support plugin directories ('plugins/' and 'usr/plugins/').
  • knowledge/main/.gitkeep
    • Renamed from 'instruments/custom/.gitkeep'.
  • knowledge/main/about/github_readme.md
    • Added the updated content of the main README.md into the knowledge base.
  • knowledge/solutions/.gitkeep
    • Renamed from 'instruments/default/.gitkeep'.
  • models.py
    • Removed nest_asyncio import and its application, simplifying asyncio integration.
    • Improved robustness by using .get() with default values for reasoning_delta and response_delta in ChatStreamer.
    • Added explicit_caching parameter to _convert_messages and unified_call for better control over LiteLLM caching behavior.
    • Ensured empty message content is skipped during message conversion to LiteLLM format.
  • plugins/chat_branching/api/branch_chat.py
    • Added new API endpoint to create a new chat context by branching from an existing chat at a specific log message.
  • plugins/chat_branching/extensions/webui/set_messages_after_loop/inject-branch-buttons.js
    • Added new WebUI extension to inject 'Branch chat' buttons into chat messages, enabling the new chat branching feature.
  • plugins/chat_branching/plugin.yaml
    • Added plugin manifest for the 'Chat Branching' plugin.
  • plugins/example_agent/agents/plugin_example/agent.yaml
    • Added a YAML-based agent profile for the 'Plugin Example Agent', demonstrating plugin-distributed agent profiles.
  • plugins/example_agent/agents/plugin_example/prompts/agent.system.plugin_example.md
    • Added a system prompt for the 'Plugin Example Agent', illustrating how plugins can define agent behaviors.
  • plugins/example_agent/plugin.yaml
    • Added plugin manifest for the 'Example Agent' plugin.
  • plugins/memory/api/import_knowledge.py
    • Renamed from 'python/api/import_knowledge.py'.
    • Updated imports to use the new memory plugin helpers and safe_filename for secure file handling.
  • plugins/memory/api/knowledge_path_get.py
    • Renamed from 'python/api/knowledge_path_get.py'.
    • Updated imports and logic to use the new memory plugin helpers and projects.get_project_meta.
  • plugins/memory/api/knowledge_reindex.py
    • Renamed from 'python/api/knowledge_reindex.py'.
    • Updated imports to use the new memory plugin helpers.
  • plugins/memory/api/memory_dashboard.py
    • Renamed from 'python/api/memory_dashboard.py'.
    • Updated imports to use the new memory plugin helpers and local plugin path for internal imports.
  • plugins/memory/default_config.yaml
    • Added default configuration settings for the 'Memory' plugin, including project memory isolation, recall parameters, and memorization settings.
  • plugins/memory/extensions/python/embedding_model_changed/_10_memory_reload.py
    • Added new Python extension to trigger a memory reload when the embedding model configuration changes.
  • plugins/memory/extensions/python/message_loop_prompts_after/_50_recall_memories.py
    • Renamed from 'python/extensions/message_loop_prompts_after/_50_recall_memories.py'.
    • Updated imports to use the new memory plugin helpers and plugins.get_plugin_config for settings.
    • Introduced a timeout for memory search tasks and changed error logging type from 'error' to 'warning'.
  • plugins/memory/extensions/python/message_loop_prompts_after/_91_recall_wait.py
    • Renamed from 'python/extensions/message_loop_prompts_after/_91_recall_wait.py'.
    • Updated imports to use the new memory plugin helpers and plugins.get_plugin_config for settings.
  • plugins/memory/extensions/python/monologue_end/_50_memorize_fragments.py
    • Added new Python extension to intelligently memorize conversation fragments, including consolidation logic and background processing.
  • plugins/memory/extensions/python/monologue_end/_51_memorize_solutions.py
    • Added new Python extension to intelligently memorize successful solutions from conversation history, including consolidation logic and background processing.
  • plugins/memory/extensions/python/monologue_start/_10_memory_init.py
    • Renamed from 'python/extensions/monologue_start/_10_memory_init.py'.
    • Updated imports to use the new memory plugin helpers.
  • plugins/memory/extensions/python/system_prompt/_20_behaviour_prompt.py
    • Renamed from 'python/extensions/system_prompt/_20_behaviour_prompt.py'.
    • Updated imports to use the new memory plugin helpers and removed datetime import.
  • plugins/memory/extensions/webui/sidebar-quick-actions-dropdown-start/memory-entry.html
    • Added new WebUI extension to include a 'Memory' entry in the sidebar quick actions dropdown.
  • plugins/memory/extensions/webui/sidebar-quick-actions-main-start/memory-entry.html
    • Added new WebUI extension to include a 'Memory' entry in the main sidebar quick actions section.
  • plugins/memory/helpers/knowledge_import.py
    • Renamed from 'python/helpers/knowledge_import.py'.
  • plugins/memory/helpers/memory.py
    • Renamed from 'python/helpers/memory.py'.
    • Refactored memory management to remove 'INSTRUMENTS' area, aligning with the new 'Skills' system.
    • Updated embedding directory path to 'tmp/memory/embeddings' for better caching management.
    • Adjusted knowledge and database directory paths to reflect the new /usr data structure and project-specific meta folders.
    • Modified get_agent_memory_subdir and get_context_memory_subdir to use plugin configuration for memory isolation.
  • plugins/memory/helpers/memory_consolidation.py
    • Renamed from 'python/helpers/memory_consolidation.py'.
    • Updated imports to use local memory plugin helpers and tools.
    • Removed temp=True from log updates during memory consolidation, making them persistent.
  • plugins/memory/plugin.yaml
    • Added plugin manifest for the 'Memory' plugin, enabling per-project and per-agent configuration.
  • plugins/memory/prompts/agent.system.memories.md
    • Renamed from 'prompts/agent.system.memories.md'.
  • plugins/memory/prompts/agent.system.solutions.md
    • Renamed from 'prompts/agent.system.solutions.md'.
  • plugins/memory/prompts/agent.system.tool.memory.md
    • Renamed from 'prompts/agent.system.tool.memory.md'.
  • plugins/memory/prompts/fw.memory.hist_suc.sys.md
    • Renamed from 'prompts/fw.memory.hist_suc.sys.md'.
  • plugins/memory/prompts/fw.memory.hist_sum.sys.md
    • Renamed from 'prompts/fw.memory.hist_sum.sys.md'.
  • plugins/memory/prompts/fw.memory_saved.md
    • Renamed from 'prompts/fw.memory_saved.md'.
  • plugins/memory/prompts/memory.consolidation.msg.md
    • Renamed from 'prompts/memory.consolidation.msg.md'.
  • plugins/memory/prompts/memory.consolidation.sys.md
    • Renamed from 'prompts/memory.consolidation.sys.md'.
  • plugins/memory/prompts/memory.keyword_extraction.msg.md
    • Renamed from 'prompts/memory.keyword_extraction.msg.md'.
  • plugins/memory/prompts/memory.keyword_extraction.sys.md
    • Renamed from 'prompts/memory.keyword_extraction.sys.md'.
  • plugins/memory/prompts/memory.memories_filter.msg.md
    • Renamed from 'prompts/memory.memories_filter.msg.md'.
  • plugins/memory/prompts/memory.memories_filter.sys.md
    • Renamed from 'prompts/memory.memories_filter.sys.md'.
  • plugins/memory/prompts/memory.memories_query.msg.md
    • Renamed from 'prompts/memory.memories_query.msg.md'.
  • plugins/memory/prompts/memory.memories_query.sys.md
    • Renamed from 'prompts/memory.memories_query.sys.md'.
  • plugins/memory/prompts/memory.memories_sum.sys.md
    • Renamed from 'prompts/memory.memories_sum.sys.md'.
  • plugins/memory/prompts/memory.recall_delay_msg.md
    • Renamed from 'prompts/memory.recall_delay_msg.md'.
  • plugins/memory/prompts/memory.solutions_query.sys.md
    • Renamed from 'prompts/memory.solutions_query.sys.md'.
  • plugins/memory/prompts/memory.solutions_sum.sys.md
    • Renamed from 'prompts/memory.solutions_sum.sys.md'.
  • plugins/memory/tools/behaviour_adjustment.py
    • Renamed from 'python/tools/behaviour_adjustment.py'.
    • Updated imports to use local memory plugin helpers.
    • Modified read_rules to use agent.read_prompt for consistent prompt loading.
  • plugins/memory/tools/memory_delete.py
    • Renamed from 'python/tools/memory_delete.py'.
    • Updated imports to use local memory plugin helpers.
  • plugins/memory/tools/memory_forget.py
    • Renamed from 'python/tools/memory_forget.py'.
    • Updated imports to use local memory plugin helpers and tools.
  • plugins/memory/tools/memory_load.py
    • Renamed from 'python/tools/memory_load.py'.
    • Updated imports to use local memory plugin helpers.
  • plugins/memory/tools/memory_save.py
    • Renamed from 'python/tools/memory_save.py'.
    • Updated imports to use local memory plugin helpers.
  • plugins/memory/webui/config.html
    • Added new WebUI configuration file for the 'Memory' plugin, allowing users to manage memory settings, including project isolation and auto-recall parameters.
  • plugins/memory/webui/main.html
    • Added new main WebUI entry point for the 'Memory Dashboard'.
  • plugins/memory/webui/memory-dashboard-store.js
    • Renamed from 'webui/components/settings/memory/memory-dashboard-store.js'.
    • Updated API endpoint path to '/plugins/memory/memory_dashboard'.
    • Adjusted modal path to '/plugins/memory/webui/memory-dashboard.html'.
    • Removed confirm dialogs for bulk and single memory deletions, relying on confirmClick helper.
  • plugins/memory/webui/memory-dashboard.html
    • Renamed from 'webui/components/settings/memory/memory-dashboard.html'.
    • Updated store import path to '/plugins/memory/webui/memory-dashboard-store.js'.
    • Modified filter header class to 'filters-header memory-filters-header' for consistent styling.
    • Changed 'Instruments' filter option to 'Skills'.
    • Integrated $confirmClick helper for bulk and single memory deletion buttons.
    • Updated table class to 'data-table memory-table' and status bar class to 'data-status-bar data-status-bar-bottom'.
    • Changed 'no-memories' class to 'data-empty-state' for generic empty state styling.
    • Refined CSS for filter headers, search input, table layout, and metadata display.
  • plugins/memory/webui/memory-detail-modal.html
    • Renamed from 'webui/components/settings/memory/memory-detail-modal.html'.
    • Integrated $confirmClick helper for the delete memory button.
    • Added 'no-scrollbar' class to the metadata sidebar for improved UI.
    • Updated CSS for modal header and added scrollbar styling for memory content display.
  • plugins/tests/test_webui_extension_surfaces.py
    • Added new test file to verify WebUI extension surface integration across various components.
  • preload.py
    • Updated completion message from 'Preload completed' to 'Preload completed.'.
  • prompts/agent.extras.agent_info.md
    • Added 'LLM: {{llm}}' to the agent information prompt.
  • prompts/agent.extras.workdir_structure.md
    • Renamed from 'prompts/agent.extras.project.file_structure.md'.
    • Updated variable from 'project_name' to 'folder' for broader applicability to working directories.
  • prompts/agent.system.main.solving.md
    • Updated agent's problem-solving steps to prefer 'skills' instead of 'instruments'.
  • prompts/agent.system.main.tips.md
    • Updated guidance for saving files to use '{{workdir_path}}' instead of '/root'.
    • Replaced 'Instruments' section with 'Skills', detailing their purpose and usage.
  • prompts/agent.system.main.tips.py
    • Added new Python plugin to dynamically provide the 'workdir_path' variable to prompts.
  • prompts/agent.system.projects.active.md
    • Added conditional display for 'Git URL' in the active project prompt.
  • prompts/agent.system.skills.loaded.md
    • Added new prompt template for displaying explicitly loaded skills.
  • prompts/agent.system.skills.md
    • Added new prompt template for listing available skills and guiding their usage.
  • prompts/agent.system.tool.call_sub.md
    • Added conditional rendering for 'agent_profiles' section using {{if agent_profiles}} and {{endif}}.
  • prompts/agent.system.tool.call_sub.py
    • Updated to use subagents.get_available_agents_dict for dynamically retrieving available agent profiles.
  • prompts/agent.system.tool.code_exe.md
    • Revised 'runtime' argument options, removing 'reset' and adding a 'reset' argument for explicit process termination.
    • Updated usage examples to reflect new runtime options and clarify long-running script handling.
  • prompts/agent.system.tool.skills.md
    • Added new prompt template for the 'skills_tool', outlining its overview, workflow, and examples for listing and loading skills.
  • prompts/agent.system.tools.py
    • Renamed class from CallSubordinate to BuidToolsPrompt.
    • Modified get_variables to pass kwargs to files.read_prompt_file, enabling dynamic prompt content.
  • prompts/fw.code.max_time.md
    • Updated prompt message to indicate that the process 'might be still running' and to check previous outputs for decision-making.
  • prompts/fw.code.no_out_time.md
    • Updated prompt message to indicate that the process 'might be still running' and to check previous outputs for decision-making.
  • prompts/fw.code.pause_time.md
    • Updated prompt message to indicate that the process 'might be still running' and to check previous outputs for decision-making.
  • prompts/fw.code.running.md
    • Updated prompt message to indicate that the terminal session 'might be still running' and to check previous outputs for decision-making.
  • prompts/fw.msg_critical_error.md
    • Added new prompt template for informing the agent about critical errors and instructing it to proceed if possible.
  • prompts/fw.msg_nudge.md
    • Added new prompt template for nudging the agent to continue its task.
  • prompts/fw.topic_summary.sys.md
    • Added instructions for the topic summary to be shorter than original messages and maximum one paragraph.
  • python/api/agents.py
    • Added new API endpoint for listing available agent profiles.
  • python/api/api_files_get.py
    • Updated internal file paths from '/a0/tmp/uploads/' to '/a0/usr/uploads/' for consistency with new user data structure.
  • python/api/api_log_get.py
    • Ensured 'progress_active' status is explicitly cast to boolean for API response consistency.
  • python/api/api_message.py
    • Updated internal file paths for attachments from '/a0/tmp/uploads' to '/a0/usr/uploads'.
    • Integrated safe_filename for secure handling of uploaded filenames.
    • Added support for 'project_name' and 'agent_profile' parameters to manage context and agent configurations.
    • Modified user message logging to have an empty heading, improving UI presentation.
  • python/api/api_reset_chat.py
    • Added persist_chat.remove_msg_files(context_id) to ensure associated message files are cleaned up upon chat reset.
  • python/api/backup_create.py
    • Changed the default value for 'include_hidden' to True in backup creation, ensuring hidden files are included by default.
  • python/api/backup_inspect.py
    • Changed the default value for 'include_hidden' to True in backup inspection, aligning with default creation behavior.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This is a substantial pull request that introduces a major refactoring to support a new plugin architecture, alongside the new Context Engine plugin. The changes are extensive, touching core components like agent.py, initialize.py, and the settings system. Key improvements include enhanced thread safety in AgentContext using RLock, making many core methods extensible with the @extensible decorator, and a significant overhaul of the subagent and plugin loading mechanisms. The migration of user data to the /usr directory and the replacement of instruments with a more formal skills system are also welcome changes for better organization and functionality.

Overall, the refactoring appears well-executed and sets a strong foundation for future extensibility. I have one specific comment regarding a piece of duplicated code that should be addressed.

Comment on lines +111 to +116
# Activate project if provided
if project_name:
try:
projects.activate_project(context_id, project_name)
except Exception as e:
return Response(f'{{"error": "Failed to activate project: {str(e)}"}}', status=400, mimetype="application/json")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This block of code for activating a project appears to be a duplicate of the logic in lines 98-109. Having duplicated logic can lead to maintenance issues and potential inconsistencies. The previous block already handles project activation, including more detailed error logging. This second block should be removed to avoid redundancy.

TerminallyLazy and others added 20 commits February 28, 2026 08:01
Merge branch 'development' of https://github.com/agent0ai/agent-zero into context-engine-a0-plugin
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…DockerHandler

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… settings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…emove path disclosure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ource

Replace non-existent ghcr.io/context-engine-ai/* images with auto-clone
from the real GitHub repository. On first deploy, the handler:

1. Clones github.com/Context-Engine-AI/Context-Engine (shallow, --depth 1)
2. Generates .env with Agent Zero-friendly defaults
3. Runs docker compose up -d --build from the cloned repo

This makes the deploy toggle fully functional — one click to go from
zero to a running Context Engine stack.

Also adds context_engine_repo_path setting (default: ~/.context-engine/repo)
and removes the broken docker-compose.context-engine.yaml.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…refresh, and cleanup

- Validate repo_path stays under home directory to prevent path traversal
- Always regenerate .env on deploy (respects user-edited files via marker)
- Replace os.getcwd() with configurable host_index_path setting
- Add asyncio.Lock to prevent concurrent clone/deploy race conditions
- Clean up partial clones on failure so retry works cleanly
- Add --remove-orphans to docker compose down
- Remove unused 'installed' field from ps response
- Add Host Index Path setting to UI and default_config.yaml

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…and container grouping

Three issues fixed:

1. Qdrant version incompatibility: upstream docker-compose.yml pulls
   qdrant:latest (v1.17.0) but Context Engine bundles qdrant-client 1.15.1
   (max minor diff is 1). Generate docker-compose.override.yml to pin
   qdrant to v1.16.1.

2. Dashboard 404: MCP streamable-http transport serves at /mcp path,
   not root. Update default endpoints from http://localhost:8003 to
   http://localhost:8003/mcp (same for 8002). Also update config.json
   so existing installs pick up the fix.

3. Container grouping: Add -p context-engine to all docker compose
   commands so containers appear grouped in Docker Desktop. Drop
   explicit -f flag in favor of cwd auto-discovery (also picks up
   the override file automatically).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… warnings

- Override upstream hardcoded subnet (172.20.0.0/16) with auto-assigned
  IPAM so it doesn't conflict with existing Docker networks
- Add _cleanup_old_project() to tear down containers from previous
  deploys that used the default project name (e.g. "repo") before
  starting the new "context-engine" project
- Add CTXCE_AUTH_SHARED_TOKEN, CTXCE_AUTH_DB_URL, QWEN3_INSTRUCTION_TEXT
  to .env template to suppress Docker Compose variable warnings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The MCP streamable-http transport returns 406 Not Acceptable unless
the client sends Accept: application/json, text/event-stream. The
server needs both because it may respond with either a direct JSON
body or an SSE stream depending on the request.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The MCP streamable-http transport responds with text/event-stream SSE
frames (event: message\ndata: {json}), not plain application/json.
The client was calling resp.json() which fails on SSE bodies.

Split response parsing into _parse_response() that checks content_type:
- text/event-stream: extract JSON from SSE data lines
- application/json: parse directly

Also extracted _unwrap_mcp_result() for readability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Context Engine MCP server exposes `qdrant_index_root` (full
workspace) and `qdrant_index` (subdirectory), not `index`. Updated:

- client.py: index() now calls qdrant_index_root (empty path) or
  qdrant_index (with subdir), matching the actual MCP tool names
- index.py: handler passes subdir/recreate params correctly
- ce-dashboard.html: Index tab now explains paths are relative to
  the mounted workspace, allows empty path for full indexing
- ce-dashboard-store.js: triggerIndex allows empty path

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The upstream Context Engine repo ships a default .env with
HOST_INDEX_PATH=./dev-workspace. Our _generate_env() only recognized
files containing our own _AUTOGEN_MARKER as safe to overwrite, so the
upstream .env was treated as "user-edited" and never regenerated with
the correct host path. This caused the indexer to mount an empty
directory, resulting in 0 indexed files and search returning no results.

Now checks a list of known default headers (our marker + upstream's
"# Environment for local Qdrant") to determine if the file is safe
to regenerate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… dir

Two fixes for search returning 0 results:

1. EMBEDDING_MODEL in .env template now uses the quantized variant
   (nomic-ai/nomic-embed-text-v1.5-Q) matching what the embedding
   service Dockerfile bakes in at build time. Without this, the
   runtime model name mismatches the cached model, causing startup
   failure after volume recreation.

2. config.json host_index_path updated from "~" (entire home dir)
   to the actual project directory for focused indexing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
asyncio.TimeoutError has an empty str() representation, causing the
dashboard to show "Unexpected error:" with no message. Now caught
explicitly with a helpful timeout message.

Indexing operations now use a 300s timeout override instead of the
default 10s connection_timeout, since workspace indexing involves
scanning/embedding many files and can take several minutes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added a rule to ignore __pycache__ directories within the usr/plugins path to keep the repository clean from Python bytecode files.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants