mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-06-01 14:21:59 +00:00
Add AGENTS.md DOX files and migrate docs
Introduce DOX (AGENTS.md) contracts across the repository to formalize ownership and local work contracts: adds .github/AGENTS.md plus AGENTS.md files for agents, api, conf, docker, docs, extensions, helpers, knowledge, lib, plugins, prompts, scripts, skills, tests, tools, usr, webui (and several subfolders). Update root AGENTS.md (content and last-updated date) to include DOX framework guidance and a child DOX index. Update .gitignore to allow usr/ and usr/plugins AGENTS.md files. Remove legacy deep-dive files under docs/agents (banners, components, modals, plugins) and migrate frontend/plugin references to webui/ and plugins/ DOX locations. Also adjust plugins/README.md and several skills/*/SKILL.md files to align with the new DOX layout.
This commit is contained in:
parent
46112c9750
commit
175baa49db
35 changed files with 999 additions and 1422 deletions
35
.github/AGENTS.md
vendored
Normal file
35
.github/AGENTS.md
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# GitHub Automation DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own repository automation that runs on GitHub, including workflows and release-planning scripts.
|
||||
- Keep CI, Docker publishing, stale issue handling, and release-note generation aligned with repository release rules.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `workflows/` contains GitHub Actions workflow definitions.
|
||||
- `scripts/` contains Python helpers called by workflows.
|
||||
- Root-level release rules remain in the root `AGENTS.md`; this file owns automation-specific details.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Docker publishing lives in `workflows/docker-publish.yml` and delegates planning to `scripts/docker_release_plan.py`.
|
||||
- Releasable tags are `vX.Y` tags at or above `v1.0`, matching the workflow environment.
|
||||
- Release-note generation reads `scripts/openrouter_release_notes_system_prompt.md` from the repository root and requires OpenRouter credentials from workflow environment variables.
|
||||
- Keep workflow secrets in GitHub Actions secrets or environment variables. Do not commit credentials, tokens, or generated release bodies containing private data.
|
||||
- Workflow scripts must fail loudly with actionable messages when required environment variables or git refs are missing.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Prefer deterministic, testable Python for workflow planning logic instead of complex inline shell in YAML.
|
||||
- Preserve manual dispatch behavior when changing Docker publishing.
|
||||
- Keep branch, tag, and release behavior synchronized between workflow YAML, release scripts, tests, and root documentation.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run `pytest tests/test_docker_release_plan.py` after changing Docker publish planning or release workflow behavior.
|
||||
- Run targeted tests for any changed script that already has coverage.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
129
AGENTS.md
129
AGENTS.md
|
|
@ -7,7 +7,7 @@ Tech Stack: Python 3.12+ | Flask | Alpine.js | LiteLLM | WebSocket (Socket.io)
|
|||
Dev Server: python run_ui.py (runs on http://localhost:50001 by default)
|
||||
Run Tests: pytest (standard) or pytest tests/test_name.py (file-scoped)
|
||||
Documentation: README.md | docs/
|
||||
Frontend Deep Dives: [Component System](docs/agents/AGENTS.components.md) | [Modal System](docs/agents/AGENTS.modals.md) | [Plugin Architecture](docs/agents/AGENTS.plugins.md) | [Banners & Discovery](docs/agents/AGENTS.banners.md)
|
||||
Frontend & Plugin DOX: [WebUI](webui/AGENTS.md) | [Components](webui/components/AGENTS.md) | [Frontend JS](webui/js/AGENTS.md) | [Plugins](plugins/AGENTS.md)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -103,9 +103,9 @@ Key Files:
|
|||
- helpers/api.py: Base class for all API endpoints.
|
||||
- scripts/openrouter_release_notes_system_prompt.md: Editable system prompt used to generate GitHub release notes during Docker publishing.
|
||||
- knowledge/main/about/: Agent self-knowledge files, indexed into the vector DB for runtime recall. Not user-facing docs - written for the agent's internal reference.
|
||||
- docs/agents/AGENTS.components.md: Deep dive into the frontend component architecture.
|
||||
- docs/agents/AGENTS.modals.md: Guide to the stacked modal system.
|
||||
- docs/agents/AGENTS.plugins.md: Comprehensive guide to the full-stack plugin system.
|
||||
- webui/components/AGENTS.md: DOX contract for Alpine component architecture.
|
||||
- webui/js/AGENTS.md: DOX contract for frontend infrastructure, modal stack, API helpers, and extension loading.
|
||||
- plugins/AGENTS.md: DOX contract for bundled and custom plugin architecture; `usr/plugins/` remains ignored user state.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -249,5 +249,124 @@ pip install -r requirements2.txt
|
|||
|
||||
---
|
||||
|
||||
*Last updated: 2026-03-25*
|
||||
*Last updated: 2026-06-01*
|
||||
*Maintained by: Agent Zero Core Team*
|
||||
|
||||
|
||||
# DOX framework
|
||||
|
||||
- DOX is highly performant AGENTS.md hierarchy installed here
|
||||
- Agent must follow DOX instructions across any edits
|
||||
|
||||
## Core Contract
|
||||
|
||||
- AGENTS.md files are binding work contracts for their subtrees
|
||||
- Work products, source materials, instructions, records, assets, and durable docs must stay understandable from the nearest applicable AGENTS.md plus every parent AGENTS.md above it
|
||||
|
||||
## Read Before Editing
|
||||
|
||||
1. Read the root AGENTS.md
|
||||
2. Identify every file or folder you expect to touch
|
||||
3. Walk from the repository root to each target path
|
||||
4. Read every AGENTS.md found along each route
|
||||
5. If a parent AGENTS.md lists a child AGENTS.md whose scope contains the path, read that child and continue from there
|
||||
6. Use the nearest AGENTS.md as the local contract and parent docs for repo-wide rules
|
||||
7. If docs conflict, the closer doc controls local work details, but no child doc may weaken DOX
|
||||
|
||||
Do not rely on memory. Re-read the applicable DOX chain in the current session before editing.
|
||||
|
||||
## Update After Editing
|
||||
|
||||
Every meaningful change requires a DOX pass before the task is done.
|
||||
|
||||
Update the closest owning AGENTS.md when a change affects:
|
||||
|
||||
- purpose, scope, ownership, or responsibilities
|
||||
- durable structure, contracts, workflows, or operating rules
|
||||
- required inputs, outputs, permissions, constraints, side effects, or artifacts
|
||||
- user preferences about behavior, communication, process, organization, or quality
|
||||
- AGENTS.md creation, deletion, move, rename, or index contents
|
||||
|
||||
Update parent docs when parent-level structure, ownership, workflow, or child index changes. Update child docs when parent changes alter local rules. Remove stale or contradictory text immediately. Small edits that do not change behavior or contracts may leave docs unchanged, but the DOX pass still must happen.
|
||||
|
||||
Do not create or update DOX docs for changes confined to ignored runtime or user-state folders under `usr/` or `tmp/` unless the user explicitly asks for those folders to be documented.
|
||||
|
||||
## Hierarchy
|
||||
|
||||
- Root AGENTS.md is the DOX rail: project-wide instructions, global preferences, durable workflow rules, and the top-level Child DOX Index
|
||||
- Child AGENTS.md files own domain-specific instructions and their own Child DOX Index
|
||||
- Each parent explains what its direct children cover and what stays owned by the parent
|
||||
- The closer a doc is to the work, the more specific and practical it must be
|
||||
|
||||
## Child Doc Shape
|
||||
|
||||
- Create a child AGENTS.md when a folder becomes a durable boundary with its own purpose, rules, responsibilities, workflow, materials, or quality standards
|
||||
- Work Guidance must reflect the current standards of the project or user instructions; if there are no specific standards or instructions yet, leave it empty
|
||||
- Verification must reflect an existing check; if no verification framework exists yet, leave it empty and update it when one exists
|
||||
|
||||
Default section order:
|
||||
- Purpose
|
||||
- Ownership
|
||||
- Local Contracts
|
||||
- Work Guidance
|
||||
- Verification
|
||||
- Child DOX Index
|
||||
|
||||
## Style
|
||||
|
||||
- Keep docs concise, current, and operational
|
||||
- Document stable contracts, not diary entries
|
||||
- Put broad rules in parent docs and concrete details in child docs
|
||||
- Prefer direct bullets with explicit names
|
||||
- Do not duplicate rules across many files unless each scope needs a local version
|
||||
- Delete stale notes instead of explaining history
|
||||
- Trim obvious statements, repeated rules, misplaced detail, and warnings for risks that no longer exist
|
||||
|
||||
## Closeout
|
||||
|
||||
1. Re-check changed paths against the DOX chain
|
||||
2. Update nearest owning docs and any affected parents or children
|
||||
3. Refresh every affected Child DOX Index
|
||||
4. Remove stale or contradictory text
|
||||
5. Run existing verification when relevant
|
||||
6. Report any docs intentionally left unchanged and why
|
||||
|
||||
## User Preferences
|
||||
|
||||
- Do not document changes in `usr/` or `tmp/`; treat both as ignored runtime/user-state folders unless explicitly requested otherwise.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
Direct child DOX files:
|
||||
|
||||
| Child | Scope |
|
||||
| --- | --- |
|
||||
| [.github/AGENTS.md](.github/AGENTS.md) | GitHub Actions workflows and release automation scripts. |
|
||||
| [agents/AGENTS.md](agents/AGENTS.md) | Bundled agent profiles, profile-local prompts, and profile-local tools. |
|
||||
| [api/AGENTS.md](api/AGENTS.md) | HTTP API handlers and WebSocket handler entry points. |
|
||||
| [conf/AGENTS.md](conf/AGENTS.md) | Repository-shipped configuration defaults and templates. |
|
||||
| [docker/AGENTS.md](docker/AGENTS.md) | Docker build contexts, image definitions, and runtime compose files. |
|
||||
| [docs/AGENTS.md](docs/AGENTS.md) | Human-facing documentation, developer guides, screenshots, and agent deep dives. |
|
||||
| [extensions/AGENTS.md](extensions/AGENTS.md) | Core lifecycle extension hook implementations for backend and WebUI surfaces. |
|
||||
| [helpers/AGENTS.md](helpers/AGENTS.md) | Shared backend framework utilities and cross-cutting runtime services. |
|
||||
| [knowledge/AGENTS.md](knowledge/AGENTS.md) | Built-in agent self-knowledge and indexed reference material. |
|
||||
| [lib/AGENTS.md](lib/AGENTS.md) | Lightweight browser-side helper scripts outside the main WebUI bundle. |
|
||||
| [plugins/AGENTS.md](plugins/AGENTS.md) | Bundled system plugins shipped with the framework. |
|
||||
| [prompts/AGENTS.md](prompts/AGENTS.md) | Core prompt templates loaded by agents and framework workflows. |
|
||||
| [scripts/AGENTS.md](scripts/AGENTS.md) | Repository maintenance scripts invoked by automation or maintainers. |
|
||||
| [skills/AGENTS.md](skills/AGENTS.md) | Bundled Agent Zero skills and their agent-facing instructions. |
|
||||
| [tests/AGENTS.md](tests/AGENTS.md) | Pytest regression and contract tests. |
|
||||
| [tools/AGENTS.md](tools/AGENTS.md) | Core agent tool implementations. |
|
||||
| [webui/AGENTS.md](webui/AGENTS.md) | Flask-served Alpine.js WebUI shell, frontend modules, components, CSS, assets, and vendor libraries. |
|
||||
|
||||
Intentionally unindexed local or generated roots:
|
||||
|
||||
| Path | Reason |
|
||||
| --- | --- |
|
||||
| `.conda/`, `.venv/` | Local Python environments. |
|
||||
| `.pytest_cache/`, `__pycache__/` | Generated test and bytecode caches. |
|
||||
| `.vscode/`, `.windsurf/` | Editor-local configuration and assistant metadata. |
|
||||
| `logs/` | Runtime output. |
|
||||
| `tmp/` | Ignored runtime caches, uploads, and generated working files; do not document changes here unless explicitly requested. |
|
||||
| `usr/` | Ignored local user data, settings, plugins, uploads, chats, and workdirs; do not document changes here unless explicitly requested. |
|
||||
| `python/` | Generated or legacy runtime cache mirror; current source lives in root-level `api/`, `helpers/`, `tools/`, and `extensions/`. |
|
||||
|
|
|
|||
34
agents/AGENTS.md
Normal file
34
agents/AGENTS.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Agent Profiles DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own bundled agent profiles, profile-specific prompts, and profile-local tools.
|
||||
- Keep profile behavior understandable without requiring edits to core framework prompts.
|
||||
|
||||
## Ownership
|
||||
|
||||
- Each direct profile directory owns its `agent.yaml`, optional `prompts/`, optional `tools/`, and optional `extensions/`.
|
||||
- `_example/` demonstrates profile layout and should stay suitable as a reference.
|
||||
- User-created local profiles belong under `usr/agents/`, not here, unless they are intended to ship with the product.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- `agent.yaml` is the profile entry point and must stay valid YAML.
|
||||
- Profile prompt overrides should be narrow and named to match the core prompt they extend or replace.
|
||||
- Profile-local tools must follow the same `Tool` contract as root `tools/`.
|
||||
- Do not put secrets, provider API keys, local paths, or user-specific settings in bundled profiles.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Prefer small profile-specific prompt files over duplicating large core prompts.
|
||||
- Keep examples generic and runnable in a clean checkout.
|
||||
- When changing profile behavior, check how the WebUI profile picker and backend profile loader discover profiles.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run `pytest` or targeted tests covering profile loading when changing `agent.yaml` structure or profile discovery.
|
||||
- Manually inspect YAML validity for changed profiles if no targeted test exists.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
36
api/AGENTS.md
Normal file
36
api/AGENTS.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# API Handlers DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own backend HTTP API handlers and WebSocket handler entry points.
|
||||
- Keep route-level behavior, authentication, CSRF, input parsing, and response shapes explicit.
|
||||
|
||||
## Ownership
|
||||
|
||||
- Files in this directory are discovered by the route registration layer in `helpers/api.py` and WebSocket registration code.
|
||||
- `ws_*.py` files define WebSocket namespaces or handlers through `helpers.ws.WsHandler`.
|
||||
- Plugin-provided API handlers belong inside plugin `api/` folders and follow the same base contracts.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- HTTP handlers must derive from `helpers.api.ApiHandler`.
|
||||
- Implement `async def process(self, input: dict, request: Request) -> dict | Response`.
|
||||
- Override `get_methods()`, `requires_auth()`, `requires_csrf()`, `requires_api_key()`, or `requires_loopback()` only when the endpoint contract requires it.
|
||||
- Keep CSRF and authentication protections intact for browser-facing state-changing endpoints.
|
||||
- WebSocket handlers must derive from `helpers.ws.WsHandler` and validate event data before using it.
|
||||
- Do not return secrets, raw environment values, private files, or unfiltered exception details to clients.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Use helpers for shared behavior instead of duplicating persistence, auth, file, project, plugin, or notification logic in endpoints.
|
||||
- Keep request and response payloads stable; update frontend callers and tests together when payloads change.
|
||||
- Prefer `Response` for files, redirects, status codes, and plain-text errors; return dictionaries for JSON success payloads.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run targeted `pytest tests/test_*api*.py`, endpoint-specific tests, or WebSocket tests after changing handler behavior.
|
||||
- For auth, CSRF, upload/download, tunnel, or file endpoints, run the nearest security regression tests.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
34
conf/AGENTS.md
Normal file
34
conf/AGENTS.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Configuration Defaults DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own repository-shipped configuration defaults and templates.
|
||||
- Keep clean-checkout defaults safe, portable, and free of user-specific state.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `model_providers.yaml` defines built-in provider metadata and LiteLLM wiring defaults.
|
||||
- `*.default.gitignore` files define templates copied or used for generated user/project/workdir directories.
|
||||
- Runtime user settings belong under ignored `usr/` local state and are not documented with local DOX files.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Do not commit API keys, provider secrets, local account identifiers, or private endpoints.
|
||||
- Keep provider IDs and settings keys stable unless all loaders, UI references, migrations, and tests are updated.
|
||||
- Defaults must work in a clean checkout and in Docker.
|
||||
- Templates must avoid accidentally unignoring private runtime content.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Prefer adding provider metadata here only when it is broadly useful to shipped Agent Zero.
|
||||
- Keep comments concise and operational.
|
||||
- Coordinate provider changes with model settings UI, plugin model overrides, and docs.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run targeted model/provider tests after changing `model_providers.yaml`.
|
||||
- Check generated ignore templates manually when changing `*.default.gitignore`.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
34
docker/AGENTS.md
Normal file
34
docker/AGENTS.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Docker DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own Docker build contexts and runtime container definitions.
|
||||
- Keep framework runtime, agent execution runtime, exposed ports, mounted paths, and image build assumptions explicit.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `base/` owns the base image context.
|
||||
- `run/` owns the runnable image context and compose file.
|
||||
- Root `DockerfileLocal` is owned by the root contract but must stay compatible with this directory.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Preserve the two-runtime model documented in the root contract: framework runtime under `/opt/venv-a0` and agent execution runtime under `/opt/venv`.
|
||||
- Do not bake secrets, local `.env` values, or user data into images.
|
||||
- Keep compose mounts aligned with `usr/`, `logs/`, and other runtime-state expectations.
|
||||
- Image changes that affect GitHub publishing must stay synchronized with `.github/workflows/docker-publish.yml`.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Keep Dockerfile steps cache-friendly and explicit about which runtime they target.
|
||||
- Avoid broad copies of ignored runtime folders.
|
||||
- Update setup docs when ports, volumes, startup commands, or runtime layout change.
|
||||
|
||||
## Verification
|
||||
|
||||
- Build the affected Docker context when Docker behavior changes.
|
||||
- Run Docker-related tests or startup smoke checks when changing runtime entrypoints.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
34
docs/AGENTS.md
Normal file
34
docs/AGENTS.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Documentation DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own human-facing documentation, screenshots, setup guides, developer guides, and documentation assets.
|
||||
- Keep docs accurate to current source behavior and practical user workflows.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `README.md`, `quickstart.md`, `guides/`, and `setup/` cover user-facing setup and workflows.
|
||||
- `developer/` covers compact developer references and source handoffs.
|
||||
- `res/` contains documentation images and other documentation assets.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Prefer local docs for practical workflows and direct users to DeepWiki for source-linked internals when appropriate.
|
||||
- Do not document secrets, private deployment details, unreleased credentials, or user-specific runtime state.
|
||||
- Screenshots and assets must be relevant to the documented UI state and should be updated when UI changes make them misleading.
|
||||
- Keep links relative inside the docs tree unless they intentionally point to external community or reference resources.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Update docs in the same change when user-visible behavior, setup steps, settings names, plugin workflows, or UI labels change.
|
||||
- Keep user guides task-oriented and avoid duplicating architecture contracts already owned by source-adjacent DOX files.
|
||||
- When editing screenshots or binary assets, avoid unrelated metadata churn.
|
||||
|
||||
## Verification
|
||||
|
||||
- Check changed internal links manually or with an available link checker.
|
||||
- For setup or Docker docs, verify commands against current scripts and Docker files.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
# Creating Discovery Cards and Banners
|
||||
|
||||
Agent Zero allows plugin developers to surface UI elements using the `banners` extension point. This allows your plugin to present information, prompts, or actionable "discovery cards" directly on the Welcome Screen without needing to inject arbitrary HTML into the frontend.
|
||||
|
||||
## The `banners` Extension Point
|
||||
|
||||
Banners are collected on the backend and sent to the frontend UI as an array of dictionaries. By appending to the `banners` array inside a Python extension, you can easily surface your plugin to the user.
|
||||
|
||||
To inject a banner, you create a Python extension script hooking into `banners`.
|
||||
|
||||
### Where to put your extension script
|
||||
|
||||
Create a python file in your plugin's extensions folder:
|
||||
`plugins/<your_plugin>/extensions/python/banners/10_my_plugin_banner.py`
|
||||
|
||||
*(Note: the `10_` prefix is for ordering; extensions run in alphabetical order).*
|
||||
|
||||
## Banner Types
|
||||
|
||||
The UI distinguishes banners primarily by the `type` property.
|
||||
|
||||
### 1. Alert Banners (`info`, `warning`, `error`)
|
||||
These are standard top-level alerts displayed on the welcome screen.
|
||||
|
||||
```python
|
||||
banners.append({
|
||||
"id": "my-plugin-warning",
|
||||
"type": "warning",
|
||||
"priority": 90,
|
||||
"title": "My Plugin Issue",
|
||||
"html": "<strong>Action required:</strong> Please configure your settings.",
|
||||
"dismissible": True,
|
||||
})
|
||||
```
|
||||
|
||||
### 2. Discovery Cards (`hero`, `feature`)
|
||||
These are rich, interactive cards displayed in the Discovery section. They are designed to prompt the user to try new plugins or features.
|
||||
|
||||
* `hero`: A wide, prominent card. Usually reserved for core system features (e.g., the Plugin Hub).
|
||||
* `feature`: A smaller card in a grid layout. This is the **recommended type** for plugin contributors to showcase their plugin.
|
||||
|
||||
### Anatomy of a Discovery Card
|
||||
|
||||
Here is an example of injecting a `feature` card for a custom plugin:
|
||||
|
||||
```python
|
||||
from helpers.extension import Extension
|
||||
from helpers import plugins
|
||||
|
||||
class MyPluginDiscoveryCard(Extension):
|
||||
"""Injects a discovery card for My Custom Plugin."""
|
||||
|
||||
async def execute(self, banners: list = [], frontend_context: dict = {}, **kwargs):
|
||||
# 1. Condition Check
|
||||
# Only show the discovery card if the user hasn't configured the plugin yet.
|
||||
config = plugins.get_plugin_config("my_custom_plugin") or {}
|
||||
|
||||
# If the API key is already set, we don't need to advertise the setup!
|
||||
if config.get("api_key"):
|
||||
return
|
||||
|
||||
# 2. Add the Card
|
||||
banners.append({
|
||||
"id": "discovery-my-custom-plugin",
|
||||
"type": "feature", # 'feature' or 'hero'
|
||||
"title": "Connect My Service", # Card title
|
||||
"description": "Unlock amazing capabilities by linking your account.",
|
||||
|
||||
# Visuals (use either thumbnail OR icon)
|
||||
"thumbnail": "/plugins/my_custom_plugin/assets/thumb.png", # Path to image
|
||||
"icon": "bolt", # Or a Material Symbol icon name
|
||||
|
||||
# Call To Action (CTA)
|
||||
"cta_text": "Setup Now",
|
||||
"cta_action": "open-plugin-config:my_custom_plugin", # Opens your plugin's config modal
|
||||
|
||||
# Behavior
|
||||
"dismissible": True, # Let the user hide it
|
||||
"priority": 40, # Higher numbers appear first
|
||||
})
|
||||
```
|
||||
|
||||
## Call To Action (CTA) Actions
|
||||
|
||||
When a user clicks the button on a discovery card, the `cta_action` string determines what happens. The frontend currently supports the following actions:
|
||||
|
||||
* `open-plugin-config:<plugin_folder_name>`: Automatically opens the settings modal for the specified plugin. (e.g., `open-plugin-config:_telegram_integration`).
|
||||
* `open-plugin-hub`: Opens the main Plugin Hub UI.
|
||||
* `open-url:<url>`: Opens a web link in a new browser tab. (e.g., `open-url:https://example.com/docs`).
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Check Configuration First**: Always check your plugin's configuration before injecting a card. If the user has already set up your plugin, they shouldn't keep seeing a discovery card asking them to set it up.
|
||||
2. **Unique IDs**: Ensure your banner `id` is highly unique (e.g., prefix it with your plugin name) to avoid collisions with other plugins.
|
||||
3. **Use `feature` type**: Community plugins should stick to the `feature` type rather than `hero` to ensure a clean grid layout for users.
|
||||
|
|
@ -1,648 +0,0 @@
|
|||
# Agent Zero Component System
|
||||
|
||||
> Generated from codebase reconnaissance on 2026-01-10
|
||||
> Scope: `webui/components/` - Self-contained Alpine.js component architecture
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Aspect | Value |
|
||||
|--------|-------|
|
||||
| Tech Stack | Alpine.js, ES Modules, CSS Variables |
|
||||
| Component Tag | `<x-component path="...">` |
|
||||
| State Management | `createStore(name, model)` from `/js/AlpineStore.js` |
|
||||
| Modals | `openModal(path)` / `closeModal()` from `/js/modals.js` |
|
||||
| API Layer | `callJsonApi()` / `fetchApi()` from `/js/api.js` |
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Architecture Overview](#1-architecture-overview)
|
||||
2. [Component Structure](#2-component-structure)
|
||||
3. [Store Pattern](#3-store-pattern)
|
||||
4. [Lifecycle Management](#4-lifecycle-management)
|
||||
5. [Integration Layer](#5-integration-layer)
|
||||
6. [Alpine.js Directives](#6-alpinejs-directives)
|
||||
7. [Patterns and Conventions](#7-patterns-and-conventions)
|
||||
8. [Pitfalls and Anti-Patterns](#8-pitfalls-and-anti-patterns)
|
||||
9. [Porting Guide](#9-porting-guide)
|
||||
|
||||
---
|
||||
|
||||
## 1. Architecture Overview
|
||||
|
||||
### Core Files (Integration Layer)
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `/js/components.js` | Component loader - hydrates `<x-component>` tags |
|
||||
| `/js/AlpineStore.js` | Store factory with Alpine proxy |
|
||||
| `/js/modals.js` | Modal stack management |
|
||||
| `/js/initFw.js` | Bootstrap: loads Alpine, registers custom directives |
|
||||
| `/js/api.js` | CSRF-protected API client (`callJsonApi`, `fetchApi`) |
|
||||
|
||||
### Component Resolution
|
||||
|
||||
```
|
||||
<x-component path="sidebar/left-sidebar.html">
|
||||
↓
|
||||
Resolves to: components/sidebar/left-sidebar.html
|
||||
↓
|
||||
Loader: importComponent() fetches, parses, injects
|
||||
```
|
||||
|
||||
- Path auto-prefixes `components/` if not present
|
||||
- Component HTML cached after first fetch
|
||||
- Module scripts cached by virtual URL
|
||||
- MutationObserver auto-loads dynamically inserted components
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
Component HTML
|
||||
↓
|
||||
imports Store module
|
||||
↓
|
||||
createStore() registers with Alpine
|
||||
↓
|
||||
Template binds via $store.name
|
||||
↓
|
||||
User actions → store methods → state updates → reactive UI
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Component Structure
|
||||
|
||||
### Anatomy of a Component
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<!-- Module imports MUST be in <head> -->
|
||||
<script type="module">
|
||||
import { store } from "/components/feature/feature-store.js";
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Store gate: prevents render until store registered -->
|
||||
<div x-data>
|
||||
<template x-if="$store.featureStore">
|
||||
<!-- Single root element inside template (mandatory) -->
|
||||
<div class="feature-container">
|
||||
<p x-text="$store.featureStore.value"></p>
|
||||
<button @click="$store.featureStore.action()">Do Thing</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Inline styles scoped to component -->
|
||||
<style>
|
||||
.feature-container {
|
||||
color: var(--color-text);
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Key Rules
|
||||
|
||||
| Rule | Rationale |
|
||||
|------|-----------|
|
||||
| Scripts in `<head>`, content in `<body>` | Loader extracts separately |
|
||||
| Use `type="module"` for scripts | Enables ES imports, caching |
|
||||
| Wrap with `x-data` + `x-if="$store.X"` | Prevents render before store ready |
|
||||
| `<template>` has ONE root element | Alpine limitation |
|
||||
| Styles inline in component | Self-contained, no global CSS files |
|
||||
|
||||
### Nesting Components
|
||||
|
||||
```html
|
||||
<div class="parent-container">
|
||||
<x-component path="child/child-component.html"></x-component>
|
||||
</div>
|
||||
```
|
||||
|
||||
Components can nest other components. Loader recursively processes `x-component` tags.
|
||||
|
||||
---
|
||||
|
||||
## 3. Store Pattern
|
||||
|
||||
### Creating a Store
|
||||
|
||||
```javascript
|
||||
// /components/feature/feature-store.js
|
||||
import { createStore } from "/js/AlpineStore.js";
|
||||
|
||||
const model = {
|
||||
// State
|
||||
items: [],
|
||||
loading: false,
|
||||
_initialized: false,
|
||||
|
||||
// Lifecycle (called once by Alpine when store registers)
|
||||
init() {
|
||||
if (this._initialized) return;
|
||||
this._initialized = true;
|
||||
this.load();
|
||||
},
|
||||
|
||||
// Actions
|
||||
async load() {
|
||||
this.loading = true;
|
||||
// ... fetch data
|
||||
this.loading = false;
|
||||
},
|
||||
|
||||
// Computed-like getters (Alpine reactivity works)
|
||||
get itemCount() {
|
||||
return this.items.length;
|
||||
}
|
||||
};
|
||||
|
||||
export const store = createStore("featureStore", model);
|
||||
```
|
||||
|
||||
### Store Proxy Behavior
|
||||
|
||||
`createStore()` returns a proxy that:
|
||||
- Before Alpine boots: reads/writes directly to `model` object
|
||||
- After Alpine boots: reads/writes through `Alpine.store(name)`
|
||||
|
||||
This enables safe module-level initialization before Alpine loads.
|
||||
|
||||
### Store Access
|
||||
|
||||
| Context | Syntax |
|
||||
|---------|--------|
|
||||
| Template (Alpine) | `$store.featureStore.prop` |
|
||||
| Module import | `import { store } from "./feature-store.js"; store.prop` |
|
||||
| Global (avoid) | `Alpine.store("featureStore").prop` |
|
||||
|
||||
Prefer module imports over global lookups.
|
||||
|
||||
### Persistence Helpers
|
||||
|
||||
```javascript
|
||||
import { saveState, loadState } from "/js/AlpineStore.js";
|
||||
|
||||
// Save to localStorage (exclude functions automatically)
|
||||
const snapshot = saveState(store, [], ["transientField"]);
|
||||
localStorage.setItem("myStore", JSON.stringify(snapshot));
|
||||
|
||||
// Restore
|
||||
const saved = JSON.parse(localStorage.getItem("myStore"));
|
||||
loadState(store, saved);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Lifecycle Management
|
||||
|
||||
### Custom Alpine Directives
|
||||
|
||||
Registered in `/js/initFw.js`:
|
||||
|
||||
| Directive | When Fires | Use Case |
|
||||
|-----------|------------|----------|
|
||||
| `x-create` | Once on mount | Initialize, subscribe to events |
|
||||
| `x-destroy` | On unmount/cleanup | Unsubscribe, clear timers |
|
||||
| `x-every-second` | Every 1s while mounted | Polling, countdowns |
|
||||
| `x-every-minute` | Every 60s while mounted | Low-frequency updates |
|
||||
| `x-every-hour` | Every 3600s while mounted | Rare periodic tasks |
|
||||
|
||||
### Usage Pattern
|
||||
|
||||
```html
|
||||
<div
|
||||
x-create="$store.myStore.onOpen()"
|
||||
x-destroy="$store.myStore.cleanup()"
|
||||
>
|
||||
<!-- content -->
|
||||
</div>
|
||||
```
|
||||
|
||||
### Store Lifecycle Pattern
|
||||
|
||||
```javascript
|
||||
const model = {
|
||||
_initialized: false,
|
||||
resizeHandler: null,
|
||||
|
||||
init() {
|
||||
// Guard: runs only once per app lifetime
|
||||
if (this._initialized) return;
|
||||
this._initialized = true;
|
||||
// Global setup: event listeners, intervals
|
||||
this.resizeHandler = () => this.handleResize();
|
||||
window.addEventListener("resize", this.resizeHandler);
|
||||
},
|
||||
|
||||
// Called via x-create when component mounts (can run multiple times)
|
||||
onOpen() {
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
// Called via x-destroy when component unmounts
|
||||
cleanup() {
|
||||
// Clear component-specific state, not global listeners
|
||||
},
|
||||
|
||||
// For full teardown (rarely needed)
|
||||
destroy() {
|
||||
if (this.resizeHandler) {
|
||||
window.removeEventListener("resize", this.resizeHandler);
|
||||
this.resizeHandler = null;
|
||||
}
|
||||
this._initialized = false;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Key distinction:
|
||||
- `init()` → once per app load (store registration)
|
||||
- `onOpen()` → each time component mounts (modal opens, etc.)
|
||||
- `cleanup()`/`destroy()` → teardown resources
|
||||
|
||||
---
|
||||
|
||||
## 5. Integration Layer
|
||||
|
||||
### API Calls
|
||||
|
||||
```javascript
|
||||
import { callJsonApi, fetchApi } from "/js/api.js";
|
||||
|
||||
// JSON POST with CSRF
|
||||
const result = await callJsonApi("/endpoint", { key: "value" });
|
||||
|
||||
// Raw fetch with CSRF
|
||||
const response = await fetchApi("/endpoint", {
|
||||
method: "GET",
|
||||
headers: { "Accept": "application/json" }
|
||||
});
|
||||
```
|
||||
|
||||
- `callJsonApi`: JSON-in, JSON-out, throws on non-2xx
|
||||
- `fetchApi`: Adds CSRF header, handles 403 retry, redirects to `/login`
|
||||
|
||||
### Modals
|
||||
|
||||
```javascript
|
||||
import { openModal, closeModal } from "/js/modals.js";
|
||||
|
||||
// Open (returns Promise that resolves when modal closes)
|
||||
await openModal("feature/feature-modal.html");
|
||||
|
||||
// Close topmost modal
|
||||
closeModal();
|
||||
|
||||
// Close specific modal by path
|
||||
closeModal("feature/feature-modal.html");
|
||||
```
|
||||
|
||||
Modal component receives title from `<title>` tag:
|
||||
```html
|
||||
<head>
|
||||
<title>My Modal Title</title>
|
||||
</head>
|
||||
```
|
||||
|
||||
Modal footer (outside scroll area):
|
||||
```html
|
||||
<div data-modal-footer>
|
||||
<button @click="closeModal()">Close</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Attribute Inheritance
|
||||
|
||||
Parent `x-component` attributes accessible via `globalThis.xAttrs(element)`:
|
||||
|
||||
```html
|
||||
<!-- Parent -->
|
||||
<x-component path="child.html" mydata='{"id": 123}'></x-component>
|
||||
|
||||
<!-- Child can access -->
|
||||
<script type="module">
|
||||
const attrs = globalThis.xAttrs(document.currentScript);
|
||||
console.log(attrs.mydata.id); // 123
|
||||
</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Alpine.js Directives
|
||||
|
||||
### Common Patterns
|
||||
|
||||
| Pattern | Syntax |
|
||||
|---------|--------|
|
||||
| Reactive text | `x-text="$store.s.value"` |
|
||||
| Conditional render | `x-if="$store.s.condition"` |
|
||||
| Visibility toggle | `x-show="$store.s.visible"` |
|
||||
| Class binding | `:class="{'active': $store.s.isActive}"` |
|
||||
| Event handler | `@click="$store.s.action()"` |
|
||||
| Two-way bind | `x-model="$store.s.inputValue"` |
|
||||
| List iteration | `<template x-for="item in $store.s.items">` |
|
||||
| Init expression | `x-init="$store.s.load()"` |
|
||||
|
||||
### Store Gating (Critical Pattern)
|
||||
|
||||
```html
|
||||
<div x-data>
|
||||
<template x-if="$store.myStore">
|
||||
<!-- Renders only when store exists -->
|
||||
</template>
|
||||
</div>
|
||||
```
|
||||
|
||||
Always gate components that depend on stores. Prevents errors during initial load race.
|
||||
|
||||
---
|
||||
|
||||
## 7. Patterns and Conventions
|
||||
|
||||
### ✅ DO
|
||||
|
||||
| Pattern | Example |
|
||||
|---------|---------|
|
||||
| Self-contained components | All HTML/CSS/JS in one component folder |
|
||||
| Module imports with absolute paths | `import { store } from "/components/..."` |
|
||||
| CSS variables for theming | `color: var(--color-text)` |
|
||||
| Guard `init()` with `_initialized` | Prevents duplicate setup |
|
||||
| Use `display: contents` for flex chains | Wrapper doesn't break parent flex |
|
||||
| Inline component styles | `<style>` in component `<body>` |
|
||||
| Import stores in `<head>` | Ensures registration before render |
|
||||
| Name stores uniquely | `createStore("featureStore", ...)` |
|
||||
|
||||
### CSS Variable Theming
|
||||
|
||||
```css
|
||||
.component {
|
||||
background: var(--color-panel);
|
||||
color: var(--color-text);
|
||||
border: 1px solid var(--color-border);
|
||||
padding: var(--spacing-md);
|
||||
transition: all var(--transition-speed) ease-in-out;
|
||||
font-size: var(--font-size-normal);
|
||||
}
|
||||
```
|
||||
|
||||
### Flex Chain Preservation
|
||||
|
||||
When `x-component` wrapper would break flex layout:
|
||||
|
||||
```css
|
||||
#parent-container > x-component,
|
||||
#parent-container > x-component > div[x-data] {
|
||||
display: contents;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Pitfalls and Anti-Patterns
|
||||
|
||||
### 🚫 DON'T
|
||||
|
||||
| Anti-Pattern | Why | Fix |
|
||||
|--------------|-----|-----|
|
||||
| Global CSS files | Breaks encapsulation | Inline styles per component |
|
||||
| `window.Alpine.store()` lookups | Timing issues, coupling | Import store module directly |
|
||||
| Call `init()` from `x-init` | Runs multiple times | Use guard, or use `x-create` for per-mount |
|
||||
| Multiple roots in `<template>` | Alpine breaks | Wrap in single `<div>` |
|
||||
| `.catch(() => null)` for errors | Hides bugs | Let errors surface, use notifications |
|
||||
| Scripts outside `<head>` | May not load before template | Move to `<head>` with `type="module"` |
|
||||
| Hardcoded colors | Breaks theming | Use CSS variables |
|
||||
| Relative imports `./file.js` | Path resolution issues | Use absolute `/components/...` |
|
||||
|
||||
### Common Mistakes
|
||||
|
||||
Race condition: store not ready
|
||||
```html
|
||||
<!-- ❌ BAD: No gate -->
|
||||
<div x-data>
|
||||
<p x-text="$store.myStore.value"></p>
|
||||
</div>
|
||||
|
||||
<!-- ✅ GOOD: Store gate -->
|
||||
<div x-data>
|
||||
<template x-if="$store.myStore">
|
||||
<p x-text="$store.myStore.value"></p>
|
||||
</template>
|
||||
</div>
|
||||
```
|
||||
|
||||
Duplicate initialization
|
||||
```javascript
|
||||
// ❌ BAD: Runs every time store accessed
|
||||
init() {
|
||||
window.addEventListener("resize", this.handler);
|
||||
}
|
||||
|
||||
// ✅ GOOD: Guard pattern
|
||||
init() {
|
||||
if (this._initialized) return;
|
||||
this._initialized = true;
|
||||
window.addEventListener("resize", this.handler);
|
||||
}
|
||||
```
|
||||
|
||||
Leaking listeners
|
||||
```javascript
|
||||
// ❌ BAD: No cleanup
|
||||
init() {
|
||||
this.interval = setInterval(() => this.tick(), 1000);
|
||||
}
|
||||
|
||||
// ✅ GOOD: With cleanup
|
||||
init() {
|
||||
this.interval = setInterval(() => this.tick(), 1000);
|
||||
},
|
||||
destroy() {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Porting Guide
|
||||
|
||||
### Minimum Requirements for External Apps
|
||||
|
||||
1. Files to copy:
|
||||
```
|
||||
/js/components.js # Component loader
|
||||
/js/AlpineStore.js # Store factory
|
||||
/js/modals.js # Modal system (optional)
|
||||
/js/initFw.js # Alpine bootstrap + directives
|
||||
```
|
||||
|
||||
2. Dependencies:
|
||||
- Alpine.js (vendor or CDN)
|
||||
- CSS variables (define your theme)
|
||||
|
||||
3. Bootstrap sequence:
|
||||
```javascript
|
||||
// initFw.js pattern:
|
||||
await import("path/to/alpine.min.js");
|
||||
|
||||
// Register custom directives
|
||||
Alpine.directive("destroy", ...);
|
||||
Alpine.directive("create", ...);
|
||||
// etc.
|
||||
```
|
||||
|
||||
4. HTML entry point:
|
||||
```html
|
||||
<script type="module" src="/js/initFw.js"></script>
|
||||
<x-component path="app/root.html"></x-component>
|
||||
```
|
||||
|
||||
### Adaptation Checklist
|
||||
|
||||
- [ ] Define CSS variables for theming (`--color-*`, `--spacing-*`, etc.)
|
||||
- [ ] Set up component directory structure
|
||||
- [ ] Configure build tool to serve `/components/` path (or adjust loader)
|
||||
- [ ] Create API wrapper matching your backend (replace `api.js`)
|
||||
- [ ] Test MutationObserver behavior with your router/SPA framework
|
||||
- [ ] Verify module caching behavior in production build
|
||||
|
||||
### Integration with Frameworks
|
||||
|
||||
| Framework | Consideration |
|
||||
|-----------|--------------|
|
||||
| Vanilla/Static | Works directly, include initFw.js |
|
||||
| Electron | Works, may need CSP adjustments for Blob URLs |
|
||||
| React/Vue | Mount Alpine in specific container, avoid conflicts |
|
||||
| SPA Routers | MutationObserver handles dynamic inserts |
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure Reference
|
||||
|
||||
```
|
||||
webui/components/
|
||||
├── _examples/ # Reference implementations
|
||||
│ ├── _example-component.html
|
||||
│ └── _example-store.js
|
||||
├── chat/
|
||||
│ ├── input/
|
||||
│ │ ├── chat-bar.html
|
||||
│ │ └── input-store.js
|
||||
│ └── ...
|
||||
├── sidebar/
|
||||
│ ├── sidebar-store.js
|
||||
│ ├── left-sidebar.html
|
||||
│ └── chats/
|
||||
│ └── chats-list.html
|
||||
├── modals/
|
||||
│ └── file-browser/
|
||||
│ ├── file-browser.html
|
||||
│ └── file-browser-store.js
|
||||
├── notifications/
|
||||
│ ├── notification-store.js
|
||||
│ └── notification-toast-stack.html
|
||||
└── settings/
|
||||
└── ...
|
||||
```
|
||||
|
||||
Naming conventions:
|
||||
- Components: `feature-name.html`
|
||||
- Stores: `feature-store.js` or `feature-name-store.js`
|
||||
- Modals: placed in `modals/` or feature folder
|
||||
|
||||
---
|
||||
|
||||
## Key Exports Summary
|
||||
|
||||
### `/js/components.js`
|
||||
```javascript
|
||||
export async function importComponent(path, targetElement)
|
||||
export async function loadComponents(roots)
|
||||
export function getParentAttributes(el)
|
||||
// Global: globalThis.xAttrs
|
||||
```
|
||||
|
||||
### `/js/AlpineStore.js`
|
||||
```javascript
|
||||
export function createStore(name, initialState)
|
||||
export function getStore(name)
|
||||
export function saveState(store, include, exclude)
|
||||
export function loadState(store, state, include, exclude)
|
||||
```
|
||||
|
||||
### `/js/modals.js`
|
||||
```javascript
|
||||
export function openModal(modalPath)
|
||||
export function closeModal(modalPath?)
|
||||
export function scrollModal(id)
|
||||
// Globals: globalThis.openModal, closeModal, scrollModal
|
||||
```
|
||||
|
||||
### `/js/api.js`
|
||||
```javascript
|
||||
export async function callJsonApi(endpoint, data)
|
||||
export async function fetchApi(url, request)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Addendum: Additional Patterns
|
||||
|
||||
### Alpine Transitions
|
||||
|
||||
Use `x-transition` for enter/leave animations:
|
||||
|
||||
```html
|
||||
<div x-show="visible"
|
||||
x-transition:enter="fade-enter"
|
||||
x-transition:leave="fade-leave">
|
||||
```
|
||||
|
||||
### Two-Click Confirmation (`$confirmClick`)
|
||||
|
||||
Magic helper for destructive actions:
|
||||
|
||||
```html
|
||||
<button @click="$confirmClick($event, () => $store.myStore.delete(item.id))">
|
||||
<span class="material-symbols-outlined">delete</span>
|
||||
</button>
|
||||
```
|
||||
|
||||
First click arms (icon changes to checkmark), second click confirms. Auto-resets after 2s.
|
||||
|
||||
### Device Detection
|
||||
|
||||
Body receives `device-touch` or `device-mouse` class via `/js/initializer.js`. Use for input-type-specific styling:
|
||||
|
||||
```css
|
||||
.device-touch .hover-only { display: none; }
|
||||
```
|
||||
|
||||
### CSS Variables Reference
|
||||
|
||||
Defined in `/webui/index.css`:
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `--color-background` | Page background |
|
||||
| `--color-text` | Primary text |
|
||||
| `--color-primary` | Headings, emphasis |
|
||||
| `--color-panel` | Card/sidebar backgrounds |
|
||||
| `--color-border` | Borders, dividers |
|
||||
| `--color-accent` | Highlights, actions |
|
||||
| `--color-input` | Form field backgrounds |
|
||||
| `--spacing-xs/sm/md/lg` | Consistent spacing scale |
|
||||
| `--font-size-small/normal/large` | Typography scale |
|
||||
| `--transition-speed` | Animation duration (0.3s) |
|
||||
|
||||
Theme switching via `.light-mode` class on root element.
|
||||
|
||||
---
|
||||
|
||||
*End of Component System Documentation*
|
||||
|
|
@ -1,325 +0,0 @@
|
|||
# Agent Zero — Frontend Modals (stacked `openModal/closeModal`)
|
||||
|
||||
This document covers the stacked modal system used by Agent Zero’s frontend, implemented in:
|
||||
|
||||
- `webui/js/modals.js`
|
||||
- `webui/css/modals.css`
|
||||
|
||||
It also defines conventions for writing modal components in `webui/components/modals/` and `webui/components/settings/`.
|
||||
|
||||
> Legacy note: there is an older overlay / teleport modal style in the codebase (e.g. `x-teleport` + `.modal-overlay`). Avoid it for new work. This doc is about the stacked modal system.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites & concepts (quick orientation)
|
||||
|
||||
### Alpine.js and `$store`
|
||||
|
||||
The UI uses Alpine.js for reactivity (`x-show`, `x-if`, `x-on`, `x-model`, …). Stores are registered via `createStore()` and read in HTML via `$store.<storeName>`.
|
||||
|
||||
- Alpine initialization + lifecycle directives: `webui/js/initFw.js`
|
||||
- Store wrapper: `webui/js/AlpineStore.js`
|
||||
|
||||
### `<x-component>` and `importComponent()`
|
||||
|
||||
Agent Zero uses a custom `<x-component path="...">` tag that is populated by the component loader.
|
||||
|
||||
The modal system does not rely on `<x-component>` directly; instead it calls the same loader function:
|
||||
|
||||
- `importComponent(path, targetElement)` from `webui/js/components.js`
|
||||
|
||||
That loader fetches component HTML, injects its `<style>` and `<script>` tags, and supports nested components.
|
||||
|
||||
---
|
||||
|
||||
## Why a “stacked modal system”?
|
||||
|
||||
Agent Zero can open modals from many places (sidebar, settings, message actions), and sometimes a modal opens another modal.
|
||||
|
||||
The stacked system provides:
|
||||
|
||||
- A single modal container structure for consistent UI
|
||||
- A stack so nested modals work predictably
|
||||
- A single backdrop that always sits behind the active modal
|
||||
- A content loader that supports component HTML + `<style>` + `<script type="module">` the same way `<x-component>` does
|
||||
|
||||
---
|
||||
|
||||
## Core API
|
||||
|
||||
File: `webui/js/modals.js`
|
||||
|
||||
### `openModal(modalPath): Promise<void>`
|
||||
|
||||
- Creates a new modal element and pushes it onto a stack.
|
||||
- Loads modal contents into the modal body by calling the component loader (`importComponent`).
|
||||
- Resolves the returned promise when the modal element is removed from the DOM.
|
||||
|
||||
Edge cases / failure behavior (current implementation):
|
||||
|
||||
- Invalid `modalPath` does not reject the returned promise. Instead, the modal remains open and shows an error message inside the modal body; the promise still resolves when the user closes the modal.
|
||||
- Calling `openModal()` multiple times with the same `modalPath` creates multiple modal instances (no deduping).
|
||||
|
||||
Modal paths are component paths, e.g.:
|
||||
|
||||
- `modals/file-browser/file-browser.html`
|
||||
- `modals/history/history.html`
|
||||
- `settings/settings.html`
|
||||
|
||||
### `closeModal(modalPath?: string): void`
|
||||
|
||||
- If no path is passed, closes the top modal.
|
||||
- If `modalPath` is passed, finds and closes that modal in the stack.
|
||||
|
||||
Edge cases / failure behavior:
|
||||
|
||||
- If the stack is empty, `closeModal()` is a no-op.
|
||||
- If `modalPath` is provided but not found, it is a no-op.
|
||||
|
||||
### `scrollModal(id: string): void`
|
||||
|
||||
Scrolls within the top modal’s `.modal-scroll` to an element by id.
|
||||
|
||||
---
|
||||
|
||||
## Modal DOM structure (what `modals.js` creates)
|
||||
|
||||
When `openModal()` runs, it creates this outer shell:
|
||||
|
||||
- `.modal` (full-screen fixed overlay container)
|
||||
- `.modal-inner`
|
||||
- `.modal-header` (title + close button)
|
||||
- `.modal-scroll`
|
||||
- `.modal-bd` (where the component HTML is imported)
|
||||
- `.modal-footer-slot` (used when the modal provides a footer)
|
||||
|
||||
The component HTML is imported into `.modal-bd`.
|
||||
|
||||
The title is taken from `<title>` inside the imported document (fallback: the modalPath).
|
||||
|
||||
### Sizing and scrolling (CSS behavior)
|
||||
|
||||
File: `webui/css/modals.css`
|
||||
|
||||
- `.modal` is full-screen fixed positioning.
|
||||
- `.modal-inner` is centered and constrained:
|
||||
- `width: 90%`
|
||||
- `max-width: 960px`
|
||||
- `max-height: 90vh`
|
||||
- Tall modals scroll inside `.modal-scroll` (`overflow-y: auto`).
|
||||
- If the modal provides a footer, `.modal-footer-slot` is pinned under the scroll area (the body scrolls; the footer doesn’t).
|
||||
|
||||
---
|
||||
|
||||
## Footer support (`data-modal-footer`)
|
||||
|
||||
Some modals want a footer that stays fixed while the body scrolls.
|
||||
|
||||
Pattern:
|
||||
|
||||
- In your modal component HTML, include a footer element marked with `data-modal-footer`.
|
||||
- `modals.js` will move that element out of the scroll area and into `.modal-footer-slot`.
|
||||
- `modals.js` adds `.modal-with-footer` to `.modal-inner` so CSS can lay out the scroll area correctly.
|
||||
|
||||
Example patterns in the repo:
|
||||
|
||||
- `webui/components/settings/settings.html` (Save / Cancel footer)
|
||||
- `webui/components/modals/file-browser/file-browser.html`
|
||||
- `webui/components/modals/scheduler/scheduler-modal.html`
|
||||
|
||||
### Practical advice
|
||||
|
||||
- The footer element must exist *after the component is loaded*, but `modals.js` uses a `requestAnimationFrame` to let Alpine mount first.
|
||||
- If you conditionally render the footer, keep it stable (don't constantly create/destroy it) or you'll fight the relocation.
|
||||
|
||||
---
|
||||
|
||||
## Shared CSS and button conventions
|
||||
|
||||
File: `webui/css/modals.css`
|
||||
|
||||
Modals should reuse shared CSS classes rather than redefining common styles. The modal system provides base classes for buttons, footers, and layout that work consistently across all modals.
|
||||
|
||||
### Button classes
|
||||
|
||||
Use these standard button classes for modal actions:
|
||||
|
||||
| Class | Use case | Visual style |
|
||||
|-------|----------|--------------|
|
||||
| `btn btn-ok` | Positive/confirmatory actions (Save, Create, Confirm) | Solid blue background, white text |
|
||||
| `btn btn-cancel` | Dismissive/negative actions (Cancel, Close, Delete) | Transparent with accent border |
|
||||
|
||||
Footer button order convention: positive action first (left), negative action second (right).
|
||||
|
||||
Example footer markup:
|
||||
|
||||
```html
|
||||
<div class="modal-footer" data-modal-footer>
|
||||
<button class="btn btn-ok" @click="$store.myStore.save()">Save</button>
|
||||
<button class="btn btn-cancel" @click="window.closeModal('...')">Cancel</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Available shared classes
|
||||
|
||||
Before writing component-specific CSS, check `webui/css/modals.css` for:
|
||||
|
||||
- `.btn`, `.btn-ok`, `.btn-cancel`, `.btn-field` — button styles
|
||||
- `.modal-footer` — footer container layout
|
||||
- `.section`, `.section-title`, `.section-description` — content sections
|
||||
- `.loading` — shimmer loading placeholder
|
||||
- `.toolbar-button`, `.toolbar-group` — editor toolbar elements
|
||||
- Range input styling for sliders
|
||||
|
||||
### When to add component-specific CSS
|
||||
|
||||
Add styles in your component's `<style>` tag only when:
|
||||
|
||||
- The style is truly unique to that component's layout/behavior
|
||||
- No existing shared class covers the use case
|
||||
- You need to override a shared class for a specific context (use sparingly)
|
||||
|
||||
Avoid redefining `.btn`, `.modal-footer`, or other shared classes in component CSS—this creates inconsistency and maintenance burden.
|
||||
|
||||
---
|
||||
|
||||
## Closing behavior (what users expect)
|
||||
|
||||
### Close by button
|
||||
|
||||
The shell provides a close button (`.modal-close`) that always closes the top modal.
|
||||
|
||||
### Close by Escape
|
||||
|
||||
`Escape` closes the top modal only (stack semantics).
|
||||
|
||||
### Close by click-outside
|
||||
|
||||
To avoid accidental close during drag/select, the shell only closes on click-outside when:
|
||||
|
||||
- both `mousedown` and `mouseup` occurred on the modal container itself (`.modal`), not on inner content.
|
||||
|
||||
---
|
||||
|
||||
## Stacking + backdrop + z-index
|
||||
|
||||
File: `webui/js/modals.js`
|
||||
|
||||
- A single `.modal-backdrop` is used for all modals.
|
||||
- Z-index logic:
|
||||
- Base z-index for modals is `3000`
|
||||
- Each modal gets `base + index*20`
|
||||
- Backdrop sits below the top modal, and between the top two when multiple modals are open.
|
||||
|
||||
Outcome:
|
||||
|
||||
- Nested modals don’t “flatten” into each other.
|
||||
- The backdrop always darkens the page behind the active modal without hiding lower modals incorrectly.
|
||||
|
||||
### Floating no-backdrop modals
|
||||
|
||||
Use `.modal-floating` on the outer `.modal` when a modal should behave like a floating utility panel instead of a blocking dialog. This is for special live surfaces where the user should keep seeing and interacting with the chat or dashboard behind the panel. The Browser now primarily lives in the Canvas, Agent Zero's right-side workspace for live surfaces, but its floating/windowed surface follows the same non-blocking modal contract.
|
||||
|
||||
Working contract:
|
||||
|
||||
- `.modal-floating` suppresses the shared `.modal-backdrop` for that modal.
|
||||
- `.modal-floating` makes the full-screen `.modal` shell pointer-transparent.
|
||||
- `.modal-floating .modal-inner` remains pointer-active, so the floating panel itself still receives clicks, keyboard focus, drag handlers, resize handles, and form input.
|
||||
- Floating modal sizing, dragging, and resizing are still component-owned unless promoted to shared modal CSS later. The modal system only provides the backdrop and pointer-event behavior.
|
||||
|
||||
Good to know:
|
||||
|
||||
- A floating modal does not close by clicking the page behind it, because those clicks pass through to the app. Keep an obvious close button in the modal header.
|
||||
- If a floating modal opens another normal modal, the normal modal can still use the backdrop; stacking remains governed by the shared z-index logic.
|
||||
- Use `.modal-no-backdrop` only when a component needs backdrop suppression without click-through floating behavior. Prefer `.modal-floating` for utility panels.
|
||||
- Do not use `.modal-floating` for destructive confirmations, settings forms, auth, import/export, or workflows that require the user to finish or dismiss the dialog before interacting with the rest of the app.
|
||||
|
||||
---
|
||||
|
||||
## Writing a modal component (conventions)
|
||||
|
||||
### File location
|
||||
|
||||
Prefer:
|
||||
|
||||
- `webui/components/modals/<name>/<name>.html` (+ optional `*-store.js`)
|
||||
|
||||
Settings uses:
|
||||
|
||||
- `webui/components/settings/settings.html` and nested settings components.
|
||||
|
||||
### Recommended HTML skeleton
|
||||
|
||||
Use this structure:
|
||||
|
||||
- `<head><title>...</title>`
|
||||
- A `<script type="module">` that imports your store (so it registers before Alpine evaluates bindings)
|
||||
- `<body>` with:
|
||||
- a single root wrapper
|
||||
- Alpine lifecycle hooks (`x-create`/`x-init` + `x-destroy`) to run open/cleanup logic
|
||||
- A `<style>` tag at the bottom of the component file containing all modal-specific styling
|
||||
|
||||
Good examples:
|
||||
|
||||
- `webui/components/modals/history/history.html`
|
||||
- `webui/components/modals/context/context.html`
|
||||
- `webui/components/modals/scheduler/scheduler-modal.html`
|
||||
|
||||
### Store conventions
|
||||
|
||||
- Define stores via `createStore()` from `webui/js/AlpineStore.js`.
|
||||
- UI reads state through `$store.<storeName>`.
|
||||
- Prefer a small public API:
|
||||
- `open()` / `openModal()` to open the modal
|
||||
- `destroy()` / `cleanup()` to reset transient state
|
||||
|
||||
---
|
||||
|
||||
## “Don’t” list (keeps the system sane)
|
||||
|
||||
- Don’t add `document.addEventListener('alpine:init', ...)` blocks inside component HTML — it conflicts with `initFw.js` ordering and can register handlers twice when components are reloaded.
|
||||
- Don’t manually manipulate `.modal-inner` or `.modal-scroll` structure — `modals.js` owns the shell and footer-slot mechanics; manual changes create layout/scroll bugs.
|
||||
- Don’t introduce a new modal overlay system; keep the stack, mixed systems break z-index/backdrop expectations and make nested modals unreliable.
|
||||
- Don’t assume a modal is the only one open; always write logic that behaves correctly when stacked — `Escape`/close behavior, z-index, and focus should all be “top modal wins”.
|
||||
- Don’t open a new modal synchronously from another modal’s close handler — it can race stack removal and produce transient z-index/backdrop glitches; schedule via `requestAnimationFrame` if needed.
|
||||
- Don’t store sensitive data in modal stores without explicit cleanup — stores often outlive a modal’s DOM and can leak values across reopen.
|
||||
- Don’t rely on modal state persisting across close/reopen cycles — design stores so `open()` rehydrates and `destroy()`/`cleanup()` resets transient state.
|
||||
|
||||
---
|
||||
|
||||
## Debugging checklist
|
||||
|
||||
### Modal opens but content never appears
|
||||
|
||||
- Verify the path passed to `openModal()` is correct and resolves under `webui/components/`.
|
||||
- Check browser console for fetch/import errors.
|
||||
- If you use `<script type="module" src="...">` in the component, ensure the URL is correct.
|
||||
|
||||
### Footer is inside the scroll area (not pinned)
|
||||
|
||||
- Ensure your footer element has the `data-modal-footer` attribute.
|
||||
- Ensure it exists after the component loads (if you gate it behind `x-if`, ensure the store is available).
|
||||
|
||||
### Closing behavior is weird with nested modals
|
||||
|
||||
- Remember `Escape` closes only the top modal.
|
||||
- `closeModal('some/path.html')` closes that modal wherever it is in the stack.
|
||||
|
||||
### Modal opens but `$store.someStore` is undefined
|
||||
|
||||
- Ensure the modal HTML imports its store in a `<script type="module">` block (so the store registers before Alpine evaluates bindings).
|
||||
- Ensure the store name matches what the markup reads (store registered as `createStore("history", ...)` is accessed as `$store.history`).
|
||||
- If you guard with `<template x-if="$store.someStore">`, verify you’re using the correct store key and not a stale name.
|
||||
|
||||
### Modal won’t close / UI feels “stuck”
|
||||
|
||||
- `closeModal()` removes the modal element immediately; if your store keeps polling or timers alive, the UI may still feel active—ensure you have `x-destroy` cleanup (`destroy()`/`cleanup()`).
|
||||
- As a last resort, inspect and remove leftover modal nodes in DevTools (`document.querySelectorAll('.modal').forEach(m => m.remove())`) and reset any store state that assumes the modal is open.
|
||||
|
||||
### Inspecting stack/z-index issues
|
||||
|
||||
- In DevTools Elements:
|
||||
- inspect `.modal` elements (multiple means you have a stack)
|
||||
- check the `style="z-index: ..."` on `.modal-inner`
|
||||
- verify `.modal-backdrop` exists and sits between modals when stacked
|
||||
- If the footer is not pinned, confirm your footer element has `data-modal-footer` and that `.modal-inner` has `.modal-with-footer`.
|
||||
|
|
@ -1,336 +0,0 @@
|
|||
# Agent Zero - Plugins Guide
|
||||
|
||||
This guide covers the Python Backend and Frontend Web UI plugin architecture. Use this as the definitive reference for building and extending Agent Zero.
|
||||
|
||||
---
|
||||
|
||||
## 1. Architecture Overview
|
||||
|
||||
Agent Zero uses a convention-over-configuration plugin model where runtime capabilities are discovered from the directory structure.
|
||||
|
||||
### Internal Components
|
||||
|
||||
1. Backend discovery (python/helpers/plugins.py): Resolves roots (usr/plugins/ first, then plugins/) and builds the effective set of plugins.
|
||||
2. Path resolution (python/helpers/subagents.py): Injects plugin paths into the agent's search space for prompts, tools, and configurations.
|
||||
3. Python extensions (python/helpers/extension.py): Executes named lifecycle hooks from `extensions/python/<point>/` and implicit `@extensible` hooks from `extensions/python/_functions/<module>/<qualname>/<start|end>/`.
|
||||
4. Web UI extensions (webui/js/extensions.js): Injects HTML/JS contributions into core UI breakpoints (x-extension).
|
||||
|
||||
---
|
||||
|
||||
## 2. File Structure
|
||||
|
||||
Each plugin lives in usr/plugins/<plugin_name>/.
|
||||
|
||||
```text
|
||||
usr/plugins/<plugin_name>/
|
||||
├── plugin.yaml # Required: Title, version, settings + activation metadata
|
||||
├── execute.py # Optional: user-triggered plugin script
|
||||
├── hooks.py # Optional: runtime hook functions callable by the framework
|
||||
├── default_config.yaml # Optional: fallback settings defaults
|
||||
├── README.md # Optional locally; strongly recommended for community plugins (Plugin Hub)
|
||||
├── LICENSE # Optional locally (shown in Plugin List UI when present); required at repo root for Plugin Index submission
|
||||
├── conf/
|
||||
│ └── model_providers.yaml # Optional: add or override model providers
|
||||
├── api/ # API handlers (ApiHandler subclasses)
|
||||
├── tools/ # Agent tools (Tool subclasses)
|
||||
├── helpers/ # Shared Python logic
|
||||
├── prompts/ # Prompt templates
|
||||
├── agents/ # Agent profiles (agents/<profile>/agent.yaml)
|
||||
├── extensions/
|
||||
│ ├── python/<point>/ # Named backend lifecycle hooks
|
||||
│ ├── python/_functions/<module>/<qualname>/<start|end>/ # Implicit @extensible hooks
|
||||
│ └── webui/<point>/ # UI HTML/JS contributions
|
||||
└── webui/
|
||||
├── config.html # Optional: Plugin settings UI
|
||||
└── ... # Full plugin pages/components
|
||||
```
|
||||
|
||||
### Python extension layouts
|
||||
|
||||
Use one of these backend extension layouts, depending on what you are extending:
|
||||
|
||||
- `extensions/python/<extension_point>/` for named lifecycle hooks such as `system_prompt`, `monologue_start`, or `tool_execute_before`
|
||||
- `extensions/python/_functions/<module>/<qualname>/<start|end>/` for implicit `@extensible` call sites
|
||||
|
||||
The `_functions` layout preserves every module segment and every nested `__qualname__` segment. Do not use the retired flattened form `extensions/python/<module>_<qualname>_<start|end>/`; those folder names no longer match the runtime lookup logic.
|
||||
|
||||
### Python import rule for user plugins
|
||||
|
||||
For plugin-local Python code in `usr/plugins/<plugin_name>/`, import through the
|
||||
fully qualified `usr.plugins.<plugin_name>...` package path.
|
||||
|
||||
Good (DO):
|
||||
|
||||
```python
|
||||
from usr.plugins.my_plugin.helpers.runtime import do_work
|
||||
import usr.plugins.my_plugin.helpers.state as state
|
||||
```
|
||||
|
||||
Avoid (DON'T):
|
||||
|
||||
```python
|
||||
# sys.path hacks
|
||||
sys.path.insert(0, ...)
|
||||
from helpers.runtime import do_work
|
||||
|
||||
# persistent symlink-based imports
|
||||
from plugins.my_plugin.helpers.runtime import do_work
|
||||
```
|
||||
|
||||
Why:
|
||||
|
||||
- `usr.plugins...` works without renaming `helpers/`
|
||||
- it avoids `sys.path` mutation for plugin-local imports
|
||||
- it avoids installation-time symlinks into `/a0/plugins/`
|
||||
- it keeps plugin removal reversible, with no import wiring left behind
|
||||
|
||||
### plugin.yaml (runtime manifest)
|
||||
|
||||
This is the manifest file that lives inside your plugin directory and drives runtime behavior. It is distinct from the index manifest (`index.yaml`) used when publishing to the Plugin Index (see Section 7).
|
||||
|
||||
```yaml
|
||||
name: my_plugin # required for community plugins (^[a-z0-9_]+$, must match dir name)
|
||||
title: My Plugin
|
||||
description: What this plugin does.
|
||||
version: 1.0.0
|
||||
settings_sections:
|
||||
- agent
|
||||
per_project_config: false
|
||||
per_agent_config: false
|
||||
# Optional: lock plugin permanently ON in UI/back-end
|
||||
always_enabled: false
|
||||
```
|
||||
|
||||
Field reference:
|
||||
- `name`: Plugin identifier. Required by CI when submitting to the Plugin Index. Must be `^[a-z0-9_]+$` and match the index folder name exactly.
|
||||
- `title`: UI display name
|
||||
- `description`: Short plugin summary
|
||||
- `version`: Plugin version string
|
||||
- `settings_sections`: Which Settings tabs show a subsection for this plugin. Valid values: `agent`, `external`, `mcp`, `developer`, `backup`. Use `[]` for no subsection.
|
||||
- `per_project_config`: Enables project-scoped settings and toggle rules
|
||||
- `per_agent_config`: Enables agent-profile-scoped settings and toggle rules
|
||||
- `always_enabled`: Forces ON and disables toggle controls in the UI (reserved for framework use)
|
||||
|
||||
### execute.py (plugin script)
|
||||
|
||||
Plugins can include an optional `execute.py` file at the plugin root for user-triggered work such as setup, post-install steps, maintenance, migrations, repair flows, or resource refreshes. It is started manually from the Plugins UI, never automatically, and should print progress while returning `0` on success.
|
||||
|
||||
Design guidance:
|
||||
- use `execute.py` for manual operations the user may need to run again later
|
||||
- prefer making it rerunnable or state-aware
|
||||
- avoid placing framework-internal automatic behavior here; that belongs in `hooks.py` or lifecycle extensions
|
||||
- do not make permanent system modifications that remain after plugin deletion unless the user explicitly asked for them and the plugin also provides a clear cleanup path
|
||||
|
||||
### hooks.py (framework runtime hooks)
|
||||
|
||||
Plugins can include an optional `hooks.py` file at the plugin root. Agent Zero loads this module on demand and calls exported functions by name through `helpers.plugins.call_plugin_hook(...)`.
|
||||
|
||||
- `hooks.py` runs inside the **Agent Zero framework runtime and Python environment**, not the separate agent execution environment.
|
||||
- Use it for framework-internal operations such as install-time setup, pre-update cleanup or preparation, plugin registration work, filesystem preparation, cache updates, or other tasks that need access to Agent Zero internals.
|
||||
- Hook functions may be synchronous or async. Async hooks are awaited by the framework.
|
||||
- Hook modules are cached until plugin caches are cleared, so changes may require a plugin refresh/reload cycle.
|
||||
- Plugin hooks should be cleanup-safe. A plugin should not leave behind permanent system modifications, symlinks, files outside its owned paths, or background services that survive plugin removal unless that behavior is explicitly part of the user-facing contract.
|
||||
|
||||
Current built-in usage:
|
||||
- the plugin installer calls `install()` from `hooks.py` after a plugin is copied into place
|
||||
- the plugin updater calls `pre_update()` from `hooks.py` immediately before pulling new plugin code into place
|
||||
|
||||
### Runtime and dependency implications
|
||||
|
||||
- If `hooks.py` installs Python packages with `sys.executable -m pip`, those packages are installed into the **same Python environment that runs Agent Zero itself**.
|
||||
- This is the correct place for Python dependencies that your plugin's backend code needs while running inside the framework runtime.
|
||||
- It is **not** the right place for dependencies meant only for the separate agent execution runtime or for arbitrary system-level tooling.
|
||||
|
||||
If your plugin needs to install packages or binaries for the agent execution environment instead of the framework runtime, launch a subprocess that explicitly activates or targets that other environment first. In practice this means invoking the correct interpreter or shell for that environment rather than relying on the current process environment. For example:
|
||||
|
||||
- target a specific Python interpreter path for that runtime
|
||||
- activate the desired virtualenv inside a subprocess shell command before running `pip`
|
||||
- invoke the appropriate package manager from a subprocess prepared for that environment
|
||||
|
||||
In Docker deployments, this distinction is especially important:
|
||||
|
||||
- Framework runtime: `/opt/venv-a0`
|
||||
- Agent execution runtime: `/opt/venv`
|
||||
|
||||
So a `hooks.py` install step affects `/opt/venv-a0` unless you intentionally switch to `/opt/venv` (or another target) inside your subprocess.
|
||||
|
||||
---
|
||||
|
||||
## 3. Frontend Extensions
|
||||
|
||||
### HTML Breakpoints
|
||||
Core UI defines insertion points like <x-extension id="sidebar-quick-actions-main-start"></x-extension>.
|
||||
To contribute:
|
||||
1. Place HTML files in extensions/webui/<extension_point>/.
|
||||
2. Include a root x-data scope.
|
||||
3. Include an x-move-* directive (e.g., x-move-to-start, x-move-after="#id").
|
||||
|
||||
### JS Hooks
|
||||
Place *.js files in extensions/webui/<extension_point>/ and export a default async function. They are called via callJsExtensions("<point>", context).
|
||||
|
||||
Core JS hooks can also expose runtime UI surfaces when static HTML breakpoints are not a fit. For example, `confirm_dialog_after_render` runs after the shared confirm dialog is built and receives the rendered dialog/body/footer nodes plus any caller-provided `extensionContext`.
|
||||
|
||||
For tool chat rows (`type === "tool"`), after built-in badge rules, core calls `get_tool_message_handler` with a mutable object containing `tool_name`, `kvps`, and `handler`. Plugins can set `handler` to entirely take over rendering for their `_tool_name`. A plugin can import `drawMessageToolSimple` and call it internally (e.g., passing `{ ...args, code: "WWW" }`) if it just wants standard tool row styling with a custom badge.
|
||||
|
||||
### User Feedback: Notifications, Not Inline Errors
|
||||
Plugin UI must use the **A0 notification system** for errors, success, and warnings. Do not render dedicated error/success boxes (e.g. a red block bound to `store.error`). Use the notification store so toasts and notification history stay consistent across the app.
|
||||
|
||||
- **Frontend (Alpine/store)**: Import `toastFrontendError`, `toastFrontendSuccess`, `toastFrontendWarning`, `toastFrontendInfo` from `/components/notifications/notification-store.js`, or call `$store.notificationStore.frontendError(message, title)` etc.
|
||||
- **Backend (Python)**: Use `AgentNotification.error(...)`, `AgentNotification.success(...)` from `helpers.notification`.
|
||||
|
||||
See [Notifications](../developer/notifications.md) for the full API.
|
||||
|
||||
---
|
||||
|
||||
## 4. Plugin Settings
|
||||
|
||||
1. Add webui/config.html to your plugin.
|
||||
2. The plugin settings wrapper instantiates a local modal context from $store.pluginSettingsPrototype.
|
||||
3. Bind plugin fields to config.* and use context.* for modal-level state and actions.
|
||||
4. Settings are scoped per-project and per-agent automatically.
|
||||
|
||||
### Resolution Priority (Highest First)
|
||||
1. project/.a0proj/agents/<profile>/plugins/<name>/config.json
|
||||
2. project/.a0proj/plugins/<name>/config.json
|
||||
3. usr/agents/<profile>/plugins/<name>/config.json
|
||||
4. usr/plugins/<name>/config.json
|
||||
5. plugins/<name>/default_config.yaml (fallback defaults)
|
||||
|
||||
## 5. Model Providers
|
||||
|
||||
Plugins can add or override model providers by placing a `conf/model_providers.yaml` inside their plugin directory. The file follows the same format as the main `conf/model_providers.yaml`.
|
||||
|
||||
At startup (and whenever a plugin is enabled/disabled), the system:
|
||||
1. Loads the base `conf/model_providers.yaml`.
|
||||
2. Discovers `conf/model_providers.yaml` from all enabled plugins.
|
||||
3. Merges them in order — matching provider IDs are overwritten, new IDs are appended.
|
||||
|
||||
Example plugin provider file (`usr/plugins/my_plugin/conf/model_providers.yaml`):
|
||||
```yaml
|
||||
chat:
|
||||
my_custom_provider:
|
||||
name: My Custom LLM
|
||||
litellm_provider: openai
|
||||
kwargs:
|
||||
api_base: https://my-llm.example.com/v1
|
||||
|
||||
embedding:
|
||||
my_custom_embed:
|
||||
name: My Embeddings
|
||||
litellm_provider: openai
|
||||
kwargs:
|
||||
api_base: https://my-embed.example.com/v1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Plugin Activation Model
|
||||
|
||||
- Global and scoped activation are independent, with no inheritance between scopes.
|
||||
- Activation flags are files: `.toggle-1` (ON) and `.toggle-0` (OFF).
|
||||
- The plugin list shows a binary `ON`/`OFF` global activation switch.
|
||||
- `always_enabled: true` in `plugin.yaml` forces ON and disables toggle controls in the UI.
|
||||
- For plugins with project/profile scoping, the plugin config modal is the canonical per-scope activation surface.
|
||||
|
||||
---
|
||||
|
||||
## 7. Routes
|
||||
|
||||
| Route | Purpose |
|
||||
|---|---|
|
||||
| GET /plugins/<name>/<path> | Serve static assets |
|
||||
| POST /api/plugins/<name>/<handler> | Call plugin API |
|
||||
| POST /api/plugins | Management (actions: get_config, save_config, list_configs, delete_config, toggle_plugin, get_doc) |
|
||||
|
||||
---
|
||||
|
||||
## 8. Plugin Index & Community Sharing
|
||||
|
||||
The **Plugin Index** is a community-maintained repository at https://github.com/agent0ai/a0-plugins that lists plugins available to the Agent Zero community. Plugins listed there can be discovered and installed by other users.
|
||||
|
||||
### Two Distinct Manifest Files
|
||||
|
||||
There are two completely different manifest files used at different stages. They must not be confused:
|
||||
|
||||
**Runtime manifest** (`plugin.yaml`, inside your plugin repo/directory — drives Agent Zero behavior):
|
||||
```yaml
|
||||
name: my_plugin # REQUIRED for index submission; must match index folder name
|
||||
title: My Plugin
|
||||
description: What this plugin does.
|
||||
version: 1.0.0
|
||||
settings_sections:
|
||||
- agent
|
||||
per_project_config: false
|
||||
per_agent_config: false
|
||||
always_enabled: false
|
||||
```
|
||||
|
||||
**Index manifest** (`index.yaml`, submitted to the `a0-plugins` repo under `plugins/<your_plugin_name>/` — drives discoverability only):
|
||||
```yaml
|
||||
title: My Plugin
|
||||
description: What this plugin does.
|
||||
github: https://github.com/yourname/your-plugin-repo
|
||||
tags:
|
||||
- tools
|
||||
- example
|
||||
screenshots: # optional, up to 5 full image URLs
|
||||
- https://raw.githubusercontent.com/yourname/your-plugin-repo/main/docs/screen.png
|
||||
```
|
||||
|
||||
The index manifest is named `index.yaml` (not `plugin.yaml`). Required fields: `title`, `description`, `github`. Optional: `tags` (up to 5), `screenshots` (up to 5 URLs). The `github` field must point to the root of a GitHub repository that contains a runtime `plugin.yaml` at the repository root, and that `plugin.yaml` must include a `name` field matching the index folder name exactly. That repository must also include a `LICENSE` file at its root so community users have explicit terms of use.
|
||||
|
||||
### Repository Structure for Community Plugins
|
||||
|
||||
When creating a plugin intended for the community, the plugin should be a standalone GitHub repository where the plugin directory contents live at the repo root:
|
||||
|
||||
```text
|
||||
your-plugin-repo/ ← GitHub repository root
|
||||
├── plugin.yaml ← runtime manifest (title, description, version, ...)
|
||||
├── default_config.yaml
|
||||
├── README.md
|
||||
├── LICENSE ← required for Plugin Index (community) plugins
|
||||
├── api/
|
||||
├── tools/
|
||||
├── extensions/
|
||||
└── webui/
|
||||
```
|
||||
|
||||
Users install it locally by cloning (or downloading) the repo contents into `/a0/usr/plugins/<plugin_name>/`.
|
||||
|
||||
### Submitting to the Plugin Index
|
||||
|
||||
1. Create a GitHub repository for your plugin with the runtime `plugin.yaml` (including the `name` field) at the repo root.
|
||||
2. Fork `https://github.com/agent0ai/a0-plugins`.
|
||||
3. Create a folder `plugins/<your_plugin_name>/` containing only an `index.yaml` (and optionally a square thumbnail image ≤ 20 KB).
|
||||
4. Open a Pull Request with exactly one new plugin folder.
|
||||
5. CI validates the submission automatically. A maintainer reviews and merges.
|
||||
|
||||
Index submission rules:
|
||||
- One plugin per PR
|
||||
- Folder name: unique, stable, `^[a-z0-9_]+$` (lowercase, numbers, underscores — no hyphens)
|
||||
- Folder name must exactly match the `name` field in your remote `plugin.yaml`
|
||||
- Folders starting with `_` are reserved for internal use
|
||||
- `github` must point to a public repo that contains `plugin.yaml` at its root with a matching `name` field
|
||||
- The same repo must contain `LICENSE` at its root (community contribution requirement)
|
||||
- `title` max 50 characters, `description` max 500 characters
|
||||
- `index.yaml` total max 2000 characters
|
||||
- `tags`: optional, up to 5, use recommended tags from https://github.com/agent0ai/a0-plugins/blob/main/TAGS.md
|
||||
- `screenshots`: optional, up to 5 full image URLs (png/jpg/webp, each ≤ 2 MB)
|
||||
|
||||
### Plugin Hub
|
||||
|
||||
The Plugin Hub is provided by the always-enabled `_plugin_installer` plugin. Users can reach it from the **Plugins** dialog in two ways:
|
||||
|
||||
- the **Browse** tab in `webui/components/plugins/list/plugin-list.html`
|
||||
- the **Install** toolbar action injected by `plugins/_plugin_installer/extensions/webui/plugins-list-header-buttons/install-buttons.html`, which opens `plugins/_plugin_installer/webui/main.html` on its own **Browse** tab
|
||||
|
||||
Both routes surface Plugin Index entries inside Agent Zero. The Plugin Hub supports search, filtering, sorting, and a detail view with README content and installation actions.
|
||||
|
||||
---
|
||||
|
||||
## 9. See Also
|
||||
|
||||
- `docs/developer/plugins.md` for the compact plugin starting point and sharing checklist
|
||||
- `plugins/README.md` for the bundled-vs-user plugin directory overview and quick links
|
||||
- `skills/a0-plugin-router/SKILL.md` for the agent-facing entry point that routes plugin tasks to the right specialist skill
|
||||
- `AGENTS.md` for the main framework guide
|
||||
39
extensions/AGENTS.md
Normal file
39
extensions/AGENTS.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Extensions DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own core lifecycle extension implementations for backend and WebUI extension points.
|
||||
- Keep built-in hook behavior ordered, discoverable, and compatible with plugin extension discovery.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `python/` contains backend lifecycle hooks executed through `helpers.extension`.
|
||||
- `webui/` contains frontend extension contributions loaded through `webui/js/extensions.js`.
|
||||
- Plugin-specific extensions belong inside each plugin's `extensions/` directory.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Extension directory names are runtime extension point names.
|
||||
- File ordering matters when names include numeric prefixes.
|
||||
- Extensions must be safe to run repeatedly when the lifecycle point can fire multiple times.
|
||||
- Secret masking, auth, security, and persistence extensions must not be bypassed by convenience changes.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Keep extension code small and focused on its hook point.
|
||||
- Move shared logic into `helpers/` when it is reused outside one extension.
|
||||
- Coordinate changes with plugin extension docs and tests when extension point semantics change.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run targeted lifecycle, prompt, stream, WebSocket, or WebUI extension tests for changed hook points.
|
||||
- Smoke-test startup when changing initialization, migration, or system-prompt extensions.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
Direct child DOX files:
|
||||
|
||||
| Child | Scope |
|
||||
| --- | --- |
|
||||
| [python/AGENTS.md](python/AGENTS.md) | Backend lifecycle extension hook files. |
|
||||
| [webui/AGENTS.md](webui/AGENTS.md) | Frontend extension contributions. |
|
||||
34
extensions/python/AGENTS.md
Normal file
34
extensions/python/AGENTS.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Python Extensions DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own built-in backend lifecycle extensions under `extensions/python/`.
|
||||
- Keep Python hook behavior compatible with `helpers.extension.call_extensions_async` and `call_extensions_sync`.
|
||||
|
||||
## Ownership
|
||||
|
||||
- Each direct subdirectory is one named extension point.
|
||||
- Python files inside an extension point are loaded in deterministic filename order.
|
||||
- Implicit `@extensible` hook implementations use `_functions/<module>/<qualname>/<start|end>/` layout when present.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Extension functions must match the arguments supplied by their hook point.
|
||||
- Preserve numeric prefixes when ordering affects prompt construction, stream masking, persistence, or cleanup.
|
||||
- Use `AgentContext` from `agent` when context access is needed.
|
||||
- Do not log unmasked secrets, raw hidden prompt sections, or private user data.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Keep extension modules import-light; many hooks run during hot paths.
|
||||
- Use mutable `ctx` or `data` dictionaries according to the hook contract when rewriting content.
|
||||
- Add or update tests when a hook changes prompt content, message history, tool output, streaming, or persistence behavior.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run targeted tests for the affected lifecycle area.
|
||||
- Run a startup smoke check for `agent_init`, `startup_migration`, or `system_prompt` changes when practical.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
34
extensions/webui/AGENTS.md
Normal file
34
extensions/webui/AGENTS.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# WebUI Extensions DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own built-in frontend extension contributions under `extensions/webui/`.
|
||||
- Keep WebUI extension points compatible with the core loader and plugin extension model.
|
||||
|
||||
## Ownership
|
||||
|
||||
- Each direct subdirectory is one frontend extension point.
|
||||
- `.html` files are injected as component references through `<x-extension>`.
|
||||
- `.js` and `.mjs` files export default functions called by `callJsExtensions`.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- HTML contributions must be valid component fragments and include Alpine state only where needed.
|
||||
- JavaScript extension modules must export a default function.
|
||||
- Extension code must not assume a plugin is installed unless it guards that dependency.
|
||||
- Keep extension point names synchronized with `x-extension` IDs and `callJsExtensions()` callers.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Prefer small extension modules that delegate to existing WebUI stores or helpers.
|
||||
- Use the notification store for user-facing success, warning, or error feedback.
|
||||
- Avoid global DOM queries when an extension hook provides scoped nodes or context.
|
||||
|
||||
## Verification
|
||||
|
||||
- Manually load the WebUI or run targeted frontend/WebUI tests after changing visible extension behavior.
|
||||
- Verify extension cache clearing paths when adding new extension points.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
34
helpers/AGENTS.md
Normal file
34
helpers/AGENTS.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Backend Helpers DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own shared Python framework utilities used by agents, APIs, tools, plugins, WebSockets, persistence, and runtime services.
|
||||
- Keep cross-cutting behavior stable and tested.
|
||||
|
||||
## Ownership
|
||||
|
||||
- Helper modules provide reusable services; feature-specific route handlers belong in `api/`, tool behavior in `tools/`, and plugin-local logic inside plugin directories.
|
||||
- Security, auth, settings, file access, plugin discovery, extension dispatch, notifications, state snapshots, scheduler, tunnel, and WebSocket primitives live here.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Preserve public helper APIs used by core code and plugins unless all callers, docs, and tests are updated.
|
||||
- Use structured parsers and serializers for YAML, JSON, paths, and URLs instead of ad hoc string handling.
|
||||
- Keep path handling constrained to intended roots for user files, uploads, downloads, projects, and workdirs.
|
||||
- Do not hardcode secrets, provider keys, local absolute paths, or environment-specific values.
|
||||
- Use `RepairableException` for errors an agent may be able to fix.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Prefer cohesive helper modules over adding unrelated utilities to large files.
|
||||
- Keep imports acyclic where possible; defer imports inside functions only when needed to avoid startup cycles.
|
||||
- For changes touching auth, CSRF, files, plugins, tunnels, WebSockets, or model calls, read the caller and tests before editing.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run targeted tests for changed helper modules.
|
||||
- Run security regression tests for auth, CSRF, filesystem, WebSocket, tunnel, upload, or image-serving changes.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
33
knowledge/AGENTS.md
Normal file
33
knowledge/AGENTS.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Knowledge DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own built-in agent self-knowledge and repository-shipped indexed reference content.
|
||||
- Keep internal reference material accurate for runtime recall without mixing in user-private data.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `main/about/` contains built-in Agent Zero self-knowledge.
|
||||
- `fragments/`, `instruments/`, and `solutions/` are reserved knowledge roots.
|
||||
- User-local knowledge belongs under `usr/knowledge/`.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Do not place secrets, chat transcripts, private user memory, or local deployment details in repository knowledge.
|
||||
- Keep self-knowledge consistent with current architecture, configuration, capabilities, and setup docs.
|
||||
- Markdown here is for agent runtime context, not general marketing copy.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Update self-knowledge when durable runtime behavior, setup, configuration, or agent capabilities change.
|
||||
- Keep entries concise and specific enough for retrieval.
|
||||
- Prefer source-grounded statements over aspirational descriptions.
|
||||
|
||||
## Verification
|
||||
|
||||
- Re-read touched source or docs before changing self-knowledge.
|
||||
- Run any available indexing or knowledge tests when changing retrieval-sensitive structure.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
32
lib/AGENTS.md
Normal file
32
lib/AGENTS.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# Library Assets DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own small browser-side helper scripts outside the main WebUI module tree.
|
||||
- Keep injected browser automation assets stable and narrowly scoped.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `browser/` contains scripts used by browser automation and DOM extraction flows.
|
||||
- Main WebUI code belongs under `webui/`.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Browser helper scripts must not depend on unavailable bundlers or Node build steps.
|
||||
- Keep scripts safe to inject into arbitrary pages by minimizing global side effects.
|
||||
- Do not collect secrets or page data beyond what the calling tool explicitly needs.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Prefer plain JavaScript with clear inputs and outputs.
|
||||
- Coordinate DOM extraction changes with browser tools, browser plugins, and tests.
|
||||
- Avoid adding large third-party libraries here.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run browser-agent or browser-tool regression tests after changing browser helper scripts.
|
||||
- Manually smoke-test browser flows when tests do not cover the changed path.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
63
plugins/AGENTS.md
Normal file
63
plugins/AGENTS.md
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Plugins DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own bundled system plugins shipped with Agent Zero.
|
||||
- Provide the tracked plugin architecture contract for both bundled plugins and custom plugins developed under ignored `usr/plugins/`.
|
||||
- Keep plugin behavior discoverable, reversible, and compatible across bundled and custom roots without creating DOX files inside `usr/`.
|
||||
|
||||
## Ownership
|
||||
|
||||
- Each direct `_plugin_name/` directory owns its `plugin.yaml`, optional `default_config.yaml`, `hooks.py`, API handlers, helpers, tools, prompts, skills, extensions, WebUI assets, and README.
|
||||
- Plugins may also own `execute.py`, `conf/model_providers.yaml`, plugin-distributed `agents/<profile>/agent.yaml`, static assets, and plugin-local docs.
|
||||
- `README.md` owns the high-level core plugin architecture summary and community Plugin Index guidance.
|
||||
- Custom or experimental user plugins belong under `usr/plugins/`, not here, but this file remains their tracked DOX contract.
|
||||
- Do not create `AGENTS.md` files under `usr/plugins/` unless the user explicitly asks for ignored user-state documentation.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Every plugin directory must include a valid `plugin.yaml`.
|
||||
- Runtime manifest fields include `name`, `title`, `description`, `version`, `settings_sections`, `per_project_config`, `per_agent_config`, and `always_enabled`.
|
||||
- Core plugins may use `plugins.<plugin_name>...` imports when they are shipped from this tree.
|
||||
- User plugins under `usr/plugins/` must use `usr.plugins.<plugin_name>...` imports and avoid `sys.path` hacks or persistent symlink-based imports.
|
||||
- Plugin extension layouts must use `extensions/python/<point>/`, `extensions/python/_functions/<module>/<qualname>/<start|end>/`, and `extensions/webui/<point>/`.
|
||||
- The `_functions` extension layout preserves every module and nested qualname segment; do not use retired flattened extension folder names.
|
||||
- Plugin settings defaults belong in `default_config.yaml`; runtime user settings belong under `usr/`.
|
||||
- Plugin settings resolution order is project/profile, project, user/profile, user plugin config, then bundled `default_config.yaml`.
|
||||
- `webui/config.html` settings UIs must bind plugin values to `config.*` and modal state/actions to `context.*` through `$store.pluginSettingsPrototype`.
|
||||
- Plugin model provider overrides belong in plugin `conf/model_providers.yaml` and merge after base `conf/model_providers.yaml`.
|
||||
- Global and scoped activation are independent and use `.toggle-1` and `.toggle-0`; `always_enabled: true` forces ON and disables UI toggles.
|
||||
- `hooks.py` runs in the framework runtime. Explicitly target another runtime if a plugin must prepare the agent execution environment.
|
||||
- `execute.py` is manual user-triggered setup, maintenance, repair, migration, or refresh work; automatic framework behavior belongs in hooks or lifecycle extensions.
|
||||
- Plugin routes are `GET /plugins/<name>/<path>`, `POST /api/plugins/<name>/<handler>`, and `POST /api/plugins` for management actions.
|
||||
- Frontend plugin HTML extensions live under `extensions/webui/<point>/`, include a root Alpine scope, and use `x-move-*` directives when targeting static breakpoints.
|
||||
- Frontend plugin JS extensions live under `extensions/webui/<point>/` and export a default function.
|
||||
- Plugin UI must use the A0 notification system for errors, warnings, success, and info instead of inline success/error boxes.
|
||||
- Banners and discovery cards are provided through Python `banners` extensions by appending dictionaries with unique `id`, `type`, `priority`, and display fields to the `banners` list.
|
||||
- Alert banner types are `info`, `warning`, and `error`; discovery card types are `hero` and `feature`.
|
||||
- Banner/card fields may include `title`, `html`, `description`, `thumbnail`, `icon`, `cta_text`, `cta_action`, and `dismissible` depending on type.
|
||||
- Community discovery cards should use `type: "feature"`; reserve `hero` cards for core system features.
|
||||
- Supported discovery CTA actions are `open-plugin-config:<plugin_folder_name>`, `open-plugin-hub`, and `open-url:<url>`.
|
||||
- Plugin deletion or disablement should not leave unmanaged services, symlinks, or files outside plugin-owned paths unless explicitly documented with cleanup.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Prefer plugin-local helpers for behavior used only by one plugin.
|
||||
- Use shared `helpers/` only for reusable framework behavior.
|
||||
- Use the notification system for plugin UI feedback.
|
||||
- Keep plugin README and docs current when user-visible plugin behavior changes.
|
||||
- Check configuration before injecting setup or discovery banners so configured plugins do not keep advertising setup.
|
||||
- Use highly unique banner IDs prefixed by plugin name.
|
||||
- When preparing community plugins, keep plugin contents at the standalone repository root with `plugin.yaml`, `README.md`, and a root `LICENSE`.
|
||||
- Plugin Index submissions use a separate `index.yaml` under `a0-plugins/plugins/<name>/`; do not confuse it with runtime `plugin.yaml`.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run plugin-specific tests after changing a bundled plugin.
|
||||
- Run framework tests for touched extension points, API handlers, tools, settings, or WebUI surfaces.
|
||||
- For plugins with external services or browser/desktop integrations, perform a targeted smoke check when practical.
|
||||
- For banner/discovery changes, verify the Welcome Screen renders alert banners, feature cards, dismiss behavior, priority ordering, and CTA behavior.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
|
|
@ -11,7 +11,7 @@ This directory contains the system-level plugins bundled with Agent Zero.
|
|||
|
||||
For detailed guides on how to create, extend, or configure plugins, refer to:
|
||||
|
||||
- [`docs/agents/AGENTS.plugins.md`](../docs/agents/AGENTS.plugins.md): Full-stack plugin architecture, manifest format, extension points, and Plugin Index submission.
|
||||
- [`plugins/AGENTS.md`](AGENTS.md): Bundled and custom plugin architecture, manifest format, extension points, banners, and Plugin Index submission rules.
|
||||
- [`docs/developer/plugins.md`](../docs/developer/plugins.md): Human-facing developer guide covering the full plugin lifecycle.
|
||||
- [`AGENTS.md`](../AGENTS.md): Main framework guide and backend context.
|
||||
- [`skills/a0-plugin-router/SKILL.md`](../skills/a0-plugin-router/SKILL.md): Agent-facing entry point that routes plugin tasks to the appropriate specialist skill.
|
||||
|
|
|
|||
35
prompts/AGENTS.md
Normal file
35
prompts/AGENTS.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Prompts DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own core prompt templates used by agents, tools, framework messages, behavior updates, summaries, skills, projects, and system context.
|
||||
- Keep prompt contracts explicit and synchronized with code that renders them.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `agent.*.md` and companion `.py` files provide system, context, tool, project, skill, and behavior prompt material.
|
||||
- `fw.*.md` files provide framework-generated message templates.
|
||||
- Profile-specific prompt overrides belong under `agents/<profile>/prompts/`.
|
||||
- Plugin prompt additions belong under the relevant plugin `prompts/` directory.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Do not include secrets, real API keys, or private user data in prompt templates.
|
||||
- Keep placeholder names, include aliases, and template assumptions synchronized with prompt-loading code and extensions.
|
||||
- Prompt changes can alter agent behavior; keep edits narrow and intentional.
|
||||
- Maintain clear separation between core behavior prompts and profile/plugin-specific customization.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Read the rendering path before changing placeholders or filenames.
|
||||
- Prefer small prompt additions over broad rewrites when fixing a specific behavior.
|
||||
- Update tests or snapshots when prompt budget, required sections, or generated system content changes.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run targeted prompt, budget, snapshot, tool, or behavior tests after prompt changes.
|
||||
- Inspect rendered prompt output when changing template wiring or placeholders.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
32
scripts/AGENTS.md
Normal file
32
scripts/AGENTS.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# Scripts DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own maintainer and automation scripts that live outside GitHub workflow directories.
|
||||
- Keep scripts deterministic, documented by nearby callers, and safe to run in clean checkouts.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `openrouter_release_notes_system_prompt.md` is consumed by `.github/scripts/docker_release_plan.py`.
|
||||
- Additional repository maintenance scripts belong here when they are not runtime application code.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Do not commit secrets, generated credentials, private release notes, or local machine paths.
|
||||
- Scripts used by CI must have stable inputs and fail with actionable errors.
|
||||
- Keep script behavior synchronized with `.github/AGENTS.md`, workflow YAML, and tests.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Prefer standard library Python or simple shell-compatible assets unless a dependency already exists for the script's runtime.
|
||||
- Keep prompts and automation inputs concise and version-controlled.
|
||||
- Update callers when renaming or moving scripts.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run targeted tests for any automation script with coverage.
|
||||
- For release-note prompt changes, inspect generated output format expectations in `.github/scripts/docker_release_plan.py`.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
34
skills/AGENTS.md
Normal file
34
skills/AGENTS.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Bundled Skills DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own bundled Agent Zero skills and their agent-facing instructions.
|
||||
- Keep skill workflows accurate, composable, and safe for runtime loading.
|
||||
|
||||
## Ownership
|
||||
|
||||
- Each direct skill directory owns its `SKILL.md` and any local supporting files.
|
||||
- Plugin-distributed skills belong under the relevant plugin directory.
|
||||
- User-local skills belong under `usr/skills/`.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Every skill directory must include a `SKILL.md`.
|
||||
- Skill instructions must be operational and scoped to the skill's purpose.
|
||||
- Do not include secrets, private user data, or environment-specific credentials.
|
||||
- Supporting files referenced by a skill must exist relative to that skill directory.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Keep skills focused on repeatable workflows that agents should actively follow.
|
||||
- Prefer updating an existing skill over creating overlapping skill variants.
|
||||
- When a skill refers to repository paths, commands, or plugin architecture, keep those references current with source and docs.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run skill runtime/import tests after changing skill loading assumptions or skill format.
|
||||
- Manually read changed `SKILL.md` files for broken relative references.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
|
|
@ -230,7 +230,7 @@ gh pr create \
|
|||
|
||||
## References
|
||||
|
||||
- Plugin architecture: `/a0/docs/agents/AGENTS.plugins.md`
|
||||
- Plugin architecture: `/a0/plugins/AGENTS.md`
|
||||
- Developer lifecycle guide: `/a0/docs/developer/plugins.md`
|
||||
- Plugin Index repo: https://github.com/agent0ai/a0-plugins
|
||||
- Recommended tags: https://github.com/agent0ai/a0-plugins/blob/main/TAGS.md
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ Related skills: `/a0/skills/a0-development/SKILL.md` (broader framework guide) |
|
|||
Primary references:
|
||||
- `/a0/agents/_example/` — the canonical reference profile (tool + extension + prompt overrides)
|
||||
- `/a0/agents/default/` — the base profile every other profile inherits from
|
||||
- `/a0/docs/agents/AGENTS.plugins.md` — plugin-distributed profiles + per-profile config
|
||||
- `/a0/plugins/AGENTS.md` — plugin-distributed profiles + per-profile config
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -21,9 +21,10 @@ Related skills: `/a0/skills/a0-review-plugin/SKILL.md` | `/a0/skills/a0-contribu
|
|||
|
||||
Primary references:
|
||||
- /a0/AGENTS.md (Full-stack architecture & AgentContext)
|
||||
- /a0/docs/agents/AGENTS.components.md (Component system deep dive)
|
||||
- /a0/docs/agents/AGENTS.modals.md (Modal system & CSS conventions)
|
||||
- /a0/docs/agents/AGENTS.plugins.md (Extension points, plugin.yaml, settings system, Plugin Index)
|
||||
- /a0/plugins/AGENTS.md (Plugin contract, plugin.yaml, settings, banners, extension contracts, Plugin Index)
|
||||
- /a0/webui/components/AGENTS.md (Component system and modal component conventions)
|
||||
- /a0/webui/js/AGENTS.md (Modal stack, API helpers, extension loader)
|
||||
- /a0/webui/css/AGENTS.md (Modal CSS and shared visual primitives)
|
||||
- /a0/docs/developer/plugins.md (Developer lifecycle and publishing)
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -183,5 +183,5 @@ Plugins are re-scanned when:
|
|||
|
||||
## References
|
||||
|
||||
- Plugin architecture: `/a0/docs/agents/AGENTS.plugins.md`
|
||||
- Plugin architecture: `/a0/plugins/AGENTS.md`
|
||||
- Manage (install/update/uninstall): read `/a0/skills/a0-manage-plugin/SKILL.md`
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ Plugins with `always_enabled: true` in `plugin.yaml` cannot be toggled (framewor
|
|||
|
||||
## References
|
||||
|
||||
- Plugin architecture: `/a0/docs/agents/AGENTS.plugins.md`
|
||||
- Plugin architecture: `/a0/plugins/AGENTS.md`
|
||||
- Developer lifecycle guide: `/a0/docs/developer/plugins.md`
|
||||
- Debug a broken plugin: read `/a0/skills/a0-debug-plugin/SKILL.md`
|
||||
- Create a new plugin: read `/a0/skills/a0-create-plugin/SKILL.md`
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ For `@extensible` targets, the only valid implicit hook layout is `extensions/py
|
|||
|
||||
### Deep-Dive References
|
||||
|
||||
- Architecture + extension points: `/a0/docs/agents/AGENTS.plugins.md`
|
||||
- Architecture + extension points: `/a0/plugins/AGENTS.md`
|
||||
- Developer guide: `/a0/docs/developer/plugins.md`
|
||||
- Component system: `/a0/docs/agents/AGENTS.components.md`
|
||||
- Modal system: `/a0/docs/agents/AGENTS.modals.md`
|
||||
- Component system: `/a0/webui/components/AGENTS.md`
|
||||
- Modal system: `/a0/webui/js/AGENTS.md` and `/a0/webui/css/AGENTS.md`
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ Fix required: version missing in plugin.yaml, inline error box in webui/settings
|
|||
## References
|
||||
|
||||
- Detailed pattern checklists: read `checklists.md` in this skill directory
|
||||
- Plugin architecture: `/a0/docs/agents/AGENTS.plugins.md`
|
||||
- Plugin architecture: `/a0/plugins/AGENTS.md`
|
||||
- Developer lifecycle guide: `/a0/docs/developer/plugins.md`
|
||||
- Component system: `/a0/docs/agents/AGENTS.components.md`
|
||||
- Component system: `/a0/webui/components/AGENTS.md`
|
||||
- If review passes and user wants to publish: read `/a0/skills/a0-contribute-plugin/SKILL.md`
|
||||
|
|
|
|||
34
tests/AGENTS.md
Normal file
34
tests/AGENTS.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Tests DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own pytest regression, security, integration, and contract tests.
|
||||
- Keep tests focused on behavior that should remain stable across framework changes.
|
||||
|
||||
## Ownership
|
||||
|
||||
- Test files live directly under `tests/` and are named for the behavior or subsystem they cover.
|
||||
- Shared fixtures should be added only when multiple tests need them.
|
||||
- Runtime artifacts created during tests should use pytest temporary directories or existing isolated test helpers.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Tests must not require real API keys, network-only services, private user data, or local `usr/` runtime state.
|
||||
- Keep tests deterministic and isolated from existing chats, uploads, downloads, memory, and settings.
|
||||
- Prefer exercising public helper/API contracts over fragile implementation details when practical.
|
||||
- Security regression tests should assert the protected behavior directly.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Add focused tests near the affected subsystem's existing tests.
|
||||
- Use descriptive test names that state the regression or contract.
|
||||
- Avoid broad sleeps or real-time dependencies; use monkeypatching or controlled clocks where possible.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run `pytest` for broad changes.
|
||||
- Run `pytest tests/test_name.py` for narrow changes and mention any broader test gaps at closeout.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
35
tools/AGENTS.md
Normal file
35
tools/AGENTS.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Agent Tools DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own core agent tool implementations available to Agent Zero agents.
|
||||
- Keep tool execution contracts, progress logging, intervention handling, and tool-result formatting stable.
|
||||
|
||||
## Ownership
|
||||
|
||||
- Tool modules in this directory are discovered by the framework and should define `Tool` subclasses.
|
||||
- Shared tool base classes and response contracts live in `helpers/tool.py`.
|
||||
- Plugin-specific tools belong in plugin `tools/` directories.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Tools must derive from `helpers.tool.Tool` and implement `async def execute(...)`.
|
||||
- Return `helpers.tool.Response(message=..., break_loop=...)`.
|
||||
- Use `await self.agent.handle_intervention(...)` when a long-running or external result should respect pause/intervention flow.
|
||||
- Sanitize or mask secrets before logging, returning, or storing tool outputs.
|
||||
- Do not perform destructive filesystem or network actions without the tool contract making that behavior explicit.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Keep tool output concise enough for message history while preserving actionable detail.
|
||||
- Put reusable parsing, provider, filesystem, or network logic in `helpers/`.
|
||||
- Update prompt tool instructions when changing tool names, arguments, or behavior.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run targeted tool tests after changing a tool or its prompt contract.
|
||||
- Run prompt/snapshot tests when tool instructions or output shape changes.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
50
webui/AGENTS.md
Normal file
50
webui/AGENTS.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# WebUI DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own the Flask-served Alpine.js WebUI shell, frontend modules, components, CSS, static assets, and vendored browser libraries.
|
||||
- Keep the UI coherent with backend APIs, WebSocket state, plugin extension points, and documented frontend patterns.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `index.html`, `index.js`, and `index.css` define the main UI shell.
|
||||
- `components/` owns self-contained Alpine components and component stores.
|
||||
- `js/` owns shared frontend modules, API clients, WebSocket clients, stores, extension loaders, and utility code.
|
||||
- `css/` owns shared stylesheet modules.
|
||||
- `public/` owns first-party static image/icon assets.
|
||||
- `vendor/` owns vendored third-party browser libraries.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Store-dependent UI must be gated with `x-data` and `x-if="$store.storeName"` before using the store.
|
||||
- Use `createStore` from `/js/AlpineStore.js` for frontend stores.
|
||||
- Use `openModal(path)` and `closeModal()` from `/js/modals.js` for modal flows.
|
||||
- Use `/js/api.js` helpers so CSRF and auth behavior stays consistent.
|
||||
- Component tags use `<x-component path="...">`; paths are resolved under `webui/components/` when not already prefixed.
|
||||
- Frontend extension breakpoints use `<x-extension id="...">` and are loaded through `/js/extensions.js`.
|
||||
- Component HTML loaded by the shared loader may include `<title>`, module scripts, body content, and scoped styles; modal content uses the same loader path.
|
||||
- Do not bypass WebSocket origin/auth/CSRF assumptions from frontend code.
|
||||
- Avoid editing vendored files unless intentionally updating the vendor asset.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Put component-specific markup and styles under `components/`; put reusable frontend infrastructure under `js/`; put shared visual primitives under `css/`.
|
||||
- Keep UI text and controls consistent with existing components.
|
||||
- Use notifications for user-facing success, warning, and error feedback where the app already uses notification flows.
|
||||
- Coordinate API payload changes with backend handlers and tests.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run targeted WebUI/frontend tests when available.
|
||||
- Manually smoke-test visible UI changes with `python run_ui.py` when behavior cannot be covered by tests.
|
||||
- Verify desktop and mobile layout for substantial UI changes.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
Direct child DOX files:
|
||||
|
||||
| Child | Scope |
|
||||
| --- | --- |
|
||||
| [components/AGENTS.md](components/AGENTS.md) | Alpine component HTML, component stores, and component-local styles. |
|
||||
| [css/AGENTS.md](css/AGENTS.md) | Shared WebUI stylesheet modules. |
|
||||
| [js/AGENTS.md](js/AGENTS.md) | Shared frontend JavaScript modules and client-side infrastructure. |
|
||||
59
webui/components/AGENTS.md
Normal file
59
webui/components/AGENTS.md
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# WebUI Components DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own self-contained Alpine.js components, component stores, and component-local styles.
|
||||
- Keep component lifecycle, store registration, and nested component loading consistent.
|
||||
|
||||
## Ownership
|
||||
|
||||
- Each subdirectory owns a UI feature area such as sidebar, settings, projects, notifications, plugins, canvas, or welcome screens.
|
||||
- `*-store.js` files own component state and actions.
|
||||
- Component HTML files own their markup, local module imports, and local scoped styles.
|
||||
- `_examples/` contains reference implementations for component and store shape.
|
||||
- Modal components normally live under `modals/<name>/<name>.html`; settings components live under `settings/`.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Module imports belong in the component `<head>`.
|
||||
- Module scripts must use `type="module"` and import stores before Alpine evaluates bindings.
|
||||
- Rendered content belongs in the component `<body>`.
|
||||
- Wrap store-dependent content with `x-data` and a `template x-if="$store.name"` gate.
|
||||
- A gated `<template>` must contain one root element.
|
||||
- Keep component-specific styles in the component `<style>` block; use shared CSS only for primitives that are genuinely reused.
|
||||
- Use CSS variables from `index.css` for color, spacing, typography, borders, and transitions.
|
||||
- Use `x-create` for per-mount setup and `x-destroy` for cleanup; do not call long-lived store `init()` from `x-init`.
|
||||
- Store `init()` must be idempotent and guarded when it registers global listeners, intervals, or one-time data.
|
||||
- Store state can be read as `$store.name` in templates and through direct module imports in JavaScript; avoid `window.Alpine.store()` lookups in component code.
|
||||
- Use `globalThis.xAttrs(element)` only for explicit parent `<x-component>` attribute inheritance.
|
||||
- Use shared API, modal, notification, confirmation, and store helpers instead of ad hoc globals.
|
||||
- Components that use polling directives may use `x-every-second`, `x-every-minute`, or `x-every-hour` only while mounted.
|
||||
- Use `$confirmClick` for destructive two-click confirmations where the existing UI pattern fits.
|
||||
- Name component files `feature-name.html` and stores `feature-store.js` or `feature-name-store.js`.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Keep component stores cohesive and avoid cross-component state mutation unless a shared store owns that state.
|
||||
- Prefer nested `<x-component path="...">` for reusable UI pieces.
|
||||
- Use absolute imports such as `/components/...` and `/js/...` so loader-generated module URLs resolve reliably.
|
||||
- Preserve flex layouts through loader wrappers with `display: contents` on the specific wrapper chain when needed.
|
||||
- Use `callJsonApi()` for JSON-in/JSON-out calls and `fetchApi()` for raw fetches that still need CSRF handling.
|
||||
- Use `openModal(path)` for modal entry points; modal titles come from component `<title>`.
|
||||
- Add modal footers with `data-modal-footer` so `modals.js` can move them to the pinned footer slot.
|
||||
- Keep modal footer elements stable after load; conditional footers should not be repeatedly created and destroyed.
|
||||
- Use `.modal-floating` only for non-blocking utility panels where page clicks must pass through; do not use it for destructive confirmations, settings, auth, import/export, or required workflows.
|
||||
- Do not add `document.addEventListener("alpine:init", ...)` blocks inside component HTML.
|
||||
- Do not use legacy `x-teleport` plus `.modal-overlay` modal patterns for new work.
|
||||
- Do not introduce a second modal overlay system or manually reshape `.modal-inner`, `.modal-scroll`, or `.modal-footer-slot`.
|
||||
- Do not hide fetch, import, or lifecycle errors with broad `.catch(() => null)` handlers; surface failures through notifications or console errors as appropriate.
|
||||
- Do not store sensitive modal values in long-lived stores without explicit cleanup on close.
|
||||
|
||||
## Verification
|
||||
|
||||
- Manually exercise the affected component in the WebUI for visible or lifecycle changes.
|
||||
- Run targeted tests for settings, plugins, notifications, projects, state sync, or other touched flows when available.
|
||||
- For modal changes, verify open, close button, Escape, click-outside, stacked modal, scroll, and pinned footer behavior.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
45
webui/css/AGENTS.md
Normal file
45
webui/css/AGENTS.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# WebUI CSS DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own shared stylesheet modules for the WebUI.
|
||||
- Keep shared visual primitives stable across components and pages.
|
||||
|
||||
## Ownership
|
||||
|
||||
- Each CSS file owns a named surface or primitive family such as buttons, messages, modals, notifications, scheduler, settings, surfaces, tables, or toast.
|
||||
- Component-specific styles should usually stay inside the component HTML unless they are intentionally shared.
|
||||
- `modals.css` owns the shared stacked modal shell, backdrop, scroll area, footer slot, modal button classes, floating/no-backdrop modal behavior, and shared modal section primitives.
|
||||
- `index.css` defines global theme variables such as `--color-*`, `--spacing-*`, `--font-size-*`, and `--transition-speed`.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Use existing CSS variables and naming patterns before introducing new global tokens.
|
||||
- Avoid broad selectors that unexpectedly restyle plugin UI or unrelated components.
|
||||
- Keep layout rules responsive and verify text does not overflow fixed controls.
|
||||
- Shared modal buttons use `btn btn-ok` for positive actions and `btn btn-cancel` for dismissive or negative actions.
|
||||
- Modal footer action order is positive action first, dismissive or negative action second.
|
||||
- Modal footers use `.modal-footer` plus `data-modal-footer`; do not redefine `.btn`, `.modal-footer`, `.modal-inner`, or `.modal-scroll` inside components.
|
||||
- Shared modal sizing keeps `.modal-inner` centered with `width: 90%`, `max-width: 960px`, and `max-height: 90vh`.
|
||||
- Tall modal bodies must scroll inside `.modal-scroll`; pinned footer content must stay outside that scroll area.
|
||||
- `.modal-floating` must keep the full-screen shell pointer-transparent while `.modal-inner` remains pointer-active.
|
||||
- Use `.modal-no-backdrop` only for backdrop suppression without click-through floating behavior.
|
||||
- Do not add decorative one-note palette changes that conflict with existing WebUI design.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Keep shared CSS small and scoped to clear class families.
|
||||
- Coordinate class renames with all component and plugin references.
|
||||
- Prefer improving an existing primitive over creating a near-duplicate style family.
|
||||
- Use component-local styles for unique layouts and shared CSS for repeated primitives such as modal sections, toolbars, buttons, tables, notifications, and surfaces.
|
||||
- Preserve modal sizing and scrolling expectations: centered `.modal-inner`, constrained viewport height, body scroll inside `.modal-scroll`, and footer outside the scroll area.
|
||||
|
||||
## Verification
|
||||
|
||||
- Manually inspect affected WebUI screens at desktop and mobile widths for shared CSS changes.
|
||||
- Run visual or frontend tests if the touched style has coverage.
|
||||
- For modal CSS, test a tall modal, a footer modal, a stacked modal, and a floating modal.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
61
webui/js/AGENTS.md
Normal file
61
webui/js/AGENTS.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# WebUI JavaScript DOX
|
||||
|
||||
## Purpose
|
||||
|
||||
- Own shared frontend JavaScript modules, client-side infrastructure, API helpers, WebSocket clients, stores, extension loaders, and UI utilities.
|
||||
- Keep frontend contracts stable for core UI and plugin extensions.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `AlpineStore.js` owns store creation and persistence helpers.
|
||||
- `api.js` owns CSRF-aware HTTP helpers.
|
||||
- `websocket.js` owns browser WebSocket client behavior.
|
||||
- `extensions.js` owns frontend extension loading.
|
||||
- `components.js` owns `<x-component>` loading, component caching, module injection, nested component processing, and `globalThis.xAttrs`.
|
||||
- `modals.js` owns the stacked modal shell, `openModal`, `closeModal`, `scrollModal`, footer relocation, backdrop, and modal z-index behavior.
|
||||
- `initFw.js` owns Alpine bootstrap and custom lifecycle directives such as `x-create`, `x-destroy`, and periodic `x-every-*` hooks.
|
||||
- Other modules own focused UI utilities such as modals, messages, safe markdown, shortcuts, TTS/STT, surfaces, and initialization.
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- Use ES modules and browser-compatible JavaScript.
|
||||
- Route JSON and fetch calls through `api.js` unless a caller has a specific nonstandard transport contract.
|
||||
- `callJsonApi()` is for JSON request/response flows and must preserve CSRF/auth behavior.
|
||||
- `fetchApi()` must continue adding CSRF headers, retrying 403 CSRF refresh paths, and redirecting to `/login` when required.
|
||||
- `createStore(name, model)` must continue working before and after Alpine boots by proxying to the raw model first and Alpine store later.
|
||||
- `saveState()` and `loadState()` must not persist functions and should support include/exclude filtering for transient fields.
|
||||
- `openModal(path)` returns a promise that resolves when that modal DOM node is removed; invalid paths show an in-modal error instead of rejecting.
|
||||
- Opening the same modal path multiple times must continue creating multiple stack entries; no dedupe is assumed.
|
||||
- `closeModal()` with no path closes the top modal; `closeModal(path)` closes that path wherever it is in the stack; missing paths are no-ops.
|
||||
- Modal stack semantics are top-modal-first for Escape, close buttons, z-index, and backdrop placement.
|
||||
- The modal shell structure is `.modal` > `.modal-inner` > `.modal-header`, `.modal-scroll` containing `.modal-bd`, and `.modal-footer-slot`.
|
||||
- `data-modal-footer` content is relocated from modal body into `.modal-footer-slot`.
|
||||
- Click-outside close requires both `mousedown` and `mouseup` on the outer `.modal` container.
|
||||
- `scrollModal(id)` scrolls inside the top modal's `.modal-scroll`.
|
||||
- Keep extension loader cache keys and extension point names stable for plugins.
|
||||
- HTML extension loading turns discovered HTML files into `<x-component>` tags; JavaScript extensions must export a default function.
|
||||
- Frontend extension hooks such as `confirm_dialog_after_render` and `get_tool_message_handler` must preserve their mutable context contracts.
|
||||
- Sanitize or safely render user/model-provided HTML and markdown.
|
||||
- Do not expose secrets in localStorage, console logs, URLs, or WebSocket payloads.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
- Prefer small named exports over adding globals.
|
||||
- Keep frontend API payload assumptions synchronized with backend handlers.
|
||||
- Use existing modal, notification, cache, device, and surface utilities before adding new infrastructure.
|
||||
- Check plugin extension callers before changing shared extension behavior.
|
||||
- Preserve the single shared modal shell and backdrop model; do not add a parallel overlay implementation.
|
||||
- Preserve modal z-index spacing with a stable base stack and a shared backdrop below the active modal.
|
||||
- If opening a new modal from a close handler, schedule it with `requestAnimationFrame` to avoid stack removal races.
|
||||
- Keep modal state cleanup explicit because stores can outlive their DOM.
|
||||
- Device-specific styling may rely on the `device-touch` or `device-mouse` body class set during initialization.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run targeted frontend/WebUI tests when available.
|
||||
- Manually smoke-test startup, API calls, WebSocket state sync, and affected UI flows after infrastructure changes.
|
||||
- For modal infrastructure, verify duplicate paths can stack, missing paths stay closable, Escape closes only the top modal, and click-outside requires both mouse down and mouse up on the overlay container.
|
||||
|
||||
## Child DOX Index
|
||||
|
||||
No child DOX files.
|
||||
Loading…
Add table
Add a link
Reference in a new issue