Skip to main content

telos_agent/tools/builtin/
enter_plan_mode.rs

1//! `EnterPlanMode` tool — switch the agent into a read-only planning mode.
2//!
3//! When invoked, the tool instructs the model to explore, design, and document
4//! an implementation plan *without* modifying any files. The model is expected
5//! to write the plan to the plan file path, then call `ExitPlanMode` to submit
6//! it for approval.
7//!
8//! Key behaviours from learn-claude-code:
9//! - Stops the model from writing files (prompt-level enforcement)
10//! - Provides a plan file path for the model to write to
11//! - Returns detailed instructions for exploration → design → exit workflow
12
13use async_trait::async_trait;
14use serde_json::{Value, json};
15use std::path::PathBuf;
16use std::sync::{Arc, Mutex};
17
18use crate::error::AgentError;
19use crate::tools::api::{Tool, ToolContext, ToolDefinition, ToolOutput};
20
21/// Shared plan-mode state so `ExitPlanMode` knows the plan file path chosen
22/// by `EnterPlanMode`.
23#[derive(Debug, Clone, Default)]
24pub struct PlanModeState {
25    pub plan_file_path: Option<PathBuf>,
26    pub active: bool,
27}
28
29pub type SharedPlanState = Arc<Mutex<PlanModeState>>;
30
31/// `EnterPlanMode` — switch to read-only exploration/design mode.
32///
33/// The model must write the plan to the plan file, then call `ExitPlanMode`.
34pub struct EnterPlanModeTool {
35    plan_state: SharedPlanState,
36}
37
38impl EnterPlanModeTool {
39    pub fn new(plan_state: SharedPlanState) -> Self {
40        Self { plan_state }
41    }
42}
43
44#[async_trait]
45impl Tool for EnterPlanModeTool {
46    fn definition(&self) -> ToolDefinition {
47        ToolDefinition {
48            name: "EnterPlanMode".into(),
49            description:
50                "Enter read-only plan mode for complex tasks (3+ files, ambiguous requirements, restructuring). \
51Explore, design, write a plan, then call ExitPlanMode to submit. Do NOT modify files while in plan mode."
52                    .into(),
53            input_schema: json!({"type": "object", "properties": {}, "additionalProperties": false}),
54        }
55    }
56
57    fn prompt_text(&self) -> Option<&'static str> {
58        Some(PLAN_MODE_PROMPT)
59    }
60
61    async fn invoke(
62        &self,
63        _arguments: Value,
64        context: ToolContext,
65    ) -> Result<ToolOutput, AgentError> {
66        let plan_file = context.cwd.join("plan.md");
67
68        {
69            let mut state = self.plan_state.lock().unwrap();
70            state.plan_file_path = Some(plan_file.clone());
71            state.active = true;
72        }
73
74        Ok(ToolOutput::text(format!(
75            "Plan mode activated. Plan file: {}\n\n\
76You are now in PLAN MODE. Follow these steps:\n\
771. **Explore** the codebase — use Read, Grep, Glob, WebSearch to understand the problem.\n\
782. **Design** the solution — consider alternatives, identify constraints, estimate effort.\n\
793. **Write the plan** — use FileWrite to save the full plan to `{}`.\n\
804. **Call ExitPlanMode** — when the plan is complete, call ExitPlanMode to submit it.\n\n\
81While in plan mode:\n\
82- DO NOT use FileEdit, Bash (write/mutate commands), or any other write tool.\n\
83- You may use Read, Grep, Glob, WebSearch, WebFetch, CodeSearch freely.\n\
84- The plan should include: problem summary, approach, affected files, steps, risks.",
85            plan_file.display(),
86            plan_file.display()
87        )))
88    }
89
90    fn is_concurrency_safe(&self, _: &Value) -> bool {
91        true
92    }
93}
94
95const PLAN_MODE_PROMPT: &str = r#"EnterPlanMode puts you in a read-only exploration and design mode.
96
97**When to use:** Multi-file changes (3+ files), new features, cross-module refactoring, ambiguous requirements, or high-impact restructuring. Skip for single-file trivial fixes or when the user shows exactly what to do.
98
99**Workflow:**
1001. Call EnterPlanMode → get plan file path
1012. Explore codebase with Read, Grep, Glob, WebSearch
1023. Write plan to plan file using Write (cover: Problem, Context, Approach, Implementation Steps, Affected Files, Risks)
1034. Call ExitPlanMode to submit for approval
104
105Do NOT use file edit or shell while in plan mode. The plan should be detailed enough that another agent could follow it."#;