Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
ECA Agent Guide (AGENTS.md)

ECA (Editor Code Assistant) is a Clojure server that editors talk to over stdin/stdout JSON-RPC to provide AI coding features (chat, tools, MCP, agents). Shipped as a GraalVM native binary.

- Architecture (request flow: editor → JSON-RPC stdio → `handlers` → `features` → `llm_api` → `llm_providers` → streamed back via `messenger`):
- `src/eca/server.clj` / `src/eca/main.clj`: stdio server entrypoint / CLI interface.
- `src/eca/handlers.clj`: entrypoint for all protocol methods, dispatches to features.
- `src/eca/features/`: high-level capabilities — `chat.clj` (+ `chat/` lifecycle, history, tool-calls), `tools.clj` (+ `tools/` built-in tools: filesystem, shell, git, mcp, task…), `agents.clj`, `skills.clj`, `rules.clj`, `hooks.clj`, `commands.clj`, `context.clj`, `prompt.clj`, `login.clj`, `plugins.clj`.
- `src/eca/llm_api.clj`: façade used by features to call an LLM; vendor adapters in `src/eca/llm_providers/` (anthropic, openai, google, ollama, copilot…).
- `src/eca/db.clj`: in-memory state (sessions, chats, MCP); `src/eca/config.clj`: config resolution from multiple sources.
- `src/eca/messenger.clj`: sends requests/notifications back to the client; `src/eca/remote/`: remote HTTP/SSE server mode.
- `src/eca/nrepl.clj`: starts an nREPL when nrepl/cider-nrepl are on the classpath (i.e. the `bb debug-cli` build; no flag needed) — port is logged to stderr, and you can eval against the live process.

- Build (requires Clojure CLI + Babashka):
- All-in-one debug CLI (JVM, nREPL): `bb debug-cli`
- Production CLI (JVM): `bb prod-cli` | Production JAR: `bb prod-jar`
Expand All @@ -9,37 +20,41 @@ ECA Agent Guide (AGENTS.md)
- Run all unit tests: `bb test` (same as `clojure -M:test`)
- Run a single unit test namespace: `clojure -M:test --focus eca.main-test`
- Run a single unit test var: `clojure -M:test --focus eca.main-test/parse-opts-test`
- Run all integration tests (requires built `./eca` or `eca.exe`): `bb integration-test`
- Run all integration tests (requires built `./eca` or `eca.exe` at repo root): `bb integration-test`
- Run a single integration test: `bb integration-test --dev --ns integration.chat.mcp-remote-test`
- `--dev` runs the server from source via the `clojure` CLI (no binary build needed); `--list-ns` lists test namespaces; `--proxy` routes via Tinyproxy (must be installed).
- Integration tests use mock LLM/MCP servers (`integration-test/llm_mock`, `mcp_mock`) — no API keys needed.

- Lint/format:
- Lint: `clj-kondo --lint src test dev integration-test`
- Formatting not enforced; follow idiomatic Clojure (`cljfmt` optional).
- Formatting not enforced in CI; follow idiomatic Clojure. `.cljfmt.edn` defines extra indents: `task` and `future*` are `[[:inner 0]]`.

- Namespaces/imports:
- One file per `ns`; always `(set! *warn-on-reflection* true)` near top.
- Group `:require` as: Clojure stdlib, third‑party, then `eca.*`; sort within groups.
- Prefer `:as` aliases; avoid `:refer` except in tests (`clojure.test` and what you use).

- Naming/types/data:
- kebab-case for fns/vars, `eca.<area>[.<subarea>]` for namespaces.
- Use snake/camel case only when mirroring external data keys.
- Prefer immutable maps/vectors/sets; use namespaced keywords for domain data.
- Add type hints only to remove reflection where it shows up.
- Internal Clojure names and domain keys use kebab-case (`chat-id`, `tool-call-id`, `parent-chat-id`).
- Client protocol/config JSON uses camelCase (`initializationOptions`, `toolCall`, `contentReceived`); keep conversions at boundaries (`shared/map->camel-cased-map`, config normalization).
- Provider/MCP payloads mirror vendor specs and may use mixed conventions (`input_tokens`, `function_call`, `inputSchema`); do not “fix” these to Clojure style.
- Hook script stdin uses top-level snake_case for shell ergonomics (`hook_name`, `chat_id`, `db_cache_path`), while nested tool data may keep its original shape.
- - Add type hints only to remove reflection where it shows up.

- Errors/logging/flows:
- Use `ex-info` with data for exceptional paths; return `{:result-code ...}` maps from CLI flows.
- Never `println` for app logs; use `eca.logger/error|warn|info|debug` (stderr-based).
- **stdout is the JSON-RPC channel** — never print to stdout; use `eca.logger/error|warn|info|debug` (stderr-based) for all app logs.
- If a chat-scoped function contains any `logger/...` call, wrap the relevant body in `logger/with-chat-context`. Pass both `chat-id` and the current chat’s `parent-chat-id`.
- Consider wrapping chat-scoped functions that call downstream code known to log, or that start `future*` work whose logs should be attributed to the chat. If there is no downstream logging, `with-chat-context` is unnecessary; instead, consider whether the function should log an important chat lifecycle event.

- Tests:
- Use `clojure.test` + `nubank/matcher-combinators`; keep tests deterministic.
- Put shared test helpers under `test/eca/test_helper.clj`.
- CI runs Linux, macOS, and Windows — use `eca.test-helper/file-path` / `file-uri` for Windows-safe paths in tests.

- General:
- Use java class typing to avoid GraalVM reflection issues
- Avoid adding too many comments, only add essential or when you think is really important to mention something.
- Use concrete Java class type hints when they prevent GraalVM/reflection issues.
- If changing dependency inputs in `deps.edn` or `bb.edn`, run `nix develop --command deps-lock-update`; PR CI fails if this leaves a `deps-lock.json` diff.
- ECA's protocol specification of client <-> server lives in docs/protocol.md
- If changing ECA config structure, remember to update its docs/config.json
- When adding support to a new feature or fixing a existing github issue, add a entry to Unreleased in CHANGELOG.md if not already there as last entry, be really concise (max 180 chars), implementation details not needed, mention the issue number in the end if you know it's related to one.
- When adding support to a new feature or fixing an existing GitHub issue, add a concise Unreleased `CHANGELOG.md` entry (max 180 chars, issue number if known).
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unreleased

- Support provider-level `extraHeaders`, sent on completion and models list requests. #517
- Improve `/init` prompt, `AGENTS.md`, and development docs.

## 0.144.0

Expand Down
85 changes: 54 additions & 31 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,49 @@ The ECA codebase follows a pragmatic **layered layout** that separates concerns

### Files overview

Path | Responsibility
-------------------------|-------------------------------------------------------
`bb.edn` | Babashka tasks (e.g. `bb test`, `bb debug-cli`) for local workflows and CI, the main entrypoint for most tasks.
`deps.edn` | Clojure dependency coordinates and aliases used by the JVM build and the native GraalVM image.
`docs/` | Markdown documentation shown at https://eca.dev
`src/eca/config.clj` | Centralized place to get ECA configs from multiple places.
`src/eca/logger.clj` | Logger interface to log to stderr.
`src/eca/shared.clj` | shared utility fns to whole project.
`src/eca/db.clj` | Simple in-memory KV store that backs sessions/MCP, all in-memory state lives here.
`src/eca/llm_api.clj` | Public façade used by features to call an LLM.
`src/eca/llm_providers/` | Vendor adapters (`openai.clj`, `anthropic.clj`, `ollama.clj`).
`src/eca/llm_util.clj` | Token counting, chunking, rate-limit helpers.
`src/eca/features/` | **High-level capabilities exposed to the editor**
├─ `chat.clj` | Streaming chat orchestration & tool-call pipeline.
├─ `prompt.clj` | Prompt templates and variable interpolation.
├─ `index.clj` | Embedding & retrieval-augmented generation helpers.
├─ `rules.clj` | Guards that enforce user-defined project rules.
├─ `tools.clj` | Registry of built-in tool descriptors (run, approve…).
└─ `tools/` | Implementation of side-effectful tools:
──├─ `filesystem.clj` | read/write/edit helpers 
──├─ `shell.clj` | runs user-approved shell commands 
──├─ `mcp.clj` | Multi-Command Plan supervisor 
──└─ `util.clj` | misc helpers shared by tools.
`src/eca/messenger.clj` | To send back to client requests/notifications over stdio.
`src/eca/handlers.clj` | Entrypoint for all features.
`src/eca/server.clj` | stdio **entry point**; wires everything together via `jsonrpc4clj`.
`src/eca/main.clj` | The CLI interface.
`src/eca/nrepl.clj` | Starts an nREPL when `:debug` flag is passed.
Path | Responsibility
----------------------------|-------------------------------------------------------
`bb.edn` | Babashka tasks (e.g. `bb test`, `bb debug-cli`) for local workflows and CI, the main entrypoint for most tasks.
`deps.edn` | Clojure dependency coordinates and aliases used by the JVM build and the native GraalVM image.
`docs/` | Markdown documentation shown at https://eca.dev
`src/eca/main.clj` | The CLI interface (`eca server`, etc.).
`src/eca/server.clj` | stdio **entry point**; wires everything together via `jsonrpc4clj`.
`src/eca/handlers.clj` | Entrypoint for all features; every JSON-RPC request/notification lands here.
`src/eca/messenger.clj` | Protocol to send requests/notifications back to the client (stdio or remote).
`src/eca/db.clj` | In-memory state atom (`db*`); sessions, chats, tool servers — all state lives here.
`src/eca/config.clj` | Centralized place to get ECA configs from multiple places (global, local, env, initializationOptions).
`src/eca/logger.clj` | Logger interface, logs to stderr (stdout is reserved for JSON-RPC).
`src/eca/shared.clj` | Shared utility fns for the whole project.
`src/eca/llm_api.clj` | Public façade used by features to call an LLM.
`src/eca/llm_providers/` | Vendor adapters (`anthropic.clj`, `openai.clj`, `openai_chat.clj`, `google.clj`, `copilot.clj`, `bedrock.clj`, `azure.clj`, `ollama.clj`, `openrouter.clj`, ...).
`src/eca/llm_util.clj` | Streaming/event helpers shared by providers.
`src/eca/features/` | **High-level capabilities exposed to the editor**
├─ `chat.clj` + `chat/` | Streaming chat orchestration & tool-call pipeline (lifecycle, history, tool calls).
├─ `agents.clj` | Agents and subagents (definitions, spawning).
├─ `commands.clj` | Chat commands (`/init`, `/login`, `/context`, custom commands, ...).
├─ `hooks.clj` | User-configured hooks triggered on server events.
├─ `skills.clj` + `skills/` | Skills discovery and loading.
├─ `rules.clj` | User-defined global/project/path-scoped rules.
├─ `context.clj` | Contexts attached to prompts (files, repo map, ...).
├─ `prompt.clj` | System prompt templates and variable interpolation.
├─ `login.clj` | Provider auth flows.
├─ `providers.clj` | Model/provider resolution.
├─ `completion.clj` | Non-chat LLM feature: code completion.
├─ `rewrite.clj` | Non-chat LLM feature: text rewrite.
├─ `index.clj` | Workspace indexing helpers (repo map).
├─ `tools.clj` | Registry of tool servers and built-in tool descriptors, approval logic.
└─ `tools/` | Implementation of built-in tools:
──├─ `filesystem.clj` | read/write/edit/grep helpers
──├─ `shell.clj` | runs user-approved shell commands, background jobs
──├─ `mcp.clj` | MCP (Model Context Protocol) servers integration
──├─ ... | other built-in tools: `git.clj`, `task.clj`, `agent.clj`, `ask_user.clj`, `skill.clj`, ...
──└─ `util.clj` | misc helpers shared by tools.
`src/eca/remote/` | Optional remote HTTP/SSE server exposing chats to non-stdio clients.
`src/eca/nrepl.clj` | Starts an nREPL when built with `bb debug-cli`.

Together these files implement the request flow:

`client/editor` → `stdin JSON-RPC` → `handlers` → `features` → `llm_api` → `llm_provider` → results streamed back.
`client/editor` → `stdin JSON-RPC` → `handlers` → `features` → `llm_api` → `llm_provider` → results streamed back via `messenger`.

With this map you can usually answer:

Expand All @@ -56,11 +67,23 @@ With this map you can usually answer:

### Unit Tests

Run with `bb test` or run test via Clojure REPL. CI will run the same task.
Run with `bb test` or run tests via Clojure REPL. CI runs the same task.

To run a single namespace or test, use kaocha's focus:

```bash
clojure -M:test --focus eca.features.chat-test
```

### Integration Tests

Run with `bb integration-test`, it will use your `eca` binary project root to spawn a server process and communicate with it via JSONRPC, testing the whole eca flow like an editor.
Run with `bb integration-test`, it will use your `eca` binary at project root (build one with `bb debug-cli` or `bb prod-cli`) to spawn a server process and communicate with it via JSONRPC, testing the whole eca flow like an editor. LLM and MCP servers are mocked (`integration-test/llm_mock`, `integration-test/mcp_mock`), so no API keys are needed.

Useful flags (see `bb integration-test -h`):

- `--dev`: run the server from source via the `clojure` CLI instead of a binary.
- `--ns integration.chat.anthropic-test`: run only specific test namespaces (comma-separated); `-l` lists them.
- `--proxy`: route requests through a transient Tinyproxy to verify proxy support.

## Coding

Expand Down
56 changes: 51 additions & 5 deletions resources/prompts/init.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,53 @@
Analyze this codebase and create an AGENTS.md file containing:
1. Build/lint/test commands - especially for running a single test
2. Code style guidelines including imports, formatting, types, naming conventions, error handling, etc.
Analyze this codebase and create or update an AGENTS.md file containing the essential information an AI coding agent needs to work effectively in this repository.

The file you create will be given to agentic coding agents (such as yourself) that operate in this repository. Make it about 20 lines long.
Create or update it at the repository root. If {{workspaceRoots}} contains multiple roots, inspect them and ask which root should receive AGENTS.md before writing.

If there's already an AGENTS.md, improve it if it's located in {{workspaceRoots}}.
## Step 1: Explore the codebase

Read the actual contents of files like these (skip any that don't exist — this is not an exhaustive list):

- **Manifest/package files**: package.json, deps.edn, project.clj, Cargo.toml, pyproject.toml, go.mod, pom.xml, build.gradle, mix.exs, etc.
- **Build/task runner configs**: Makefile, bb.edn, Justfile, Taskfile.yml, package.json scripts, etc.
- **CI config**: .github/workflows/*, .gitlab-ci.yml, .circleci/, azure-pipelines.yml, etc.
- **Existing AI instructions**: AGENTS.md, CLAUDE.md, .cursor/rules/, .cursorrules, .github/copilot-instructions.md, .windsurfrules, .clinerules, etc.
- **README**, **CONTRIBUTING**, or **DEVELOPERS** docs, etc.
- **Linter/formatter configs**: .clj-kondo/, .eslintrc*, ruff.toml, .golangci.yml, biome.json, .prettierrc, etc.

Do not guess from filenames — read the actual file contents.

From what you read, identify (among other things):
- **Build commands** — especially non-standard ones (wrapper scripts, aliases, specific flags)
- **Test commands** — including how to run a single test (namespace, file, or individual test)
- **Lint/format commands** — exact invocations
- **Project structure** — monorepo, multi-module, or single project; workspace conventions
- **Code style rules that DIFFER from language defaults** — imports, formatting, naming, types, error handling
- **Non-obvious gotchas** — required env vars, setup steps, platform-specific issues
- **Repo conventions** — branch naming, PR/commit style, changelog practices
- **Architectural constraints** — things that constrain how code should be written (e.g., "must work with GraalVM native image", "no reflection")

Do not invent missing conventions. If missing information is essential to avoid misleading instructions, ask targeted questions (via ask_user tool) before writing AGENTS.md. Otherwise omit unknown conventions rather than guessing.

## Step 2: Write AGENTS.md

Write a concise AGENTS.md. Every line must pass this test: **would removing it cause an agent to make mistakes or work less efficiently?** If not, cut it.

Include:
- Non-standard build/test/lint commands (especially single-test invocation)
- Style rules that differ from defaults
- Testing quirks and instructions
- Repo etiquette (branch/PR/commit conventions)
- Required env vars or setup steps
- Non-obvious gotchas or architectural constraints
- Concise architecture notes that are not obvious from filenames: major boundaries, request/data flow, extension points, generated-code areas, or constraints that affect how changes should be made
- Key information from existing AI tool configs — read instructions meant for other AI tools and adapt them for AGENTS.md

Exclude:
- File-by-file structure or component lists (agents can discover these by reading code)
- Standard language conventions agents already know
- Generic advice ("write clean code", "handle errors")
- Information that changes frequently — reference the source file instead
- Detailed tutorials — link to docs instead

Use short sections with bullet points, not paragraphs.

If AGENTS.md already exists in the chosen repository root, read it first. Improve it by filling gaps, removing outdated information, and tightening the language. Preserve what's already correct and useful.
Loading