harness-dispatch 0.4.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 +21 -0
- package/README.md +582 -0
- package/config.default.yaml +397 -0
- package/data/coding_benchmarks.json +431 -0
- package/dist/auth.d.ts +9 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +73 -0
- package/dist/auth.js.map +1 -0
- package/dist/billing.d.ts +7 -0
- package/dist/billing.d.ts.map +1 -0
- package/dist/billing.js +201 -0
- package/dist/billing.js.map +1 -0
- package/dist/bin.d.ts +6 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +488 -0
- package/dist/bin.js.map +1 -0
- package/dist/breaker-store.d.ts +31 -0
- package/dist/breaker-store.d.ts.map +1 -0
- package/dist/breaker-store.js +103 -0
- package/dist/breaker-store.js.map +1 -0
- package/dist/circuit-breaker.d.ts +47 -0
- package/dist/circuit-breaker.d.ts.map +1 -0
- package/dist/circuit-breaker.js +102 -0
- package/dist/circuit-breaker.js.map +1 -0
- package/dist/config.d.ts +48 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +1248 -0
- package/dist/config.js.map +1 -0
- package/dist/dashboard/live.d.ts +49 -0
- package/dist/dashboard/live.d.ts.map +1 -0
- package/dist/dashboard/live.js +149 -0
- package/dist/dashboard/live.js.map +1 -0
- package/dist/dispatch-log.d.ts +46 -0
- package/dist/dispatch-log.d.ts.map +1 -0
- package/dist/dispatch-log.js +89 -0
- package/dist/dispatch-log.js.map +1 -0
- package/dist/dispatchers/base.d.ts +55 -0
- package/dist/dispatchers/base.d.ts.map +1 -0
- package/dist/dispatchers/base.js +80 -0
- package/dist/dispatchers/base.js.map +1 -0
- package/dist/dispatchers/generic-cli.d.ts +30 -0
- package/dist/dispatchers/generic-cli.d.ts.map +1 -0
- package/dist/dispatchers/generic-cli.js +471 -0
- package/dist/dispatchers/generic-cli.js.map +1 -0
- package/dist/dispatchers/openai-compatible.d.ts +57 -0
- package/dist/dispatchers/openai-compatible.d.ts.map +1 -0
- package/dist/dispatchers/openai-compatible.js +662 -0
- package/dist/dispatchers/openai-compatible.js.map +1 -0
- package/dist/dispatchers/shared/kill-tree.d.ts +21 -0
- package/dist/dispatchers/shared/kill-tree.d.ts.map +1 -0
- package/dist/dispatchers/shared/kill-tree.js +35 -0
- package/dist/dispatchers/shared/kill-tree.js.map +1 -0
- package/dist/dispatchers/shared/rate-limit-headers.d.ts +22 -0
- package/dist/dispatchers/shared/rate-limit-headers.d.ts.map +1 -0
- package/dist/dispatchers/shared/rate-limit-headers.js +124 -0
- package/dist/dispatchers/shared/rate-limit-headers.js.map +1 -0
- package/dist/dispatchers/shared/stream-subprocess.d.ts +53 -0
- package/dist/dispatchers/shared/stream-subprocess.d.ts.map +1 -0
- package/dist/dispatchers/shared/stream-subprocess.js +274 -0
- package/dist/dispatchers/shared/stream-subprocess.js.map +1 -0
- package/dist/dispatchers/shared/subprocess.d.ts +25 -0
- package/dist/dispatchers/shared/subprocess.d.ts.map +1 -0
- package/dist/dispatchers/shared/subprocess.js +110 -0
- package/dist/dispatchers/shared/subprocess.js.map +1 -0
- package/dist/dispatchers/shared/which-available.d.ts +2 -0
- package/dist/dispatchers/shared/which-available.d.ts.map +1 -0
- package/dist/dispatchers/shared/which-available.js +8 -0
- package/dist/dispatchers/shared/which-available.js.map +1 -0
- package/dist/dispatchers/shared/windows-cmd.d.ts +38 -0
- package/dist/dispatchers/shared/windows-cmd.d.ts.map +1 -0
- package/dist/dispatchers/shared/windows-cmd.js +91 -0
- package/dist/dispatchers/shared/windows-cmd.js.map +1 -0
- package/dist/http/server.d.ts +15 -0
- package/dist/http/server.d.ts.map +1 -0
- package/dist/http/server.js +495 -0
- package/dist/http/server.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/job-runner.d.ts +19 -0
- package/dist/job-runner.d.ts.map +1 -0
- package/dist/job-runner.js +42 -0
- package/dist/job-runner.js.map +1 -0
- package/dist/jobs.d.ts +116 -0
- package/dist/jobs.d.ts.map +1 -0
- package/dist/jobs.js +542 -0
- package/dist/jobs.js.map +1 -0
- package/dist/leaderboard.d.ts +62 -0
- package/dist/leaderboard.d.ts.map +1 -0
- package/dist/leaderboard.js +287 -0
- package/dist/leaderboard.js.map +1 -0
- package/dist/mcp/config-hot-reload.d.ts +64 -0
- package/dist/mcp/config-hot-reload.d.ts.map +1 -0
- package/dist/mcp/config-hot-reload.js +144 -0
- package/dist/mcp/config-hot-reload.js.map +1 -0
- package/dist/mcp/dispatcher-factory.d.ts +20 -0
- package/dist/mcp/dispatcher-factory.d.ts.map +1 -0
- package/dist/mcp/dispatcher-factory.js +30 -0
- package/dist/mcp/dispatcher-factory.js.map +1 -0
- package/dist/mcp/resources.d.ts +8 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +45 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts +36 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +80 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +171 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +658 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/observability/index.d.ts +52 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +111 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/spans.d.ts +47 -0
- package/dist/observability/spans.d.ts.map +1 -0
- package/dist/observability/spans.js +72 -0
- package/dist/observability/spans.js.map +1 -0
- package/dist/quota.d.ts +91 -0
- package/dist/quota.d.ts.map +1 -0
- package/dist/quota.js +331 -0
- package/dist/quota.js.map +1 -0
- package/dist/route-policy.d.ts +24 -0
- package/dist/route-policy.d.ts.map +1 -0
- package/dist/route-policy.js +92 -0
- package/dist/route-policy.js.map +1 -0
- package/dist/router.d.ts +162 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +878 -0
- package/dist/router.js.map +1 -0
- package/dist/safety.d.ts +7 -0
- package/dist/safety.d.ts.map +1 -0
- package/dist/safety.js +33 -0
- package/dist/safety.js.map +1 -0
- package/dist/status.d.ts +100 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +228 -0
- package/dist/status.js.map +1 -0
- package/dist/types.d.ts +402 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +13 -0
- package/dist/version.js.map +1 -0
- package/dist/working-dir.d.ts +15 -0
- package/dist/working-dir.d.ts.map +1 -0
- package/dist/working-dir.js +22 -0
- package/dist/working-dir.js.map +1 -0
- package/dist/workspaces.d.ts +19 -0
- package/dist/workspaces.d.ts.map +1 -0
- package/dist/workspaces.js +352 -0
- package/dist/workspaces.js.map +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# harness-dispatch configuration — shipped defaults
|
|
2
|
+
#
|
|
3
|
+
# This is the config harness-dispatch ships with — not a separate "defaults
|
|
4
|
+
# registry" in some other format, just an ordinary config.yaml shape. A
|
|
5
|
+
# DIFFERENT file from your own config.yaml on purpose: this one is tracked
|
|
6
|
+
# and updated by the package itself, yours is gitignored/untouched by
|
|
7
|
+
# updates and may hold secrets/local overrides — keeping them separate means
|
|
8
|
+
# neither ever clobbers the other. The entries below are both the built-in
|
|
9
|
+
# defaults and the worked examples of the pattern. With no config.yaml of
|
|
10
|
+
# your own, the router uses this file directly, filtered by which CLIs are
|
|
11
|
+
# actually installed. To customize, copy this file to config.yaml in your
|
|
12
|
+
# own project and edit — or run `harness-dispatch configure` to generate a
|
|
13
|
+
# starting point instead. Same schema, same parser, no special cases either
|
|
14
|
+
# way. Add a new entry and it's a route; delete one and it's gone.
|
|
15
|
+
#
|
|
16
|
+
# Route selection scores each entry by task fit:
|
|
17
|
+
# capabilities[task_type] x leaderboard ELO x cli_capability x quota x weight
|
|
18
|
+
# Billing safety: routes that can cost money (metered api_key, unknown billing)
|
|
19
|
+
# stay blocked until you set allow_paid_usage: true on them. Product-login CLIs
|
|
20
|
+
# (Claude Code, Codex, Cursor) run by default — their providers hard-stop at
|
|
21
|
+
# your plan's included usage.
|
|
22
|
+
#
|
|
23
|
+
# ${ENV_VAR} anywhere in a string value is replaced from the environment.
|
|
24
|
+
|
|
25
|
+
clis:
|
|
26
|
+
# ── Claude Code ─────────────────────────────────────────────────────────────
|
|
27
|
+
# Best for plan + review (extended thinking). Subscription auth via the CLI's
|
|
28
|
+
# own login; add api_key: ${ANTHROPIC_API_KEY} only for API billing.
|
|
29
|
+
- name: claude_code_cli
|
|
30
|
+
harness: claude_code
|
|
31
|
+
command: claude
|
|
32
|
+
model_hint: >-
|
|
33
|
+
Anthropic model family only. Current model ids:
|
|
34
|
+
https://platform.claude.com/docs/en/docs/about-claude/models/overview
|
|
35
|
+
(e.g. claude-opus-4-8, claude-sonnet-5) — the installed claude CLI may
|
|
36
|
+
lag behind what's newly listed there.
|
|
37
|
+
leaderboard_model: claude-opus-4-6
|
|
38
|
+
cli_capability: 1.1
|
|
39
|
+
tier: 1
|
|
40
|
+
capabilities: { execute: 0.95, plan: 1.0, review: 1.0 }
|
|
41
|
+
max_output_tokens: 64000
|
|
42
|
+
max_input_tokens: 1000000 # Opus + Sonnet 1M context
|
|
43
|
+
provider: anthropic
|
|
44
|
+
surface: claude_agent_sdk
|
|
45
|
+
auth_source: oauth_session
|
|
46
|
+
# protocol: is the full invocation template — args is a literal command
|
|
47
|
+
# line; {{tokens}} are substituted at dispatch time (see the reference at
|
|
48
|
+
# the bottom of this file).
|
|
49
|
+
protocol:
|
|
50
|
+
args: ["-p", "{{prompt}}", "--output-format", "json", "{{safety}}", "{{model}}"]
|
|
51
|
+
model: { flag: "--model" }
|
|
52
|
+
safety:
|
|
53
|
+
read_only: ["--allowedTools", "Read", "--permission-mode", "plan"]
|
|
54
|
+
workspace_edit: ["--allowedTools", "Read,Edit,Write", "--permission-mode", "acceptEdits"]
|
|
55
|
+
full_auto: ["--allowedTools", "Bash,Read,Edit,Write", "--permission-mode", "acceptEdits"]
|
|
56
|
+
# Claude Code reads ANTHROPIC_API_KEY itself to switch from
|
|
57
|
+
# subscription/OAuth session auth to API-key billing — without this,
|
|
58
|
+
# setting api_key: on the route reclassified billing to metered_api
|
|
59
|
+
# (blocking it) while the CLI kept silently using subscription auth.
|
|
60
|
+
api_key_env_var: ANTHROPIC_API_KEY
|
|
61
|
+
file_list_header: "Files to work with:"
|
|
62
|
+
file_list_bullet: " "
|
|
63
|
+
output:
|
|
64
|
+
mode: json_field
|
|
65
|
+
fields: [result, response, text]
|
|
66
|
+
usage: { input: [usage.input_tokens], output: [usage.output_tokens] }
|
|
67
|
+
# Confirmed live 2026-07-24: a successful response carries a sibling
|
|
68
|
+
# "is_error": false (and "api_error_status": null) alongside "result"
|
|
69
|
+
# — without this, an API-level failure that still exits 0 would be
|
|
70
|
+
# reported as success (success_requires_output: false takes ANY
|
|
71
|
+
# exit-0 output as a win, including an error's own JSON text).
|
|
72
|
+
# message_fields omitted deliberately: the error text lands in the
|
|
73
|
+
# same "result" field as a successful answer, already covered above.
|
|
74
|
+
error: { field: is_error }
|
|
75
|
+
success_requires_output: false
|
|
76
|
+
|
|
77
|
+
# ── Codex ───────────────────────────────────────────────────────────────────
|
|
78
|
+
# Best for execute — full-auto drives code + tests in a loop. Streams NDJSON
|
|
79
|
+
# events mid-run; event_rules below surface tool_use/thinking/usage live.
|
|
80
|
+
- name: codex_cli
|
|
81
|
+
harness: codex
|
|
82
|
+
command: codex
|
|
83
|
+
model_hint: >-
|
|
84
|
+
OpenAI/Codex model family only. Current model ids:
|
|
85
|
+
https://developers.openai.com/api/docs/models (e.g. gpt-5.6-sol,
|
|
86
|
+
gpt-5.6-terra) — the installed codex CLI may lag behind what's newly
|
|
87
|
+
listed there.
|
|
88
|
+
leaderboard_model: gpt-5.4
|
|
89
|
+
cli_capability: 1.08
|
|
90
|
+
tier: 1
|
|
91
|
+
capabilities: { execute: 1.0, plan: 0.83, review: 0.82 }
|
|
92
|
+
max_output_tokens: 128000
|
|
93
|
+
max_input_tokens: 400000
|
|
94
|
+
provider: openai
|
|
95
|
+
surface: codex_cli
|
|
96
|
+
auth_source: product_login
|
|
97
|
+
billing_kind: included_plan_then_flexible_credits
|
|
98
|
+
# OpenAI hard-stops at the plan's included usage unless you enabled
|
|
99
|
+
# flexible-credit overage on your account — set true here if you did.
|
|
100
|
+
paid_usage_possible: false
|
|
101
|
+
protocol:
|
|
102
|
+
# "exec" is Codex's required subcommand; trailing "-" = read prompt from
|
|
103
|
+
# stdin (stdin: true below).
|
|
104
|
+
args: ["exec", "{{native_args}}", "{{safety}}", "{{model}}", "{{working_dir}}", "--json", "-"]
|
|
105
|
+
stdin: true
|
|
106
|
+
working_dir: { flag: "--cd", extra_args_when_set: ["--skip-git-repo-check"] }
|
|
107
|
+
model: { flag: "--model" }
|
|
108
|
+
safety:
|
|
109
|
+
read_only: ["--sandbox", "read-only"]
|
|
110
|
+
workspace_edit: ["--sandbox", "workspace-write"]
|
|
111
|
+
full_auto: ["--full-auto"]
|
|
112
|
+
api_key_env_var: OPENAI_API_KEY
|
|
113
|
+
file_list_header: "Files to work with:"
|
|
114
|
+
file_list_bullet: " "
|
|
115
|
+
output:
|
|
116
|
+
mode: jsonl_stream
|
|
117
|
+
event_rules:
|
|
118
|
+
- when: { type: "item.completed", "item.type": "agent_message" }
|
|
119
|
+
emit: text
|
|
120
|
+
text_field: item.text
|
|
121
|
+
- when: { type: "message" }
|
|
122
|
+
emit: text
|
|
123
|
+
text_field: message.content
|
|
124
|
+
- when: { "item.type": "tool_use" }
|
|
125
|
+
emit: tool_use
|
|
126
|
+
name_field: item.name
|
|
127
|
+
input_field: item.input
|
|
128
|
+
- when: { type: "thinking" }
|
|
129
|
+
emit: thinking
|
|
130
|
+
chunk_field: item.text
|
|
131
|
+
- when: {} # unconditional — fires on every line carrying usage
|
|
132
|
+
emit: usage
|
|
133
|
+
input_token_fields: [usage.input_tokens, usage.prompt_tokens]
|
|
134
|
+
output_token_fields: [usage.output_tokens, usage.completion_tokens]
|
|
135
|
+
# Real shapes confirmed live 2026-07-24 against an actually-exhausted
|
|
136
|
+
# account: {"type":"error","message":"You've hit your usage
|
|
137
|
+
# limit..."} followed by {"type":"turn.failed","error":{"message":
|
|
138
|
+
# "..."}}. Without these, the dispatcher never sees either frame —
|
|
139
|
+
# it falls back to stderr text (just "Reading additional input from
|
|
140
|
+
# stdin..." noise) and reports a useless, unclassifiable failure.
|
|
141
|
+
- when: { type: "error" }
|
|
142
|
+
emit: error
|
|
143
|
+
message_field: message
|
|
144
|
+
- when: { type: "turn.failed" }
|
|
145
|
+
emit: error
|
|
146
|
+
message_field: error.message
|
|
147
|
+
success_requires_output: false
|
|
148
|
+
# Used only when a route runs endpoint_mode: harness_native_endpoint
|
|
149
|
+
# against a matching endpoint_provider (see codex_ollama example below).
|
|
150
|
+
endpoint_native_args:
|
|
151
|
+
ollama: ["--oss", "--local-provider", "ollama"]
|
|
152
|
+
lmstudio: ["--oss", "--local-provider", "lmstudio"]
|
|
153
|
+
|
|
154
|
+
# ── Cursor ──────────────────────────────────────────────────────────────────
|
|
155
|
+
# Best for execute with editor-aware codebase indexing. Note: Cursor print
|
|
156
|
+
# mode has write+shell capability, so these routes run under full_auto —
|
|
157
|
+
# they're skipped for read_only/workspace_edit requests.
|
|
158
|
+
- name: cursor_cli
|
|
159
|
+
harness: cursor
|
|
160
|
+
command: cursor-agent
|
|
161
|
+
model_hint: >-
|
|
162
|
+
Wide multi-vendor catalog. Current model ids and pricing:
|
|
163
|
+
https://cursor.com/docs/models — or run `cursor-agent --list-models`
|
|
164
|
+
for what's actually available on this install.
|
|
165
|
+
leaderboard_model: claude-sonnet-4-6
|
|
166
|
+
cli_capability: 1.05
|
|
167
|
+
tier: 1
|
|
168
|
+
capabilities: { execute: 1.0, plan: 0.82, review: 0.9 }
|
|
169
|
+
max_output_tokens: 64000
|
|
170
|
+
max_input_tokens: 1000000
|
|
171
|
+
provider: cursor
|
|
172
|
+
surface: cursor_agent_cli
|
|
173
|
+
auth_source: product_login
|
|
174
|
+
billing_kind: included_usage_then_on_demand
|
|
175
|
+
# Cursor hard-stops at the plan's included pool unless on-demand billing is
|
|
176
|
+
# enabled in Settings -> Billing -> Spending — set true here if you did.
|
|
177
|
+
paid_usage_possible: false
|
|
178
|
+
# Capability floor: cursor-agent print mode always has write+shell
|
|
179
|
+
# capability, so this route only serves requests that allow full_auto —
|
|
180
|
+
# it is skipped (safety_incompatible) for read_only/workspace_edit calls.
|
|
181
|
+
# Override here if a future cursor-agent grows restricted modes.
|
|
182
|
+
effective_safety: full_auto
|
|
183
|
+
protocol:
|
|
184
|
+
# -p is Cursor's boolean "print mode" flag; the prompt itself is the
|
|
185
|
+
# trailing positional {{prompt}}.
|
|
186
|
+
args: ["-p", "--trust", "{{working_dir}}", "--output-format", "json", "{{model}}", "{{prompt}}"]
|
|
187
|
+
# cursor-agent needs SOME --workspace value even with no workingDir —
|
|
188
|
+
# fall back to the user's home directory.
|
|
189
|
+
working_dir: { flag: "--workspace", fallback: home }
|
|
190
|
+
model: { flag: "--model" }
|
|
191
|
+
api_key_env_var: CURSOR_API_KEY
|
|
192
|
+
file_list_header: "Focus on these files:"
|
|
193
|
+
file_list_bullet: " - "
|
|
194
|
+
output:
|
|
195
|
+
mode: json_field
|
|
196
|
+
fields: [result, output, text]
|
|
197
|
+
usage: { input: [usage.input_tokens, usage.prompt_tokens], output: [usage.output_tokens, usage.completion_tokens] }
|
|
198
|
+
# success_requires_output omitted -> strict: exit 0 with no parseable
|
|
199
|
+
# output still counts as failure.
|
|
200
|
+
# No protocol.output.error entry: unlike Codex/Claude Code above (both
|
|
201
|
+
# verified live 2026-07-24 against real exhausted-quota responses),
|
|
202
|
+
# cursor-agent isn't installed on this machine to capture its actual
|
|
203
|
+
# on-quota-exhaustion JSON shape — deliberately not guessing one. A
|
|
204
|
+
# real Cursor exhaustion still falls through to detectRateLimit's raw
|
|
205
|
+
# text scan (rate limit/quota exceeded/usage limit/429), just without
|
|
206
|
+
# a structured message or forced-failure-past-exit-0 override.
|
|
207
|
+
|
|
208
|
+
# ── Antigravity ─────────────────────────────────────────────────────────────
|
|
209
|
+
# Google's successor to Gemini CLI (shut down 2026-06-18). Best for plan +
|
|
210
|
+
# review — 1M+ context holds whole codebases; free_quota billing. Model
|
|
211
|
+
# selection lives in the agy CLI's own config, not per route.
|
|
212
|
+
- name: antigravity_cli
|
|
213
|
+
harness: antigravity_cli
|
|
214
|
+
command: agy
|
|
215
|
+
model_hint: >-
|
|
216
|
+
Cross-vendor catalog (Gemini plus some Claude/GPT-OSS models). Gemini's
|
|
217
|
+
portion: https://ai.google.dev/gemini-api/docs/models; check the agy
|
|
218
|
+
CLI's own docs for the rest.
|
|
219
|
+
leaderboard_model: gemini-3.1-pro-preview # closest benchmarked model, for scoring
|
|
220
|
+
cli_capability: 1.0
|
|
221
|
+
tier: 1
|
|
222
|
+
capabilities: { execute: 0.87, plan: 0.97, review: 0.95 }
|
|
223
|
+
max_output_tokens: 65536
|
|
224
|
+
max_input_tokens: 2000000
|
|
225
|
+
provider: google
|
|
226
|
+
surface: antigravity_cli
|
|
227
|
+
auth_source: product_login
|
|
228
|
+
billing_kind: free_quota
|
|
229
|
+
paid_usage_possible: false
|
|
230
|
+
protocol:
|
|
231
|
+
args: ["{{model}}", "{{safety}}", "{{working_dir}}", "{{file_dirs}}", "--print", "{{prompt}}"]
|
|
232
|
+
# --print is headless: agy cannot prompt for per-tool permissions, so
|
|
233
|
+
# every profile needs auto-approval or tools are silently auto-denied
|
|
234
|
+
# ("a tool required the read_file permission that headless mode cannot
|
|
235
|
+
# prompt for"). read_only stays safe via --mode plan --sandbox (blocks
|
|
236
|
+
# writes/shell); the skip-permissions flag just lets reads proceed.
|
|
237
|
+
working_dir: { flag: "--add-dir" }
|
|
238
|
+
file_dirs: { flag: "--add-dir" }
|
|
239
|
+
model: { flag: "--model" }
|
|
240
|
+
safety:
|
|
241
|
+
read_only: ["--mode", "plan", "--sandbox", "--dangerously-skip-permissions"]
|
|
242
|
+
workspace_edit: ["--mode", "accept-edits", "--dangerously-skip-permissions"]
|
|
243
|
+
full_auto: ["--dangerously-skip-permissions"]
|
|
244
|
+
file_list_header: "Files to work with:"
|
|
245
|
+
file_list_bullet: " "
|
|
246
|
+
output:
|
|
247
|
+
mode: text
|
|
248
|
+
success_requires_output: false
|
|
249
|
+
|
|
250
|
+
# ── More routes from the same harnesses ─────────────────────────────────────
|
|
251
|
+
# A route is (harness, model) — declare as many as you want. `harness:` picks
|
|
252
|
+
# up everything from the matching entry above (including protocol), so a
|
|
253
|
+
# variant is a few lines:
|
|
254
|
+
#
|
|
255
|
+
# - name: codex_sol
|
|
256
|
+
# harness: codex
|
|
257
|
+
# model: gpt-5.6-sol
|
|
258
|
+
# tier: 1
|
|
259
|
+
# weight: 0.9
|
|
260
|
+
#
|
|
261
|
+
# - name: codex_ollama # Codex harness driving a local Ollama model
|
|
262
|
+
# harness: codex
|
|
263
|
+
# model: qwen3-coder:latest
|
|
264
|
+
# endpoint_mode: harness_native_endpoint
|
|
265
|
+
# endpoint_provider: ollama
|
|
266
|
+
# billing_kind: local_compute
|
|
267
|
+
# tier: 3
|
|
268
|
+
|
|
269
|
+
# ── A wholly new CLI harness ────────────────────────────────────────────────
|
|
270
|
+
# harness: generic + your own protocol: block — no code changes. protocol.args
|
|
271
|
+
# is written the way you'd type the command line; reserved {{tokens}}:
|
|
272
|
+
#
|
|
273
|
+
# {{prompt}} the prompt text (omitted from args if stdin: true)
|
|
274
|
+
# {{model}} [model.flag, value] if a model is set, else nothing
|
|
275
|
+
# {{safety}} safety[requested profile], zero or more tokens
|
|
276
|
+
# {{working_dir}} [working_dir.flag, dir, ...extra_args_when_set] if set
|
|
277
|
+
# {{file_dirs}} [file_dirs.flag, dir] per unique file directory
|
|
278
|
+
# {{native_args}} endpoint_native_args[endpoint_provider] under
|
|
279
|
+
# endpoint_mode: harness_native_endpoint
|
|
280
|
+
#
|
|
281
|
+
# Everything else in args passes through literally. You can also reuse an
|
|
282
|
+
# entry above by name (protocol: cursor) or extend one (protocol: { extends:
|
|
283
|
+
# codex, model: { flag: "--llm-model" } }) — safety merges per-profile.
|
|
284
|
+
# See README.md#adding-a-harness for the full reference.
|
|
285
|
+
#
|
|
286
|
+
# - name: my_cli
|
|
287
|
+
# harness: generic
|
|
288
|
+
# command: my-cli
|
|
289
|
+
# tier: 3
|
|
290
|
+
# protocol:
|
|
291
|
+
# args: ["-p", "{{prompt}}", "{{model}}", "--json"]
|
|
292
|
+
# model: { flag: "--model" }
|
|
293
|
+
# output: { mode: json_field, fields: [result] }
|
|
294
|
+
|
|
295
|
+
endpoints:
|
|
296
|
+
# OpenAI-compatible HTTP endpoints — local or hosted. Same idea: an entry is
|
|
297
|
+
# a route. Endpoints are structurally read_only (no agent loop or file
|
|
298
|
+
# access), so they serve plan/review calls, never execute.
|
|
299
|
+
#
|
|
300
|
+
# - name: ollama
|
|
301
|
+
# base_url: http://localhost:11434/v1
|
|
302
|
+
# model: llama3.2
|
|
303
|
+
# billing_kind: local_compute
|
|
304
|
+
# tier: 3
|
|
305
|
+
#
|
|
306
|
+
# - name: lmstudio
|
|
307
|
+
# base_url: http://localhost:1234/v1
|
|
308
|
+
# model: mistral-7b-instruct
|
|
309
|
+
# api_key: lm-studio
|
|
310
|
+
# billing_kind: local_compute
|
|
311
|
+
# tier: 3
|
|
312
|
+
#
|
|
313
|
+
# - name: gemini_api # AI Studio direct (free tier)
|
|
314
|
+
# base_url: https://generativelanguage.googleapis.com/v1beta/openai
|
|
315
|
+
# model: gemini-2.5-flash
|
|
316
|
+
# api_key: ${GEMINI_API_KEY}
|
|
317
|
+
# billing_kind: free_quota
|
|
318
|
+
# tier: 3
|
|
319
|
+
#
|
|
320
|
+
# - name: openrouter # metered — blocked until you opt in
|
|
321
|
+
# base_url: https://openrouter.ai/api/v1
|
|
322
|
+
# model: openai/gpt-5.4
|
|
323
|
+
# api_key: ${OPENROUTER_API_KEY}
|
|
324
|
+
# allow_paid_usage: true
|
|
325
|
+
# tier: 1
|
|
326
|
+
#
|
|
327
|
+
# - name: nvidia_nim # NVIDIA-hosted models (build.nvidia.com)
|
|
328
|
+
# base_url: https://integrate.api.nvidia.com/v1
|
|
329
|
+
# model: qwen/qwen3-coder-480b-a35b-instruct # any model id from build.nvidia.com
|
|
330
|
+
# api_key: ${NVIDIA_API_KEY}
|
|
331
|
+
# allow_paid_usage: true # metered API key -> blocked until you opt in
|
|
332
|
+
# tier: 2
|
|
333
|
+
# # Optional, both surfaced to calling agents via the `usage` tool. `usage`
|
|
334
|
+
# # with listModels: nvidia_nim returns this models: list VERBATIM, no
|
|
335
|
+
# # network call — declaring it overrides live discovery, e.g. to pin
|
|
336
|
+
# # specific ids or because the endpoint's live /models is noisy/untrusted.
|
|
337
|
+
# # Omit models: and listModels instead does a live GET {base_url}/models
|
|
338
|
+
# # (key stays server-side either way). model_hint points humans/agents at
|
|
339
|
+
# # the full catalog for picking new ids to add here.
|
|
340
|
+
# models: [qwen/qwen3-coder-480b-a35b-instruct]
|
|
341
|
+
# model_hint: "Full catalog: https://build.nvidia.com/models"
|
|
342
|
+
#
|
|
343
|
+
# - name: anthropic_api # Claude via the direct Anthropic API
|
|
344
|
+
# base_url: https://api.anthropic.com/v1
|
|
345
|
+
# model: claude-opus-4-6
|
|
346
|
+
# api_key: ${ANTHROPIC_API_KEY}
|
|
347
|
+
# wire_protocol: anthropic_messages # see below — different from the default
|
|
348
|
+
# allow_paid_usage: true # metered API key -> blocked until you opt in
|
|
349
|
+
# max_output_tokens: 8192 # required by the Messages API; defaults to 8192 if omitted
|
|
350
|
+
# tier: 1
|
|
351
|
+
#
|
|
352
|
+
# wire_protocol picks which request/response shape this endpoint speaks:
|
|
353
|
+
#
|
|
354
|
+
# openai_chat_completions (default) POST {base_url}/chat/completions,
|
|
355
|
+
# Authorization: Bearer <api_key>, OpenAI's messages[]/choices[] shape.
|
|
356
|
+
# Covers Ollama, LM Studio, OpenRouter, NVIDIA NIM, Gemini's OpenAI-
|
|
357
|
+
# compatible endpoint, and most other hosted/local model servers.
|
|
358
|
+
#
|
|
359
|
+
# anthropic_messages POST {base_url}/messages, x-api-key + anthropic-
|
|
360
|
+
# version headers (NOT Bearer), system prompt at the top level (not a
|
|
361
|
+
# messages[] entry), max_tokens required, content: [{type,text}] +
|
|
362
|
+
# usage: {input_tokens,output_tokens} response shape. Use this for
|
|
363
|
+
# Anthropic's own API or any third-party host that mirrors its
|
|
364
|
+
# Messages API. thinking_level isn't translated to Anthropic's
|
|
365
|
+
# extended-thinking parameter yet.
|
|
366
|
+
#
|
|
367
|
+
# - name: claude_compatible_host # a third party serving the Anthropic shape
|
|
368
|
+
# base_url: https://your-host.example.com/v1
|
|
369
|
+
# model: claude-opus-4-6
|
|
370
|
+
# api_key: ${CLAUDE_COMPATIBLE_API_KEY}
|
|
371
|
+
# wire_protocol: anthropic_messages
|
|
372
|
+
# allow_paid_usage: true
|
|
373
|
+
# tier: 2
|
|
374
|
+
|
|
375
|
+
# ── Global settings ───────────────────────────────────────────────────────────
|
|
376
|
+
|
|
377
|
+
# OpenTelemetry traces — OFF by default. Purely local operator observability:
|
|
378
|
+
# only useful if you run an OTLP collector (Jaeger, Tempo, ...) on
|
|
379
|
+
# localhost:4318 (or point OTEL_EXPORTER_OTLP_ENDPOINT elsewhere). Nothing is
|
|
380
|
+
# ever sent anywhere unless you enable this AND run a collector.
|
|
381
|
+
# telemetry:
|
|
382
|
+
# enabled: true
|
|
383
|
+
|
|
384
|
+
# How long job artifacts (~/.harness-dispatch/jobs: manifests, stdout/stderr
|
|
385
|
+
# logs, workspace snapshots) are kept before being pruned. Default: 7 days.
|
|
386
|
+
# The dispatch log (~/.harness-dispatch/logs/dispatches.jsonl) is size-capped
|
|
387
|
+
# at ~5MB with one rotation instead of time-based.
|
|
388
|
+
# retention:
|
|
389
|
+
# jobs_days: 7
|
|
390
|
+
|
|
391
|
+
# Per-route knobs worth knowing (all optional, all shown in the entries above
|
|
392
|
+
# or README.md): enabled, weight, timeout_ms, safety_profile, effective_safety,
|
|
393
|
+
# workspace_policy (shared | shared_locked | copy | git_worktree),
|
|
394
|
+
# thinking_level, escalate_on, allow_paid_usage, billing_kind,
|
|
395
|
+
# paid_usage_possible.
|
|
396
|
+
#
|
|
397
|
+
# disabled: [route_name, ...] hides an entry without deleting it.
|