task-graph-commit-lock — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited task-graph-commit-lock (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Serialize git operations across multiple concurrent agents using a well-known sentinel task as a mutex. This pattern uses existing task-graph primitives (claim/release) -- no code changes or new tools are needed.
Prerequisite: Understand task-graph-basics for tool reference.
When multiple agents work in the same repository concurrently, their git operations can collide:
git add + git commit simultaneouslygit pull --rebase conflicts with another's in-flight commitGit's index is a shared mutable resource. Without serialization, concurrent agents produce merge conflicts, lost commits, or corrupted state.
Create a well-known task with a reserved ID (e.g., _lock:git-commit) that serves as a mutex. Agents must claim this task before performing git operations and release it immediately after.
The task-graph claiming system already provides the semantics we need:
working (a timed state), which sets exclusive ownership. If another agent already owns it, the claim fails.This is exactly a mutex lock/unlock pattern.
The coordinator (or any agent during project setup) creates the sentinel task once:
create(
id="_lock:git-commit",
title="[LOCK] Git Commit Serialization",
description="Sentinel task for serializing git operations. Claim before git add/commit/push, release after. Do NOT complete or delete this task.",
tags=["lock", "infrastructure"],
priority=0
)Important properties of the sentinel task:
_lock:git-commit -- all agents reference this exact IDpending/working cycle forever# 1. ACQUIRE the lock (claim the sentinel task)
claim(worker_id=your_id, task="_lock:git-commit")
# If this fails -> another agent is committing. Wait and retry.
# 2. PERFORM git operations (you have exclusive access)
git add <files>
git commit -m "your message"
git push # optional
# 3. RELEASE the lock (return sentinel to pending)
update(worker_id=your_id, task="_lock:git-commit", status="pending",
reason="Git operations complete")
# The sentinel is now available for other agents.MAX_RETRIES = 5
RETRY_DELAY_MS = 2000
for attempt in range(MAX_RETRIES):
try:
# Acquire lock
claim(worker_id=my_id, task="_lock:git-commit")
# Protected section - git operations
try:
git add <staged_files>
git commit -m "message"
# optional: git push
finally:
# ALWAYS release, even on failure
update(worker_id=my_id, task="_lock:git-commit",
status="pending", reason="Released after git ops")
break # Success - exit retry loop
except ClaimFailed:
# Another agent holds the lock
thinking(agent=my_id,
thought=f"Waiting for git lock (attempt {attempt+1}/{MAX_RETRIES})")
sleep(RETRY_DELAY_MS * (attempt + 1)) # Linear backoff
raise Error("Could not acquire git lock after retries")| Property | Task-Graph Behavior | Mutex Equivalent |
|---|---|---|
claim() succeeds | Task transitions to working, owner set | Lock acquired |
claim() fails | Task already owned by another agent | Lock contention |
update(status="pending") | Owner cleared, task returns to pool | Lock released |
| Agent disconnects | Stale reaper releases claims after timeout | Lock timeout / deadlock recovery |
claim(force=true) | Takes ownership regardless | Force-unlock (coordinator recovery) |
If an agent crashes or disconnects while holding the lock:
pending, and other agents can claim itThis provides automatic deadlock recovery with no additional infrastructure.
For scenarios where multiple agents can read concurrently but writes need exclusivity:
# Write lock (exclusive, as above)
_lock:git-commit # Only one writer at a time
# Read coordination (advisory, via file marks)
mark_file(worker_id=id, file=".git/index", reason="Reading git state")
# Multiple readers can mark simultaneously - marks are advisoryFor repositories with multiple active branches:
# Branch-specific sentinel tasks
_lock:git-commit:main
_lock:git-commit:feature-x
_lock:git-commit:hotfix-yIf you need to protect git pull --rebase or other operations beyond commit:
# Use a broader lock
_lock:git-ops # Covers pull, rebase, merge, commit, push
# Or layer locks
_lock:git-commit # Just add/commit
_lock:git-sync # Pull/push/rebase (claim BOTH for full protection)The hierarchical and swarm workflow configs include commit lock guidance in their working state prompts. Workers entering the working state are reminded to:
When setting up a multi-agent project:
create(id="_lock:git-commit", title="[LOCK] Git Commit Serialization", tags=["lock", "infrastructure"], priority=0)get(task="_lock:git-commit")| Avoid | Why | Instead |
|---|---|---|
| Completing the sentinel | Removes it from the lock cycle | Only use pending/working transitions |
| Holding lock during long operations | Blocks all other agents' commits | Stage files first, then lock-commit-unlock |
| Forgetting to release | Deadlocks until stale timeout | Always release in a finally/cleanup block |
| Skipping the lock | Merge conflicts, lost work | Always acquire before git operations |
Using force=true casually | Breaks another agent's commit | Only coordinators should force-unlock |
# Check who holds it
get(task="_lock:git-commit")
# Look at worker_id field
# Check if that worker is still alive
list_agents()
# If worker is gone, force-release (coordinator only)
update(worker_id=coordinator_id, task="_lock:git-commit",
status="pending", force=true, reason="Force-releasing stuck lock")# Recreate it
create(
id="_lock:git-commit",
title="[LOCK] Git Commit Serialization",
description="Sentinel task for serializing git operations.",
tags=["lock", "infrastructure"],
priority=0
)# Check for stale claims
get(task="_lock:git-commit")
# If claimed by a disconnected agent, the stale reaper will
# release it within the stale_timeout (default: 5 min).
# For faster recovery, a coordinator can force-release.| Skill | When to Use |
|---|---|
task-graph-basics | Tool reference, connection workflow, task trees |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.