Claude Skills Guide

Claude Code for Halmos Symbolic Workflow Guide

Symbolic testing has emerged as one of the most powerful techniques for discovering edge cases and bugs that traditional unit tests often miss. Halmos, a Python symbolic testing library, uses symbolic execution to automatically generate test cases and verify code correctness. When combined with Claude Code’s natural language interface, you can create a powerful workflow for symbolic testing that feels almost like having a pair programmer specialized in formal verification at your side.

This guide walks you through integrating Claude Code with Halmos, setting up automated symbolic testing workflows, and extracting maximum value from this combination.

Understanding Halmos and Symbolic Testing

Before diving into the integration, let’s briefly cover what makes Halmos special. Unlike conventional testing where you provide concrete inputs, symbolic testing treats inputs as symbolic variables and explores all possible execution paths through your code.

Halmos works by:

  1. Collecting functions marked for testing
  2. Running them with symbolic arguments
  3. Exploring all branches and paths
  4. Checking for crashes, assertion failures, or contract violations

This approach catches bugs that would only manifest with specific inputs you’d likely never think to test manually.

Setting Up Halmos with Claude Code

The first step is installing Halmos and configuring your project for symbolic testing:

pip install halmos

Create a pyproject.toml or halmos.toml configuration in your project root:

[tool.halmos]
timeout = 30
max-memory = 2048
path = ["src/your_package"]

Mark your functions for testing using the @halmos.main decorator or by adding docstrings with Halmos: markers:

# src/your_package/math_utils.py
def calculate_discount(price: float, discount_percent: float) -> float:
    """Calculate the final price after applying a discount.
    
    Halmos: test-when price > 0, discount_percent >= 0, discount_percent <= 100
    """
    if discount_percent < 0 or discount_percent > 100:
        raise ValueError("Discount must be between 0 and 100")
    return price * (1 - discount_percent / 100)

Creating a Claude Skill for Halmos Workflows

Now let’s create a Claude skill that encapsulates Halmos workflow patterns. This skill will help you:

  1. Set up symbolic testing for new modules
  2. Analyze and interpret Halmos results
  3. Generate additional test cases based on findings

Create a file halmos-workflow-skill.md:

---
name: Halmos Symbolic Testing Workflow
description: Assists with Halmos symbolic testing setup, execution, and result analysis
---

# Halmos Symbolic Testing Workflow

You help users integrate Halmos symbolic testing into their Python projects.

## Initial Setup

When setting up Halmos for a new project:
1. Verify Halmos is installed: `pip show halmos`
2. Create/update `pyproject.toml` with Halmos configuration
3. Identify candidate functions for symbolic testing
4. Add appropriate markers/docstrings

## Running Symbolic Tests

Execute Halmos from the project root:
- Full run: `halmos`
- Specific module: `halmos --path src/my_package`
- With verbose output: `halmos -v`

## Interpreting Results

When Halmos reports findings:
1. Identify the specific path/branch that triggered the issue
2. Understand the symbolic constraints at that point
3. Determine if it's a genuine bug or a false positive
4. If genuine, add appropriate guards or fix the code
5. If false positive, add contract assertions to constrain the domain

This skill becomes your interface for all Halmos-related interactions with Claude.

Practical Example: Testing a Payment Processor

Let’s walk through a realistic example of using Claude Code with Halmos. Consider a payment processing module:

# src/payment/processor.py
def calculate_total(base_amount: float, tax_rate: float, discount: float) -> float:
    """Calculate total with tax and discount applied."""
    if tax_rate < 0:
        raise ValueError("Tax rate cannot be negative")
    if discount < 0:
        raise ValueError("Discount cannot be negative")
    
    subtotal = base_amount - discount
    if subtotal < 0:
        subtotal = 0
    
    return subtotal * (1 + tax_rate)

Ask Claude Code to set up symbolic testing:

“Set up Halmos testing for this payment processor. Configure it to explore paths where tax_rate and discount have various values.”

Claude will:

  1. Create the appropriate configuration
  2. Run Halmos with targeted options
  3. Analyze the output for potential issues

Typical output might reveal edge cases:

Exploring paths in calculate_total...
Found 12 paths
Path 5: base_amount=0, tax_rate=0.0825, discount=100
  Result: subtotal clamped to 0, returns 0
  
Path 8: base_amount=50, tax_rate=-0.5, discount=0  
  ERROR: ValueError: Tax rate cannot be negative

This reveals that while we handle negative discounts, the interaction with zero base amounts might need attention.

Automating Halmos Workflows

One of Claude Code’s strengths is automating repetitive tasks. Create patterns for common workflows:

Continuous Integration Pattern

Add a script that runs Halmos on changed code:

#!/bin/bash
# scripts/symbolic-check.sh

MODULE=$1
if [ -z "$MODULE" ]; then
    echo "Usage: $0 <module_path>"
    exit 1
fi

echo "Running symbolic tests for $MODULE..."
halmos --path "src/$MODULE" --report-on "src/$MODULE"

if [ $? -eq 0 ]; then
    echo "✓ Symbolic tests passed"
else
    echo "✗ Symbolic tests found issues"
    exit 1
fi

Pre-commit Integration

Configure Halmos to run before commits:

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: halmos-check
        name: Halmos Symbolic Tests
        entry: ./scripts/symbolic-check.sh
        language: system
        pass_filenames: false
        types: [python]
        args: ["payment"]  # Adjust per project

Best Practices for Claude + Halmos Workflows

When combining Claude Code with Halmos, keep these tips in mind:

  1. Start small: Begin with focused functions rather than entire modules. Halmos exploration grows exponentially with code complexity.

  2. Add contracts: Use assertions and type hints to help Halmos narrow the search space:

def process_order(items: list[dict], tax_rate: float) -> float:
    assert all(isinstance(i.get('price'), (int, float)) and i['price'] >= 0 for i in items)
    assert 0 <= tax_rate <= 1
    # Now Halmos knows the valid input domain
  1. Iterate on failures: When Halmos finds issues, fix one at a time and re-run. This prevents overwhelming output.

  2. Use timeouts wisely: Set reasonable timeouts (--timeout) to prevent indefinite exploration of complex code paths.

  3. Document discovered invariants: When Halmos reveals patterns (like “this function never returns negative”), document them as contracts for future maintainers.

Conclusion

Integrating Claude Code with Halmos transforms symbolic testing from an advanced technique into an accessible daily practice. Claude acts as your interface—translating natural language requests into precise Halmos commands, interpreting complex output, and guiding you through fixing discovered issues. Together, they form a powerful debugging and verification workflow that catches bugs before they reach production.

Start by adding Halmos to one module in your project, create the Claude skill for Halmos workflows, and gradually expand symbolic testing coverage. The initial investment pays dividends in code quality and confidence.

Built by theluckystrike — More at zovo.one