vally-claudecodecli 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Waldek Mastykarz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,211 @@
1
- # Temporary Holding Version
1
+ # Vally Claude Code CLI executor
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **Evaluate Claude Code the way developers run it: the real `claude` CLI, in a real workspace.**
4
+
5
+ `vally-claudecodecli` is a [Vally](https://aka.ms/vally) executor plugin that runs evals against the [Claude Code](https://code.claude.com/docs) CLI. Test your agent skills, MCP servers, and prompts with Claude Code, then grade the resulting files, tool calls, and responses with Vally.
6
+
7
+ - **Real CLI, headless:** runs `claude -p` with streaming JSON input and output. No UI automation.
8
+ - **Full Vally feature set:** multi-turn stimuli with per-turn workspace diffs, skills, MCP servers, attachments, tool-call simulation, agent working-time limits, reasoning effort, env vars, and session resume.
9
+ - **Detailed trajectories:** tool calls, results, skill activations, and token usage, converted to [ATIF](https://github.com/harbor-framework/harbor/blob/main/rfcs/0001-trajectory-format.md) with [atifact](https://github.com/waldekmastykarz/atifact) and saved with every trial.
10
+
11
+ ## Run your first eval
12
+
13
+ ### 1. Install
14
+
15
+ You need:
16
+
17
+ - Node.js 22.15 or newer
18
+ - [Claude Code](https://code.claude.com/docs/en/setup) on your `PATH`, signed in (run `claude` once and complete `/login`, or set `ANTHROPIC_API_KEY`)
19
+
20
+ Install the CLI and executor in the project that contains your evals:
21
+
22
+ ```sh
23
+ npm install --save-dev @microsoft/vally-cli vally-claudecodecli
24
+ ```
25
+
26
+ Already using Vally? Install just `vally-claudecodecli`. It requires `@microsoft/vally` 0.21 or newer; npm installs that peer dependency if needed.
27
+
28
+ ### 2. Create an eval
29
+
30
+ Save this as `eval.yaml`:
31
+
32
+ ```yaml
33
+ name: claude-file-creation
34
+ defaults:
35
+ executor: claude-code-cli
36
+ model: sonnet
37
+ timeout: 5m
38
+ stimuli:
39
+ - name: creates-the-requested-file
40
+ prompt: "Create hello.txt containing exactly: Hello from Vally"
41
+ graders:
42
+ - type: file-contains
43
+ config:
44
+ path: hello.txt
45
+ value: Hello from Vally
46
+ ```
47
+
48
+ `model` accepts anything `claude --model` does: an alias such as `sonnet`, `opus`, or `haiku`, or a full model name. Omit it to use Claude Code's default model.
49
+
50
+ ### 3. Run it
51
+
52
+ ```sh
53
+ npx vally eval -e eval.yaml --executor-plugin vally-claudecodecli
54
+ ```
55
+
56
+ Vally prepares a workspace for each trial, the executor runs Claude Code in it, and Vally grades the result. Trials run in parallel, one Claude Code process per trial.
57
+
58
+ To avoid repeating the flag, add this to your project's `.vally.yaml`:
59
+
60
+ ```yaml
61
+ plugins:
62
+ executor:
63
+ - vally-claudecodecli
64
+ ```
65
+
66
+ ## How it works
67
+
68
+ For each trial, the executor starts one Claude Code process in the trial workspace:
69
+
70
+ ```sh
71
+ claude -p --input-format stream-json --output-format stream-json --verbose \
72
+ --replay-user-messages --permission-mode bypassPermissions --strict-mcp-config ...
73
+ ```
74
+
75
+ It sends each prompt over stdin and waits for Claude Code to finish the turn. For a multi-turn stimulus (`turns`), every prompt goes to the same session, and Vally captures the workspace after each turn. After the last turn, the executor closes stdin and waits for Claude Code to exit, because Claude Code can keep working, for example when a background task finishes.
76
+
77
+ **Only run trusted evals, fixtures, and MCP servers.** By default, Claude Code runs with `bypassPermissions`, so it runs commands and edits files without asking, using your account and credentials. Change this with [`permissionMode`](#configuration).
78
+
79
+ ### What Claude Code loads
80
+
81
+ The executor doesn't isolate Claude Code from your machine's configuration. Like running `claude` yourself, a trial loads your user, project, and local settings, including authentication (such as an `apiKeyHelper`), installed plugins, `CLAUDE.md` files, hooks, and skills. This keeps your sign-in working, but it means results can depend on the machine. Keep configuration consistent when comparing runs, or narrow it:
82
+
83
+ - [`settingSources`](#configuration) limits which settings files load. `[]` loads none, so authenticate with an environment variable or [`provider`](#model-provider) instead.
84
+ - `extraArgs: ["--bare"]` or `["--safe-mode"]` turn off customizations. See `claude --help`.
85
+
86
+ MCP servers are the exception: Claude Code loads only the servers declared in the eval (`agent_environment.mcpServers`).
87
+
88
+ ## Supported Vally features
89
+
90
+ | Feature | How it maps to Claude Code |
91
+ | --- | --- |
92
+ | `model` | `--model` |
93
+ | `reasoning_effort` | `--effort` (`low`, `medium`, `high`, `xhigh`, `max`, depending on the model) |
94
+ | `turns` | Sent one after another to the same session; Vally captures the workspace after each turn, so turn-scoped diff graders work |
95
+ | `agent_environment.skills` | Linked into a temporary directory outside the workspace and added with `--add-dir`, so skill names stay as they are and the graded workspace stays clean |
96
+ | `agent_environment.mcpServers` | `--mcp-config` with `--strict-mcp-config`. `timeout` becomes the server's tool-call timeout. `cwd` isn't supported by Claude Code and is rejected |
97
+ | `agent_environment.env` | Set on the Claude Code process |
98
+ | `attachments` | Sent with the first prompt. Images (`.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`) and PDFs |
99
+ | `simulation` | See [Tool-call simulation](#tool-call-simulation) |
100
+ | `constraints.max_agent_duration` | Interrupts Claude Code when time runs out; the partial run is graded with `endReason: agent_timeout` |
101
+ | `constraints.max_duration` / `timeout` | Hard limit; Claude Code is stopped and the trial fails |
102
+ | Session resume | `--resume <session id>`. The resumed conversation continues to be saved |
103
+ | Trace context | Vally's W3C trace context is passed as `TRACEPARENT`/`TRACESTATE`, which Claude Code uses as the parent of its spans when [telemetry](https://code.claude.com/docs/en/monitoring-usage) is enabled |
104
+
105
+ Sessions created for a trial aren't saved (`--no-session-persistence`). Claude Code still creates an empty project directory for each trial workspace under `~/.claude/projects` (or `$CLAUDE_CONFIG_DIR/projects`); the executor leaves these in place.
106
+
107
+ ### Tool-call simulation
108
+
109
+ Simulated calls are answered by a Claude Code `PreToolUse` hook that the executor adds for the trial:
110
+
111
+ - **Shell commands:** overrides keyed `bash`, `shell`, or `powershell` apply to Claude Code's `Bash` and `PowerShell` tools. The command is replaced with one that prints the canned output, so it can succeed or fail.
112
+ - **Other tools:** key overrides by the Claude Code tool name, such as `Read`, `WebFetch`, or `mcp__<server>__<tool>`. Claude Code can't return a canned result for these, so the call is blocked and the model sees the output as the tool's error. Vally allows only error results for these tools.
113
+ - `max_iterations` counts Claude Code's model responses; the run stops cleanly with `endReason: simulation_cap`.
114
+
115
+ Simulated calls are marked `simulated: true` in the trajectory.
116
+
117
+ ```yaml
118
+ stimuli:
119
+ - name: handles-failing-tests
120
+ prompt: Run the tests and summarize the failures.
121
+ simulation:
122
+ tool_overrides:
123
+ bash:
124
+ patterns:
125
+ - match: "npm test"
126
+ output: "1 failing: add() returns NaN"
127
+ is_error: true
128
+ WebFetch: { output: "Network is unavailable", is_error: true }
129
+ ```
130
+
131
+ ## Configuration
132
+
133
+ Most evals need no executor configuration. These options go under `defaults.executor.config`:
134
+
135
+ | Option | Purpose |
136
+ | --- | --- |
137
+ | `claudePath` | Path to the Claude Code executable. Default: `claude` on `PATH` |
138
+ | `permissionMode` | `acceptEdits`, `auto`, `bypassPermissions` (default), `dontAsk`, `manual`, or `plan` |
139
+ | `settingSources` | Settings files to load: any of `user`, `project`, `local`. Default: all |
140
+ | `allowedTools` / `disallowedTools` | Tool rules, for example `["Bash(git *)", "Edit"]` |
141
+ | `systemPrompt` / `appendSystemPrompt` | Replace or extend Claude Code's system prompt |
142
+ | `maxBudgetUsd` | Spending limit per trial. When it's reached, the run ends and is graded with an `error` event |
143
+ | `fallbackModel` | Model to fall back to when the main model is overloaded |
144
+ | `extraArgs` | Additional `claude` arguments. Flags the executor sets itself are rejected |
145
+ | `provider` | See [Model provider](#model-provider) |
146
+
147
+ ```yaml
148
+ defaults:
149
+ executor:
150
+ name: claude-code-cli
151
+ config:
152
+ permissionMode: acceptEdits
153
+ settingSources: [project]
154
+ disallowedTools: [WebFetch, WebSearch]
155
+ ```
156
+
157
+ `vally lint` doesn't load executor plugins, so `vally eval` validates this configuration.
158
+
159
+ ### Model provider
160
+
161
+ `provider` points Claude Code at a specific model provider, like the `copilot-sdk` executor's `provider`. Credentials are read from environment variables you name, so secrets never appear in the eval spec. When `provider` is set, inherited provider and credential variables (such as `ANTHROPIC_API_KEY` or `CLAUDE_CODE_USE_BEDROCK`) are removed first, so the configured provider is the one used.
162
+
163
+ | `type` | Options | Claude Code variables |
164
+ | --- | --- | --- |
165
+ | `anthropic` (default) | `baseUrl`, `apiKeyEnv`, `bearerTokenEnv`, `headers` | `ANTHROPIC_BASE_URL`, `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN` (wins over the API key), `ANTHROPIC_CUSTOM_HEADERS` |
166
+ | `bedrock` | `region`, `apiKeyEnv`, `baseUrl` | `CLAUDE_CODE_USE_BEDROCK`, `AWS_REGION`, `AWS_BEARER_TOKEN_BEDROCK`, `ANTHROPIC_BEDROCK_BASE_URL` |
167
+ | `vertex` | `region`, `projectId`, `baseUrl` | `CLAUDE_CODE_USE_VERTEX`, `CLOUD_ML_REGION`, `ANTHROPIC_VERTEX_PROJECT_ID`, `ANTHROPIC_VERTEX_BASE_URL` |
168
+ | `foundry` | `resource` or `baseUrl`, `apiKeyEnv` | `CLAUDE_CODE_USE_FOUNDRY`, `ANTHROPIC_FOUNDRY_RESOURCE`, `ANTHROPIC_FOUNDRY_BASE_URL`, `ANTHROPIC_FOUNDRY_API_KEY` |
169
+
170
+ ```yaml
171
+ defaults:
172
+ executor:
173
+ name: claude-code-cli
174
+ config:
175
+ provider:
176
+ baseUrl: https://llm-gateway.example.com
177
+ bearerTokenEnv: LLM_GATEWAY_TOKEN
178
+ ```
179
+
180
+ Cloud providers otherwise use their usual credentials, such as your AWS or Google Cloud sign-in. Variables in `agent_environment.env` are applied last and override the provider.
181
+
182
+ ## Artifacts
183
+
184
+ Each trial's `executor-artifacts` directory contains:
185
+
186
+ | File | Contents |
187
+ | --- | --- |
188
+ | `claude-code.jsonl` | Claude Code's raw `stream-json` output |
189
+ | `claude-code.stderr.log` | Claude Code's stderr |
190
+ | `trajectory.atif.json` | The ATIF trajectory the Vally trajectory was built from |
191
+
192
+ **Review artifacts before sharing them.** They contain prompts, generated code, tool output, and local paths.
193
+
194
+ ## Troubleshooting
195
+
196
+ | Symptom | Check |
197
+ | --- | --- |
198
+ | `Claude Code executable 'claude' was not found` | Install Claude Code or set `claudePath`. |
199
+ | `Not logged in · Please run /login` | Sign in with `claude`, or set `ANTHROPIC_API_KEY`. If you limited `settingSources`, your `apiKeyHelper` or login may not load; use `provider` instead. |
200
+ | Trial times out | Raise `timeout`, or use `constraints.max_agent_duration` to grade partial runs. Check `claude-code.jsonl` to see what the agent was doing. |
201
+ | Unexpected skills, hooks, or instructions | Your user configuration is loaded. See [What Claude Code loads](#what-claude-code-loads). |
202
+
203
+ ## Limitations
204
+
205
+ - **Token metrics are approximate.** The trajectory comes from atifact's Claude Code parser, which currently counts usage once per content block rather than once per model response and reads output tokens before a response finishes. It also drops reasoning, failed-tool status, subagent activity, and timestamps. These are tracked in atifact ([#27](https://github.com/waldekmastykarz/atifact/issues/27)–[#32](https://github.com/waldekmastykarz/atifact/issues/32)) and improve as atifact is updated. Check `claude-code.jsonl` for exact values; the `result` line has Claude Code's totals and cost.
206
+ - **Simulation of non-shell tools is error-only**, and MCP tools can't be given canned successful results.
207
+ - **Machine-dependent configuration.** See [What Claude Code loads](#what-claude-code-loads).
208
+
209
+ ## License
210
+
211
+ [MIT](LICENSE)
package/dist/args.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ import type { McpServerConfig } from "@microsoft/vally";
2
+ import type { ClaudeCodeExecutorConfig } from "./config.js";
3
+ export declare function parseDuration(value: string): number;
4
+ /** Converts Vally MCP server configs to Claude Code's `--mcp-config` JSON. */
5
+ export declare function toClaudeMcpConfig(servers: Record<string, McpServerConfig>): string;
6
+ export interface ClaudeArgsInput {
7
+ config: ClaudeCodeExecutorConfig;
8
+ model?: string;
9
+ reasoningEffort?: string;
10
+ mcpServers?: Record<string, McpServerConfig>;
11
+ resumeSessionId?: string;
12
+ sessionId?: string;
13
+ skillsDir?: string;
14
+ settings?: string;
15
+ }
16
+ export declare function buildClaudeArgs(input: ClaudeArgsInput): string[];
17
+ export type ContentBlock = {
18
+ type: "text";
19
+ text: string;
20
+ } | {
21
+ type: "image";
22
+ source: {
23
+ type: "base64";
24
+ media_type: string;
25
+ data: string;
26
+ };
27
+ } | {
28
+ type: "document";
29
+ source: {
30
+ type: "base64";
31
+ media_type: "application/pdf";
32
+ data: string;
33
+ };
34
+ title?: string;
35
+ };
36
+ /** Reads attachments as Anthropic content blocks. Supports images and PDFs. */
37
+ export declare function attachmentBlocks(paths: readonly string[]): Promise<ContentBlock[]>;
38
+ export declare function userMessage(content: ContentBlock[]): string;
39
+ export declare function interruptRequest(id: string): string;
package/dist/args.js ADDED
@@ -0,0 +1,129 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ const DURATION = /^(\d+(?:\.\d+)?)(ms|s|m|h|d)$/;
4
+ const UNIT_MS = { ms: 1, s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000 };
5
+ export function parseDuration(value) {
6
+ const match = DURATION.exec(value.trim());
7
+ if (!match)
8
+ throw new Error(`Invalid duration '${value}' (expected e.g. 500ms, 30s, 5m)`);
9
+ return Math.round(Number(match[1]) * UNIT_MS[match[2]]);
10
+ }
11
+ /** Converts Vally MCP server configs to Claude Code's `--mcp-config` JSON. */
12
+ export function toClaudeMcpConfig(servers) {
13
+ const mcpServers = {};
14
+ for (const [name, server] of Object.entries(servers)) {
15
+ const timeout = server.timeout !== undefined ? { timeout: parseDuration(server.timeout) } : {};
16
+ if (server.type === "stdio") {
17
+ if (server.cwd !== undefined) {
18
+ throw new Error(`MCP server '${name}': 'cwd' is not supported by Claude Code; wrap the command instead`);
19
+ }
20
+ mcpServers[name] = {
21
+ type: "stdio",
22
+ command: server.command,
23
+ args: server.args ?? [],
24
+ ...(server.env && { env: server.env }),
25
+ ...timeout,
26
+ };
27
+ }
28
+ else {
29
+ mcpServers[name] = {
30
+ type: server.type,
31
+ url: server.url,
32
+ ...(server.headers && { headers: server.headers }),
33
+ ...timeout,
34
+ };
35
+ }
36
+ }
37
+ return JSON.stringify({ mcpServers });
38
+ }
39
+ export function buildClaudeArgs(input) {
40
+ const { config } = input;
41
+ const args = [
42
+ "-p",
43
+ "--output-format",
44
+ "stream-json",
45
+ "--input-format",
46
+ "stream-json",
47
+ "--verbose",
48
+ // Echoes each prompt back so the log (and the ATIF built from it) contains the user turns.
49
+ "--replay-user-messages",
50
+ "--permission-mode",
51
+ config.permissionMode ?? "bypassPermissions",
52
+ // MCP servers come only from the eval spec, like the copilot-sdk executor.
53
+ "--strict-mcp-config",
54
+ ];
55
+ if (input.mcpServers && Object.keys(input.mcpServers).length > 0) {
56
+ args.push("--mcp-config", toClaudeMcpConfig(input.mcpServers));
57
+ }
58
+ if (input.model)
59
+ args.push("--model", input.model);
60
+ if (input.reasoningEffort)
61
+ args.push("--effort", input.reasoningEffort);
62
+ if (input.resumeSessionId) {
63
+ args.push("--resume", input.resumeSessionId);
64
+ }
65
+ else {
66
+ // Sessions created for a trial aren't kept around, mirroring the copilot-sdk executor.
67
+ args.push("--no-session-persistence");
68
+ if (input.sessionId)
69
+ args.push("--session-id", input.sessionId);
70
+ }
71
+ if (config.settingSources)
72
+ args.push("--setting-sources", config.settingSources.join(","));
73
+ if (input.settings)
74
+ args.push("--settings", input.settings);
75
+ if (input.skillsDir)
76
+ args.push("--add-dir", input.skillsDir);
77
+ if (config.allowedTools)
78
+ args.push("--allowedTools", config.allowedTools.join(","));
79
+ if (config.disallowedTools)
80
+ args.push("--disallowedTools", config.disallowedTools.join(","));
81
+ if (config.systemPrompt)
82
+ args.push("--system-prompt", config.systemPrompt);
83
+ if (config.appendSystemPrompt)
84
+ args.push("--append-system-prompt", config.appendSystemPrompt);
85
+ if (config.maxBudgetUsd !== undefined)
86
+ args.push("--max-budget-usd", String(config.maxBudgetUsd));
87
+ if (config.fallbackModel)
88
+ args.push("--fallback-model", config.fallbackModel);
89
+ if (config.extraArgs)
90
+ args.push(...config.extraArgs);
91
+ return args;
92
+ }
93
+ const IMAGE_TYPES = {
94
+ ".png": "image/png",
95
+ ".jpg": "image/jpeg",
96
+ ".jpeg": "image/jpeg",
97
+ ".gif": "image/gif",
98
+ ".webp": "image/webp",
99
+ };
100
+ /** Reads attachments as Anthropic content blocks. Supports images and PDFs. */
101
+ export async function attachmentBlocks(paths) {
102
+ const blocks = [];
103
+ for (const file of paths) {
104
+ const ext = path.extname(file).toLowerCase();
105
+ const data = await readFile(file).catch((error) => {
106
+ throw new Error(`Failed to read attachment '${file}'`, { cause: error });
107
+ });
108
+ if (IMAGE_TYPES[ext]) {
109
+ blocks.push({ type: "image", source: { type: "base64", media_type: IMAGE_TYPES[ext], data: data.toString("base64") } });
110
+ }
111
+ else if (ext === ".pdf") {
112
+ blocks.push({
113
+ type: "document",
114
+ source: { type: "base64", media_type: "application/pdf", data: data.toString("base64") },
115
+ title: path.basename(file),
116
+ });
117
+ }
118
+ else {
119
+ throw new Error(`Unsupported attachment '${file}': Claude Code accepts images (${Object.keys(IMAGE_TYPES).join(", ")}) and PDFs (.pdf)`);
120
+ }
121
+ }
122
+ return blocks;
123
+ }
124
+ export function userMessage(content) {
125
+ return `${JSON.stringify({ type: "user", message: { role: "user", content }, parent_tool_use_id: null, session_id: "" })}\n`;
126
+ }
127
+ export function interruptRequest(id) {
128
+ return `${JSON.stringify({ type: "control_request", request_id: id, request: { subtype: "interrupt" } })}\n`;
129
+ }
@@ -0,0 +1,63 @@
1
+ export declare const PERMISSION_MODES: readonly ["acceptEdits", "auto", "bypassPermissions", "dontAsk", "manual", "plan"];
2
+ export type PermissionMode = (typeof PERMISSION_MODES)[number];
3
+ export declare const SETTING_SOURCES: readonly ["user", "project", "local"];
4
+ export type SettingSource = (typeof SETTING_SOURCES)[number];
5
+ export declare const PROVIDER_TYPES: readonly ["anthropic", "bedrock", "vertex", "foundry"];
6
+ export type ProviderType = (typeof PROVIDER_TYPES)[number];
7
+ /**
8
+ * Model provider for Claude Code, the counterpart of the copilot-sdk executor's
9
+ * BYOK `provider`. Credentials are referenced by environment-variable name so
10
+ * secrets never live in the eval spec.
11
+ */
12
+ export interface ClaudeCodeProviderConfig {
13
+ /** Defaults to `anthropic` (Claude API or an Anthropic-compatible gateway). */
14
+ type?: ProviderType;
15
+ /** Endpoint override (ANTHROPIC_BASE_URL or the provider-specific base URL variable). */
16
+ baseUrl?: string;
17
+ /** Name of the env var holding the API key (anthropic, foundry) or Bedrock API key (bedrock). */
18
+ apiKeyEnv?: string;
19
+ /** Name of the env var holding a bearer token (anthropic only; sent as `Authorization: Bearer`). */
20
+ bearerTokenEnv?: string;
21
+ /** Extra HTTP headers sent with every model request (anthropic only). */
22
+ headers?: Record<string, string>;
23
+ /** Cloud region (bedrock: AWS_REGION, vertex: CLOUD_ML_REGION). */
24
+ region?: string;
25
+ /** GCP project ID (vertex only). */
26
+ projectId?: string;
27
+ /** Microsoft Foundry resource name (foundry only). */
28
+ resource?: string;
29
+ }
30
+ export interface ClaudeCodeExecutorConfig {
31
+ /** Path to the Claude Code executable. Defaults to `claude` on PATH. */
32
+ claudePath?: string;
33
+ /** Defaults to `bypassPermissions`, so the agent never stalls on a permission prompt. */
34
+ permissionMode?: PermissionMode;
35
+ /** Claude Code setting sources to load. Defaults to Claude Code's own default (all sources). */
36
+ settingSources?: SettingSource[];
37
+ allowedTools?: string[];
38
+ disallowedTools?: string[];
39
+ appendSystemPrompt?: string;
40
+ systemPrompt?: string;
41
+ maxBudgetUsd?: number;
42
+ fallbackModel?: string;
43
+ /** Extra CLI arguments appended verbatim. Flags managed by the executor are rejected. */
44
+ extraArgs?: string[];
45
+ provider?: ClaudeCodeProviderConfig;
46
+ }
47
+ /** Flags the executor sets itself; passing them through `extraArgs` would break the protocol. */
48
+ export declare const MANAGED_FLAGS: Set<string>;
49
+ /** Parses and validates `defaults.executor.config`. Throws actionable errors. */
50
+ export declare function parseConfig(value: unknown, label?: string): ClaudeCodeExecutorConfig;
51
+ export interface ProviderEnv {
52
+ /** Variables to set on the Claude Code process. */
53
+ set: Record<string, string>;
54
+ /** Inherited variables to remove so they can't override the configured provider. */
55
+ unset: string[];
56
+ /** Resolved credentials, for redaction. */
57
+ secrets: string[];
58
+ }
59
+ /**
60
+ * Maps a provider config to Claude Code environment variables, resolving the
61
+ * referenced credentials from `env` (the Vally process environment).
62
+ */
63
+ export declare function providerEnv(provider: ClaudeCodeProviderConfig, env?: NodeJS.ProcessEnv, label?: string): ProviderEnv;