Skip to content

explore/plan/refactor: wire local providers with tools at all; fix lex_audit's --calls/--uses-host flags - #105

Merged
alpibrupa merged 1 commit into
mainfrom
fix-explore-plan-refactor-tools
Sep 4, 2026
Merged

explore/plan/refactor: wire local providers with tools at all; fix lex_audit's --calls/--uses-host flags#105
alpibrupa merged 1 commit into
mainfrom
fix-explore-plan-refactor-tools

Conversation

@alpibrupa

Copy link
Copy Markdown
Contributor

Found by testing the four modes untouched all session (plan/explore/refactor/bar). explore, plan, and refactor's local variants all had tools: [] and max_steps: Some(3) — every other provider variant was correctly wired, only the two local paths were unfinished stubs. Confirmed live: an explore-mode call said "Let me locate the shout function" and then just stopped.

Each mode's new toolset matches its own permissions/rules.lex spec exactly, not shared with the others or with dynamic_tools() — the three permission specs genuinely differ.

One wrong turn, caught and reverted: initially added "write" to plan_permission(), reasoning from the prompt's own claim. tests/test_permissions.lex immediately failed a deliberate, documented security invariant ("read-only means read-only... a mode that can suddenly write looks identical from the outside until it does"). The bug was in the prompt, not the permission spec — reverted the permission change, fixed plan.lex's prompt instead to stop claiming a capability it was never granted.

A second real bug, caught by inspecting the actual dispatched tool list directly rather than trusting a live run: an earlier refactor_dynamic_tools() duplicated propagate_effect/lex_store_merge in the schema (already present via dynamic_tools()'s gated store group). Rebuilt cleanly.

A third, independent bug, surfaced by refactor's own mandatory-audit-first workflow: lex_audit.lex built --call/--host for those two dimensions, but the real CLI only has --calls/--uses-host. The model self-diagnosed the crash and fell back to grep — fixed so it doesn't have to.

lex check --strict, lex fmt --check, lex test (including the permissions security suite), and the bar-mode gate are all green. All three modes live-verified against litellm/qwen3.8:27b-mlx post-fix.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

…x_audit's --calls/--uses-host flags

Found by testing the four modes untouched all session. explore, plan,
and refactor's ollama_agent()/litellm_agent() all had `tools: []` and
`max_steps: Some(3)` — not curated-minimal like every other local mode,
just entirely unwired. Every other provider variant (cloud, mistral,
vllm, openai, google, opencode) correctly used tools_for_spec(...) with
the mode's real max_steps (20/30/40); only the two local paths were
stubs. Confirmed live: an explore-mode call said "Let me locate the
`shout` function in `widget.lex`" and then stopped, having no tool to
do it with.

Each mode's new toolset is built to match its own permissions/rules.lex
spec exactly, not shared with the others or with dynamic_tools() — the
three permission specs genuinely differ (explore gets sigid_lookup/
effects_of/attestation_query, plan gets todowrite/remember instead,
refactor gets the full edit+vcs surface), and a tool outside a mode's
own allowlist is silently dropped by with_permission_gate regardless of
what's offered, so listing it would just be dead schema weight a local
model still pays for.

Caught and reverted one wrong turn along the way: initially added
"write" to plan_permission(), reasoning from the prompt's own claim
("except writing to `.lex/plans/*.md`"). tests/test_permissions.lex
immediately failed — "explore, plan, review and bar all deny
write/edit/bash" is a deliberate, documented security invariant ("a
read-only mode that can suddenly write... looks identical from the
outside until it does"), not an oversight. The bug was in the prompt,
which had never been true on any provider, not the permission spec.
Reverted the permission change; fixed plan.lex's prompt instead to stop
claiming a write capability it was never granted, matching bar.lex's
already-correct "output is the response text" pattern.

Also caught and fixed a second, real toolset bug while inspecting the
actual dispatched lists directly (not trusting a live run): an earlier
version of refactor_dynamic_tools() extended dynamic_tools() and
separately re-added propagate_effect/lex_store_merge, which are already
in dynamic_tools()'s gated store group — duplicating both tools in the
schema. Rebuilt from vcs_read_tools()/vcs_write_tools() directly
instead.

Separately, live-testing refactor's mandatory lex_audit-first workflow
surfaced a real, independent bug in lex_audit.lex: dimension=call built
`--call` and dimension=host built `--host`, but the actual `lex audit`
CLI only has `--calls` (plural) and `--uses-host`. The model correctly
self-diagnosed the resulting `stat --call: No such file or directory`
and fell back to grep, but the tool shouldn't need that. Fixed with an
explicit dimension-to-flag mapping; verified directly against the CLI
that the crash is gone.

lex check --strict, lex fmt --check, lex test (including the
permissions security suite), and the bar-mode gate are all green.
explore/plan/refactor all live-verified against litellm/qwen3.8:27b-mlx
after the fix: explore gave a grounded, correct answer quoting real
file content; plan produced a clean text-only plan with no confused
"I have no write tool" caveat; refactor correctly found the one real
caller of a function (working around the still-separately-real
audit_tool bug until this same commit fixed it).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@alpibrupa
alpibrupa merged commit f1441d6 into main Sep 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant