Skip to content

brokenbartender/causal-field

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

causal-field

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-field

PyPI version Downloads Python 3.10+ License: MIT CI


The idea

Traditional 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.


Quickstart

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))

ASCII heatmap (zero dependencies)

+------------------------------------------------------------+
|                                                            |
|                    ░░░░                                    |
|                  ░░▒▒▒▒░░                                  |
|                ░░▒▒▓▓▓▒▒░░                                 |
|               ░▒▒▓▓██████▓▒░                               |
|               ░▒▒▓▓██████▓▒░                               |
|                ░░▒▒▓▓▓▒▒░░                                 |
|                  ░░▒▒▒▒░░                                  |
+------------------------------------------------------------+
  [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.


Benchmark

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)

Benchmark (concurrent, real threads)

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.


Per-resource-type thresholds

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.


Semantic coordinates

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]

Adaptive sigma

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%

SplatOptimizer

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.


matplotlib visualizer (optional)

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]

Multi-session use

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)

Known Limitations

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

Comparison: CausalField vs. alternatives

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.


Part of the LexiPro Sovereign OS

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.


License

MIT — see LICENSE.

Built by Broken Arrow Entertainment LLC · Sovereign Intelligence Systems Group


OS Integration — MSCL CAP Layer

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.