Skip to content
Open
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
103 changes: 48 additions & 55 deletions docs/commands.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Coven Code Slash Commands Reference

This document is the complete reference for every slash command available in Coven Code, the Rust reimplementation of Claude Code CLI. Commands are invoked by typing `/command-name` at the REPL prompt.
This document is the reference for the visible slash commands available in Coven Code. Commands are invoked by typing `/command-name` at the REPL prompt.

---

Expand All @@ -27,30 +27,21 @@ This document is the complete reference for every slash command available in Cov

## Command System Overview

Commands are registered in a priority-ordered registry. When you type a command name, Coven Code resolves it through this chain:

```
bundledSkills -> builtinPluginSkills -> skillDirCommands ->
workflowCommands -> pluginCommands -> pluginSkills -> COMMANDS()
```

### Command Types

| Type | Behavior |
|------|----------|
| `local` | Runs synchronously; returns text output directly |
| `local-jsx` | Renders an interactive TUI component (model picker, theme selector, etc.) |
| `prompt` | Expands to a prompt sent to the model via the main inference loop |

Commands support aliases — for example `/h`, `/?`, and `/help` all invoke the same handler.
Commands are resolved in a priority-ordered registry. When you type a command name, Coven Code checks:

```
built-in commands -> user command templates -> discovered skills -> plugin commands
```

Commands support aliases — for example `/h`, `/?`, and `/help` all invoke the same handler.

### Usage Syntax

```
/command-name [arguments]
```

Arguments are passed as a single string after the command name. Most commands that accept arguments are documented with an `argumentHint` shown in the command palette.
Arguments are passed as a single string after the command name.

---

Expand All @@ -59,7 +50,7 @@ Arguments are passed as a single string after the command name. Most commands th
### /help
**Aliases:** `h`, `?`

Display all available commands with their descriptions. Respects `isHidden` flags — internal or rarely-needed commands are suppressed unless you are an Anthropic employee.
Display all available commands with their descriptions. Hidden and setup-only commands are suppressed from the default listing.

```
/help
Expand Down Expand Up @@ -342,15 +333,21 @@ Open Coven Code privacy settings. Launches a browser to the Anthropic privacy po

### /mcp

Configure and manage Model Context Protocol (MCP) servers. MCP servers expose additional tools and resources to the agent.
Inspect Model Context Protocol (MCP) servers and reconnect configured servers. MCP servers expose additional tools and resources to the agent.

```
/mcp
/mcp list
/mcp add <name> <command>
/mcp remove <name>
/mcp restart <name>
```
/mcp
/mcp list
/mcp status
/mcp auth <name>
/mcp connect <name>
/mcp logs <name>
/mcp resources [name]
/mcp prompts [name]
/mcp get-prompt <name> <prompt> [key=value ...]
```

Add or remove MCP servers by editing `~/.coven-code/settings.json`.

---

Expand Down Expand Up @@ -782,19 +779,22 @@ List and manage skills. Skills are bundled prompt-commands that extend Coven Cod

---

### /plugin
**Aliases:** `plugins`, `marketplace`

Manage plugins. Plugins are loadable modules that can register new commands, tools, and hooks. Browse the marketplace or install from a local path.

```
/plugin
/plugin list
/plugin install <name>
/plugin install <path>
/plugin remove <name>
/plugin reload
```
### /plugin
**Aliases:** `plugins`

Manage plugins. Plugins are loadable modules that can register new commands, tools, hooks, agents, skills, and MCP server definitions.

```
/plugin
/plugin list
/plugin info <name>
/plugin enable <name>
/plugin disable <name>
/plugin install <path>
/plugin reload
```

`/plugin reload` refreshes the active session plugin registry, hook registry, plugin commands, agents, skills, and in-memory MCP server definitions. New plugin MCP servers are included in the initial MCP connection at startup; if a reload adds a new MCP server after startup, start a new session before expecting its tools in the model tool list.

---

Expand Down Expand Up @@ -1182,22 +1182,15 @@ Over the Remote Control bridge (used by IDE integrations), only `local`-type com

`compact`, `clear`, `cost`, `files`

### Internal-Only Commands

The following commands are only available when the `USER_TYPE` environment variable is set to `ant` (Anthropic internal builds):

`commit-push-pr`, `ctx_viz`, `good-claude`, `issue`, `init-verifiers`, `mock-limits`, `bridge-kick`, `ultraplan`, `summary`, `teleport`, `ant-trace`, `perf-issue`, `env`, `oauth-refresh`, `debug-tool-call`, `autofix-pr`, `bughunter`, `backfill-sessions`, `break-cache`

### Availability-Restricted Commands

Some commands are available only under certain account or platform conditions:
### Availability-Restricted Commands

Some commands are available only under certain account or platform conditions:

| Command | Restriction |
|---------|-------------|
| `/fast` | Available when a fast-mode model is configured for the active provider |
| `/privacy-settings` | Opens Anthropic privacy portal (useful for claude.ai accounts) |
| `/sandbox-toggle` | Functional on macOS, Linux, WSL2 only; no-op on native Windows |

### Feature-Flagged Commands

Some commands check `isEnabled()` at runtime. For example, voice-related commands check for audio device availability; the desktop command checks for a display server.
| `/fast` | Available when a fast-mode model is configured for the active provider |
| `/install-slack-app` | Hidden; Slack setup is unavailable in this build |
| `/privacy-settings` | Opens the provider privacy portal where supported |
| `/sandbox-toggle` | Functional on macOS, Linux, WSL2 only; no-op on native Windows |
| `/voice` | Requires an audio backend plus `OPENAI_API_KEY` or `WHISPER_ENDPOINT_URL` for transcription |
| `/chrome` | Requires a running Chrome/Chromium instance launched with remote debugging enabled |
15 changes: 11 additions & 4 deletions docs/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ MCP defines three primitives a server can offer:

Coven Code discovers tools, resources, and prompts from connected MCP servers during the handshake phase and wraps them as native `Tool` instances (via `McpToolWrapper`), making them transparent to the query loop.

Plugin-provided MCP server definitions are merged into the in-memory config before the initial MCP connection. That means plugin MCP tools are available on first startup instead of requiring a reconnect after plugins load.

---

## Transports
Expand Down Expand Up @@ -136,9 +138,12 @@ Use `/mcp` inside an interactive session to inspect and manage MCP servers at ru
```
/mcp — show status of all configured servers
/mcp status — same as above
/mcp connect <name> — connect to a server by name
/mcp disconnect <name> — disconnect a server
/mcp restart <name> — disconnect then reconnect a server
/mcp auth <name> — show OAuth auth instructions for a server
/mcp connect <name> — retry a disconnected configured server
/mcp logs <name> — show recent error/log information
/mcp resources [name] — list resources from connected servers
/mcp prompts [name] — list prompt templates from connected servers
/mcp get-prompt <name> <prompt> [key=value ...] — expand a prompt template
```

The status display shows the connection state and discovered tool count for each server:
Expand Down Expand Up @@ -184,6 +189,8 @@ Use `ListMcpResources` to discover available URIs before calling `ReadMcpResourc

In addition to these, every tool that an MCP server exposes is automatically available to the model under its declared name (wrapped transparently by `McpToolWrapper`).

MCP tool wrappers are built from the servers connected during session startup. `/reload-plugins` refreshes plugin MCP definitions in memory, but newly added plugin MCP servers need a new session before their tools are exposed to the model tool list.

---

## Reconnection with Exponential Backoff
Expand All @@ -194,7 +201,7 @@ When an MCP server disconnects or fails to connect, Coven Code starts a backgrou
- Backoff factor: **2x** after each failed attempt
- Maximum delay: **60 seconds**

The loop exits as soon as the server connects successfully. A new loop can be started again if the server disconnects again later. The `/mcp restart <name>` command cancels any running loop and starts a fresh connection attempt immediately.
The loop exits as soon as the server connects successfully. If a configured server is disconnected, `/mcp connect <name>` attempts a reconnect. Add or remove servers by editing `~/.coven-code/settings.json` and starting a new session.

Server statuses during reconnection:

Expand Down
20 changes: 7 additions & 13 deletions docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,31 +349,25 @@ The `/plugin` slash command manages plugins from within an interactive session:
/plugin reload — reload all plugins from disk
```

After enabling or disabling a plugin, run `/plugin reload` or use `/reload-plugins` to apply changes in the current session without restarting.
After enabling or disabling a plugin, run `/plugin reload` or use `/reload-plugins` to refresh the session plugin registry without restarting.

### /reload-plugins

```
/reload-plugins
```

Rescans `~/.coven-code/plugins/`, re-reads all manifests, and refreshes the active hook registry, commands, agents, skills, and MCP server definitions. Use this after making changes to a plugin directory or after installing a new plugin.
Rescans `~/.coven-code/plugins/`, re-reads all manifests, and refreshes the active plugin registry, hook registry, plugin commands, agents, skills, and in-memory MCP server definitions. Use this after making changes to a plugin directory or after installing a new plugin.

---

## Plugin Marketplace Integration
Plugin-provided MCP servers are merged before the initial MCP connection during startup, so their tools are available in the first session tool list. If a reload adds a new MCP server after startup, restart the session to expose that server's tools to the model tool list.

Plugins published to the Coven Code marketplace have a `marketplace_id` field in their manifest (e.g. `"author/plugin-name"`). The marketplace integration allows:
---

- Browsing available plugins
- Installing plugins by ID
- Updating installed plugins to newer versions
## Marketplace Metadata

```
/plugin install author/plugin-name — install from the marketplace
```
Plugin manifests may include a `marketplace_id` field (e.g. `"author/plugin-name"`) for catalog metadata and future marketplace workflows.

Locally installed plugins (via a file path) do not require a `marketplace_id`.
The current `/plugin install` command installs from a local plugin path. It does not install marketplace IDs directly.

---

Expand Down
18 changes: 9 additions & 9 deletions docs/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,20 @@ This document is the complete reference for every tool available to the Coven Co

## Tool System Overview

Every tool in Coven Code implements a common `Tool` interface. This interface defines:
Every tool in Coven Code implements the Rust `Tool` trait in `src-rust/crates/tools/src/lib.rs`. This trait defines:

- **Identity** — name, aliases, MCP info
- **Input schema** — a Zod schema validating the input the model must provide
- **Capability flags** — `isReadOnly`, `isDestructive`, `isConcurrencySafe`
- **Permission check** — `checkPermissions()` called before execution
- **Execution** — `call()` performs the actual operation
- **UI rendering** — React/Ink components for TUI display
- **Identity** — the tool name the model uses to call it
- **Description** — instructions shown to the model
- **Input schema** — a JSON Schema object validating the input the model must provide
- **Permission level** — `None`, `ReadOnly`, `Write`, `Execute`, `Dangerous`, or `Forbidden`
- **Execution** — `execute()` performs the operation after permission resolution
- **Tool definition** — `to_definition()` serializes the name, description, and schema for providers

Tools are loaded eagerly at session start. The model receives tool descriptions and schemas and selects tools to call. Each tool call goes through permission resolution before `call()` is invoked.
Built-in tools are constructed once per session by `all_tools()`. Cheap lookup paths use a static built-in tool-name catalog so status/help flows do not instantiate every tool just to list names. MCP tools are added after MCP servers connect and are wrapped as native `Tool` instances.

### Tool Concurrency

Tools marked `isConcurrencySafe` may run in parallel with other tool calls. Most write tools are not concurrency-safe. Read-only tools are generally safe to parallelize.
The query loop may run compatible tool calls in parallel. Write and execute tools still pass through permission checks, while read-only tools are generally safe to parallelize.

---

Expand Down
22 changes: 8 additions & 14 deletions src-rust/crates/acp/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ where

if has_id && (has_result || has_error) && !has_method {
// Response — route to pending.
let id: acp::RequestId = serde_json::from_value(v["id"].clone()).unwrap_or(acp::RequestId::Null);
let id: acp::RequestId =
serde_json::from_value(v["id"].clone()).unwrap_or(acp::RequestId::Null);
if has_result {
let value = v["result"].clone();
connection.complete_pending(&id, Ok(value));
Expand All @@ -237,17 +238,15 @@ where
}
} else if has_id && has_method {
// Request.
let id: acp::RequestId = serde_json::from_value(v["id"].clone()).unwrap_or(acp::RequestId::Null);
let id: acp::RequestId =
serde_json::from_value(v["id"].clone()).unwrap_or(acp::RequestId::Null);
let method = v
.get("method")
.and_then(Value::as_str)
.unwrap_or("")
.to_string();
let params = v.get("params").cloned();
if tx
.send(Inbound::Request { id, method, params })
.is_err()
{
if tx.send(Inbound::Request { id, method, params }).is_err() {
break;
}
} else if has_method {
Expand Down Expand Up @@ -349,9 +348,7 @@ mod tests {
.await
.unwrap();
writer_handle
.write_all(
b"{\"jsonrpc\":\"2.0\",\"id\":99,\"result\":{\"orphan\":true}}\n",
)
.write_all(b"{\"jsonrpc\":\"2.0\",\"id\":99,\"result\":{\"orphan\":true}}\n")
.await
.unwrap();
drop(writer_handle); // EOF the reader
Expand Down Expand Up @@ -383,8 +380,7 @@ mod tests {
let (server_to_client_reader, server_to_client) = duplex(8192);
let connection = Connection::new(server_to_client);
let (tx, _rx) = mpsc::unbounded_channel();
let reader_handle =
tokio::spawn(run_reader(connection.clone(), server_reader, tx));
let reader_handle = tokio::spawn(run_reader(connection.clone(), server_reader, tx));

// Background: as a fake client, read the outbound request and write a
// matching response.
Expand All @@ -403,8 +399,7 @@ mod tests {
break;
}
}
let outbound: serde_json::Value =
serde_json::from_slice(buf.trim_ascii_end()).unwrap();
let outbound: serde_json::Value = serde_json::from_slice(buf.trim_ascii_end()).unwrap();
let id = outbound["id"].clone();
// Send the response back through the client_to_server pipe.
let response = serde_json::json!({
Expand All @@ -429,4 +424,3 @@ mod tests {
let _ = reader_handle.await;
}
}

3 changes: 2 additions & 1 deletion src-rust/crates/acp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ fn install_stderr_tracing() {
use tracing_subscriber::{fmt, EnvFilter};
let _ = fmt()
.with_env_filter(
EnvFilter::try_from_env("COVEN_CODE_ACP_LOG").unwrap_or_else(|_| EnvFilter::new("warn")),
EnvFilter::try_from_env("COVEN_CODE_ACP_LOG")
.unwrap_or_else(|_| EnvFilter::new("warn")),
)
.with_writer(std::io::stderr)
.try_init();
Expand Down
11 changes: 8 additions & 3 deletions src-rust/crates/acp/src/permission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::sync::Arc;
use agent_client_protocol_schema as acp;
use claurst_core::permissions::{PermissionDecision, PermissionRequest};
use claurst_core::PermissionHandler;
use claurst_tools::{PendingPermissionStore, PendingPermissionRequest};
use claurst_tools::{PendingPermissionRequest, PendingPermissionStore};
use tracing::{debug, warn};

use crate::connection::Connection;
Expand Down Expand Up @@ -56,7 +56,10 @@ pub async fn forward_pending(
} = pending;

let Some(decision_tx) = decision_tx else {
warn!(tool_use_id, "ACP permission: pending request had no decision_tx");
warn!(
tool_use_id,
"ACP permission: pending request had no decision_tx"
);
return;
};

Expand Down Expand Up @@ -130,7 +133,9 @@ fn infer_tool_kind(request: &PermissionRequest) -> acp::ToolKind {
return acp::ToolKind::Read;
}
match request.tool_name.as_str() {
"Edit" | "FileEdit" | "Write" | "FileWrite" | "BatchEdit" | "ApplyPatch" => acp::ToolKind::Edit,
"Edit" | "FileEdit" | "Write" | "FileWrite" | "BatchEdit" | "ApplyPatch" => {
acp::ToolKind::Edit
}
"Bash" | "Shell" | "Execute" => acp::ToolKind::Execute,
"WebFetch" | "WebSearch" => acp::ToolKind::Fetch,
"Glob" | "Grep" | "GlobTool" => acp::ToolKind::Search,
Expand Down
Loading