release: v0.1.0-rc15 - #294
Merged
Merged
Conversation
ADR-0040 is the reusable part: the C1-C10 capability checklist plus the five-tier wiring inventory any future vendor gets probed against. The spike is Copilot's answers, every claim citing a command that was run. Second probe round closes the items that were blocking a complete ADR: - stdin carries the prompt. 24 250 bytes piped in with no -p arrived intact, markers on both the first and last line echoed back. Ralphy's charter is ~24 KB against a ~32 KB Windows argv ceiling, so this was the one mandatory answer. - --effort is not universal, and that changes the design. Four picker-enabled models (kimi-k2.7-code, claude-haiku-4.5, claude-sonnet-4.5, gemini-2.5-pro) reject the flag outright with exit 1. A hardcoded medium would break --model kimi-k2.7-code on every run. The flag must be omitted when unset -- the OpenCode --variant rule of ADR-0005 D3, arrived at independently. An unsupported level on a supporting model is silently coerced instead, so the requested effort is not the effort you got; only the usage row knows. - Omitting --model selects the operator current default, not auto mode. - ACCEPTS_IMAGES is true: --attachment read a word out of a PNG. - --disable-builtin-mcps emits status "disabled" in the stream, so the hardening is assertable in-band rather than merely passed. - request_multiplier is per-model and independent of the rate card: gemini-3.5-flash billed 14 premium requests for one trivial call while costing less per token than claude-sonnet-5. Cost cannot be inferred from the catalog prices. No adapter code here. Implementation stays blocked until the decisions are settled. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OpenCode is the template, not Codex: Copilot shares the SQLite session store and, more importantly, the rule that the adapter must not pick the operator's model for them. The two model-axis decisions are the ones with teeth. --model is Option<String>, omitted when unset, and omission is not a degraded fallback -- a run with no --model uses the operator's current selection and never enters auto mode. --effort follows the same rule for a harder reason: four picker-enabled models reject the flag outright, so a fixed medium would hard-fail every run on kimi-k2.7-code. That is ADR-0005 D3's --variant rule arrived at from a second vendor's evidence, which promotes it from an OpenCode quirk to the house rule for optional passthrough knobs. No complexity routing in v1. Model ids are plan-gated and effort is not universal, and request_multiplier turns out to be independent of the rate card -- gemini-3.5-flash bills 14 premium requests for a call that costs less per token than claude-sonnet-5 -- so an adapter routing on the operator's behalf cannot reason about what it spends. The GitHub MCP server gets closed by default and, unusually, verifiably: the stream reports status "disabled", so the run fails if a builtin server is ever seen connected. Defaulted rather than mandated, because the receipt makes the default honest enough not to need mandating. Skills reuse Codex's symlink-into-.agents/skills dance rather than reimplementing it; two vendors needing the identical thing is the threshold for lifting it into adapter-support. Status is proposed. No adapter code exists and none is authorized. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…clamped Probe P6 against gpt-5-mini, which supports exactly low/medium/high: asking for xhigh records medium, and asking for minimal also records medium. Only an in-range value survives. Corroborated on claude-sonnet-5. So requesting xhigh on a model that stops at high yields LESS effort than requesting high would have. The intent is inverted, the exit code is 0, and nothing in the stream mentions it. That makes the vendor fallback intent-destroying rather than merely lossy, which is the argument for the adapter normalising effort itself instead of passing the string through. Recorded with the level ordering and the observation that low/medium/high are universal across every effort-supporting model, so a clamp that never exceeds the request is always satisfiable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Probe P6 showed the vendor fallback for an out-of-range effort is the model default, not the nearest supported level, in both directions. On gpt-5-mini, which stops at high, asking for xhigh records medium — so asking for more yields less than asking for high would have, at exit 0 and in silence. An adapter that forwards the operator string inherits that inversion. The clamp is one rule rather than a pair of special cases: take the nearest supported level at or below the request, fall to the lowest supported when nothing sits below, omit the flag entirely when the model supports no effort. That covers xhigh->high and minimal->low, and it degrades claude-sonnet-4.6 (which has max but not xhigh) to high instead of escalating to max — the clamp never buys more than was asked for, so it cannot surprise the operator with cost. The support table is read from the live CAPI catalog, never hardcoded. Baking one in would repeat the mistake this spike documented, where copilot help config lists 21 ids of which 8 are unselectable. The catalog costs zero model calls via the invalid-model debug-log route, and folds into the per-run auth preflight ADR-0013 already performs. Scope is deliberately the adapter, not the core. Making low|medium|high| xhigh Ralphy's vocabulary touches CONTEXT.md and all five adapters, and a vocabulary one vendor of five honours is worse than none — tracked separately so it stays off this adapter's critical path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Conversation may happen in any language; the artifact is English. Issues are work orders an agent consumes and they quote English ADRs, identifiers and paths, so prose in a second language makes one document speak two per sentence. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Where things live listed three adapters when there are four, and omitted the daemon, usage-scan and proc-util entirely. The enumeration is the defect: it would go stale again on the next vendor, so it becomes ralphy-agent-* with a pointer to ADR-0040's wiring inventory. Also drops a stray "#teste 1" left at the end of the file. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…023 ladder (#229) New `ralphy-agent-copilot`: argv fixed at --allow-all-tools/--output-format json/--session-id plus the five blast-radius flags (D7), the three GitHub token vars removed from the child (D8), the charter piped on stdin with no -p (D2), and a stream parser that keeps the last non-ephemeral assistant.message with an empty toolRequests. The terminal envelope's change counters are never read — a source-scan test pins that, since probe P2 showed them zeroed after a real shell-tool commit. Plus the Tier 2 plan overlay (no ## Execution model line, D6) and its regenerated artifact.
…ry (#229) CliAgent::Copilot + cli_name, init/gate.rs Agent/ALL (array length bumped to 5) and its token-free agent_logged_in probe, run/wiring.rs build_agent, models.rs agent_slug, and the capture.rs emit-site rows. The four one-shot dispatches (diagnose, draft-issues, triage, consolidate) get a bailing arm naming the missing tasks.rs slice — the new variant makes those matches non-exhaustive at compile time, and an honest bail beats a silent wrong-vendor fallback.
#229) New `echo-stdin` mode on headless_test_child plus a round-trip test asserting markers on BOTH the first and last line. Head-only would pass on a payload cut in half; verified by truncating the child's write to 1000 bytes, which reds the LAST-line assertion.
#229) Two HIGH from the adversarial review of this issue's commits: - `Agent::ALL` is an ORDERED auto-selection list, not a set: `init`/`triage` take the first logged-in agent, and every Copilot one-shot bails until the tasks.rs slice. Copilot inserted third would have turned a working `ralphy init` into a hard bail wherever Copilot and Kimi are both logged in. Moved last, with the contract in a doc comment and a test pinning the position rather than just the membership. - `--exec-model` was accepted, emitted on the event stream, then dropped on the floor: argv was built with a hardcoded `None`, so the run used the account default while the report, TUI and CloudEvents all claimed the pinned id — and capture.rs pinned that emission as correct. The model now reaches argv. Plus: no fabricated session id on the plan resume path; the limit predicate tightened to error-shaped phrases, since it scans a log that echoes the charter and the issue body; the plan-phase limit routed through PlanLimit instead of aborting with "produced no plan". Live evidence in docs/evidence/copilot-229-run.md: a real run planned 16 steps, committed three times and classified Timeout at the wall — and the stream shows `github-mcp-server` `"status":"disabled"`, the D7 receipt observed in band.
…ws (#230) Rows are per-call and summed (`ORDER BY id`, model carried from the last); `reasoning_tokens` is never selected. The store is copied with its `-wal`/`-shm` sidecars into a Drop-guarded temp dir and the COPY opened read-write, because a read-only handle cannot replay an uncheckpointed WAL.
`plan`/`execute` no longer report zero: the minted `--session-id` keys the store rows. A RESUMED finalized plan ran no child, so it still reports zero rather than another run's rows.
#230) Copilot bills in AI credits; USD here is ADR-0034's metered-API counterfactual, never a credit conversion. `claude-haiku-4.5` reuses the `claude-haiku-4-5` row rather than duplicating four Anthropic entries.
Self-review HIGHs: `copilot_never_writes_the_live_store` ran against a checkpointed DELETE-mode fixture that any pure-SELECT reader passes, and `copilot_wal_rows_need_the_sidecars` never invoked `copy_store`. Both now drive the production path over a live WAL store with its writer still open. Also: `remove_dir_all` before reusing a pid+seq temp dir, model-carry/fallback-query/ attribution coverage, an exact USD oracle, and `KimiScan`'s stolen doc comment.
Parses the vendor's CAPI /models log line into selectability, effort support and the rate card; fetch_catalog() drives the probe with the D7/D8 flags and never reads the exit status (observed 0 and 1 for the same failure).
H1: the live test now runs a positive control before asserting zero usage — copilot_usage defaults to zero on every read failure, so the oracle was green on a host with a dead reader. M1: parse_catalog refuses a log that never rejected the sentinel model, which would mean a billed turn. M2: the probe runs in its throwaway temp dir, not the operator's repo.
CopilotSettings (plan_model/exec_model, both None by default) persists under the copilot.* settings section. CopilotAgent now carries plan_model alongside the existing exec_model, selected per-phase via a private Phase enum so plan()/execute() pass the right override into build_copilot_command — omitted model still selects the account's own default (ADR-0041 D4).
…exec-model (#232) Adds copilot.plan_model / copilot.exec_model to the config registry, a vendor-neutral resolve_optional_model (opencode's resolver now delegates to it), and ResolvedCopilot/resolve_copilot in run/wiring.rs so both build_agent call sites (executor and split-run planner) resolve per-phase precedence: flag > persisted settings.json > omit --model. No new CLI flag — the existing --plan-model/--exec-model now reach the Copilot adapter too.
H1: warn_effort_mismatch evaluated the store reader eagerly — a default run copied the whole session-store.db twice per issue. H2: the clamp property test's floor escape hatch was unconditional, so an always-lowest implementation satisfied it.
…234) Live-captured fixture: copilot 1.0.71 emits the mcp_servers_loaded receipt three times, every copy ephemeral:true — so the scanner must NOT filter on it.
…e limits, and verification gate - Created `agents.md` to detail agent selection and functionality. - Added `run-options.md` for comprehensive options available with `ralphy run`. - Introduced `telegram.md` to explain the optional Telegram run monitor setup and usage. - Added `usage-and-cost.md` to outline usage limits and cost reporting mechanisms. - Created `verify-gate.md` to describe the runner-enforced verification process before closing issues.
- Updated the indexing gate to create the `.cursorindexingignore` file in unprotected repositories before spawning the `cursor-agent`, instead of refusing to run. - The opt-out file contains a single line (`*`) to suppress the upload of the repository to Cursor's servers, and its creation is logged for operator visibility. - The change ensures that the upload is prevented before any child process is spawned, maintaining the original intent of the policy while improving the operator experience. - Adjusted tests to reflect the new behavior of the indexing gate, ensuring it writes the opt-out file as expected and does not refuse when the operator opts in. - Updated documentation to clarify the new behavior of the indexing gate and its implications for repository management.
Stop folding OpenCode dialect into the effort slot; emit reports variant under its own name. Co-authored-by: Cursor <cursoragent@cursor.com>
Thread the resolved word to each adapter so the discard site is real; keep OpenCode --variant as --exec-variant-only. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…285) Co-authored-by: Cursor <cursoragent@cursor.com>
Drop inaccurate `minimal` from EventFields.effort docs (ADR-0044 D2) and pin the lexicon plus Kimi's documented discard sites. Co-authored-by: Cursor <cursoragent@cursor.com>
Self-review MEDIUM: planning-only roundtrips left a re-fold on executing uncovered; add the symmetric twins. Co-authored-by: Cursor <cursoragent@cursor.com>
Codex honours --plan-effort/--exec-effort as model_reasoning_effort (default medium). Copilot merges the resolved word ahead of persisted copilot.*_effort; clamp unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
Route argv assertions through resolved_*_effort helpers used by plan/execute; pin Copilot merge expressions fully; clarify stale Codex hardcode in ADR-0041. Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the hand-written defaults.rs table with models.dev-shaped seed JSON plus a bare-id overlay, behind ingest and layered resolve (overrides > cache > seed > overlay). Co-authored-by: Cursor <cursoragent@cursor.com>
Address self-review MEDIUMs: golden 39-id rate lock, cache-beats-seed and disk-cache load coverage, plus synthesize prefix unit cases. Co-authored-by: Cursor <cursoragent@cursor.com>
Fetch+TTL+atomic write+--refresh+offline gate via ureq; sole trigger on usage_cmd. Loopback tests cover success, TTL, retries, malformed, $0 drop. Co-authored-by: Cursor <cursoragent@cursor.com>
Halve ureq connect/read timeouts so two attempts + retry sleep stay near the ADR ~2-3s bound under a hung peer. Co-authored-by: Cursor <cursoragent@cursor.com>
On Windows, ralphy spawns cursor-agent from a native process (MSYSTEM absent,
SHELL empty), so the vendor's shell classifier falls through to PowerShell. The
model's POSIX habit for multi-line commits -- `-m "$(cat <<'EOF' ... EOF)"` --
then ParserErrors on PowerShell's `<<`, burning one wasted tool call per execute
session before it self-heals.
Pin SHELL to a located git-bash so the classifier routes to bash. Live e2e found
SHELL alone is insufficient: git-bash without its MSYS runtime flag returns "no
exit status" for every command (a worse break than the papercut), so MSYSTEM=
MINGW64 rides along -- with both set, commands run with real exit codes and the
heredoc commit lands first try, no ps-script/ParserError.
- ralphy-proc-util: locate_git_bash{,_with} + is_git_bash_shape (rejects the WSL
System32\bash.exe), reusable by the daemon's interactive launch (mirrors D19).
- ralphy-agent-cursor: build_cursor_command sets SHELL+MSYSTEM on Windows only,
git-bash located, operator SHELL never overridden, degrades to PowerShell when
bash.exe is absent. Adds an #[ignore] production-path e2e proving it against
the real cursor-agent.
- ADR-0042 D20 records the decision and the live-validated MSYSTEM requirement.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keep the offline pricing floor (assets/pricing/models-dev-seed.json) current without hand-editing it (ADR-0034 A3). A new `xtask` crate regenerates the seed from live models.dev, and a weekly CI job opens a diffable PR only when the numbers change; the build stays hermetic since the refresh runs out-of-band, never in build.rs. The generator refreshes in place: for each id already in the seed it updates the price where upstream publishes one, preserving (never dropping or adding) the id set, so vendor spellings the catalog does not carry (Copilot dotted ids, the CLI's Gemini forms, kimi-for-coding) survive. It owns seed.json wholesale and never touches the human-owned slug-overlay.json. Output is deterministic (sorted keys) so its diff is reviewable and a no-op run is byte-identical. This lands the tooling only; the seed data is unchanged, so the floor.rs golden tests stay green. The first live regeneration is the reviewed CI PR, where a deliberate floor above upstream (e.g. claude-opus-4-8, ADR-0008 D8) is restored and the golden values move with the data. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A missing git CLI otherwise surfaces as `NoGithubRemote` — git::origin_url fails, so github_remote() is false — naming the symptom, not the cause. Add an explicit `git` finding and a `MissingGit` hard fail that leads the report, with a remediation note pointing Windows operators at Git for Windows (which also provides the git-bash shell #291 pins SHELL to). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the ports-&-adapters / ubiquitous-language architecture summary, the tests-live-next-to-code convention, the smallest-change-that-fits-the-seam rule, and the always-on Rust baseline (errors, signatures, idiom, async) to CLAUDE.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e drift (#293) Class A — the 0002 collision + boundary drift: - Renumber blocked-by gating 0002 -> 0045 (the one free number), clearing 0002 hosting two unrelated decisions; add a renumber note in the file. - Canonicalize the core/adapter boundary as ADR-0002 (cited that way ~40x with explicit file links; only ~14 sites had drifted to "ADR-0004"). Fix the drifted cites in CLAUDE.md, CONTEXT.md, ralphy-adapter-support, cursor/lib.rs, core/runner/phases.rs, and ADRs 0011/0025/0042. - Repoint blocked-by cites (CONTEXT.md, core/queue_view.rs, ADR-0014, ADR-0020) from 0002 -> 0045. - Re-home the "no shared headless runner" invariant into ADR-0002 (its home as a boundary property; it had only been stated in 0004-codex); 0004 now defers to it, and the "does not reopen the ban" cites in 0023/0005 follow. Codex keeps 0004 for every genuine adapter cite. - Remove the "known numbering drift" stopgap from CLAUDE.md. Class B — per-vendor grouping is a convention, not a collision: - Add docs/adr/README.md documenting the numbering convention: one number = one decision; -validation/-revalidation are companion notes under the same decision number (opencode/kimi/copilot/cursor/gemini). It records the 0002<->0004 history and this resolution. No behavioural code change (Rust edits are comment-only). cargo fmt --check passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A full `kimi logout` strips the login-populated model catalog from config.toml, so kimi-code 0.28 fails with `config.invalid … is not configured` (adapter's pinned `-m kimi-code/k3` path) or `No model configured … /login` (bare) — neither carries `auth.login_required`. `is_kimi_auth_error` matched only the latter, so a logged-out run fell through to the generic "kimi produced no plan" instead of the auth stop (ADR-0028 D6). Found live in the #274 capstone, Phase 0. Add the two full-logout signatures to `is_kimi_auth_error` via the shared `auth_error` multi-group helper (Codex's precedent), reword KIMI_AUTH_ERROR_MSG to "no active login" to cover all three, and pin all three logged-out strings in a regression test. The `config.invalid` group carries an accepted conflation risk (an operator model-config typo reads as "run kimi login"); documented in ADR-0028 D6, which also reconciles the earlier boundary note that deliberately did not claim `No model configured…` as logged-out. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review follow-ups on the Cursor co-authored clusters (#286/#288/#289): - Codex effort: clamp the neutral lexicon's `xhigh`/`max` (ADR-0044) to `high` before the `-c model_reasoning_effort` override, so `codex exec` accepts it instead of rejecting the run at startup. Argv only; telemetry keeps the operator's original word. (#286) - Pricing cache: drop the Windows `remove_file`-before-`rename` block — `std::fs::rename` already replaces atomically on Windows, and the delete opened the no-canonical-file gap ADR-0034 says to avoid. (#289) - models.dev fetch: add a hard per-request `.timeout(1500ms)` and `.redirects(0)` so the ~3s worst-case bound holds against slow-drip bodies and redirect chains, not just a hung peer. (#289) - floor.rs: move the misplaced Gemini-axis doc comment back onto its test. (#288) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
) A real kimi-code 0.28 billing-cycle 403 blocks the very first call, so it bites during planning where the plan is never written. The plan path passed `|_log| None` as its limit detector, so every ceiling was misclassified as "kimi produced no plan" — Outcome::Limit never fired and --stop-on-limit / the ADR-0030 cadence never engaged. - lib.rs: pass is_kimi_limit_text through detect_limit as the plan-time detector, mapping to PlanLimit { reset: None } (Kimi 403 promises only "the next cycle", no timestamp -> synthetic cadence). Mirrors Codex/Gemini; no new machinery. The no-plan-written state is itself the non-clean-exit guard, so an echoed phrase (which still writes a plan) cannot false-trip. - auth.rs: regression test pinning the exact plan-closure composition against the live 0.28 provider.api_error body -> Some(None), plus a clean-log negative. - ADR-0028 D9: amend the "unvalidated" note with the #274 live finding — the billing cap exits 1 + text, not 75; exit-75 remains unobserved-live. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r Codex - Added a new execution model `opus-high` to the Claude planning prompt, allowing for high reasoning effort on a per-issue basis. - Updated the `resolve_exec_effort` method to derive effort from the new `opus-high` rung, defaulting to high when selected. - Enhanced Codex to include a new `xhigh` tier, mapping to high effort for the `gpt-5.6-sol` model, allowing for more granular control over execution effort. - Updated relevant documentation to reflect changes in execution models and tiers, ensuring clarity on how effort is determined during execution. - Adjusted tests to validate the new execution models and their corresponding efforts, ensuring that the changes are correctly implemented and functioning as intended.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…fort The opus-high change (5c80efd) moved Claude's execute-phase effort from `self.exec.exec_effort` to a plan-resolved local `exec_effort` at both the interactive and headless emit sites. The `adapter_emit_sites_pass_the_right_arguments` position-scan still expected the old `self.exec.` source expression, so it failed on Windows CI. The argument POSITION is unchanged; only the source binding moved — update the two pinned fragments to match. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cut v0.1.0-rc15: fold the
feat/copilotline intomainand bump all crates0.1.0-rc13 → 0.1.0-rc15(the last tag wasv0.1.0-rc14; Cargo.toml had lagged at rc13).This branch carries the accumulated work since the previous release, including:
opus-high(Claude) andxhigh(Codex) execution models; variant split from effort in runstate telemetry.SHELL+MSYSTEMto git-bash; harden effort clamp, cache atomicity, fetch bound.consolidate_knowledge.Release mechanics
Merging this and pushing the
v0.1.0-rc15tag triggersrelease.yml, which builds all four platform archives (+.sha256) and publishes a GitHub pre-release.Green gate
cargo fmt --checkand a full workspace build pass locally; CI runs the full matrix on the PR.🤖 Generated with Claude Code