Files
Everjoy/AGENTS.md
2026-06-04 20:12:43 +08:00

10 KiB

Everjoy — Agent Onboarding Guide

This file is written for AI coding agents. It assumes you know Rust but nothing about this project. For background, also read doc/Purpose.MD, doc/Architecture.md, doc/Architecture-Runtime-and-Plugin.md, doc/Plugin-Lifecycle-Tool-vs-Provider.md, and TECH_STACK.md.

Project Overview

Everjoy is an AI-native TUI IDE / workflow tool written in Rust. It is currently at version 0.1.0 and is best described as an early MVP:

  • A terminal user interface built with ratatui + crossterm.
  • Three-panel layout: Sidebar (file tree), Main (editor / terminal), Agent (chat).
  • A runtime architecture based on providers, tools, and an explicit Command pattern.
  • An agent framework skeleton (roles, orchestrator, memory, tool invoker) that is not yet fully wired to an LLM.
  • A plugin subsystem designed for external .wasm / .so extensions, but the loader and translator are currently stubs.

The project is organized as a single Cargo crate. There is no pyproject.toml, package.json, or other build system — Rust/Cargo is the only toolchain you need.

Key Configuration Files

  • Cargo.toml — Single crate named everjoy, edition 2021. Lists all production dependencies (TUI, async, serialization, SQLite, text/files, config, utils). [dev-dependencies] is empty.
  • Cargo.lock — Committed; pin your dependency versions.
  • .gitignore — Standard Rust ignore (/target).

No custom rustfmt.toml or clippy.toml was found; use the default toolchain settings.

Build and Run

# Compile
cargo build

# Run the TUI application
cargo run

# Fast check
cargo check

# Release build
cargo build --release

The binary runs in the terminal using the alternate screen. Current controls:

  • Ctrl+Q — quit.
  • Ctrl+J / Ctrl+K / Ctrl+L — focus Sidebar / Main / Agent panel.
  • Alt+<underlined letter> — open menubar.
  • Press any key from the splash screen to enter the main UI.

Test Commands

cargo test

There are 23 unit tests, all passing. They live in inline #[cfg(test)] modules inside the built-in providers:

  • src/builtin/editor/tests.rs
  • src/builtin/filetree/tests.rs
  • src/builtin/agentchat/tests.rs
  • src/builtin/terminal/tests.rs

There are no integration tests or benchmarks yet. Keep it that way unless a feature genuinely needs them.

Code Organization

src/
  main.rs              # App struct, event loop, command dispatch, terminal setup
  lib.rs               # Re-exports: agent, builtin, plugin, runtime, ui

  runtime/             # Core engine interfaces and registry
    mod.rs
    traits.rs          # Plugin, PanelProvider, Tool, Command, Source, Registrar, etc.
    registry.rs        # ModuleRegistry: lazy provider factories, tool/menu/status storage, bidding
    lifecycle.rs       # LifecycleManager (mostly TODO)
    ctx.rs             # RuntimeServices trait (ProviderCtx was removed)

  ui/                  # TUI framework helpers
    mod.rs
    layout.rs          # Three-panel ratios (sidebar 20%, main 52%, agent 28%)
    focus.rs           # FocusManager across panels
    menubar.rs         # Top menubar with Alt+ shortcuts
    statusbar.rs       # Bottom status bar
    splash.rs          # Startup splash screen
    scheduler.rs       # RenderScheduler (stub)
    router.rs          # EventRouter (stub)

  agent/               # Agent framework skeleton
    mod.rs
    roles.rs           # Built-in roles: secretary, driver, negfeedback, executor
    orchestrator.rs    # Multi-agent coordinator (stub)
    memory.rs          # MemorySystem (stub)
    tools.rs           # ToolInvoker (stub)

  plugin/              # External plugin adapter (designed but not implemented)
    mod.rs
    loader.rs          # ExtensionLoader (stub)
    translator.rs      # C-ABI ↔ Rust trait wrapper (stub)
    surface.rs         # EjSurface / EjCell for plugin rendering
    panic.rs           # Panic isolation helper

  builtin/             # Built-in panel providers
    mod.rs
    editor/mod.rs      # EditorProvider (Main panel, text files)
    filetree/mod.rs    # FileTreeProvider (Sidebar, project navigator)
    agentchat/mod.rs   # AgentChatProvider (Agent panel, chat UI)
    terminal/mod.rs    # TerminalProvider (Main panel, mock shell)
    tasktree/mod.rs    # TaskTreeProvider (Main panel, task view stub)

Runtime Architecture

The project centers on the Runtime Subsystem (src/runtime/). Understand these concepts before changing anything:

  1. PanelProvider — Anything that renders into one of the three panels (Sidebar, Main, Agent). Each provider has:

    • id() — unique string id.
    • render(area, buf) — called every frame.
    • handle_event(event) -> (EventResult, Vec<Command>) — input handling plus explicit commands back to the app.
    • focus_changed, hide, show, shutdown — lifecycle hooks.
    • can_open(source, mime_hint) -> i32 — bidding score; higher wins when the app needs to present content.
    • as_any / as_any_mut — implemented so the app can downcast to concrete types (e.g. to read editor cursor state for the status bar).
  2. Command pattern — Providers do not call system APIs directly. They return Vec<Command> from handle_event. The App in main.rs is the sole dispatcher. Commands are:

    • Present { panel, source, mime_hint } — let providers bid for the source.
    • Launch { panel, tool_id, params } — direct dispatch by provider id.
    • FocusPanel(panel) — change focus.
    • ShowMessage { msg, level } — show a transient status message.
  3. ModuleRegistry — Holds provider factories, tool handlers, menu items, and status widgets. Provider instances are created lazily via ensure_instance(id). It also implements Registrar, which is the interface exposed during plugin bootstrap.

  4. Tool vs Provider lifecycle — Tools are registered once at plugin bootstrap and live until unload. Providers are created/destroyed per panel instance. This separation is intentional; see doc/Plugin-Lifecycle-Tool-vs-Provider.md.

  5. Built-in vs External — Built-in modules implement Runtime traits directly. External modules are planned to be loaded by plugin::loader and wrapped by plugin::translator into Box<dyn PanelProvider> / Box<dyn Tool>.

Current Built-in Providers

Id Panel Purpose
filetree Sidebar Project file navigator; emits Command::Present on Enter to open files in Main.
editor Main Simple text editor with line numbers, basic Rust highlighting, and cursor movement.
terminal Main Mock integrated terminal with command history (help, clear, pwd, ls, agents, version).
agentchat Agent Chat UI with backend selector (Claude / GPT-4 / Local), message scrolling, and input.
tasktree Main Visual stub of agent task lists.

Default active providers are hard-coded in main.rs: Sidebar = filetree, Main = editor, Agent = agentchat.

Agent Framework

The agent code is intentionally lightweight and not yet connected to an LLM:

  • agent::roles::builtin_roles() defines four roles (secretary, driver, negfeedback, executor) with icons, colors, system prompts, and allowed tools.
  • agent::tools::ToolInvoker is a stub that returns ToolOutput::err("not implemented").
  • agent::orchestrator::Orchestrator, agent::memory::MemorySystem are also stubs.
  • The Tool trait lives in runtime::traits and is the interface agents will call via LLM function calling.

When you add LLM integration, the expected flow is:

  1. Agent decides to call a tool.
  2. ToolInvoker looks up the tool by name in ModuleRegistry::tools.
  3. Tool::execute() runs and returns ToolOutput.
  4. Result goes back into the agent conversation loop.

Code Style Guidelines

  • Follow the existing module structure: one folder per subsystem, mod.rs + focused files.
  • Implement PanelProvider using the same pattern as the built-ins:
    • Implement as_any / as_any_mut with self.
    • Return (EventResult, Vec<Command>) from handle_event.
    • Provide lifecycle methods (focus_changed, hide, show, shutdown).
  • Keep main.rs as the single dispatcher for Command. Do not re-introduce a ProviderCtx-style black-box router.
  • Use anyhow::Result for application-level error handling. thiserror is a dependency but not yet used heavily.
  • Prefer explicit TODO comments for missing functionality; many already exist. Do not delete them unless you actually implement the feature.
  • Avoid adding heavy new dependencies without updating TECH_STACK.md and this file.

Testing Instructions

  • Add unit tests inside #[cfg(test)] mod tests; in the relevant module. Reference the existing test modules for style.
  • Use crossterm::event::{Event, KeyCode, KeyEvent} to simulate keyboard input in tests.
  • Assert on EventResult::Consumed vs EventResult::PassThrough and on emitted Commands where appropriate.
  • Run cargo test before finishing any change. The current baseline is 23 passed tests.

Security Considerations

  • There are no secrets, API keys, or credentials in this repository.
  • Future AI provider API keys are planned to live in ~/.config/everjoy/config.toml (not yet implemented). Do not commit keys.
  • Tool execution is intended to be guarded by auto_execute_tools = false in user config; dangerous operations should require user confirmation. Respect this design if you wire up tool execution.
  • External plugins are designed to be sandboxed via WASM / C-ABI translation with panic isolation. Until the loader and translator are implemented, no external plugins are actually loaded.
  • The terminal provider is currently a mock shell. If you replace it with real tokio::process::Command execution, sanitize inputs and require explicit user approval before running commands.

Useful References

  • doc/Purpose.MD — Why the project exists.
  • doc/Architecture.md — High-level architecture and data flows.
  • doc/Architecture-Runtime-and-Plugin.md — Runtime vs Plugin subsystem responsibilities.
  • doc/Plugin-Lifecycle-Tool-vs-Provider.md — Why tools and providers have separate lifecycles.
  • TECH_STACK.md — Dependency map and design decisions (note: some entries are aspirational).

Have fun building Everjoy. — For Hoshu Chiu & Everjoy Chiu 🐕