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
2 changes: 2 additions & 0 deletions backend/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface AppConfig {
debugMode: boolean;
staticPath: string;
cliPath: string; // Actual CLI script path detected by validateClaudeCli
claudeArgs: string[]; // Additional CLI arguments to pass to claude-code
}

export function createApp(
Expand Down Expand Up @@ -52,6 +53,7 @@ export function createApp(
debugMode: config.debugMode,
runtime,
cliPath: config.cliPath,
claudeArgs: config.claudeArgs,
}),
);

Expand Down
9 changes: 8 additions & 1 deletion backend/cli/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface ParsedArgs {
port: number;
host: string;
claudePath?: string;
claudeArgs: string[];
}

export function parseCliArgs(): ParsedArgs {
Expand Down Expand Up @@ -48,7 +49,12 @@ export function parseCliArgs(): ParsedArgs {
"--claude-path <path>",
"Path to claude executable (overrides automatic detection)",
)
.option("-d, --debug", "Enable debug mode", false);
.option("-d, --debug", "Enable debug mode", false)
.option(
"--claude-arg <arg...>",
"Pass additional arguments to claude-code CLI (can be used multiple times)",
[],
);

// Parse arguments - Commander.js v14 handles this automatically
program.parse(getArgs(), { from: "user" });
Expand All @@ -63,5 +69,6 @@ export function parseCliArgs(): ParsedArgs {
port: options.port,
host: options.host,
claudePath: options.claudePath,
claudeArgs: options.claudeArg || [],
};
}
1 change: 1 addition & 0 deletions backend/cli/deno.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ async function main(runtime: DenoRuntime) {
debugMode: args.debug,
staticPath,
cliPath: cliPath,
claudeArgs: args.claudeArgs,
});

// Start server (only show this message when everything is ready)
Expand Down
1 change: 1 addition & 0 deletions backend/cli/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ async function main(runtime: NodeRuntime) {
debugMode: args.debug,
staticPath,
cliPath,
claudeArgs: args.claudeArgs,
});

// Start server (only show this message when everything is ready)
Expand Down
13 changes: 11 additions & 2 deletions backend/handlers/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { logger } from "../utils/logger.ts";
* @param allowedTools - Optional array of allowed tool names
* @param workingDirectory - Optional working directory for Claude execution
* @param permissionMode - Optional permission mode for Claude execution
* @param claudeArgs - Optional additional CLI arguments to pass to claude-code
* @returns AsyncGenerator yielding StreamResponse objects
*/
async function* executeClaudeCommand(
Expand All @@ -24,6 +25,7 @@ async function* executeClaudeCommand(
allowedTools?: string[],
workingDirectory?: string,
permissionMode?: PermissionMode,
claudeArgs?: string[],
): AsyncGenerator<StreamResponse> {
let abortController: AbortController;

Expand All @@ -44,7 +46,7 @@ async function* executeClaudeCommand(
options: {
abortController,
executable: "node" as const,
executableArgs: [],
executableArgs: claudeArgs || [],
pathToClaudeCodeExecutable: cliPath,
...(sessionId ? { resume: sessionId } : {}),
...(allowedTools ? { allowedTools } : {}),
Expand Down Expand Up @@ -94,13 +96,19 @@ export async function handleChatRequest(
requestAbortControllers: Map<string, AbortController>,
) {
const chatRequest: ChatRequest = await c.req.json();
const { cliPath } = c.var.config;
const { cliPath, claudeArgs: globalClaudeArgs } = c.var.config;

logger.chat.debug(
"Received chat request {*}",
chatRequest as unknown as Record<string, unknown>,
);

// Merge global claudeArgs with request-specific claudeArgs (if any)
const mergedClaudeArgs = [
...(globalClaudeArgs || []),
...(chatRequest.claudeArgs || []),
];

const stream = new ReadableStream({
async start(controller) {
try {
Expand All @@ -113,6 +121,7 @@ export async function handleChatRequest(
chatRequest.allowedTools,
chatRequest.workingDirectory,
chatRequest.permissionMode,
mergedClaudeArgs,
)) {
const data = JSON.stringify(chunk) + "\n";
controller.enqueue(new TextEncoder().encode(data));
Expand Down
1 change: 1 addition & 0 deletions backend/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export interface AppConfig {
debugMode: boolean;
runtime: Runtime;
cliPath: string; // Path to actual CLI script detected by validateClaudeCli
claudeArgs: string[]; // Additional CLI arguments to pass to claude-code
// Future configuration options can be added here
}
190 changes: 190 additions & 0 deletions docs/CLAUDE_ARGS_USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Claude Code Web UI - CLI Argument Passthrough

## Overview

This feature allows you to pass through any claude-code CLI arguments when starting claude-code-webui, including `--dangerously-skip-permissions` and others.

## Usage

### 1. Global Configuration (Recommended)

Pass arguments through `--claude-arg` when starting the web UI:

```bash
# Single argument
node backend/cli/node.js --claude-arg --dangerously-skip-permissions

# Multiple arguments
node backend/cli/node.js \
--claude-arg --dangerously-skip-permissions \
--claude-arg --debug \
--claude-arg --permission-mode=bypassPermissions

# Arguments with values
node backend/cli/node.js \
--claude-arg --model=sonnet \
--claude-arg --allowed-tools=Bash,Edit,Read
```

### 2. Argument Merging

- **Global Arguments**: Passed via `--claude-arg` at startup, applied to all requests
- **Request-Specific Arguments**: Passed via `claudeArgs` field in API requests, applied only to current request

Argument merging logic:

```
Final Arguments = [Global Arguments, ..., Request-Specific Arguments, ...]
```

## Implementation Details

### 1. CLI Argument Parsing (backend/cli/args.ts)

```typescript
interface ParsedArgs {
debug: boolean;
port: number;
host: string;
claudePath?: string;
claudeArgs: string[]; // New field
}

program.option(
"--claude-arg <arg...>",
"Pass additional arguments to claude-code CLI (can be used multiple times)",
[],
);
```

### 2. Type Definitions (shared/types.ts)

```typescript
export interface ChatRequest {
message: string;
sessionId?: string;
requestId: string;
allowedTools?: string[];
workingDirectory?: string;
permissionMode?: "default" | "plan" | "acceptEdits";
claudeArgs?: string[]; // New field
}
```

### 3. Configuration Propagation (backend/handlers/chat.ts)

```typescript
// Merge global and request-specific arguments
const mergedClaudeArgs = [
...(globalClaudeArgs || []),
...(chatRequest.claudeArgs || []),
];

// Pass to claude-code CLI
for await (const sdkMessage of query({
prompt: processedMessage,
options: {
abortController,
executable: "node" as const,
executableArgs: mergedClaudeArgs, // Use merged arguments
pathToClaudeCodeExecutable: cliPath,
// ... other options
},
})) {
// ...
}
```

## Supported Parameter Examples

Based on `claude --help` output, the following parameters are supported:

### Permission-related

- `--dangerously-skip-permissions` - Skip all permission checks
- `--allow-dangerously-skip-permissions` - Enable bypassing all permission checks as an option
- `--permission-mode <mode>` - Permission mode (acceptEdits, bypassPermissions, default, dontAsk, plan)

### Tool-related

- `--allowed-tools <tools...>` - Comma or space-separated list of tool names to allow
- `--disallowed-tools <tools...>` - Comma or space-separated list of tool names to deny
- `--tools <tools...>` - Specify the list of available tools from the built-in set

### Model-related

- `--model <model>` - Model for the current session (sonnet, opus, etc.)
- `--fallback-model <model>` - Enable automatic fallback to specified model when default model is overloaded

### MCP-related

- `--mcp-config <configs...>` - Load MCP servers from JSON files or strings
- `--strict-mcp-config` - Only use MCP servers from --mcp-config, ignoring all other MCP configurations

### Debug-related

- `--debug [filter]` - Enable debug mode with optional category filtering
- `--verbose` - Override verbose mode setting from config

### Other

- `--system-prompt <prompt>` - System prompt to use for the session
- `--append-system-prompt <prompt>` - Append a system prompt to the default system prompt
- `--settings <file-or-json>` - Path to a settings JSON file or a JSON string to load additional settings from
- `--add-dir <directories...>` - Additional directories to allow tool access to

## API Usage Examples

### 1. Frontend Integration

If the frontend needs to support these arguments, you can add a settings interface:

```typescript
const chatRequest: ChatRequest = {
message: "Hello Claude",
requestId: generateId(),
sessionId: "session-123",
allowedTools: ["Bash", "Edit"],
permissionMode: "default",
claudeArgs: ["--dangerously-skip-permissions"], // Request-specific arguments
};

fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(chatRequest),
});
```

### 2. Environment Variable Configuration

You can also consider setting default arguments through environment variables:

```bash
export CLAUDE_WEBUI_DEFAULT_ARGS="--dangerously-skip-permissions --debug"
node backend/cli/node.js
```

## Security Considerations

1. **`--dangerously-skip-permissions`**: This parameter bypasses all permission checks and should only be used in sandboxed or trusted environments
2. **Tool Restrictions**: It's recommended to always explicitly specify `--allowed-tools` to limit available tools
3. **Directory Access**: Only add necessary directories when using `--add-dir`

## Troubleshooting

### 1. Arguments Not Taking Effect

Check if the startup logs contain the passed-through arguments:

```bash
node backend/cli/node.js --claude-arg --dangerously-skip-permissions --debug
```

### 2. Type Errors

Ensure that frontend and backend type definitions are consistent, especially the `ChatRequest` interface.

### 3. Parameter Conflicts

Some parameters may conflict with each other, such as `--allowed-tools` and `--disallowed-tools`. Please refer to the claude-code official documentation.
1 change: 1 addition & 0 deletions shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface ChatRequest {
allowedTools?: string[];
workingDirectory?: string;
permissionMode?: "default" | "plan" | "acceptEdits";
claudeArgs?: string[];
}

export interface AbortRequest {
Expand Down