Skip to content

Commit e687e12

Browse files
committed
Release v0.1.8 with install guidance and review fixes
1 parent 631c14c commit e687e12

27 files changed

Lines changed: 762 additions & 61 deletions

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,31 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [0.1.8] - 2026-05-09
6+
7+
### Fixed
8+
- Renamed base exception class from `RouterSmitError` to `RoutesmithError` (typo fix).
9+
- Removed unused `import time` from `metrics.py` and `import os` from `state.py`.
10+
- Moved `import math` from inside function body to module level in `planner.py`.
11+
- Fixed TOML fallback parser not parsing float values (e.g. `7.5` stayed as a string).
12+
13+
### Changed
14+
- `hosts/__init__.py` now exports all host adapters (Aider, ClaudeCode, Codex, Copilot, Cursor, GeminiCLI, Generic) instead of only GeminiCLI.
15+
16+
## [0.1.7] - 2026-05-09
17+
18+
### Added
19+
- Token-efficient install guidance for Claude Code, Codex, Gemini CLI, Copilot, Cursor, VS Code, and Aider with delegation tiers, spawn depth rules, preferred tool selection, and context-management recommendations.
20+
- Project-scoped Claude Code settings generation for `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` and `CLAUDE_CODE_DISABLE_1M_CONTEXT`, merged additively into `.claude/settings.json`.
21+
- Concrete Aider context defaults for chat history limits, prompt caching, and repo-map size.
22+
- New `SkillConfig` fields for `context_window_limit`, `autocompact_threshold`, and `max_spawn_depth`.
23+
- New `HostCapabilities.supports_context_management` flag.
24+
- Delegation-tier, task-complexity, and tool-cost advisories.
25+
- Install adapter tests covering Claude, Codex, Gemini, Copilot, Cursor, and Aider token-saving config output.
26+
27+
### Changed
28+
- Aider installs now write `.aider.conf.yml` when safe and fall back to `.aider.routesmith.yml` when an existing config is already present.
29+
530
## [0.1.6] - Unreleased
631

732
### Added

README.md

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,54 @@ Dependencies are resolved automatically — tests wait for code, docs wait for i
137137
| `ROUTESMITH_PERFORMANCE_FILE` | Performance telemetry store path | `.routesmith/performance.json` |
138138
| `ROUTESMITH_PERFORMANCE_MAX_RECORDS` | Max stored telemetry records | `500` |
139139
| `ROUTESMITH_PERFORMANCE_MAX_AGE_DAYS` | Optional age-based pruning window ||
140+
| `ROUTESMITH_CONTEXT_WINDOW_LIMIT` | Prefer leaner context defaults for supported hosts | `true` |
141+
| `ROUTESMITH_AUTOCOMPACT_THRESHOLD` | Auto-compaction threshold percentage for supported hosts | `80` |
142+
| `ROUTESMITH_MAX_SPAWN_DEPTH` | Advisory max subagent nesting depth written into host configs | `2` |
140143

141144
### Config File
142145

143146
Create `.routesmith.toml` in your project root:
144147

148+
Example:
149+
150+
```toml
151+
[routesmith]
152+
default_mode = "auto"
153+
allow_model_switch = true
154+
routing_preference = "cost"
155+
156+
# Performance-aware routing
157+
performance_routing_enabled = true
158+
performance_store_file = ".routesmith/performance.json"
159+
performance_max_records = 500
160+
performance_max_age_days = 30
161+
162+
# Token-efficiency knobs
163+
context_window_limit = true
164+
autocompact_threshold = 80
165+
max_spawn_depth = 2
166+
167+
# Optional Python hooks
168+
policy_plugins = [
169+
"my_project.routing:plugin",
170+
"my_project.routing:CustomPlugin",
171+
]
172+
173+
[routesmith.policy_overrides]
174+
planning = "balanced"
175+
documentation = "fast"
176+
```
177+
178+
What the new knobs do:
179+
180+
- `context_window_limit = true` tells install adapters to prefer leaner context defaults when the host exposes a real setting. Today this produces concrete settings for Claude Code and advisory guidance for the other hosts.
181+
- `autocompact_threshold = 80` lowers the context usage percentage at which auto-compaction should kick in for hosts that support it. Today Claude Code uses this to write `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`.
182+
- `max_spawn_depth = 2` controls the advisory spawn-depth limit written into generated host instruction files so subagents do not recurse into wasteful coordination trees.
183+
145184
Recommended config shape:
146185

147186
- Add a `[routesmith]` section with values such as `default_mode = "auto"`, `allow_model_switch = true`, and `routing_preference = "cost"` when you want cheaper model selection.
187+
- Add token-efficiency settings such as `context_window_limit`, `autocompact_threshold`, and `max_spawn_depth` when you want generated host configs to bias toward smaller contexts and shallower delegation.
148188
- Add a `[routesmith.policy_overrides]` section when you want static remaps such as `planning = "balanced"` or `documentation = "fast"`.
149189
- Add a `policy_plugins` list when you want importable Python hooks such as `my_project.routing:plugin` or `my_project.routing:CustomPlugin` to participate in route resolution.
150190
- Add performance settings such as `performance_routing_enabled = true`, `performance_store_file = ".routesmith/performance.json"`, `performance_max_records = 500`, and `performance_max_age_days = 30` when you want tighter telemetry control.
@@ -175,12 +215,12 @@ When a model's historical success rate drops below 70% or average latency exceed
175215

176216
Generate host-specific configuration files:
177217

178-
- `routesmith install claude` writes `CLAUDE.md`.
218+
- `routesmith install claude` writes `CLAUDE.md` and merges token-saving settings into `.claude/settings.json`.
179219
- `routesmith install codex` writes `AGENTS.md`.
180220
- `routesmith install gemini` writes `GEMINI.md`.
181221
- `routesmith install copilot` writes `.github/copilot-instructions.md`.
182-
- `routesmith install cursor` writes `.cursorrules`.
183-
- `routesmith install aider` writes `.aider.conf.yml`.
222+
- `routesmith install cursor` writes `.cursorules`.
223+
- `routesmith install aider` writes `.aider.conf.yml`, or `.aider.routesmith.yml` if an existing Aider config is already present.
184224

185225
## Auto Mode (Default)
186226

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "routesmith"
7-
version = "0.1.6"
7+
version = "0.1.8"
88
description = "Auto-route coding agent tasks to the best model in your IDE. Python library + MCP server for Claude Code, Codex, Gemini CLI, Copilot, Cursor, and Aider."
99
readme = "README.md"
1010
license = "MIT"

src/routesmith/__init__.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,12 @@ def serve_stdio() -> None:
9898
run_stdio_server()
9999

100100

101-
def install(target: str) -> InstallResult:
101+
def install(
102+
target: str,
103+
*,
104+
root: Path | None = None,
105+
config: SkillConfig | None = None,
106+
) -> InstallResult:
102107
"""Install routesmith configuration for a target host."""
103108
from routesmith.install import run_install
104-
return run_install(target)
109+
return run_install(target, root=root, config=config)

src/routesmith/advisory.py

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,30 @@
2020
"Single-task prompt detected. No multi-step decomposition needed."
2121
)
2222

23+
DELEGATION_TIER_ADVISORY = (
24+
"Use the cheapest capability tier that can handle each subtask. "
25+
"Reserve deep reasoning for planning, architecture, and tradeoff decisions."
26+
)
27+
28+
TASK_COMPLEXITY_ADVISORY = (
29+
"Complex plan may benefit from parallel delegation."
30+
)
31+
32+
TOOL_COST_ADVISORY = (
33+
"Prefer low-cost tool alternatives: text-first web fetch over screenshot-heavy browsing, "
34+
"extracted PDF text over heavier readers, and reusable helpers for repeated fetch workflows."
35+
)
36+
2337

2438
def generate_advisory(
2539
plan: RoutePlan,
2640
capabilities: HostCapabilities,
2741
pinned_model: str | None = None,
42+
max_spawn_depth: int = 2,
2843
) -> list[str]:
2944
"""Generate advisory messages based on plan and host capabilities."""
3045
messages: list[str] = []
46+
capability_classes = {task.preferred_capability_class for task in plan.tasks}
3147

3248
if pinned_model:
3349
messages.append(PINNED_MODEL_ADVISORY)
@@ -38,10 +54,23 @@ def generate_advisory(
3854
if len(plan.tasks) == 1:
3955
messages.append(SINGLE_TASK_ADVISORY)
4056

41-
if len(plan.tasks) > 3 and not capabilities.supports_dynamic_switch:
42-
messages.append(
43-
f"Complex multi-step task ({len(plan.tasks)} steps) detected in a host "
44-
f"without model switching. Each step will use optimized prompts."
45-
)
57+
if len(capability_classes) > 1:
58+
messages.append(DELEGATION_TIER_ADVISORY)
59+
60+
if len(plan.tasks) > 3:
61+
if not capabilities.supports_dynamic_switch:
62+
messages.append(
63+
f"Complex multi-step task ({len(plan.tasks)} steps) detected in a host "
64+
f"without model switching. Each step will use optimized prompts."
65+
)
66+
else:
67+
messages.append(
68+
f"{TASK_COMPLEXITY_ADVISORY} "
69+
f"Plan has {len(plan.tasks)} subtasks; "
70+
f"generated host configs limit subagent nesting to {max_spawn_depth} levels."
71+
)
72+
73+
if capabilities.supports_context_management:
74+
messages.append(TOOL_COST_ADVISORY)
4675

4776
return messages

src/routesmith/config.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ def _parse_value(raw_value: str) -> Any:
5353
return value.lower() == "true"
5454
if value.isdigit():
5555
return int(value)
56-
return value
56+
try:
57+
return float(value)
58+
except ValueError:
59+
return value
5760

5861
def _get_section_target(section: list[str]) -> dict[str, Any]:
5962
target = result
@@ -145,6 +148,24 @@ def _get(key: str, env_var: str, default: Any, cast: type = str) -> Any:
145148
None,
146149
float,
147150
),
151+
context_window_limit=_get(
152+
"context_window_limit",
153+
"ROUTESMITH_CONTEXT_WINDOW_LIMIT",
154+
True,
155+
bool,
156+
),
157+
autocompact_threshold=_get(
158+
"autocompact_threshold",
159+
"ROUTESMITH_AUTOCOMPACT_THRESHOLD",
160+
80,
161+
int,
162+
),
163+
max_spawn_depth=_get(
164+
"max_spawn_depth",
165+
"ROUTESMITH_MAX_SPAWN_DEPTH",
166+
2,
167+
int,
168+
),
148169
config_file=config_file,
149170
policy_overrides=file_config.get("policy_overrides", {}),
150171
policy_plugins=_get("policy_plugins", "ROUTESMITH_POLICY_PLUGINS", [], list),

src/routesmith/exceptions.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11
"""Custom exceptions for routesmith."""
22

33

4-
class RouterSmitError(Exception):
4+
class RoutesmithError(Exception):
55
"""Base exception for routesmith."""
66

77

8-
class HostDetectionError(RouterSmitError):
8+
class HostDetectionError(RoutesmithError):
99
"""Raised when host detection fails critically."""
1010

1111

12-
class ModelSwitchError(RouterSmitError):
12+
class ModelSwitchError(RoutesmithError):
1313
"""Raised when a model switch attempt fails."""
1414

1515

16-
class PlannerError(RouterSmitError):
16+
class PlannerError(RoutesmithError):
1717
"""Raised when the planner cannot decompose a prompt."""
1818

1919

20-
class PolicyError(RouterSmitError):
20+
class PolicyError(RoutesmithError):
2121
"""Raised when policy resolution fails."""
2222

2323

24-
class ExecutionError(RouterSmitError):
24+
class ExecutionError(RoutesmithError):
2525
"""Raised when task execution fails."""
2626

2727

28-
class ConfigurationError(RouterSmitError):
28+
class ConfigurationError(RoutesmithError):
2929
"""Raised when configuration is invalid."""
3030

3131

32-
class InstallError(RouterSmitError):
32+
class InstallError(RoutesmithError):
3333
"""Raised when an install operation fails."""
3434

3535

36-
class ProviderError(RouterSmitError):
36+
class ProviderError(RoutesmithError):
3737
"""Raised when a provider operation fails."""

src/routesmith/executor.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ def explain(self, prompt: str) -> RoutePlan:
4949
plan = router.resolve_plan(plan)
5050

5151
# Generate advisory
52-
advisory = generate_advisory(plan, capabilities)
52+
advisory = generate_advisory(
53+
plan,
54+
capabilities,
55+
max_spawn_depth=self.config.max_spawn_depth,
56+
)
5357
plan.advisory.extend(advisory)
5458

5559
# Review
@@ -90,7 +94,12 @@ def run(
9094
task.suggested_model = model
9195

9296
# Generate advisory
93-
advisory = generate_advisory(plan, capabilities, pinned_model=pinned_model)
97+
advisory = generate_advisory(
98+
plan,
99+
capabilities,
100+
pinned_model=pinned_model,
101+
max_spawn_depth=self.config.max_spawn_depth,
102+
)
94103
plan.advisory.extend(advisory)
95104
t_route_end = time.perf_counter()
96105

src/routesmith/hosts/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,23 @@
22

33
from routesmith.hosts.base import BaseHostAdapter
44
from routesmith.hosts.detector import detect_host, get_host_capabilities
5+
from routesmith.hosts.aider import AiderHostAdapter
6+
from routesmith.hosts.claude_code import ClaudeCodeHostAdapter
7+
from routesmith.hosts.codex import CodexHostAdapter
8+
from routesmith.hosts.copilot import CopilotHostAdapter
9+
from routesmith.hosts.cursor import CursorHostAdapter
510
from routesmith.hosts.gemini_cli import GeminiCLIHostAdapter
11+
from routesmith.hosts.generic import GenericHostAdapter
612

713
__all__ = [
814
"BaseHostAdapter",
915
"detect_host",
1016
"get_host_capabilities",
17+
"AiderHostAdapter",
18+
"ClaudeCodeHostAdapter",
19+
"CodexHostAdapter",
20+
"CopilotHostAdapter",
21+
"CursorHostAdapter",
1122
"GeminiCLIHostAdapter",
23+
"GenericHostAdapter",
1224
]

src/routesmith/hosts/aider.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def get_capabilities(self) -> HostCapabilities:
7373
supports_repo_instructions=True,
7474
supports_settings_edit=True,
7575
supports_env_override=True,
76+
supports_context_management=True,
7677
model_family="mixed",
7778
notes=[
7879
"Aider supports multiple providers (Anthropic, OpenAI, etc.).",

0 commit comments

Comments
 (0)