Metadata-Version: 2.3
Name: planguard
Version: 0.7.6
Summary: Make AI-assisted development safer, auditable, and release-ready without breaking normal CLI and git workflows
License: MIT
Keywords: ai,agents,cli,developer-tools,governance,pypi
Author: Arkimetrix Analytics Ltd.
Requires-Python: >=3.9,<4.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Dist: networkx (>=3.0)
Requires-Dist: pyyaml (>=6.0.3,<7.0.0)
Requires-Dist: rich (>=13)
Requires-Dist: typer (>=0.9)
Project-URL: Documentation, https://github.com/DBArkimetrix/planguard#readme
Project-URL: Homepage, https://github.com/DBArkimetrix/planguard
Project-URL: Issues, https://github.com/DBArkimetrix/planguard/issues
Project-URL: Repository, https://github.com/DBArkimetrix/planguard
Description-Content-Type: text/markdown

# 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

```bash
# 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

```bash
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.6 Highlights

PlanGuard `0.7.6` is a Windows correctness fix:

- `planguard complete` no longer rejects plans whose `status.yaml` was rewritten by `planguard verify` on Windows
- bookkeeping paths are now normalized to forward slashes so they match the paths git produces, regardless of OS

### 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:

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

For existing repositories, prefer the scripted upgrade path:

```bash
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:

```bash
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

```bash
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:

```bash
planguard plan
```

Or tell the agent to create one:

```text
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:

```bash
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`:

```yaml
plans_root: .planguard/plans    # or any relative path
```

### Templates

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

```bash
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

```bash
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

```bash
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:

```text
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:

```bash
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](#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 boundary** — `migrations/` 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**:

```bash
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](https://bandit.readthedocs.io/), [Semgrep](https://semgrep.dev/), or [CodeQL](https://codeql.github.com/) 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:

```yaml
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: **draft** → **active** → **completed** → **archived**

| 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:

```bash
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.

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

## All Commands

```bash
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](https://developers.openai.com/codex/learn/best-practices) and [Claude Code best practices](https://code.claude.com/docs/en/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

