Replace hard mutex locks with Gaussian interference fields.
causal-field implements probabilistic resource coordination for multi-agent
systems. Instead of hard locks that block, agents project Gaussian "splats" into
a shared latent space — overlapping splats signal contention before conflict
occurs. Inspired by 3D Gaussian Splatting.
pip install causal-fieldTraditional locks are binary: locked or free. Under contention, agents queue up and throughput collapses.
causal-field treats resource occupancy as a continuous probability landscape.
Each agent projects a Gaussian splat at the resource's semantic coordinate. Before
acquiring, an agent reads the total interference at that coordinate:
- Interference below threshold → acquired (proceed normally)
- Interference above threshold → soft-blocked (defer, retry later, or fallback)
Agents sense each other's intent — not just their current state.
from causal_field import CausalField, render_ascii
field = CausalField(dim=64)
# Two agents want the same resource
field.soft_acquire("agent-A", "file_write:/data/output.csv")
result = field.soft_acquire("agent-B", "file_write:/data/output.csv")
print(result)
# {"acquired": False, "interference": 0.91, "resource": "file_write:/data/output.csv", ...}
# Visualize in the terminal
print(render_ascii(field))+------------------------------------------------------------+
| |
| ░░░░ |
| ░░▒▒▒▒░░ |
| ░░▒▒▓▓▓▒▒░░ |
| ░▒▒▓▓██████▓▒░ |
| ░▒▒▓▓██████▓▒░ |
| ░░▒▒▓▓▓▒▒░░ |
| ░░▒▒▒▒░░ |
+------------------------------------------------------------+
[agent-A] file_write:/data/output.csv ████████░░ 0.80
[agent-B] file_write:/data/output.csv ████████░░ 0.80
High-intensity zones (heavy contention) appear as █; low as ░ or space.
from causal_field import benchmark
print(benchmark(n_agents=10, n_rounds=1000)["note"])
# "Soft-lock is 1.4x faster than threading.Lock (10 agents, 1000 rounds, dim=64)"Soft-lock wins when:
- Many agents but sparse contention (most acquire without blocking)
- Read-heavy workloads (threshold=0.95 — almost never blocked)
- You need routing not serialization (soft-blocked agents can fallback, not deadlock)
threading.Lock wins when:
- You need strict mutual exclusion (critical sections with real shared memory)
- Two or fewer agents (no benefit from contention awareness)
from causal_field import contention_benchmark
result = contention_benchmark(n_agents=8, n_rounds=200, n_resources=2)
print(result["verdict"])
# "Soft-lock: 14,200 ops/s (p50=0.04ms, p99=0.18ms, 12% collision rate)
# Mutex: 11,800 ops/s (p50=0.05ms, p99=0.31ms)
# Soft-lock is 1.2x faster under 8-agent contention on 2 resources."contention_benchmark() uses real threading.Thread objects competing concurrently —
not a sequential simulation. Collision rate reflects actual contention under the test load.
Soft-lock wins when contention is sparse; threading.Lock wins for strict serialization.
from causal_field import SOFT_LOCK_THRESHOLDS
print(SOFT_LOCK_THRESHOLDS)
# {
# "file_read": 0.95, # permissive — reads rarely conflict
# "file_write": 0.82, # aggressive — writes need protection
# "gpu": 0.78, # most aggressive — GPU is singular
# "db_write": 0.80,
# "default": 0.90,
# }Resources are classified by prefix — file_write:*, gpu:*, db_write:*.
Threshold selection is automatic.
Resources are embedded into the field using nomic-embed-text (via local Ollama).
Semantically similar resources land near each other — "write_file reports.csv" and
"save reports.csv" will detect mutual contention. Falls back to deterministic
SHA-256 hashing when Ollama is unavailable.
# Optional: install Ollama for semantic embeddings
pip install causal-field[embed]After each acquire/release, adjust the splat's spread based on outcome:
# Collision detected (splat was too wide, blocked others unnecessarily)
field.adjust_sigma("agent-A", "file_write:/data/out.csv", "collision")
# → sigma shrinks by 15%
# False positive (blocked but no real conflict existed)
field.adjust_sigma("agent-A", "file_write:/data/out.csv", "false_positive")
# → sigma grows by 15%Runs gradient descent during idle cycles to drift inactive splats apart, reducing future contention before it starts:
from causal_field import CausalField, SplatOptimizer
opt = SplatOptimizer(field, lr=0.05, max_steps=200)
result = opt.run()
print(result)
# {"steps": 47, "initial_loss": 2.3, "final_loss": 0.1, "converged": True, "frozen_splats": 2}Active splats (mid-task, active=True) are never moved — only idle splats are optimized.
from causal_field import CausalField, visualize
field = CausalField(dim=8)
for i in range(4):
field.soft_acquire(f"agent-{i}", f"gpu:slot_{i % 2}")
visualize(field, title="GPU Slot Contention")pip install causal-field[viz]from pathlib import Path
from causal_field import CausalField
# Save field state between runs
path = Path(".causal-field-state.json")
field = CausalField(dim=64)
field.soft_acquire("agent-A", "file_write:/data/x.csv")
field.save(path)
# Restore in next process
field2 = CausalField.load(path)| Limitation | Impact | Mitigation |
|---|---|---|
| Advisory only — not atomic | Two agents can race through the same low-interference window | Always back with threading.Lock for true mutual exclusion |
| Hash-based coordinates (Ollama down) | Semantically similar resources may not collide | Run pip install causal-field[embed] and keep Ollama up |
| In-memory only (single process) | No cross-process coordination | Use field.save() / CausalField.load() between processes; not suitable for distributed systems |
| Gaussian spread can block unrelated resources | High sigma can create false positives across coordinate space | Call adjust_sigma(agent, resource, "false_positive") to shrink splat width |
| Not a real-time system | intensity_at() is a point-in-time snapshot |
For high-throughput systems, pair with a hard mutex for serialization-critical sections |
| Feature | causal-field | threading.Lock |
asyncio.Lock |
multiprocessing.Lock |
|---|---|---|---|---|
| Probabilistic (no hard block) | Yes | No | No | No |
| Intent sensing before conflict | Yes | No | No | No |
| Works across threads | Yes | Yes | No | No |
| Works across processes | Via save/load | No | No | Yes |
| Distributed systems | No | No | No | Limited |
| Deadlock-free | Yes | No | No | No |
| Throughput advantage | 1.4x (sparse contention) | Baseline | Baseline | Higher overhead |
When to use threading.Lock instead: Any time you need strict mutual exclusion
(e.g., shared memory writes, counter increments). CausalField is not a replacement —
it's a routing layer that sits in front of your hard lock.
causal-field is extracted from LexiPro — a local-first
agentic OS running 15 MCP servers, 228 tools, and 20 agent personas. In the full OS,
CausalField powers the tool allocation layer: before any agent acquires a
destructive tool, the field measures interference and auto-defers if another agent
already holds a write-type resource at the same coordinate.
The hard mutex (acquire_mutex MCP tool) remains the sole serialization gate for actual
file writes — CausalField is advisory, operating one layer earlier for routing decisions.
MIT — see LICENSE.
Built by Broken Arrow Entertainment LLC · Sovereign Intelligence Systems Group
causal-field wires into the Minimal Stable Control Loop (MSCL) as the first
contention check before any write-type tool executes. This is the integration
pattern used in the LexiPro Sovereign OS:
# mscl.py — _check_contention() CAP layer (v22.8)
from causal_field import get_global_field, _resource_to_mu, _get_threshold
_WRITE_KWS = ("write", "edit", "save", "delete", "create", "append",
"db_write", "insert", "update", "drop")
def check_write_contention(resource_mu: str, directorate: str) -> dict:
if any(kw in resource_mu.lower() for kw in _WRITE_KWS):
cf = get_global_field()
mu = _resource_to_mu(resource_mu, cf.dim)
interference = cf.intensity_at(mu) # read-only — no splat projection
threshold = _get_threshold(resource_mu)
if interference > threshold:
return {
"decision": "DENY",
"reason": (
f"CAUSAL_FIELD_BLOCKED: {resource_mu} "
f"interference={interference:.3f} (>{threshold}). "
f"Acquire hard mutex first."
),
}
return {"decision": "ALLOW"}Key design: the auth check reads the field via intensity_at(mu) — it does NOT
call soft_acquire(). This avoids phantom splats during auth checks. Actual splat
projection only happens when the agent explicitly calls soft_acquire() at execution
time.
Full authority stack:
CausalField intensity_at() ← instant snapshot, write-type resources
→ NeuralBus WRITE_CONTENTION ← 60-second pheromone sliding window
→ MetaGovernor seniority ← deferred-enough agents get priority boost
→ hard mutex acquire ← sole serialization gate for actual writes
Adaptive sigma closes the loop: after each write, call
field.adjust_sigma(agent_id, resource, outcome) so the field self-calibrates.
Collisions shrink sigma (splat was too wide); false positives grow it.