forked from admin/VolcanicAgenticCore
docs: CLAUDE.md with project overview, commands and architecture
This commit is contained in:
98
CLAUDE.md
98
CLAUDE.md
@@ -1,3 +1,101 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
<!-- release-notes-config
|
||||
declined: true
|
||||
-->
|
||||
|
||||
## What this is
|
||||
|
||||
VolcanicAgenticCore is a headless, extensible agent harness for .NET 10, ported from
|
||||
[earendil-works/pi](https://github.com/earendil-works/pi) without the terminal UI. It also ships a C# port of
|
||||
[chem/pi-claude-code-provider](https://github.com/chem/pi-claude-code-provider), which drives the local `claude`
|
||||
CLI on a Claude subscription as a model provider. A Telegram bot is the first front end.
|
||||
|
||||
When porting behaviour, pi and pi-claude-code-provider are the reference: event names, JSON shapes and invariants
|
||||
deliberately match them.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
dotnet build # whole solution (VolcanicAgenticCore.slnx)
|
||||
dotnet test # all three test projects; no test calls a paid API
|
||||
dotnet test tests/Volcanic.AgenticCore.Tests # one project
|
||||
dotnet test --filter "FullyQualifiedName~AgentLoopTests" # one class
|
||||
dotnet test --filter "FullyQualifiedName~AgentLoopTests.SomeTest" # one test
|
||||
|
||||
# reference host with the scripted faux provider (no keys)
|
||||
dotnet run --project samples/Volcanic.AgenticCore.Sample.Headless -- --faux "Say hello"
|
||||
dotnet run --project samples/Volcanic.AgenticCore.Sample.Headless -- --model claude-code/sonnet "List the files here"
|
||||
|
||||
# Telegram bot
|
||||
TELEGRAM_BOT_TOKEN=123:abc TELEGRAM_ALLOWED_USER_IDS=111111111 dotnet run --project hosts/Volcanic.AgenticCore.Telegram
|
||||
```
|
||||
|
||||
`Directory.Build.props` sets `TreatWarningsAsErrors=true`, nullable and implicit usings for every non-test project,
|
||||
so a new warning fails the build. Test projects turn warnings-as-errors off. Tests use xunit 2.
|
||||
|
||||
## Architecture
|
||||
|
||||
Read `docs/architecture.md` first. Key points:
|
||||
|
||||
- **`src/Volcanic.AgenticCore.Abstractions`** holds the contracts: messages, `Model`/`IProvider`, the streaming
|
||||
event protocol, `ITool`/`Tool<TArgs>`, `IExtension`/`IExtensionApi` and extension events, session entries/stores,
|
||||
`IUserInterface`, and `AgentSessionEvent`. Extensions reference **only** this assembly, so it stays small and
|
||||
stable. Don't let runtime types leak into it.
|
||||
- **`src/Volcanic.AgenticCore`** is organised as **vertical slices** under `Features/` (`Agent`, `Sessions`, `Models`,
|
||||
`Tools`, `Extensions`, `Commands`, `SystemPrompt`, `Compaction`). Each slice exposes one entry type
|
||||
(`AgentSession`, `SessionManager`, `ModelRegistry`, `ToolRegistry`, `ExtensionRunner`, `CommandRegistry`,
|
||||
`SystemPromptBuilder`, `Compactor`). Slices talk only through those entry types and the Abstractions.
|
||||
`Hosting/` has `AddAgenticCore(...)` and `AgenticCoreOptions`; `Testing/FauxProvider.cs` is the scripted provider
|
||||
that tests and `--faux` use.
|
||||
- **One conversation = one `AgentSession`**, built by `IAgentSessionFactory.CreateAsync`. Extensions are
|
||||
**instantiated per session** and each session has its own `ModelRegistry`, so provider registrations and extension
|
||||
fields are per conversation. Process-wide state has to be explicit (e.g. `ClaudeLoginCoordinator.Shared`).
|
||||
- **Two event systems.** `AgentSessionEvent`s go to hosts via `session.Subscribe` and are invoked synchronously on the
|
||||
loop. `ExtensionEvent`s go to extensions via `api.On<T>`: they are mutable event args (`Block`, `Cancel`,
|
||||
`MarkHandled`, set `Text`/`Message`/...), run sequentially in load order, and some short-circuit.
|
||||
- **Loop invariants** (from pi): providers never throw, they emit `Error` events. An error or abort ends the run.
|
||||
Tool preparation runs in source order, execution runs in parallel by default, results are appended in source order.
|
||||
Failed assistant messages are persisted but dropped from model context. Context overflow triggers one compaction
|
||||
and a retry.
|
||||
- **Persistence**: a session is a tree of JSONL entries (`id`/`parentId` + leaf pointer) under
|
||||
`~/.volcanic/agent/sessions/<scope>/` (`VOLCANIC_AGENT_DIR` overrides the root). Compaction entries replace older
|
||||
messages when context is built.
|
||||
- **System prompt** pulls project context from the working directory: `AGENTS.md`, or `CLAUDE.md` if there is no
|
||||
`AGENTS.md` (never both), plus `PERSONA.md` and `MEMORY.md`. File names match case-insensitively.
|
||||
- **Extension discovery**: host code, then `<cwd>/.volcanic/settings.json` / `.volcanic/extensions/*.dll`, then the same
|
||||
under `~/.volcanic/agent`. Earlier sources win name collisions. Each assembly loads in its own
|
||||
`AssemblyLoadContext` and shares `Volcanic.AgenticCore.*`, `Microsoft.Extensions.*` and `System.*` with the host.
|
||||
|
||||
### Extensions (`extensions/`)
|
||||
|
||||
Provider extensions built on the public API only: `Anthropic` (Messages API), `OpenAI` (chat-completions compatible),
|
||||
and `ClaudeCode` + `ClaudeCode.Bridge`. The Claude Code provider is the most intricate piece (`docs/claude-code-provider.md`):
|
||||
|
||||
- Every model call spawns a fresh `claude -p` with built-in tools off and replays the whole transcript as stream-json.
|
||||
Core tools are exposed as MCP tools `mcp__volcanic__<alias>` through the Bridge, a tiny MCP server that **never
|
||||
executes** tools. On `tool_use` the provider kills the process and returns `Done(ToolUse)`, and the core runs the tool.
|
||||
- `system/init` is validated strictly (fail closed). The extension refuses to run if `ANTHROPIC_API_KEY` or a similar
|
||||
env var is set, because it is subscription-only.
|
||||
- Session expiry → `ClaudeLoginCoordinator` runs one login flow at a time through `ClaudeCodeProviderOptions.LoginUi`,
|
||||
then replays the paused request exactly once. `/claude-code-doctor` and `/claude-code-login` are its commands.
|
||||
- Tests replay recorded CLI output from `tests/Volcanic.AgenticCore.Extensions.Tests/ClaudeCode/Fixtures/*.jsonl`.
|
||||
|
||||
### Telegram host (`hosts/Volcanic.AgenticCore.Telegram`)
|
||||
|
||||
Long polling (`Polling/`, with `ReconnectPolicy` backoff). Each private chat gets its own `AgentSession`
|
||||
(`Chats/ChatRegistry`), with workspace `<WorkspaceRoot>/<chatId>` and session scope `telegram-<chatId>`. Access is
|
||||
limited by `AllowedUserIds`. The first allowed id is the "owner": `OwnerLoginChannel` sends Claude Code re-login
|
||||
prompts to that chat. It resolves lazily to break the DI cycle ChatRegistry → session factory → extension → ChatRegistry.
|
||||
Answers go out complete, not streamed (`Rendering/`). Tests drive the host through `Support/FakeBotClient` and `ChatHost`.
|
||||
|
||||
## Conventions
|
||||
|
||||
- Commits follow Conventional Commits scoped by area: `feat(claude-code): ...`, `fix(telegram): ...`, `docs(spec): ...`,
|
||||
`test(...)`, `chore: ...`.
|
||||
- Design specs and implementation plans live in `docs/superpowers/specs/` and `docs/superpowers/plans/`. Update the
|
||||
relevant spec and the user docs in `docs/` when behaviour changes.
|
||||
- By design, the port leaves out pi's terminal UI, themes, keybindings, skills/prompt templates, OAuth logins and
|
||||
session-tree navigation commands.
|
||||
|
||||
Reference in New Issue
Block a user