Skip to main content

Make AI-assisted development safer, auditable, and release-ready without breaking normal CLI and git workflows

Project description

PlanGuard

Plan and control how AI coding agents make changes in your project.

PlanGuard is a lightweight, language-agnostic framework that makes AI-assisted development safer and auditable. It enforces a simple rule: plan first, then implement.

Why

AI agents are powerful but unconstrained. Without guardrails they can:

  • Modify files you didn't intend them to touch
  • Skip tests or verification steps
  • Make "small" database changes that break production
  • Leave no audit trail of what they did or why

PlanGuard fixes this with scope enforcement, safety checks, verification gates, and an immutable session log — all driven from the CLI, with no external services required.

Quick Start

# Install or upgrade
pipx install planguard          # or: pip install planguard

# Set up in your project
cd /path/to/your-project
planguard init                  # detects stack, creates context files and AGENTS.md

# Plan → Check → Activate → Implement → Verify → Complete
planguard plan                  # interactive wizard to define scope, risks, verification
planguard check                 # validate structure, risk score, collisions
planguard activate my_plan      # record baseline, allow implementation
# ... now prompt the agent — see "Activation and Implementation" below ...
planguard verify my_plan        # run verification commands
planguard complete my_plan      # mark done (only if verified snapshot matches)

That's the whole workflow. Everything below is detail you can read as you need it.

Install

pipx install planguard          # any project (recommended)
pip install planguard            # or as a Python dependency
poetry add --group dev planguard # or with Poetry

Works on Linux, macOS, and Windows. Requires Python 3.9+.

Upgrade

0.7.5 Highlights

PlanGuard 0.7.5 keeps legacy verification configs working while improving the migration path:

  • plain-string verify_commands still run for backward compatibility, so upgrades do not break existing plans
  • planguard upgrade --no-wizard now rewrites legacy string-based verify_commands into structured {command: ..., shell: true} entries
  • planguard verify warns when a plan still uses legacy string entries and points to the structured replacement format
  • structured command entries continue to support per-command env, non-shell execution, and better timeout diagnostics

This release preserves the old execution path while making the structured format the preferred steady state.

0.7.2 Highlights

PlanGuard 0.7.2 is a robustness release focused on day-to-day workflow quality:

  • planguard status and planguard list now tolerate malformed plans and flag them inline instead of crashing the whole command
  • baseline capture is scope-aware by default, with unrelated repo dirt tracked separately as context
  • planguard activate --baseline-mode repo and planguard resume --refresh-baseline --baseline-mode repo keep the older repo-wide baseline behavior when you explicitly want it
  • structured verification checks and explicit interpreters are documented as first-class verification options
  • common CLI usage suppresses known low-level dependency warning noise by default, while planguard --verbose ... still leaves a path for debugging unexpected internal failures

Existing 0.5+ installs should upgrade in place:

pipx upgrade planguard
pip install -U planguard
poetry add --group dev planguard@latest

For existing repositories, prefer the scripted upgrade path:

planguard upgrade --no-wizard
planguard check

On legacy repositories that still keep plans under docs/, planguard upgrade --no-wizard now migrates them to the local default .planguard/plans/, refreshes the managed AGENTS workflow, keeps runtime state under .planguard/state/, and rewrites legacy plain-string verify_commands into structured command entries.

Upgrade also normalizes common legacy plan shapes so that a follow-up planguard check is usable immediately:

  • legacy placeholder or deferred plans are converted into suspended review plans instead of remaining executable-but-invalid
  • older migrated plans get safe mechanical backfills for fields such as sprint focus_paths, backlog tests, and newer runtime status sections
  • malformed plan.yaml files are not silently rewritten; planguard check reports them as per-plan parse failures with file and line information and continues checking the remaining plans

During upgrade, the CLI prints a summary of migrated plans, which plans were normalized, which ones were suspended for review, and which ones still need manual intervention.

Manual Fallback

If you only need to refresh the managed AGENTS workflow without migrating plan storage, the manual fallback is:

planguard init --refresh-agents --no-wizard
planguard check

Adopt the Newer Features

Existing plans remain compatible. Once upgraded, you can use the newer capabilities where they help:

  • use planguard plan --template <name> for tailored plan generation
  • use structured verify_commands entries for deterministic or shell-free verification; planguard upgrade can rewrite older string entries for you
  • add renames: mappings to plans that intentionally move files after activation
  • use planguard suspend <plan> / planguard resume <plan> when overlapping work needs to pause safely

Setting Up a Project

planguard init

The wizard scans your repo, detects languages, frameworks, test/build commands, and creates:

File Purpose
AGENTS.md Workflow rules that AI agents read before working
.planguard/project.yaml System description and detected stack
.planguard/conventions.md Coding patterns and style constraints
.planguard/boundaries.md Files/directories agents must never modify
.planguard/policies.yaml Governance rules (database, security, custom)
.gitignore Updated to keep local plans and runtime state out of commits
.planguard/state/active_plans.yaml Local runtime registry of active plans

Review these files, then commit them. Any agent that reads AGENTS.md will follow the workflow.

Storage Layout

Plan definitions and runtime state are intentionally separated:

Path Purpose
.planguard/plans/<plan_name>/plan.yaml Canonical plan definition
.planguard/state/plans/<plan_name>/status.yaml Runtime status, activation baseline, verification results, handoff notes
.planguard/state/active_plans.yaml Local registry of plans and statuses
.planguard/state/log.jsonl Append-only lifecycle log

Legacy repositories that still keep plans under docs/ can be migrated with planguard upgrade --no-wizard.

Creating a Plan

Run the wizard yourself:

planguard plan

Or tell the agent to create one:

Read AGENTS.md and the .planguard context. Create a PlanGuard plan for
"add JWT authentication to the API". Do not change application code yet.

Or skip the wizard entirely:

planguard plan "jwt-auth" --objective "Add JWT auth" --scope "src/api, tests" --priority high --no-wizard

Each plan produces:

  • <plans_root>/<plan_name>/plan.yaml for the local plan definition
  • .planguard/state/plans/<plan_name>/status.yaml for local runtime progress state

That split is intentional: keep both plan definitions and runtime churn local by default, while only the install scaffold stays commit-worthy.

By default, plan definitions are stored under .planguard/plans/ and ignored via .gitignore. If you need a different local path, create .planguard/config.yaml:

plans_root: .planguard/plans    # or any relative path

Templates

Use --template to generate plans tailored to specific change types:

planguard plan --template docs-only "update-readme" --objective "..." --no-wizard
planguard plan --template schema-change "add-users-table" --objective "..." --no-wizard

Available templates: default, docs-only, refactor, schema-change, service-integration. Each adjusts the generated phases, risks, and test strategy. When omitted, default is used — identical to the current behaviour.

Review the plan before activating.

Running Checks

planguard check              # all plans
planguard check my_plan      # specific plan

Checks: structure validation, risk scoring (severity-weighted, threshold 6), dependency graph cycles, scope collisions between plans, scope drift after activation, policy and boundary enforcement.

Activation and Implementation

planguard activate my_plan
# or, when you intentionally want repo-wide baseline capture:
planguard activate my_plan --baseline-mode repo

This re-runs checks, records a git-backed baseline, and marks the plan as active. Only now may the agent write code — and only within the declared scope. If the agent needs to touch files outside scope, update the plan first.

By default, activation captures a scoped baseline from the plan's scope.included paths. If the repo already has unrelated dirty files, PlanGuard records them separately as out-of-scope context instead of mixing them into the scoped baseline. This keeps baseline_changed_files focused on the plan while still preserving visibility into the rest of the worktree.

Example first prompt after activation:

The plan is now active. Implement the approved work for <plan_name>.
Only modify files inside the declared scope, update or add tests as
needed, run the relevant checks, and summarize what changed.

After implementation:

planguard verify my_plan     # runs verify_commands, records passing snapshot
planguard complete my_plan   # succeeds only if snapshot still matches

Small Changes

Not everything needs a plan. Typos, single-line fixes, formatting, and config tweaks can proceed directly.

Exception: database and schema changes are never small. Even adding a single column can require a migration, lock a table, or break downstream consumers. See Database Safety below.

Database Safety

PlanGuard ships with default protections for database work:

  • Migration policy — plans touching migrations/**, alembic/**, or **/migrations/** are flagged as high-risk
  • Schema-change policy — diffs containing SQL DDL or ORM migration operations are flagged
  • Migration boundarymigrations/ is off-limits without an active plan

These are enforced by planguard check when a plan exists. For changes that bypass planning entirely, use guard:

planguard guard

Guard scans the staged diff (or unstaged changes) for migration files, schema DDL, and ORM operations — no plan required. It exits with code 1 if anything is found, making it suitable as a pre-commit hook.

Security

PlanGuard is not a security scanner — use Bandit, Semgrep, or CodeQL for that. But it complements them in two ways:

  1. Policy rules.planguard/policies.yaml includes commented-out security rules you can enable (hardcoded secrets, SQL injection, eval/exec, shell injection, disabled auth). These are regex-based guardrails, not a substitute for AST-aware analysis.

  2. Verification commands — add security scanners to a plan's verify_commands (e.g., bandit -r src/ -ll) so they run during planguard verify and become part of the auditable lifecycle.

Verification Commands

verify_commands in plan.yaml supports three formats:

verify_commands:
  # Plain string — runs via default shell (backward compatible)
  - "pytest tests/ -v"

  # Shell command with explicit interpreter — avoids cross-platform shell issues
  - command: "Get-ChildItem *.ps1 | ForEach-Object { & $_.FullName }"
    interpreter: pwsh
    timeout: 120

  # Non-shell argv invocation with per-command environment variables
  - argv: ["dotnet", "test", "tests/PlanGuard.Tests.csproj"]
    shell: false
    env:
      DOTNET_CLI_HOME: .planguard/tmp/dotnet
      NUGET_PACKAGES: .planguard/tmp/nuget

  # Structured assertion — no shell, declarative
  - check: file_exists
    path: src/config.py
  - check: text_contains
    path: README.md
    pattern: "## Installation"
  - check: file_moved
    from: src/old_module.py
    to: src/new_module.py
  - check: text_not_contains
    path: src/app.py
    pattern: "TODO: remove"

Available structured checks: file_exists, file_not_exists, file_moved, text_contains, text_not_contains.

Command entries also support:

  • env: merge extra environment variables into the subprocess environment
  • shell: false: bypass the platform shell for command strings
  • argv: provide an explicit argument vector for the most portable non-shell execution path

The interpreter field solves cross-platform issues: PlanGuard uses the right invocation style for common interpreters (cmd /C, pwsh -Command, python -c, and shell-style -c for Unix shells) instead of relying on the default system shell. Use bash, sh, pwsh, powershell, cmd, python3, or any executable on PATH.

When a verification command fails or times out, PlanGuard now preserves the tail of partial stdout and stderr so timeout debugging does not lose the most relevant context.

All three formats can be mixed in the same list. Existing plans with plain string commands continue to work unchanged. Invalid structured entries fail verification with concise user-facing messages instead of raw tracebacks.

Policies and Boundaries

.planguard/policies.yaml defines pattern-based rules enforced by planguard check. Rules can block or require_approval, and are scoped to specific paths. Content-pattern rules are evaluated against actual changed files after activation.

.planguard/boundaries.md lists files and directories agents must never modify. If a plan's scope overlaps a boundary, planguard check blocks it.

Plan Lifecycle

Every plan moves through: draftactivecompletedarchived

Status Meaning
draft Plan exists, not yet approved for implementation
active Checks passed, implementation allowed
suspended Paused — other plans can proceed on overlapping scope
completed Work done, verified
archived Removed from active consideration

Suspend and Resume

When one plan needs to pause while a smaller change goes through:

planguard suspend my_plan --reason "waiting on API deploy"
# ... other work proceeds, even on overlapping scope ...
planguard resume my_plan                    # picks up where it left off
planguard resume my_plan --refresh-baseline # re-capture baseline if repo changed significantly

Suspended plans retain their activation data and are excluded from collision detection.

Multiple Plans

Each piece of work gets its own plan with a declared scope. planguard check detects when two active plans have overlapping paths — collisions must be resolved before both can be active. planguard status shows a table of all plans.

If one plan is malformed, planguard status and planguard list still show the other plans and flag the invalid one with a concise parse summary.

For performance, status and list use cached verification results by default. Use --refresh-verification when you want current passed vs stale freshness against the repo.

Session Log

Every lifecycle event is logged to .planguard/state/log.jsonl — an append-only audit trail of what happened, when, and against which git state.

planguard log                # all events
planguard log my_plan        # filter by plan

All Commands

planguard init                    # Set up PlanGuard in a project (wizard)
planguard plan                    # Create a plan (wizard)
planguard plan --template <name>  # Create from template: docs-only, refactor, schema-change, service-integration
planguard check [name]            # Run all checks, or check a specific plan
planguard activate <name>         # Mark plan as ready to implement
planguard activate <name> --baseline-mode repo
planguard verify <name>           # Run verification commands (strings, interpreter, or structured checks)
planguard complete <name>         # Mark plan as done (auto-fills handoff metadata)
planguard suspend <name>          # Pause plan, unblock overlapping work
planguard resume <name>           # Resume a suspended plan
planguard resume <name> --refresh-baseline --baseline-mode repo
planguard archive <name>          # Archive a plan
planguard guard                   # Scan staged diff for database/schema risks
planguard status                  # Fast table of all plans with cached verification state
planguard status --refresh-verification
planguard list [--all]            # Fast list view with cached verification state
planguard list --all --refresh-verification
planguard log [name]              # Show session log (optionally filtered by plan)
planguard graph <name>            # Show dependency graph for a plan

Compatibility

PlanGuard works with any agent that reads AGENTS.md — Claude, Codex, Cursor, Copilot, and others. It incorporates practices from the OpenAI Codex cookbook and Claude Code best practices.

Disabling or Removing

Override the risk threshold — add risk_threshold: 12 to the plan: section of any plan.yaml (default is 6).

Remove PlanGuard — delete .planguard/, the PlanGuard section from AGENTS.md, and uninstall the CLI (pipx uninstall planguard).

Requirements

  • Python 3.9 or newer
  • Works on Linux, macOS, and Windows
  • No system dependencies beyond Python

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

planguard-0.7.5.tar.gz (58.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

planguard-0.7.5-py3-none-any.whl (64.0 kB view details)

Uploaded Python 3

File details

Details for the file planguard-0.7.5.tar.gz.

File metadata

  • Download URL: planguard-0.7.5.tar.gz
  • Upload date:
  • Size: 58.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.12.3 Linux/6.6.87.2-microsoft-standard-WSL2

File hashes

Hashes for planguard-0.7.5.tar.gz
Algorithm Hash digest
SHA256 50ec6ba10528df221afaeead9e799db88e7d760a139de1ad83cf79049f8241f3
MD5 e17292cf578ea31147244d537aebc559
BLAKE2b-256 8d42dea2a9936ff96ab5b2a684e482a3abfefe6acf8208ffe753caf509c478ed

See more details on using hashes here.

File details

Details for the file planguard-0.7.5-py3-none-any.whl.

File metadata

  • Download URL: planguard-0.7.5-py3-none-any.whl
  • Upload date:
  • Size: 64.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.12.3 Linux/6.6.87.2-microsoft-standard-WSL2

File hashes

Hashes for planguard-0.7.5-py3-none-any.whl
Algorithm Hash digest
SHA256 dba45a173c78b2cb9c2d06cf4c4724667db712d6212446afba5699584de12c4c
MD5 f77aa91684e39a9edd6697e2a5c7e17b
BLAKE2b-256 d590b9d96ee9ee8a1d09a4acc18bda0ad486959daa864b1d8efd9482c562bf1b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page