Best for
- Use this skill when documenting APIs, creating formal verification annotations, defining function contracts, specifying class invariants, writing design-by-contract code, or preparing code for formal verification.
ArabelaTso/Skills-4-SE/skills/specification-generator/SKILL.md
Generate formal specifications including preconditions, postconditions, invariants, and contracts from code or requirements. Use this skill when documenting APIs, creating formal verification annotations, defining function contracts, specifying class invariants, writing design-by-contract code, or preparing code for formal verification. Supports multiple specification languages including JML, ACSL, Dafny, Eiffel contracts, and documentation annotations.
Decision brief
Systematically generate formal specifications from code and requirements. Produces preconditions, postconditions, invariants, and behavioral contracts that enable verification, documentation, and design-by-contract programming.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/ArabelaTso/Skills-4-SE --skill "skills/specification-generator"Inspect the Agent Skill "specification-generator" from https://github.com/ArabelaTso/Skills-4-SE/blob/4f38503747e0617504bce5329283ef837d375c09/skills/specification-generator/SKILL.md at commit 4f38503747e0617504bce5329283ef837d375c09. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Understand what needs to be specified:
Understand what needs to be specified:
Determine what to specify:
Select appropriate format:
Generate formal contracts:
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 95/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 236 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Systematically generate formal specifications from code and requirements. Produces preconditions, postconditions, invariants, and behavioral contracts that enable verification, documentation, and design-by-contract programming.
Define required conditions before execution:
Specify guaranteed outcomes after execution:
Identify properties that always hold:
Create complete behavioral specifications:
Understand what needs to be specified:
For existing code:
For requirements:
Example code:
def withdraw(account, amount):
if account.balance < amount:
raise InsufficientFundsError()
account.balance -= amount
return account.balance
Analysis:
Determine what to specify:
Preconditions (requires/assume):
Postconditions (ensures/guarantee):
Invariants:
Example identification:
# withdraw function
Preconditions:
- account is not None
- amount > 0
- account.balance >= amount (to succeed without exception)
Postconditions:
- If successful: account.balance == old(account.balance) - amount
- If successful: return value == new balance
- If insufficient: raises InsufficientFundsError
- account object still valid
Invariants (Account class):
- balance >= 0 (always)
- account_number is immutable
Select appropriate format:
Specification languages:
| Language | Use Case | Example |
|---|---|---|
| JML (Java) | Java programs | //@ requires, //@ ensures |
| ACSL (C) | C programs | /*@ requires, /*@ ensures |
| Dafny | Verified code | requires, ensures |
| Eiffel | Design-by-contract | require, ensure |
| Python docstring | Documentation | :param:, :raises:, :returns: |
| TypeScript | Type annotations | Type predicates, assertions |
| Hoare logic | Formal proofs | {P} S {Q} notation |
Example language choice:
Generate formal contracts:
Format depends on language:
JML (Java):
/*@ requires amount > 0;
@ requires account != null;
@ requires account.balance >= amount;
@ ensures account.balance == \old(account.balance) - amount;
@ ensures \result == account.balance;
@ signals (InsufficientFundsError e) account.balance < amount;
@*/
public int withdraw(Account account, int amount) {
// implementation
}
ACSL (C):
/*@ requires amount > 0;
@ requires \valid(account);
@ requires account->balance >= amount;
@ ensures account->balance == \old(account->balance) - amount;
@ ensures \result == account->balance;
@*/
int withdraw(Account *account, int amount) {
// implementation
}
Dafny:
method Withdraw(account: Account, amount: int) returns (newBalance: int)
requires amount > 0
requires account.balance >= amount
ensures account.balance == old(account.balance) - amount
ensures newBalance == account.balance
modifies account
{
// implementation
}
Python (docstring):
def withdraw(account: Account, amount: float) -> float:
"""
Withdraw amount from account.
:param account: The account to withdraw from
:param amount: The amount to withdraw (must be positive)
:raises InsufficientFundsError: If balance < amount
:raises ValueError: If amount <= 0
:returns: The new account balance
Preconditions:
- account is not None
- amount > 0
- account.balance >= amount (for successful withdrawal)
Postconditions:
- account.balance == old_balance - amount
- return value == account.balance
- If insufficient funds: InsufficientFundsError raised
- account.balance >= 0 (invariant preserved)
"""
# implementation
Ensure specifications are correct:
Verification steps:
Example verification:
# Test preconditions
assert amount > 0 # Valid
assert account is not None # Valid
assert account.balance >= amount # Valid for success case
# Test postconditions
old_balance = account.balance
result = withdraw(account, 100)
assert account.balance == old_balance - 100 # Check
assert result == account.balance # Check
# Test invariants
assert account.balance >= 0 # Should always hold
Code:
def sqrt(x):
"""Compute square root."""
return x ** 0.5
Generated specification:
def sqrt(x: float) -> float:
"""
Compute the square root of x.
:param x: The number to compute square root of
:returns: The square root of x
:raises ValueError: If x < 0
Preconditions:
- x >= 0
Postconditions:
- result >= 0
- abs(result * result - x) < 1e-10 # Precision tolerance
- If x == 0, then result == 0
- If x == 1, then result == 1
"""
if x < 0:
raise ValueError("Cannot compute square root of negative number")
return x ** 0.5
JML version:
/*@ requires x >= 0;
@ ensures \result >= 0;
@ ensures Math.abs(\result * \result - x) < 1e-10;
@ ensures x == 0 ==> \result == 0;
@ ensures x == 1 ==> \result == 1;
@ signals (IllegalArgumentException e) x < 0;
@*/
public double sqrt(double x) {
if (x < 0) throw new IllegalArgumentException();
return Math.sqrt(x);
}
Code:
def sort_list(items):
"""Sort list in-place."""
items.sort()
Generated specification:
def sort_list(items: List[int]) -> None:
"""
Sort list in ascending order (in-place).
:param items: List to sort (modified in-place)
Preconditions:
- items is not None
- All elements in items are comparable
Postconditions:
- len(items) == len(old(items)) # Same length
- set(items) == set(old(items)) # Same elements
- For all i, j: i < j implies items[i] <= items[j] # Sorted
- items is sorted in ascending order
Frame conditions:
- Only items is modified
- No other data structures affected
"""
if items is None:
raise ValueError("items cannot be None")
items.sort()
ACSL version:
/*@ requires \valid(arr + (0..len-1));
@ ensures \forall integer i, j;
@ 0 <= i < j < len ==> arr[i] <= arr[j];
@ ensures Permutation{Pre,Post}(arr, 0, len-1);
@ assigns arr[0..len-1];
@*/
void sort_array(int *arr, int len) {
// implementation
}
Code:
class BankAccount:
def __init__(self, account_number, initial_balance):
self.account_number = account_number
self.balance = initial_balance
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
if self.balance < amount:
raise InsufficientFundsError()
self.balance -= amount
Generated specification:
class BankAccount:
"""
Bank account with balance and account number.
Class Invariants:
- balance >= 0 (balance never negative)
- account_number is immutable (never changes after init)
- account_number is unique (within system)
"""
def __init__(self, account_number: str, initial_balance: float) -> None:
"""
Create new bank account.
Preconditions:
- account_number is not None and not empty
- initial_balance >= 0
- account_number not already in use
Postconditions:
- self.account_number == account_number
- self.balance == initial_balance
- Invariants established
"""
if not account_number:
raise ValueError("Account number required")
if initial_balance < 0:
raise ValueError("Initial balance cannot be negative")
self.account_number = account_number
self.balance = initial_balance
def deposit(self, amount: float) -> None:
"""
Deposit amount into account.
Preconditions:
- amount > 0
- Invariants hold
Postconditions:
- self.balance == old(self.balance) + amount
- Invariants still hold
Frame conditions:
- Only self.balance modified
- account_number unchanged
"""
if amount <= 0:
raise ValueError("Deposit amount must be positive")
self.balance += amount
assert self.balance >= 0 # Invariant check
def withdraw(self, amount: float) -> None:
"""
Withdraw amount from account.
Preconditions:
- amount > 0
- self.balance >= amount
- Invariants hold
Postconditions:
- self.balance == old(self.balance) - amount
- Invariants still hold
Exceptional postconditions:
- If balance < amount: InsufficientFundsError raised
- If balance < amount: balance unchanged
"""
if amount <= 0:
raise ValueError("Withdrawal amount must be positive")
if self.balance < amount:
raise InsufficientFundsError()
self.balance -= amount
assert self.balance >= 0 # Invariant check
JML version:
public class BankAccount {
/*@ invariant balance >= 0;
@ invariant account_number != null;
@*/
private /*@ spec_public @*/ double balance;
private /*@ spec_public @*/ final String account_number;
/*@ requires account_number != null;
@ requires initial_balance >= 0;
@ ensures this.account_number == account_number;
@ ensures this.balance == initial_balance;
@*/
public BankAccount(String account_number, double initial_balance) {
// implementation
}
/*@ requires amount > 0;
@ ensures balance == \old(balance) + amount;
@ assignable balance;
@*/
public void deposit(double amount) {
// implementation
}
/*@ requires amount > 0;
@ requires balance >= amount;
@ ensures balance == \old(balance) - amount;
@ signals (InsufficientFundsError e) \old(balance) < amount;
@ assignable balance;
@*/
public void withdraw(double amount) throws InsufficientFundsError {
// implementation
}
}
Code:
def sum_array(arr):
total = 0
for i in range(len(arr)):
total += arr[i]
return total
Generated specification with loop invariants:
def sum_array(arr: List[int]) -> int:
"""
Compute sum of all elements in array.
Preconditions:
- arr is not None
Postconditions:
- result == sum of all elements in arr
"""
total = 0
# Loop invariant:
# - 0 <= i <= len(arr)
# - total == sum(arr[0:i])
# - total is sum of elements seen so far
for i in range(len(arr)):
# At this point:
# - Invariant holds at loop entry
# - i < len(arr)
total += arr[i]
# At this point:
# - total == sum(arr[0:i+1])
# - Invariant holds for next iteration
# At loop exit:
# - i == len(arr)
# - total == sum(arr[0:len(arr)]) == sum(arr)
return total
Dafny version:
method SumArray(arr: array<int>) returns (total: int)
requires arr != null
ensures total == sum(arr[..])
{
total := 0;
var i := 0;
while i < arr.Length
invariant 0 <= i <= arr.Length
invariant total == sum(arr[..i])
{
total := total + arr[i];
i := i + 1;
}
}
Code:
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
Generated specification:
def binary_search(arr: List[int], target: int) -> int:
"""
Search for target in sorted array using binary search.
Preconditions:
- arr is not None
- arr is sorted in ascending order:
For all i, j: 0 <= i < j < len(arr) implies arr[i] <= arr[j]
Postconditions:
- If result >= 0: arr[result] == target
- If result >= 0: 0 <= result < len(arr)
- If result == -1: target not in arr
- If multiple occurrences: returns any valid index
"""
if arr is None:
raise ValueError("Array cannot be None")
left, right = 0, len(arr) - 1
# Loop invariant:
# - 0 <= left <= right + 1 <= len(arr)
# - If target in arr, then target in arr[left:right+1]
# - All elements in arr[0:left] < target
# - All elements in arr[right+1:] > target
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
# Postcondition: arr[mid] == target
return mid
elif arr[mid] < target:
left = mid + 1
# Invariant maintained: arr[0:left] < target
else:
right = mid - 1
# Invariant maintained: arr[right+1:] > target
# Loop exit: left > right
# Invariant implies target not in arr
return -1
ACSL version:
/*@ requires \valid_read(arr + (0..len-1));
@ requires Sorted(arr, 0, len-1);
@
@ behavior found:
@ ensures 0 <= \result < len;
@ ensures arr[\result] == target;
@
@ behavior not_found:
@ ensures \result == -1;
@ ensures \forall integer i; 0 <= i < len ==> arr[i] != target;
@
@ complete behaviors;
@ disjoint behaviors;
@*/
int binary_search(int *arr, int len, int target) {
int left = 0, right = len - 1;
/*@ loop invariant 0 <= left <= right + 1 <= len;
@ loop invariant \forall integer i; 0 <= i < left ==> arr[i] < target;
@ loop invariant \forall integer i; right < i < len ==> arr[i] > target;
@ loop variant right - left;
@*/
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
Code:
class Node:
def __init__(self, data):
self.data = data
self.next = None
def reverse_list(head):
prev = None
current = head
while current:
next_node = current.next
current.next = prev
prev = current
current = next_node
return prev
Generated specification:
class Node:
"""
Linked list node.
Invariants:
- data can be any value
- next is either None or a Node
"""
def __init__(self, data: Any) -> None:
"""
Create new node.
Postconditions:
- self.data == data
- self.next == None
"""
self.data = data
self.next = None
def reverse_list(head: Optional[Node]) -> Optional[Node]:
"""
Reverse a singly linked list in-place.
Preconditions:
- head is None or points to valid linked list
- List is acyclic (no cycles)
Postconditions:
- Returns new head of reversed list
- If head is None, returns None
- Number of nodes unchanged
- All data values preserved
- Order of data values is reversed
- Original list structure modified
- If original: A -> B -> C -> None
Then result: C -> B -> A -> None
Frame conditions:
- Only next pointers modified
- data values unchanged
- No new nodes created
- No nodes deleted
"""
prev = None
current = head
# Loop invariant:
# - prev points to reversed portion
# - current points to unreversed portion
# - prev is reverse of head[0:processed]
# - current is head[processed:]
while current is not None:
next_node = current.next
current.next = prev
prev = current
current = next_node
# Invariant maintained:
# - Moved one node from unreversed to reversed
# - All processed nodes are reversed and point to prev
# Loop exit: current is None
# prev points to new head (last original node)
# All nodes reversed
return prev
Code:
from threading import Lock
class Counter:
def __init__(self):
self.value = 0
self.lock = Lock()
def increment(self):
with self.lock:
self.value += 1
Generated specification:
class Counter:
"""
Thread-safe counter.
Class Invariants:
- value >= 0
- lock is always valid
- value reflects total increments
Concurrency Properties:
- increment is atomic
- Multiple threads can safely call increment
- No race conditions
- Each increment increases value by exactly 1
"""
def __init__(self) -> None:
"""
Create new counter.
Postconditions:
- self.value == 0
- self.lock is initialized
- Thread-safe operations enabled
"""
self.value = 0
self.lock = Lock()
def increment(self) -> None:
"""
Atomically increment counter by 1.
Preconditions:
- Counter is initialized
Postconditions:
- self.value == old(self.value) + 1
- Operation is atomic (thread-safe)
Concurrency guarantees:
- Mutual exclusion: Only one thread in critical section
- Progress: Non-blocking (eventually acquires lock)
- No deadlock: Lock always released
- Visibility: Changes visible to all threads
"""
with self.lock:
# Critical section
old_value = self.value
self.value += 1
# Postcondition: self.value == old_value + 1
def function_name(param1: Type1, param2: Type2) -> ReturnType:
"""
[Brief description]
:param param1: [Description]
:param param2: [Description]
:returns: [Description]
:raises ExceptionType: [When]
Preconditions:
- [Condition on param1]
- [Condition on param2]
- [State requirement]
Postconditions:
- [Property of return value]
- [State change]
- [Side effect]
"""
class ClassName:
"""
[Description]
Class Invariants:
- [Property 1 always true]
- [Property 2 always true]
"""
def __init__(self, ...):
"""
Preconditions: [...]
Postconditions: [Invariants established]
"""
def method(self, ...):
"""
Preconditions: [Invariants hold, ...]
Postconditions: [Invariants still hold, ...]
"""
# Loop invariant:
# - [Property true at loop entry and after each iteration]
# - [Relates loop variable to progress]
# - [Relates accumulator to partial result]
while condition:
# Invariant holds here
# Loop body
# Invariant maintained
for all i: 0 <= i < len(arr) implies arr[i] >= 0exists i: 0 <= i < len(arr) and arr[i] == targetold(variable) - Value before execution\old(x) (JML/ACSL) - Previous value of x== - Equality!= - Inequality<, <=, >, >= - Ordering==> - Implication&&, || - Logical and/orset(arr) - Set of elementslen(arr) - Length/sizearr[i:j] - Slice/rangeFrequently asked questions
Systematically generate formal specifications from code and requirements. Produces preconditions, postconditions, invariants, and behavioral contracts that enable verification, documentation, and design-by-contract programming.
The source record exposes this install command: npx skills add https://github.com/ArabelaTso/Skills-4-SE --skill "skills/specification-generator". Inspect the command and pinned source before running it.
Alternatives
NintendaDev/unikit-ai
Generate and maintain the project's TECHNICAL documentation from its codebase — scans the project structure, tech stack, and module boundaries, then writes a lean README landing page plus detailed topic pages (architecture, modules, setup, build, APIs), only the docs that are relevant. Use whenever the user wants to create, update, or validate documentation of the CODE or the project itself, e.g. "generate documentation", "create docs", "write the README", "update the project docs", "document th
mgiovani/cc-arsenal
Multi-agent review team: architecture, security, performance, testing, style, docs/UX, plus an adversary that cross-examines the other 6, for security-sensitive, architectural, or large PRs (15+ files) where a single-agent pass risks missing cross-cutting issues. Use for auth/payments/PII changes, schema/pattern changes, compliance sign-off, or when asked to 'get the review team on this' / 'multi-agent review' / 'thorough review before merge'. For a standard PR or a quick pre-merge check, use /r
Jamie-BitFlight/claude_skills
Use when creating a new Claude Code plugin from scratch — orchestrates prerequisite check, user discussion, parallel research, design with verification, atomic implementation, multi-layer validation, documentation, and final verification. For existing plugin improvement, use /plugin-creator:plugin-lifecycle instead.
wyre-technology/msp-claude-plugins
Hudu secure credential storage: the /api/v1/asset_passwords endpoint (the UI calls these "Passwords"), company scoping and password folders, TOTP secrets, per-API-key password permissions, activity-log auditing, rotation workflows, and output-safety rules for handling plaintext credential values.