Skip to content

refactor: extract plan mode into tools/plan_mode.py#52

Draft
Simon-Free wants to merge 3 commits intoSafeRL-Lab:mainfrom
Simon-Free:pr10-plan-mode-tools
Draft

refactor: extract plan mode into tools/plan_mode.py#52
Simon-Free wants to merge 3 commits intoSafeRL-Lab:mainfrom
Simon-Free:pr10-plan-mode-tools

Conversation

@Simon-Free
Copy link
Copy Markdown

@Simon-Free Simon-Free commented Apr 17, 2026

Summary

Consolidate the plan-mode tools (EnterPlanMode / ExitPlanMode) into a single module tools/plan_mode.py. The previous revision split them out but left an inline copy at the bottom of tools/__init__.py, and the extension-loader list had a "task.tools",, "plan_mode"] syntax error that crashed the tools package import - so plan-mode registrations were both duplicated and unreachable.

Why this matters

Plan mode is the agent's structured-thinking entry point: EnterPlanMode flips config["permission_mode"] to "plan", which tells agent._check_permission to allow Write only on the per-session plan file. ExitPlanMode reads the plan back, refuses to leave if it is empty or only a top-level title, and restores the previous permission mode. There is no dedicated WritePlan tool - the normal Write tool, scoped by the permission check, does the right thing and avoids teaching the LLM a second file-writing primitive.

Changes

File +/- What
tools/plan_mode.py ~120 (rewritten) _enter_plan_mode, _exit_plan_mode, tiny helpers _plan_file_for, _read_plan_content, _plan_has_substance; register both tools
tools/__init__.py ?91 / +4 Drop the inline 91-line plan-mode block; fix the extension-loader list ("tools.plan_mode" added, "task.tools",,"plan_mode"] syntax error corrected); replace the silent except Exception: pass with a stderr log so optional-module load failures are visible
tests/test_plan_mode.py rewritten Unit: plan file header, permission-mode flip, idempotency on re-enter, empty-plan guard on exit, noop exit outside plan mode
tests/test_plan_mode_e2e.py new, +95 E2E through agent.run with a mocked providers.stream: full Enter?Write(plan_file)?Exit flow on disk; Write outside the plan file in plan mode is denied and the target file is never created

Backwards compatibility

config["disabled_tools"] = ["EnterPlanMode", "ExitPlanMode"] will suppress registration once #55 lands (it adds that gate to the registry). Behaviour on disk is the same as before this PR: same plan-file location (<cwd>/.nano_claude/plans/<session_id>.md), same permission-mode semantics, same empty-plan guard. The only model-facing change is that WritePlan is no longer advertised - the existing Write tool is used instead.

Ref #43

…nExtract inline plan mode code from tools/__init__.py into tools/plan_mode.py.`nAdd WritePlan tool (was missing). Validate plan file before exit.`n`nRef SafeRL-Lab#43
@Simon-Free Simon-Free marked this pull request as draft April 17, 2026 19:45
Simon FREYBURGER and others added 2 commits April 17, 2026 22:01
The previous revision of this PR created tools/plan_mode.py but left an
inline copy of EnterPlanMode / ExitPlanMode at the bottom of
tools/__init__.py which was loaded AFTER the extension module, so plan_mode.py's
registrations were silently overwritten. On top of that the extension loader
list had a syntax error (`"task.tools",, "plan_mode"]`) which crashed
tools/__init__.py import, making every test that touched the tools package
fail at collection time.

Changes:
- Fix the extension list syntax and use the fully-qualified
  `"tools.plan_mode"` module name.
- Delete the ~90-line inline plan_mode block from tools/__init__.py.
- Rewrite tools/plan_mode.py around the inline block's mature logic
  (.nano_claude/plans/<_session_id>.md, header-detection for empty-plan
  guard, permission restoration on exit). WritePlan is dropped: the
  regular Write tool is used, scoped by agent._check_permission's "plan"
  branch to only allow writes to the plan_file.
- Replace the unit tests: they now exercise the actual
  _enter_plan_mode / _exit_plan_mode and the empty-plan guard.
- Add tests/test_plan_mode_e2e.py driving agent.run with a mocked stream:
  (1) full EnterPlanMode -> Write(plan_file) -> ExitPlanMode flow,
  (2) Write to an unrelated path in plan mode is rejected and the file is
  never created.
- Upgrade the silent `except Exception: pass` in the extension loader to
  a stderr log so optional-module load failures are visible without
  crashing startup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Simon-Free Simon-Free changed the title feat: EnterPlanMode, WritePlan, ExitPlanMode tools for structured planning refactor: extract plan mode into tools/plan_mode.py Apr 20, 2026
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