Feature Request: Declarative Conditional Permissions Based on Tool Outcomes

Resolved 💬 3 comments Opened Aug 1, 2025 by coygeek Closed Jan 4, 2026

Subject: Feature Request: Declarative Conditional Permissions Based on Tool Outcomes

Labels: feature-request, enhancement, permissions, security, automation

Is your feature request related to a problem? Please describe.

The current permission system (allowedTools, disallowedTools in settings.json) is powerful but static. It allows pre-defining which tools Claude can use, but it lacks the ability to make permission decisions based on the immediate context or the outcome of previous actions within the same session.

A common and critical development workflow is to run tests before committing code. We want to enforce a rule like: "Allow git commit only if the npm run test command just ran and succeeded."

Currently, there is no simple, declarative way to configure this rule. This makes it difficult to build fully robust and safe automated workflows (e.g., in headless -p mode or with --dangerously-skip-permissions) without resorting to more complex solutions.

Describe the solution you'd like

I propose extending the settings.json file with a new declarative section, perhaps called conditionalPermissions. This would allow users to define rules that grant temporary, one-time permissions for a tool if a specific condition, based on the outcome of a recently used tool, is met.

Here is a conceptual example of what the configuration might look like:

{
  "permissions": {
    "allow": [
      "Bash(npm run test)",
      "Read(*)"
    ],
    // ... other static permissions
  },
  "conditionalPermissions": [
    {
      "description": "Allow committing only after tests pass.",
      "if": {
        "tool": "Bash",
        "command": "npm run test",
        "outcome": "success" // Could also support "failure", or checks on stdout/stderr
      },
      "then": {
        "allowOnce": "Bash(git commit*)"
      }
    },
    {
      "description": "Allow pushing only after committing.",
      "if": {
        "tool": "Bash",
        "command": "git commit*",
        "outcome": "success"
      },
      "then": {
        "allowOnce": "Bash(git push*)"
      }
    }
  ]
}

How it would work:

  1. Claude decides to run a tool, for example, git commit -m "feat: new feature".
  2. The permission system checks the static allow/deny lists. Let's assume git commit is not in the static allow list.
  3. The system then checks the conditionalPermissions rules.
  4. It finds the "Allow committing only after tests pass" rule.
  5. It inspects the immediate conversation history to see if the if condition is met (i.e., the last tool call was npm run test and it was successful).
  6. If the condition is true, the git commit action is temporarily allowed for this one instance.
  7. If the condition is false, the standard permission prompt is shown to the user (or the action is denied in non-interactive mode).

Describe alternatives you've considered

The current Claude Code Hooks system (PreToolUse hook) can be used to achieve similar results. A custom script could be written to receive the tool call information, parse the session's transcript_path, check the outcome of the last command, and then exit with a specific code to allow or deny the new tool call.

However, this approach has significant drawbacks compared to a declarative solution:

  • Complexity: It requires writing, testing, and maintaining a separate script (e.g., in Python or Bash) to parse JSON and implement the logic.
  • Accessibility: It's much less accessible for users who just want to define a simple rule without programming.
  • Auditability: A declarative JSON rule is far easier to read, audit, and understand for security reviews than a custom script.

While hooks are a great power-user feature for complex logic, a declarative system for this common pattern would be a major improvement in usability and security for a vast number of workflows.

Additional context

Implementing this feature would provide several key benefits:

  • Enhanced Safety: Enables safer automation and use of --dangerously-skip-permissions, especially in CI/CD pipelines.
  • Workflow Enforcement: Allows teams to easily enforce best practices (e.g., Test-Driven Development, lint-before-commit) directly in the tool's configuration.
  • Improved User Experience: Simplifies the configuration of complex agentic behaviors, making the tool more powerful and intuitive.

This feature would align perfectly with the "safe power tool" philosophy of Claude Code by giving users more granular, context-aware control over its most powerful capabilities.

Other Usage Examples

Here are several other scenarios where declarative conditional permissions would be invaluable:

1. Safe Deployments (Terraform, Serverless, etc.)

Goal: Prevent a deployment to a staging or production environment unless all validation and build steps have passed.

Configuration:

"conditionalPermissions": [
  {
    "description": "Allow Terraform apply only after validation passes.",
    "if": {
      "tool": "Bash",
      "command": "terraform validate",
      "outcome": "success"
    },
    "then": {
      "allowOnce": "Bash(terraform apply*)"
    }
  },
  {
    "description": "Allow serverless deployment only after the project builds successfully.",
    "if": {
      "tool": "Bash",
      "command": "npm run build",
      "outcome": "success"
    },
    "then": {
      "allowOnce": "Bash(serverless deploy*)"
    }
  }
]

How it Works: This configuration acts as a critical safety gate. Claude can be instructed to "validate and deploy the infrastructure," but it will be programmatically blocked from running terraform apply if the terraform validate step fails, preventing potentially costly or breaking changes.

---

2. Package Publishing

Goal: Ensure a package is only published to a registry (like NPM or PyPI) after it has been successfully built and tested.

Configuration:

"conditionalPermissions": [
  {
    "description": "Allow publishing to NPM only after tests succeed.",
    "if": {
      "tool": "Bash",
      "command": "npm run test",
      "outcome": "success"
    },
    "then": {
      "allowOnce": "Bash(npm publish)"
    }
  }
]

How it Works: This prevents the accidental release of a broken or failing version of a package. Claude can automate the entire release process, but this rule ensures quality control is enforced at the final, critical step.

---

3. Database Migrations

Goal: Ensure a database migration is only applied after a custom validation script (e.g., checking for schema conflicts or backing up data) runs successfully.

Configuration:

"conditionalPermissions": [
  {
    "description": "Allow running database migrations only after the backup script succeeds.",
    "if": {
      "tool": "Bash",
      "command": "/scripts/backup_production_db.sh",
      "outcome": "success"
    },
    "then": {
      "allowOnce": "Bash(prisma migrate deploy)"
    }
  }
]

How it Works: This is a crucial data-safety pattern. It codifies the rule that a potentially destructive operation (migrate deploy) can only proceed after its prerequisite safety check (backup_production_db.sh) is confirmed to have completed without errors.

---

4. Promoting a Configuration File

Goal: Allow a newly generated configuration file to be moved into a sensitive location only after it passes validation.

Configuration:

"conditionalPermissions": [
  {
    "description": "Allow moving a new nginx config into place only after it has been validated.",
    "if": {
      "tool": "Bash",
      "command": "nginx -t -c /tmp/new_config.conf",
      "outcome": "success"
    },
    "then": {
      "allowOnce": "Bash(sudo mv /tmp/new_config.conf /etc/nginx/sites-enabled/)"
    }
  }
]

How it Works: Claude can be tasked with generating complex configuration files (e.g., for web servers, CI/CD, or application routing). This rule ensures that a syntactically invalid or problematic configuration file is never promoted to an active state where it could cause an outage.

---

5. Interacting with External Services (via MCP)

Goal: Automate a cross-platform workflow, such as adding a label to a GitHub issue only after confirming its status in Jira.

Configuration:

"conditionalPermissions": [
  {
    "description": "Allow adding a 'Ready for QA' label in GitHub if the linked Jira ticket is in the 'Ready for QA' status.",
    "if": {
      "tool": "mcp__jira__get_issue_status",
      "command": "PROJ-123",
      "outcome": "stdout_contains:Ready for QA" // An example of a more advanced outcome check
    },
    "then": {
      "allowOnce": "mcp__github__add_label --issue 456 --label 'qa-needed'"
    }
  }
]

How it Works: This demonstrates how the feature can orchestrate workflows across different systems connected via the Model Context Protocol (MCP). It moves complex business logic (the "if/then" rule) out of a fragile, hard-coded script and into a simple, auditable configuration file.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗