mcpbeat Sign in

Program Correctness Prover Agent Skill

Generate Isabelle or Coq proofs establishing partial or total correctness of imperative programs from code and formal specifications. Use when users need to: (1) Prove program correctness using Hoare logic, (2) Generate verification conditions from pre/postconditions, (3) Construct loop invariants and termination arguments, (4) Verify imperative programs with assignments, conditionals, and loops. Supports both partial correctness (if terminates, postcondition holds) and total correctness (terminates and postcondition holds) for both Isabelle/HOL and Coq.

7k tokens
context cost
the whole folder, loaded on every use
3
files
instructions only
0
copies elsewhere
how many repositories repackaged it
141
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/ArabelaTso/Skills-4-SE --skill program-correctness-prover

The instruction itself

21 sections, as written by the author

Program Correctness Prover

Generate formal proofs establishing correctness of imperative programs.

Overview

This skill takes imperative program code with formal specifications (preconditions and postconditions) and generates complete correctness proofs in Isabelle or Coq using Hoare logic. It handles loop invariant generation, verification condition generation, and proof construction for both partial and total correctness.

How to Use

Provide:

  • Program code: Imperative program (assignments, conditionals, loops)
  • Specification: Precondition and postcondition
  • Target system: Isabelle or Coq
  • Correctness type: Partial or total correctness

The skill will generate:

  • Loop invariants (if needed)
  • Verification conditions
  • Complete formal proof
  • Termination argument (for total correctness)

Verification Workflow

Step 1: Analyze Program Structure

Identify program components:

  • Assignments: x := E
  • Sequences: C1; C2
  • Conditionals: if B then C1 else C2
  • Loops: while B do C

Step 2: Generate Loop Invariants

For each loop, construct an invariant that:

  • Holds initially: Precondition implies invariant
  • Preserved by loop body: {I ∧ B} C {I}
  • Implies postcondition: I ∧ ¬B ⟹ Q

Strategies:

  • Generalize postcondition by replacing constants with loop variables
  • Express partial computation at iteration i
  • Maintain relationships between variables

Step 3: Generate Verification Conditions

Apply Hoare logic rules to generate VCs:

Assignment: {P[E/x]} x := E {P}

Sequence: Chain intermediate conditions

Conditional: Prove both branches

Loop: Prove initialization, preservation, and termination

Step 4: Construct Proof

Build formal proof in target system:

  • Apply Hoare logic rules
  • Prove each verification condition
  • Use simplification and automation where possible

Step 5: Add Termination Argument (Total Correctness)

Provide variant function V that:

  • Is non-negative when loop condition holds
  • Strictly decreases each iteration

Example: Sum of Array

Program:

sum := 0;
i := 0;
while i < n do
  sum := sum + a[i];
  i := i + 1
done

Specification:

  • Precondition: n ≥ 0
  • Postcondition: sum = Σ(a[0..n-1])

Analysis:

  • Loop accumulates sum of array elements
  • Loop counter i ranges from 0 to n

Loop Invariant:

I: sum = Σ(a[0..i-1]) ∧ 0 ≤ i ≤ n

Verification Conditions:

  • Initialization: n ≥ 0 ⟹ 0 = Σ(a[0..-1]) ∧ 0 ≤ 0 ≤ n
  • Simplifies to: n ≥ 0 ⟹ 0 = 0 ∧ 0 ≤ n ✓
  • Preservation: {I ∧ i < n} sum := sum + a[i]; i := i + 1 {I}
  • WP: sum + a[i] = Σ(a[0..i]) ∧ 0 ≤ i + 1 ≤ n
  • Verify: From I and i < n, this holds ✓
  • Postcondition: I ∧ ¬(i < n) ⟹ sum = Σ(a[0..n-1])
  • From I and i ≥ n and i ≤ n, get i = n
  • So sum = Σ(a[0..n-1]) ✓
  • Termination (total correctness): V = n - i
  • Initially: V = n ≥ 0 ✓
  • Decreases: i := i + 1 makes V' = V - 1 < V ✓
  • Bounded: i ≤ n ⟹ V ≥ 0 ✓

Isabelle Proof (abbreviated):

lemma sum_array_partial:
  "⦃λs. s ''n'' ≥ 0⦄
   sum := 0;; i := 0;;
   While (λs. s ''i'' < s ''n'')
   Do (sum := (λs. s ''sum'' + s ''a'' (s ''i''));;
       i := (λs. s ''i'' + 1))
   ⦃λs. s ''sum'' = (∑j<s ''n''. s ''a'' j)⦄"
proof -
  define I where "I = (λs. s ''sum'' = (∑j<s ''i''. s ''a'' j) ∧
                            0 ≤ s ''i'' ∧ s ''i'' ≤ s ''n'')"

  (* Initialization *)
  have "⦃λs. s ''n'' ≥ 0⦄ sum := 0;; i := 0 ⦃I⦄"
    unfolding I_def by (auto intro: hoare_seq hoare_asgn)

  (* Loop body preserves invariant *)
  moreover have "⦃λs. I s ∧ s ''i'' < s ''n''⦄
                 sum := (λs. s ''sum'' + s ''a'' (s ''i''));;
                 i := (λs. s ''i'' + 1)
                 ⦃I⦄"
    unfolding I_def by (auto intro: hoare_seq hoare_asgn)

  (* Apply while rule *)
  ultimately have "⦃λs. s ''n'' ≥ 0⦄
                   sum := 0;; i := 0;;
                   While (λs. s ''i'' < s ''n'')
                   Do (sum := (λs. s ''sum'' + s ''a'' (s ''i''));;
                       i := (λs. s ''i'' + 1))
                   ⦃λs. I s ∧ ¬(s ''i'' < s ''n'')⦄"
    by (auto intro: hoare_seq hoare_while)

  (* Postcondition follows from invariant *)
  then show ?thesis
    unfolding I_def by (rule hoare_conseq) auto
qed

Coq Proof (abbreviated):

Theorem sum_array_partial : forall n a,
  n >= 0 ->
  {{ fun st => st N = n /\ n >= 0 }}
  sum ::= 0;;
  i ::= 0;;
  while i < N do
    sum ::= sum + a[i];;
    i ::= i + 1
  done
  {{ fun st => st sum = sum_array a n }}.
Proof.
  intros n a Hn.
  remember (fun st => st sum = sum_array a (st i) /\
                      0 <= st i /\ st i <= st N) as I.

  (* Initialization *)
  eapply hoare_seq. apply hoare_asgn.
  eapply hoare_seq. apply hoare_asgn.

  (* Loop *)
  eapply hoare_consequence_post.
  - apply hoare_while.
    (* Loop body *)
    eapply hoare_seq. apply hoare_asgn.
    eapply hoare_consequence_pre.
    + apply hoare_asgn.
    + intros st [HI Hcond]. subst I. simpl.
      destruct HI as [Hsum [Hi1 Hi2]].
      split; [|split]; try lia.
      rewrite Hsum. unfold sum_array. lia.
  - (* Postcondition *)
    intros st [HI Hcond]. subst I.
    destruct HI as [Hsum [Hi1 Hi2]].
    assert (st i = n) by lia.
    rewrite H. exact Hsum.
Qed.

Example: Maximum of Two Numbers

Program:

if x >= y then
  max := x
else
  max := y

Specification:

  • Precondition: true
  • Postcondition: max = max(x, y)

Analysis:

  • Conditional with two branches
  • No loops, so no invariants needed

Verification Conditions:

  • Then branch: {x ≥ y} max := x {max = max(x, y)}
  • WP: x = max(x, y)
  • Verify: x ≥ y ⟹ x = max(x, y) ✓
  • Else branch: {x < y} max := y {max = max(x, y)}
  • WP: y = max(x, y)
  • Verify: x < y ⟹ y = max(x, y) ✓

Isabelle Proof:

lemma max_correct:
  "⦃λs. True⦄
   If (λs. s ''x'' ≥ s ''y'')
   Then max := (λs. s ''x'')
   Else max := (λs. s ''y'')
   ⦃λs. s ''max'' = max (s ''x'') (s ''y'')⦄"
proof (rule hoare_if)
  show "⦃λs. s ''x'' ≥ s ''y''⦄
        max := (λs. s ''x'')
        ⦃λs. s ''max'' = max (s ''x'') (s ''y'')⦄"
    by (rule hoare_conseq[OF hoare_asgn]) simp
next
  show "⦃λs. ¬(s ''x'' ≥ s ''y'')⦄
        max := (λs. s ''y'')
        ⦃λs. s ''max'' = max (s ''x'') (s ''y'')⦄"
    by (rule hoare_conseq[OF hoare_asgn]) simp
qed

Coq Proof:

Example max_correct :
  {{ fun st => True }}
  if x >= y then
    max ::= x
  else
    max ::= y
  {{ fun st => st max = max (st x) (st y) }}.
Proof.
  apply hoare_if.
  - eapply hoare_consequence_pre.
    + apply hoare_asgn.
    + intros st H. simpl. lia.
  - eapply hoare_consequence_pre.
    + apply hoare_asgn.
    + intros st H. simpl. lia.
Qed.

Common Patterns

Pattern: Sequential Assignments

Program: x := E1; y := E2; z := E3

Strategy: Work backwards with weakest precondition

Pattern: Accumulation Loop

Program: result := init; while i < n do result := f(result, a[i]); i := i + 1

Invariant: result = fold(f, init, a[0..i-1]) ∧ 0 ≤ i ≤ n

Pattern: Search Loop

Program: found := false; while i < n && !found do if a[i] == target then found := true else i := i + 1

Invariant: (∀j. 0 ≤ j < i ⟹ a[j] ≠ target) ∧ 0 ≤ i ≤ n

Pattern: Nested Loops

Program: Outer loop with inner loop

Invariants: Outer invariant + inner invariant (may depend on outer variables)

Correctness Types

Partial Correctness

Definition: If precondition holds and program terminates, postcondition holds

Hoare triple: {P} C {Q}

What to prove:

  • Initialization
  • Preservation
  • Postcondition follows from invariant

Total Correctness

Definition: If precondition holds, program terminates AND postcondition holds

Hoare triple: [P] C [Q] (square brackets)

What to prove:

  • Everything from partial correctness
  • Termination via variant function

Variant requirements:

  • Non-negative when loop condition holds
  • Strictly decreases each iteration

References

Detailed guides for program verification:

  • hoare_logic.md: Complete Hoare logic rules, weakest preconditions, and verification condition generation
  • verification_patterns.md: Common verification patterns with complete proofs in Isabelle and Coq

Load these references when:

  • Need detailed Hoare logic rules
  • Working with complex loop invariants
  • Generating verification conditions
  • Need example proofs for similar programs

Tips

  • Start simple: Verify assignments and sequences before loops
  • Generalize postcondition: Often leads to good loop invariants
  • State partial progress: Invariant should express what's computed so far
  • Include bounds: Always include loop counter bounds in invariant
  • Work backwards: Use weakest precondition for simple programs
  • Test invariant: Check initialization, preservation, and postcondition
  • Choose simple variants: n - i is often sufficient for termination
  • Use automation: Let simp/auto handle arithmetic when possible

Other skills for the same job

different authors, same section of the catalogue
MCP Builder
by anthropics
vendor ×13

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

30k tokens scripts
Changelog Generator
by frostant
×9

Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.

774 tokens
Finishing A Development Branch
by ZhanlinCui
×7

Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup

1k tokens
MCP Builder
by JayZeeDesign
×7

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

37k tokens scripts
Vercel React Native Skills
by vercel-labs
vendor ×6

React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.

39k tokens
Vercel React Best Practices
by ratacat
×5

React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

34k tokens
Next Best Practices
by vercel-labs
vendor ×4

Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling

20k tokens
Using Git Worktrees
by ZhanlinCui
×4

Use when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees with smart directory selection and safety verification

1k tokens

How to use it

Copy the folder

Take arabelatso/program-correctness-prover from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.