Five idempotency patterns for automation: check-before-act, upsert, force overwrite, unique identifiers, and tombstones. Choose based on constraints and APIs.
Provides five idempotency patterns (check-before-act, upsert, force overwrite, unique identifiers, tombstones) for automation. Use when writing scripts to prevent duplicate operations and handle API constraints.
/plugin marketplace add adaptive-enforcement-lab/claude-skills/plugin install patterns@ael-skillsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
examples.mdscripts/example-1.shscripts/example-2.shscripts/example-3.shscripts/example-4.shscripts/example-5.shscripts/example-6.mermaid| Pattern | Best For | Tradeoff |
|---|---|---|
| Check-Before-Act | Creating resources | Race conditions possible |
| Upsert | APIs with atomic operations | Not universally available |
| Force Overwrite | Content that can be safely replaced | Destructive if misused |
| Unique Identifiers | Natural deduplication | ID logic can be complex |
| Tombstone Markers | Multi-step operations | Markers need cleanup |
Five patterns for making operations idempotent. Each has tradeoffs; choose based on your constraints.
| Pattern | Best For | Tradeoff |
|---|---|---|
| Check-Before-Act | Creating resources | Race conditions possible |
| Upsert | APIs with atomic operations | Not universally available |
| Force Overwrite | Content that can be safely replaced | Destructive if misused |
| Unique Identifiers | Natural deduplication | ID logic can be complex |
| Tombstone Markers | Multi-step operations | Markers need cleanup |
The most common pattern. Check if the target state exists before attempting to create it.
if git ls-remote --heads origin "$BRANCH" | grep -q "$BRANCH"; then
git checkout -B "$BRANCH" "origin/$BRANCH"
else
git checkout -b "$BRANCH"
fi
Use APIs or commands that handle both cases atomically.
gh release create v1.0.0 --notes "Release" || gh release edit v1.0.0 --notes "Release"
Don't check, just overwrite. Safe when overwriting with identical content is acceptable.
git push --force-with-lease origin "$BRANCH"
Generate deterministic IDs so duplicate operations target the same resource.
BRANCH="update-$(sha256sum file.txt | cut -c1-8)"
Leave markers indicating operations completed.
MARKER=".completed-$RUN_ID"
[ -f "$MARKER" ] && exit 0
# Do work...
touch "$MARKER"
See examples.md for detailed code examples.
| Scenario | Recommended Pattern |
|---|---|
| Creating resources (PRs, branches, files) | Check-Before-Act |
| Updating existing resources | Upsert or Force Overwrite |
| Operations with natural keys | Unique Identifiers |
| Complex multi-step operations | Tombstone Markers |
| API supports atomic operations | Upsert |
Combine Patterns
Real-world automation often combines multiple patterns. A workflow might use Check-Before-Act for PR creation, Force Overwrite for branch updates, and Unique Identifiers for naming.
| Pattern | Best For | Tradeoff |
|---|---|---|
| Check-Before-Act | Creating resources | Race conditions possible |
| Upsert | APIs with atomic operations | Not universally available |
| Force Overwrite | Content that can be safely replaced | Destructive if misused |
| Unique Identifiers | Natural deduplication | ID logic can be complex |
| Tombstone Markers | Multi-step operations | Markers need cleanup |
The most common pattern. Check if the target state exists before attempting to create it.
if git ls-remote --heads origin "$BRANCH" | grep -q "$BRANCH"; then
git checkout -B "$BRANCH" "origin/$BRANCH"
else
git checkout -b "$BRANCH"
fi
Use APIs or commands that handle both cases atomically.
gh release create v1.0.0 --notes "Release" || gh release edit v1.0.0 --notes "Release"
Don't check, just overwrite. Safe when overwriting with identical content is acceptable.
git push --force-with-lease origin "$BRANCH"
Generate deterministic IDs so duplicate operations target the same resource.
BRANCH="update-$(sha256sum file.txt | cut -c1-8)"
Leave markers indicating operations completed.
MARKER=".completed-$RUN_ID"
[ -f "$MARKER" ] && exit 0
# Do work...
touch "$MARKER"
See examples.md for detailed code examples.
| Scenario | Recommended Pattern |
|---|---|
| Creating resources (PRs, branches, files) | Check-Before-Act |
| Updating existing resources | Upsert or Force Overwrite |
| Operations with natural keys | Unique Identifiers |
| Complex multi-step operations | Tombstone Markers |
| API supports atomic operations | Upsert |
Combine Patterns
Real-world automation often combines multiple patterns. A workflow might use Check-Before-Act for PR creation, Force Overwrite for branch updates, and Unique Identifiers for naming.
| Pattern | Best For | Tradeoff |
|---|---|---|
| Check-Before-Act | Creating resources | Race conditions possible |
| Upsert | APIs with atomic operations | Not universally available |
| Force Overwrite | Content that can be safely replaced | Destructive if misused |
| Unique Identifiers | Natural deduplication | ID logic can be complex |
| Tombstone Markers | Multi-step operations | Markers need cleanup |
The most common pattern. Check if the target state exists before attempting to create it.
if git ls-remote --heads origin "$BRANCH" | grep -q "$BRANCH"; then
git checkout -B "$BRANCH" "origin/$BRANCH"
else
git checkout -b "$BRANCH"
fi
Use APIs or commands that handle both cases atomically.
gh release create v1.0.0 --notes "Release" || gh release edit v1.0.0 --notes "Release"
Don't check, just overwrite. Safe when overwriting with identical content is acceptable.
git push --force-with-lease origin "$BRANCH"
Generate deterministic IDs so duplicate operations target the same resource.
BRANCH="update-$(sha256sum file.txt | cut -c1-8)"
Leave markers indicating operations completed.
MARKER=".completed-$RUN_ID"
[ -f "$MARKER" ] && exit 0
# Do work...
touch "$MARKER"
flowchart TD
A[Need idempotency] --> B{API has upsert?}
B -->|Yes| C[Use Upsert]
B -->|No| D{Safe to overwrite?}
D -->|Yes| E[Use Force Overwrite]
D -->|No| F{Natural unique key?}
F -->|Yes| G[Use Unique Identifiers]
F -->|No| H{Multi-step operation?}
H -->|Yes| I[Use Tombstone Markers]
H -->|No| J[Use Check-Before-Act]
%% Ghostty Hardcore Theme
style A fill:#5e7175,color:#f8f8f3
style B fill:#fd971e,color:#1b1d1e
style C fill:#a7e22e,color:#1b1d1e
style D fill:#fd971e,color:#1b1d1e
style E fill:#e6db74,color:#1b1d1e
style F fill:#fd971e,color:#1b1d1e
style G fill:#65d9ef,color:#1b1d1e
style H fill:#fd971e,color:#1b1d1e
style I fill:#9e6ffe,color:#1b1d1e
style J fill:#65d9ef,color:#1b1d1e
| Scenario | Recommended Pattern |
|---|---|
| Creating resources (PRs, branches, files) | Check-Before-Act |
| Updating existing resources | Upsert or Force Overwrite |
| Operations with natural keys | Unique Identifiers |
| Complex multi-step operations | Tombstone Markers |
| API supports atomic operations | Upsert |
Combine Patterns
Real-world automation often combines multiple patterns. A workflow might use Check-Before-Act for PR creation, Force Overwrite for branch updates, and Unique Identifiers for naming.
See examples.md for code examples.