Skip to content

feat: implement extensible plan mode with custom directory configuration#18775

Closed
mahimashanware wants to merge 16 commits intomainfrom
mshanware/17690-extensible-plan-mode
Closed

feat: implement extensible plan mode with custom directory configuration#18775
mahimashanware wants to merge 16 commits intomainfrom
mshanware/17690-extensible-plan-mode

Conversation

@mahimashanware
Copy link
Copy Markdown
Contributor

@mahimashanware mahimashanware commented Feb 10, 2026

Summary

This PR enhances Plan Mode by making it more extensible and configurable. It introduces the ability to specify a custom directory for plans and leverages the policy engine to selectively enable tools (like write_file) that are normally restricted. This allows for the creation of "Plan & Execute" workflows where the agent can manage specific files within a designated area while the broader workspace remains safely read-only.

Key Changes

  • Configurable Plan Directory:

    • Introduces a general.plan.directory setting, allowing users to define a custom location (e.g., conductor/) for storing implementation plans.
    • Includes validation to ensure the specified directory remains within the project workspace for security.
  • Policy-Driven Plan Mode Overrides:

    • Fixes a core issue where Plan Mode would prevent a tool from being used even if a high-priority policy explicitly allowed it.
    • The default "deny" rules for Plan Mode can now be correctly overridden by more specific allow rules in user or workspace policies.
    • The system prompt is now dynamically updated to reflect any tools that have been enabled via policy, ensuring the model is aware of its full capabilities.

How to Test

  1. Configure Directory:
    Add to .gemini/settings.json:

    {
      "general": {
        "plan": {
          "directory": "conductor"
        }
      }
    }
  2. Define Policy:
    Create a policy file (e.g., in .gemini/policies/) to allow write_file within the conductor directory during plan mode:

    [[rule]]
    toolName = "write_file"
    decision = "allow"
    priority = 200 # Ensure this overrides the default plan mode deny rule
    # Allow writing only to the conductor directory
    argsPattern = "\"file_path\":\"[^\"]*conductor/"
    modes = ["plan"]
  3. Verify Behavior:

    • Enter Plan Mode: /plan
    • Ask the agent to write a file to conductor/test.md. Result: Should be Allowed.
    • Ask the agent to write a file to src/code.ts. Result: Should be Denied.

Verification

  • Automated Tests: Added comprehensive tests covering configuration loading, policy overrides for plan mode, and dynamic prompt generation.
  • Preflight: npm run preflight passes.

@mahimashanware mahimashanware requested a review from a team as a code owner February 10, 2026 23:02
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @mahimashanware, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the flexibility and power of Plan Mode by introducing dynamic policy management. It allows agents to specify particular files or directories for write access during planning, moving beyond a fixed temporary directory. This change streamlines the planning process by enabling workspace-wide plan creation and ensures that temporary permissions are properly managed and cleaned up, improving both security and usability.

Highlights

  • Dynamic Write Access in Plan Mode: The enter_plan_mode tool now accepts path and allowed_tools parameters, enabling dynamic injection of ALLOW policy rules for specific paths and tools during the planning phase.
  • Workspace-Wide Plan Locations: The exit_plan_mode tool no longer restricts plans to a temporary plans/ directory, allowing any path within the workspace to be a valid plan location.
  • Directory Support for Plans: Plans can now be directories, with validation ensuring that the specified directory is not empty.
  • Automated Policy Cleanup: Dynamic policy rules added during enter_plan_mode are automatically removed when exiting plan mode, preventing permission leaks into Act mode.
Changelog
  • packages/core/src/config/config.test.ts
    • Imported PolicyDecision and PolicyRule types.
    • Imported PolicyEngine type.
    • Added new test suite for 'Dynamic Policy Rules' to verify addPolicyRule and removePolicyRulesBySource methods.
  • packages/core/src/config/config.ts
    • Imported PolicyRule type.
    • Added addPolicyRule method to Config class to dynamically add policy rules.
    • Added removePolicyRulesBySource method to Config class to remove policy rules by their source identifier.
  • packages/core/src/policy/policy-engine.ts
    • Implemented removeRulesBySource method to filter and remove policy rules based on their source.
  • packages/core/src/tools/enter-plan-mode.test.ts
    • Updated mock Config to include addPolicyRule, validatePathAccess, and getTargetDir for testing dynamic policies.
    • Modified shouldConfirmExecute and execute tests to use createInvocation helper.
    • Added tests to verify dynamic policy rule addition when a path is provided, including support for directory access and relative paths.
    • Added a test case to ensure enter_plan_mode fails if path validation returns an error.
  • packages/core/src/tools/enter-plan-mode.ts
    • Imported path module and PolicyDecision type.
    • Extended EnterPlanModeParams interface to include optional path and allowed_tools.
    • Updated tool schema to reflect new path and allowed_tools parameters.
    • Implemented logic within execute to validate the provided path using config.validatePathAccess.
    • Added dynamic policy rules to the Config for specified path and allowed_tools (defaulting to write_file and replace), allowing write access to the path and its subpaths.
    • Modified llmContent and returnDisplay messages to indicate when write access is enabled for a specific path.
  • packages/core/src/tools/exit-plan-mode.test.ts
    • Updated mock Config to include removePolicyRulesBySource and validatePathAccess.
    • Refined type checking in shouldConfirmExecute test for exit_plan_mode result.
    • Added tests to verify support for directory paths as plans and rejection of empty plan directories.
    • Verified that removePolicyRulesBySource is called with 'PlanMode' during plan approval.
    • Updated path validation tests to use mockConfig.validatePathAccess and reflect workspace-wide path checks.
  • packages/core/src/tools/exit-plan-mode.ts
    • Removed unused imports resolveToRealPath and isSubpath.
    • Removed plansDir variable from constructor as it's no longer strictly needed for path validation.
    • Updated plan_path description in tool schema to indicate it must be within the project directory.
    • Modified validateToolParamValues to use this.config.validatePathAccess for path validation, allowing workspace-wide plan locations.
    • Added a call to this.config.removePolicyRulesBySource('PlanMode') when exiting plan mode to clean up dynamic rules.
  • packages/core/src/utils/planUtils.test.ts
    • Added a test case for validatePlanPath to ensure valid paths outside the plans directory but within the project root are allowed.
    • Updated symbolic link traversal test to create an outside directory for better isolation and cleanup.
    • Added tests for validatePlanContent to handle non-empty and empty directories correctly.
  • packages/core/src/utils/planUtils.ts
    • Imported fs/promises for directory operations.
    • Updated PlanErrorMessages.PATH_ACCESS_DENIED to refer to the 'project directory' instead of 'designated plans directory'.
    • Modified validatePlanPath to validate against the targetDir (project root) instead of a specific plansDir, making plan locations workspace-wide.
    • Enhanced validatePlanContent to check if the planPath is a directory and, if so, ensure it's not empty.
Activity
  • The pull request introduces new features for extensible plan mode.
  • Tests have been added and updated to cover the new functionality, including dynamic policy rules and directory support for plans.
  • The changes have been validated on Linux.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an extensible plan mode, allowing dynamic write access to specified paths and supporting workspace-wide plan locations. However, a significant security flaw exists: the user confirmation prompt is misleading, stating that the agent will be restricted to read-only tools, while it may actually be gaining write access to the entire workspace. Additionally, the list of allowed tools is unrestricted, which could lead to privilege escalation if dangerous tools are enabled in Plan Mode. Furthermore, a critical bug related to path escaping on Windows has been identified, and an information disclosure vulnerability where detailed error messages are passed to the LLM has been addressed in line with prompt injection prevention guidelines.

Comment thread packages/core/src/tools/enter-plan-mode.ts Outdated
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request successfully extends the plan mode to allow dynamic write access and workspace-wide plan locations. However, a high-severity security issue was identified in the user confirmation flow: the EnterPlanModeTool provides a misleading prompt that fails to disclose when write access is being enabled for a specific path, potentially tricking users into granting excessive permissions. This should be addressed by dynamically updating the confirmation prompt based on the tool's parameters. Additionally, a high-severity issue concerning path escaping on Windows was found, which could prevent the feature from working as expected on that platform.

Comment thread packages/core/src/tools/enter-plan-mode.ts Outdated
Comment thread packages/core/src/tools/enter-plan-mode.ts Outdated
Comment thread packages/core/src/tools/enter-plan-mode.ts Outdated
Comment thread packages/core/src/utils/planUtils.ts Outdated
@gemini-cli gemini-cli Bot added area/core Issues related to User Interface, OS Support, Core Functionality 🔒 maintainer only ⛔ Do not contribute. Internal roadmap item. labels Feb 10, 2026
@mahimashanware mahimashanware force-pushed the mshanware/17690-extensible-plan-mode branch from 6b21379 to e65aecc Compare February 14, 2026 00:34
@mahimashanware mahimashanware requested a review from a team as a code owner February 14, 2026 00:34
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 14, 2026

Size Change: +3.5 kB (+0.01%)

Total Size: 24.5 MB

Filename Size Change
./bundle/gemini.js 24.5 MB +3.5 kB (+0.01%)
ℹ️ View Unchanged
Filename Size
./bundle/sandbox-macos-permissive-open.sb 890 B
./bundle/sandbox-macos-permissive-proxied.sb 1.31 kB
./bundle/sandbox-macos-restrictive-open.sb 3.36 kB
./bundle/sandbox-macos-restrictive-proxied.sb 3.56 kB
./bundle/sandbox-macos-strict-open.sb 4.82 kB
./bundle/sandbox-macos-strict-proxied.sb 5.02 kB

compressed-size-action

@mahimashanware mahimashanware force-pushed the mshanware/17690-extensible-plan-mode branch from e65aecc to 7c94a4e Compare February 16, 2026 19:24
@mahimashanware mahimashanware changed the title feat(core): extensible plan mode feat(core): support custom plan directory via configuration Feb 16, 2026
@mahimashanware mahimashanware force-pushed the mshanware/17690-extensible-plan-mode branch from 7c94a4e to 6b9d4ed Compare February 17, 2026 20:17
@mahimashanware mahimashanware requested a review from a team as a code owner February 17, 2026 20:17
@mahimashanware mahimashanware force-pushed the mshanware/17690-extensible-plan-mode branch from 6b9d4ed to eb2d6f8 Compare February 17, 2026 20:27
@mahimashanware mahimashanware changed the title feat(core): support custom plan directory via configuration feat: implement extensible plan mode with custom directory configuration Feb 17, 2026
@mahimashanware mahimashanware self-assigned this Feb 17, 2026
@mahimashanware mahimashanware force-pushed the mshanware/17690-extensible-plan-mode branch from eb2d6f8 to 1627e9d Compare February 17, 2026 20:48
@mahimashanware
Copy link
Copy Markdown
Contributor Author

@gemini-code-assist review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a configurable directory for plan files, moving the configuration from an experimental flag to a general.plan setting. While the approach of dynamically injecting high-priority security policies for write access in Plan Mode is good, a high-severity security risk exists: the custom directory path is not validated. This oversight could allow a malicious repository to configure the plan directory to point to sensitive system locations, granting the LLM unauthorized write access. It is crucial to add validation to ensure the plan directory remains within the workspace. Additionally, a critical issue was identified regarding how paths are escaped for the dynamic policy regex, which could lead to incorrect policy enforcement.

Comment thread packages/core/src/config/config.ts Outdated
Comment thread packages/core/src/config/config.ts
Comment thread packages/core/src/config/config.ts Outdated
Comment thread packages/core/src/config/config.ts
@gemini-cli gemini-cli Bot added the area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality label Feb 17, 2026
@mahimashanware mahimashanware force-pushed the mshanware/17690-extensible-plan-mode branch 5 times, most recently from 3129416 to 181904e Compare February 18, 2026 01:08
@mahimashanware
Copy link
Copy Markdown
Contributor Author

@gemini-code-assist review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a feature to allow users to configure a custom directory for implementation plans. The changes span configuration loading, schema updates, core logic in the Config class to handle the new directory, and UI updates. While the implementation of the configuration and path resolution is solid, there is a critical discrepancy between the feature's description and its implementation. The PR summary claims dynamic policy injection for the custom plan directory, but the code and documentation require manual policy creation by the user. This will lead to a broken user experience and should be addressed before merging.

Comment thread docs/cli/plan-mode.md
@gemini-cli gemini-cli Bot reopened this Feb 18, 2026
@gemini-cli
Copy link
Copy Markdown
Contributor

gemini-cli Bot commented Feb 18, 2026

Thank you for linking an issue! This pull request has been automatically reopened.

@mahimashanware mahimashanware force-pushed the mshanware/17690-extensible-plan-mode branch 2 times, most recently from f4a96bb to 891f88d Compare February 18, 2026 07:39
Comment thread packages/cli/src/config/policy.ts
Comment thread packages/cli/src/config/config.ts
Comment thread packages/core/src/policy/config.ts
Comment thread pr_description.md Outdated
Comment thread scripts/diagnose-policy.ts Outdated
Comment thread integration-tests/policy-reproduction.test.ts Outdated
Comment thread integration-tests/cli-e2e-policy.test.ts Outdated
@jerop jerop linked an issue Feb 18, 2026 that may be closed by this pull request
@mahimashanware mahimashanware force-pushed the mshanware/17690-extensible-plan-mode branch from 891f88d to 45fcd98 Compare February 18, 2026 18:59
Abhijit-2592 and others added 15 commits February 18, 2026 15:18
Introduces a new 'Project' tier (Tier 3) for policies, allowing users to define
project-specific rules in `$PROJECT_ROOT/.gemini/policies`.

Key Changes:
- **Core**: Added `PROJECT_POLICY_TIER` (3) and bumped `ADMIN_POLICY_TIER` to 4.
  Updated `getPolicyDirectories`, `getPolicyTier`, and `createPolicyEngineConfig` to handle
  project-level policy directories.
- **Storage**: Added `getProjectPoliciesDir()` to the `Storage` class.
- **CLI**: Updated `loadCliConfig` to securely load project policies.
  Crucially, project policies are **only loaded if the workspace is trusted**.
- **Tests**: Added comprehensive tests for both core policy logic and CLI integration,
  verifying priority hierarchy (Admin > Project > User > Default) and trust checks.

This hierarchy ensures that project-specific rules override user defaults but are still
subject to system-wide admin enforcement.
Adds the 'Project' tier (Base 3) to the policy engine documentation.
Updates the priority hierarchy, location table, and formula examples
to reflect the new Project -> User precedence.
…efault

Updates the policy engine to prioritize User policies over Project-specific policies.
This change is a security measure to ensure that users maintain control over their
environment and are not inadvertently compromised by policies defined in a cloned
repository.

Key Changes:
- Swapped Tier 2 (now Project) and Tier 3 (now User).
- Updated documentation to reflect the new hierarchy.
- Updated all built-in policy TOML files with correct tier information.
- Adjusted all tests and integration test expectations to match new priority values.
Adds a security mechanism to detect and prompt for confirmation when project-level policies are added or modified. This prevents unauthorized policy changes from being applied silently.

- PolicyIntegrityManager calculates and persists policy directory hashes.
- Config integrates integrity checks during startup.
- PolicyUpdateDialog prompts users in interactive mode.
- --accept-changed-policies flag supports non-interactive workflows.
- toml-loader refactored to expose file reading logic.
…tegration tests

- Refactored `PolicyUpdateDialog` to remove side effects (`process.exit`, `relaunchApp`) and delegate logic to parent.
- Updated `AppContainer` to handle relaunch logic.
- Added comprehensive unit tests for `PolicyUpdateDialog`.
- Fixed `project-policy-cli.test.ts` to correctly mock `PolicyIntegrityManager`.
- Fixed typo in `packages/core/src/policy/config.ts`.
Updates config.test.ts to fix createPolicyEngineConfig mock expectations and expands project-policy-cli.test.ts to cover integrity check scenarios (NEW, MISMATCH) and interactive confirmation flows.
Updates the terminology and configuration for the intermediate policy tier
from "Project" to "Workspace" to better align with the Gemini CLI ecosystem.

Key changes:
- Renamed `PROJECT_POLICY_TIER` to `WORKSPACE_POLICY_TIER`.
- Renamed `getProjectPoliciesDir` to `getWorkspacePoliciesDir`.
- Updated integrity scope from `project` to `workspace`.
- Updated UI dialogs and documentation.
- Renamed related test files.
This change eliminates the need for a CLI restart when a user accepts new or
changed project-level policies. Workspace rules are now dynamically injected
into the active PolicyEngine instance.

Key improvements:
- Added Config.loadWorkspacePolicies() to handle mid-session rule injection.
- Fully encapsulated acceptance and integrity logic within PolicyUpdateDialog.
- Integrated centralized keybindings (Command.ESCAPE) for dialog dismissal.
- Refactored PolicyIntegrityManager tests to use a real temporary directory
  instead of filesystem mocks for improved reliability.
- Updated copyright headers to 2026 across affected files.
- Added UI snapshot tests for the policy update dialog.

Addresses review feedback from PR #18682.
Simplified createPolicyEngineConfig signature by moving workspacePoliciesDir into the PolicySettings interface. Updated all core and CLI call sites and tests to align with the consolidated settings structure.
Centralized the workspace policy discovery and integrity verification
logic into a new 'resolveWorkspacePolicyState' helper in the policy
module. This significantly simplifies 'loadCliConfig' in config.ts,
reducing its imperative bloat and removing low-level core dependencies
from the main configuration flow.

- Moved workspace integrity check and directory discovery to policy.ts
- Refactored loadCliConfig to use the new declarative resolver
- Added comprehensive unit tests for the resolver using real temp dirs
- Cleaned up redundant function arguments in core and CLI calls
- Verified project integrity with 'npm run preflight'
- Adds 'general.plan' configuration object for plan settings (directory).
- Updates 'experimental.plan' to a boolean flag for enablement.
- Implements dynamic high-priority policy for custom plan directories in core.
- Adds migration logic for previous configuration formats.
- Updates documentation and schema.
@mahimashanware mahimashanware force-pushed the mshanware/17690-extensible-plan-mode branch from 45fcd98 to e62362f Compare February 19, 2026 19:16
@mahimashanware
Copy link
Copy Markdown
Contributor Author

@gemini-code-assist review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant and valuable enhancements to Plan Mode, making it more extensible and configurable. The ability to define a custom plan directory and override default tool restrictions with policies is a great improvement. The implementation of workspace-level policies with integrity checks is a solid security addition. The code changes are extensive but well-structured, and the inclusion of new tests is appreciated. I've found a couple of issues: one in the documentation regarding security validation for the custom plan directory, and a potential bug in the policy directory loading logic. Please see my detailed comments.

Comment thread docs/cli/plan-mode.md
Comment on lines +121 to +123
Add the `plan.directory` setting to your `~/.gemini/settings.json` file. This
path can be **absolute** or **relative** to your project root, and **can be
located outside your project directory**.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The documentation states that the custom plan directory can be located outside the project directory. However, the implementation in packages/core/src/tools/enter-plan-mode.ts includes a validation step (config.validatePathAccess) that ensures the directory is within the workspace for security reasons. If a path outside the workspace is configured, entering plan mode will fail. The documentation should be updated to reflect this security constraint to avoid user confusion and misconfiguration.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jerop what is the ideal behavior here? for conductor it will always be within the workspace but want to confirm

Comment thread packages/core/src/policy/config.ts Outdated
Manually resolved merge conflicts in CLI and Core config files that occurred during the rebase of the extensible plan mode feature branch onto `abhijit-2592/read-proj-dir-policy-file`.
@hminooei
Copy link
Copy Markdown
Contributor

It seems the 'configurable plan directory' part is now done separately #19577 .

@jerop jerop closed this Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality area/core Issues related to User Interface, OS Support, Core Functionality 🔒 maintainer only ⛔ Do not contribute. Internal roadmap item.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants