Skip to content

Commit 6844540

Browse files
jobordujoborduclaude
authored
chore(providers): retire ccr-1..ccr-6 from default fleet (#147)
* chore(providers): retire ccr-1..ccr-6 from default fleet Removes the 6 Together.xyz-routed Claude Code Router slots from bin/providers.json. They were shipped as the default fleet but should have been opt-in — keeping them in the default install silently consumed user TOGETHER_API_KEY and added 6 always-on MCP servers regardless of whether the user wanted CCR. CCR feature support is unchanged: - /nf:mcp-setup still offers ccr-1..ccr-6 templates as configurable options (now with a "not pre-installed" preamble) - bin/quorum-slot-dispatch.cjs's CCR routing logic still detects any slot with display_type=claude-code-router (unchanged) - bin/manage-agents-core.cjs CCR_KEY_NAMES (AkashML, Together, Fireworks) still drives the wizard's API-key prompts Cascading edits: - bin/providers.json: 11 → 5 entries (codex-1, gemini-1, opencode-1, copilot-1, claude-1) - bin/provider-mapping.test.cjs: the "at least one provider maps to 2+ slots" assertion was a fixture-only check that broke when ccr-1..6 (all together-routed) were dropped. Rewritten to test groupByProvider with synthetic data — the production providers.json keeping a 1:1 slot:provider mapping is fine. - commands/nf/mcp-setup.md: added a "not pre-installed" preamble to the Together.xyz wizard table; menu options still work — picking one writes the slot to ~/.claude/nf/bin/providers.json on demand. - commands/nf/mcp-update.md, mcp-repair.md: human-facing example outputs switched from ccr-* to default-fleet slots (codex-1, claude-1, etc.). allowed-tools frontmatter listings of mcp__ccr-N__* are LEFT IN PLACE — they're idempotent permissions (no-op when slot doesn't exist; useful when user adds it via /nf:mcp-setup). - bin/manage-agents-core.cjs / bin/quorum-preflight.cjs: comment cleanup (s/ccr-1..ccr-6/multiple ccr-* slots/) so the example references read forward-compatibly. Test status: full suite 1541/1541 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: update .secrets.baseline after line-number drift Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: jobordu <jonathan@jonathanborduas.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 85b34f3 commit 6844540

8 files changed

Lines changed: 35 additions & 274 deletions

File tree

.secrets.baseline

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@
240240
"filename": "bin/manage-agents-core.cjs",
241241
"hashed_secret": "32df82dccdd26b62d92eaefa9ccc2550d5ec96bd",
242242
"is_verified": false,
243-
"line_number": 454
243+
"line_number": 455
244244
}
245245
],
246246
"bin/manage-agents.test.cjs": [
@@ -391,5 +391,5 @@
391391
}
392392
]
393393
},
394-
"generated_at": "2026-04-23T07:59:26Z"
394+
"generated_at": "2026-05-01T19:11:19Z"
395395
}

bin/manage-agents-core.cjs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,9 @@ function writeProvidersJson(data) {
346346
* in unified-mcp-server.mjs so that resolvedCli is populated before probing.
347347
* If resolvedCli is absent (e.g. called out-of-order or in isolation), the raw `cli`
348348
* field is used as a best-effort fallback. Test with fs.accessSync(path, fs.constants.X_OK).
349-
* - De-duplicate probes: slots sharing the same binary path (e.g. ccr-1..ccr-6 all use
350-
* /opt/homebrew/bin/ccr) check the filesystem only once per unique path.
349+
* - De-duplicate probes: slots sharing the same binary path (e.g. multiple ccr-* slots
350+
* added by /nf:mcp-setup that all point at /opt/homebrew/bin/ccr) check the filesystem
351+
* only once per unique path.
351352
* - Fail-open: any unexpected error returns the full providers list unchanged.
352353
*
353354
* @param {Array} providers - array of provider objects from providers.json

bin/provider-mapping.test.cjs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -149,16 +149,21 @@ test('providers.json: provider field values are canonical kebab-case (lowercase-
149149
}
150150
});
151151

152-
test('providers.json: at least one provider maps to 2+ slots (verifying grouping)', () => {
153-
assert.ok(providers.length > 0, 'providers.json is empty or unreadable');
154-
155-
const groupedByProvider = groupByProvider(providers);
156-
const multiSlotProvider = Object.entries(groupedByProvider).find(([, slots]) => slots.length >= 2);
157-
158-
assert.ok(
159-
multiSlotProvider,
160-
'No provider maps to 2+ slots — Plan 03 must ensure at least one provider has multiple slots for testing provider-skip logic'
161-
);
152+
test('groupByProvider: groups multi-slot fixture into one entry (provider-skip prerequisite)', () => {
153+
// Plan 03 needs provider-skip logic to work when 2+ slots share a provider. The shipped
154+
// providers.json no longer has any multi-slot provider (the ccr-1..ccr-6 fleet was removed),
155+
// so this assertion now uses a synthetic fixture to verify grouping works correctly.
156+
// The production providers.json keeping a 1:1 slot:provider mapping is fine — the runtime
157+
// behavior is exercised when users add their own ccr-* or other multi-slot configurations.
158+
const fixture = [
159+
{ name: 'ccr-1', provider: 'together' },
160+
{ name: 'ccr-2', provider: 'together' },
161+
{ name: 'codex-1', provider: 'openai' },
162+
];
163+
const grouped = groupByProvider(fixture);
164+
assert.equal(Object.keys(grouped).length, 2, 'must produce 2 provider buckets');
165+
assert.equal(grouped.together.length, 2, 'together must have 2 slots');
166+
assert.equal(grouped.openai.length, 1, 'openai must have 1 slot');
162167
});
163168

164169
const NF_PROMPT_PATH = path.resolve(__dirname, '../hooks/nf-prompt.js');

bin/providers.json

Lines changed: 0 additions & 252 deletions
Original file line numberDiff line numberDiff line change
@@ -325,258 +325,6 @@
325325
"expect": "PROBE_OK",
326326
"timeout_ms": 45000
327327
}
328-
},
329-
{
330-
"name": "ccr-1",
331-
"provider": "together",
332-
"type": "subprocess",
333-
"auth_type": "sub",
334-
"has_file_access": true,
335-
"description": "MiniMax-M2.5 via Together.xyz — Claude Code Router (CCR) preset claude-1",
336-
"mainTool": "claude",
337-
"model": "MiniMaxAI/MiniMax-M2.5",
338-
"display_provider": "Together.xyz",
339-
"cli": null,
340-
"args_template": [
341-
"claude-1",
342-
"-p",
343-
"{prompt}",
344-
"--dangerously-skip-permissions"
345-
],
346-
"health_check_args": [
347-
"-v"
348-
],
349-
"helpArgs": [
350-
"--help"
351-
],
352-
"extraTools": [],
353-
"timeout_ms": 300000,
354-
"quorum_timeout_ms": 300000,
355-
"idle_timeout_ms": 90000,
356-
"hard_timeout_ms": 600000,
357-
"latency_budget_ms": null,
358-
"max_context_tokens": 131072,
359-
"max_output_tokens": 4096,
360-
"max_concurrency": 3,
361-
"ccr_overhead_tokens": 95000,
362-
"ccr_response_budget_tokens": 64000,
363-
"env": {},
364-
"display_type": "claude-code-router",
365-
"deep_probe": {
366-
"prompt": "respond with: PROBE_OK",
367-
"expect": "PROBE_OK",
368-
"timeout_ms": 45000
369-
}
370-
},
371-
{
372-
"name": "ccr-2",
373-
"provider": "together",
374-
"type": "subprocess",
375-
"auth_type": "sub",
376-
"has_file_access": true,
377-
"description": "Qwen3.5-397B via Together.xyz — Claude Code Router (CCR) preset claude-2",
378-
"mainTool": "claude",
379-
"model": "Qwen/Qwen3.5-397B-A17B",
380-
"display_provider": "Together.xyz",
381-
"cli": null,
382-
"args_template": [
383-
"claude-2",
384-
"-p",
385-
"{prompt}",
386-
"--dangerously-skip-permissions"
387-
],
388-
"health_check_args": [
389-
"-v"
390-
],
391-
"helpArgs": [
392-
"--help"
393-
],
394-
"extraTools": [],
395-
"timeout_ms": 300000,
396-
"quorum_timeout_ms": 300000,
397-
"idle_timeout_ms": 90000,
398-
"hard_timeout_ms": 600000,
399-
"latency_budget_ms": null,
400-
"max_context_tokens": 131072,
401-
"max_output_tokens": 4096,
402-
"max_concurrency": 3,
403-
"ccr_overhead_tokens": 95000,
404-
"ccr_response_budget_tokens": 64000,
405-
"env": {},
406-
"display_type": "claude-code-router",
407-
"deep_probe": {
408-
"prompt": "respond with: PROBE_OK",
409-
"expect": "PROBE_OK",
410-
"timeout_ms": 45000
411-
}
412-
},
413-
{
414-
"name": "ccr-3",
415-
"provider": "together",
416-
"type": "subprocess",
417-
"auth_type": "sub",
418-
"has_file_access": true,
419-
"description": "Qwen3-Coder-480B via Together.xyz — Claude Code Router (CCR) preset claude-3",
420-
"mainTool": "claude",
421-
"model": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8",
422-
"display_provider": "Together.xyz",
423-
"cli": null,
424-
"args_template": [
425-
"claude-3",
426-
"-p",
427-
"{prompt}",
428-
"--dangerously-skip-permissions"
429-
],
430-
"health_check_args": [
431-
"-v"
432-
],
433-
"helpArgs": [
434-
"--help"
435-
],
436-
"extraTools": [],
437-
"timeout_ms": 300000,
438-
"quorum_timeout_ms": 300000,
439-
"idle_timeout_ms": 90000,
440-
"hard_timeout_ms": 600000,
441-
"latency_budget_ms": null,
442-
"max_context_tokens": 131072,
443-
"max_output_tokens": 4096,
444-
"max_concurrency": 3,
445-
"ccr_overhead_tokens": 95000,
446-
"ccr_response_budget_tokens": 64000,
447-
"env": {},
448-
"display_type": "claude-code-router",
449-
"deep_probe": {
450-
"prompt": "respond with: PROBE_OK",
451-
"expect": "PROBE_OK",
452-
"timeout_ms": 45000
453-
}
454-
},
455-
{
456-
"name": "ccr-4",
457-
"provider": "together",
458-
"type": "subprocess",
459-
"auth_type": "sub",
460-
"has_file_access": true,
461-
"description": "Kimi-K2.5 via Together.xyz — Claude Code Router (CCR) preset claude-4",
462-
"mainTool": "claude",
463-
"model": "moonshotai/Kimi-K2.5",
464-
"display_provider": "Together.xyz",
465-
"cli": null,
466-
"args_template": [
467-
"claude-4",
468-
"-p",
469-
"{prompt}",
470-
"--dangerously-skip-permissions"
471-
],
472-
"health_check_args": [
473-
"-v"
474-
],
475-
"helpArgs": [
476-
"--help"
477-
],
478-
"extraTools": [],
479-
"timeout_ms": 300000,
480-
"quorum_timeout_ms": 300000,
481-
"idle_timeout_ms": 90000,
482-
"hard_timeout_ms": 600000,
483-
"latency_budget_ms": null,
484-
"max_context_tokens": 131072,
485-
"max_output_tokens": 4096,
486-
"max_concurrency": 3,
487-
"ccr_overhead_tokens": 95000,
488-
"ccr_response_budget_tokens": 64000,
489-
"env": {},
490-
"display_type": "claude-code-router",
491-
"deep_probe": {
492-
"prompt": "respond with: PROBE_OK",
493-
"expect": "PROBE_OK",
494-
"timeout_ms": 45000
495-
}
496-
},
497-
{
498-
"name": "ccr-5",
499-
"provider": "together",
500-
"type": "subprocess",
501-
"auth_type": "sub",
502-
"has_file_access": true,
503-
"description": "GPT-OSS-120B via Together.xyz — Claude Code Router (CCR) preset claude-5",
504-
"mainTool": "claude",
505-
"model": "openai/gpt-oss-120b",
506-
"display_provider": "Together.xyz",
507-
"cli": null,
508-
"args_template": [
509-
"claude-5",
510-
"-p",
511-
"{prompt}",
512-
"--dangerously-skip-permissions"
513-
],
514-
"health_check_args": [
515-
"-v"
516-
],
517-
"helpArgs": [
518-
"--help"
519-
],
520-
"extraTools": [],
521-
"timeout_ms": 300000,
522-
"quorum_timeout_ms": 300000,
523-
"idle_timeout_ms": 90000,
524-
"hard_timeout_ms": 600000,
525-
"latency_budget_ms": null,
526-
"max_context_tokens": 131072,
527-
"max_output_tokens": 4096,
528-
"max_concurrency": 3,
529-
"ccr_overhead_tokens": 95000,
530-
"ccr_response_budget_tokens": 64000,
531-
"env": {},
532-
"display_type": "claude-code-router",
533-
"deep_probe": {
534-
"prompt": "respond with: PROBE_OK",
535-
"expect": "PROBE_OK",
536-
"timeout_ms": 45000
537-
}
538-
},
539-
{
540-
"name": "ccr-6",
541-
"provider": "together",
542-
"type": "subprocess",
543-
"auth_type": "sub",
544-
"has_file_access": true,
545-
"description": "GLM-5.1 via Together.xyz — Claude Code Router (CCR) preset claude-6",
546-
"mainTool": "claude",
547-
"model": "zai-org/GLM-5.1",
548-
"display_provider": "Together.xyz",
549-
"cli": null,
550-
"args_template": [
551-
"claude-6",
552-
"-p",
553-
"{prompt}",
554-
"--dangerously-skip-permissions"
555-
],
556-
"health_check_args": [
557-
"-v"
558-
],
559-
"helpArgs": [
560-
"--help"
561-
],
562-
"extraTools": [],
563-
"timeout_ms": 300000,
564-
"quorum_timeout_ms": 300000,
565-
"idle_timeout_ms": 90000,
566-
"hard_timeout_ms": 600000,
567-
"latency_budget_ms": null,
568-
"max_context_tokens": 131072,
569-
"max_output_tokens": 4096,
570-
"max_concurrency": 3,
571-
"ccr_overhead_tokens": 95000,
572-
"ccr_response_budget_tokens": 64000,
573-
"env": {},
574-
"display_type": "claude-code-router",
575-
"deep_probe": {
576-
"prompt": "respond with: PROBE_OK",
577-
"expect": "PROBE_OK",
578-
"timeout_ms": 45000
579-
}
580328
}
581329
]
582330
}

bin/quorum-preflight.cjs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,9 +523,10 @@ async function main() {
523523
});
524524

525525
// ─── Model dedup guard (DEDUP-01) ────────────────────────────────────
526-
// When the same model appears in both CCR and API tiers (e.g., ccr-1 and
527-
// api-1 both → DeepSeek-V3.1), keep the first occurrence (higher-tier slot
528-
// due to sort order: CLI/CCR before HTTP) and move the duplicate to backup.
526+
// When the same model appears in both CCR and API tiers (e.g., a user-added
527+
// ccr-* slot and an api-* slot both → DeepSeek-V3.1), keep the first occurrence
528+
// (higher-tier slot due to sort order: CLI/CCR before HTTP) and move the
529+
// duplicate to backup.
529530
const modelMap = new Map(activeProviders.map(p => [p.name, p.model]));
530531
const seenModels = new Set();
531532
const deduped = [];

commands/nf/mcp-repair.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ NF_EVAL
5252
)
5353
```
5454

55-
`$SLOT_NAMES` is now a JSON array string. Example: `["codex-1","gemini-1","opencode-1","copilot-1","claude-1","ccr-1","ccr-2","ccr-3","ccr-4","ccr-5","ccr-6"]`
55+
`$SLOT_NAMES` is now a JSON array string. Example with the default fleet: `["codex-1","gemini-1","opencode-1","copilot-1","claude-1"]`. With user-added Claude Code Router slots, the array also includes entries like `"ccr-1"`, `"ccr-2"`, etc. — those are no longer pre-installed.
5656

5757
Parse the slot count from `$SLOT_NAMES` (array length) for the banner. Store as `$SLOT_COUNT`.
5858

@@ -352,7 +352,7 @@ If no repairs were attempted, skip this step.
352352
353353
Repaired:
354354
claude-1: SERVICE_DOWN → INFERENCE_OK
355-
ccr-3: SERVICE_DOWN → INFERENCE_OK
355+
codex-1: SERVICE_DOWN → INFERENCE_OK
356356
357357
Still broken (manual action needed):
358358
gemini-1: QUOTA_EXCEEDED — wait ~30min

commands/nf/mcp-setup.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ different LLM provider. You need at least one to use quorum.
6464

6565
**Provider template map** (reference throughout the first-run flow):
6666

67+
> ℹ️ **Note**: The `ccr-*` templates below are **not pre-installed** in
68+
> `bin/providers.json` (they were retired from the default fleet — Together.xyz routing via
69+
> Claude Code Router is still fully supported, just opt-in). This wizard still configures
70+
> them on demand: picking one writes both the MCP server entry to `~/.claude.json` and a
71+
> matching provider entry to `~/.claude/nf/bin/providers.json`. Pick "Skip" if you don't
72+
> need open-weight routing.
73+
6774
| Agent | Provider | Base URL | Model |
6875
|---|---|---|---|
6976
| ccr-1 | Together.xyz | https://api.together.xyz/v1 | MiniMaxAI/MiniMax-M2.5 |

commands/nf/mcp-update.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,8 @@ Update results:
188188
gemini-1 npm install -g @tuannvm/gemini-... ✓ UPDATED
189189
opencode-1 git pull + build in /code/opencode ✓ UPDATED
190190
copilot-1 git pull + build in /code/copilot ✓ UPDATED
191-
ccr-1 git pull + build in /code/QGSD ✓ UPDATED
192-
ccr-2 (shared repo with ccr-1) ⚡ SKIPPED
193-
ccr-3 (shared repo) ⚡ SKIPPED
191+
claude-1 npm install -g @anthropic-ai/claude ✓ UPDATED
192+
(any user-added ccr-* / fleet-extension slots) git pull + build in /code/QGSD ✓ UPDATED
194193
...
195194
196195
To load new binaries, restart updated agents:

0 commit comments

Comments
 (0)