Rune-stone

How to Use

When given an existing function (or class method), analyze it and generate a complete RUNE spec that describes its current behavior.

Input: source code of one or more functions (any language). Output: a .rune YAML spec or Markdown section for each function.


Process

Step 1: Extract SIGNATURE

Read the function declaration exactly as written. Use the source language’s actual syntax:

Python:

def calculate_discount(price: float, percentage: int) -> float:
SIGNATURE: |
  def calculate_discount(price: float, percentage: int) -> float

Go:

func CalculateDiscount(price float64, percentage int) (float64, error) {
SIGNATURE: |
  func CalculateDiscount(price float64, percentage int) (float64, error)

TypeScript:

function calculateDiscount(price: number, percentage: number): number {
SIGNATURE: |
  function calculateDiscount(price: number, percentage: number): number

If the language doesn’t have type annotations (plain JavaScript, Ruby, Lua), infer types from:

Step 2: Write INTENT

Summarize what the function does in 1-3 sentences based on:

Do NOT describe implementation details. Describe purpose.

# Bad (implementation details):
INTENT: |
  Uses regex pattern to match RFC 5322 emails and returns a tuple.

# Good (purpose):
INTENT: |
  Validates an email address against RFC 5322 standards.
  Returns a validity flag and a message explaining the result.

Step 3: Extract BEHAVIOR Rules

Analyze the function’s control flow and convert each branch to a WHEN/THEN rule. The source language varies, but the BEHAVIOR output is always the same WHEN/THEN format:

From Python:

if not email:
    return (False, "Email cannot be empty")

From Go:

if email == "" {
    return false, fmt.Errorf("email cannot be empty")
}

From Rust:

if email.is_empty() {
    return Err("Email cannot be empty".to_string());
}

All extract to the same BEHAVIOR:

BEHAVIOR:
  - WHEN email is empty THEN return error "Email cannot be empty"

Rules for extraction:

Step 4: Extract CONSTRAINTS

Look for input validation patterns in any language:

CONSTRAINTS:
  - "price: must be non-negative number"
  - "percentage: integer between 0 and 100 inclusive"

Step 5: Identify EDGE_CASES

Look for:

EDGE_CASES:
  - "empty string: returns error"
  - "percentage = 0: returns original price"
  - "percentage = 100: returns 0.0"

Step 6: Generate TESTS

Create test cases that cover:

  1. Happy path — normal inputs that succeed (2-3 tests)
  2. Boundary — values at the edges of conditions (2-3 tests)
  3. Error cases — inputs that trigger each error branch (1 per branch)
TESTS:
  # Happy path
  - "calculate_discount(100.0, 20) == 80.0"
  - "calculate_discount(50.0, 10) == 45.0"

  # Boundary
  - "calculate_discount(100.0, 0) == 100.0"
  - "calculate_discount(100.0, 100) == 0.0"

  # Error cases
  - "calculate_discount(-10.0, 20) raises error"
  - "calculate_discount(100.0, -5) raises error"

Step 7: Add Metadata

DEPENDENCIES:
  - "library_name"  # only external imports/packages used by the function

COMPLEXITY:
  time: O(n)  # analyze loops and recursion
  space: O(1) # analyze allocations

Step 8: Assemble and Validate

Combine all sections into a complete spec. Then self-validate:


Output Format

Ask the user which format they prefer. Default to the format used elsewhere in their project.

Set meta.language to the language detected from the source code.

YAML format:

---
meta:
  name: function_name
  language: <detected from source>
  version: 1.0
  tags: [inferred, tags]
---

RUNE: function_name

SIGNATURE: |
  ...
INTENT: |
  ...
BEHAVIOR:
  - ...
TESTS:
  - ...
# ... remaining fields

Markdown format:

### function_name

**SIGNATURE:** `...`

**INTENT:** ...

**BEHAVIOR:**
- WHEN ... THEN ...

**TESTS:**
- `...`

Rules