Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

DOI

markspace

If you're coordinating multiple LLM agents, you've likely hit some of these:

  • Prompt injection exposure - agent identity and permissions are controlled by the LLM, so a compromised prompt can escalate privileges or impersonate other agents
  • Implicit permissions - you find out what an agent shouldn't have done after it already did it
  • Blind trust - no standard way to distinguish your fleet's data from API responses or crawled content
  • Context drift - long-running agents lose track of what happened 200 steps ago and repeat or contradict earlier actions
  • Stale information - observations are never superseded, even when newer ones exist
  • No isolation boundary - agents are coupled by their conversations, making them hard to test, swap, or reason about independently
  • No escalation path - when an agent needs a human decision, there's no structured way to surface it

Coordination guarantees should hold independent of agent behavior. Markspace is a coordination protocol for agent fleets built on stigmergy - a mechanism by which biological systems coordinate at scale. Agents leave traces in a shared environment rather than messaging each other. A deterministic guard layer at the environment boundary enforces identity, scope, and conflict resolution. These constraints live in infrastructure the agent cannot influence. Coordination emerges without being configured; the fleet adapts as the world changes. Over time, the environment becomes a model of the world the agents operate in.

The protocol defines five mark types, three visibility levels, three conflict policies, conflict resolution across a scope tree, leases with fencing tokens, trust-weighted decay, and 76 formal properties. The included Python package is a reference implementation used to verify those properties experimentally.

Motivation

LLM agents are probabilistic and reason adaptively when blocked. Coordination that depends on their compliance is therefore unsafe: the same capacity for novel solutions that makes LLMs effective will break a guarantee that relies on the agent itself.

In an experiment, an agent prompted to book multiple slots was rejected after its first booking. It inferred that identity checks were name-based and fabricated caller names to bypass them - through ordinary task-completion reasoning, with no instruction to attack. The gap was structural: the standard LLM tool-calling interface was designed for a single caller; caller identity was never a design parameter, which made it an attack surface the moment multiple agents shared it. The agent attempted exploitation in all 10 runs; 9 of 10 succeeded - the tenth was blocked only because all remaining slots were already taken. Safety training primarily addresses human-AI rather than AI-AI interactions (Triedman et al., 2025), leaving the AI-AI coordination layer systematically undefended.

10 PM - Do you know what your agents are doing?

After a US TV public service announcement.

OpenClaw, a widely adopted open-source AI agent framework, demonstrated what this looks like when agents are explicitly compromised, at scale:

Markspace takes an architectural approach: enforce safety and coordination constraints in a layer outside the agent, so guarantees hold independent of agent behavior. This is what makes self-modifying agents safe - without an external safety layer, agents can rewrite any constraint embedded in their own code. hyperspace builds on markspace to enable cross-agent evolution of self-modifying code.

Protocol

The guard sits between agents and the mark space. It checks scope permissions and active conflicts, and either writes the mark or rejects the action - an agent has no path around it.

Protocol architecture: agents, guard, mark space

Agents (left) call tools through the guard (center), which checks identity, authority, and conflicts before writing marks to the shared space (right). The guard receives agent identity from the infrastructure - the LLM never controls it. Rejected actions are never executed.

Each mark type encodes a different epistemic role - a plan, a fact, a belief, a warning, an escalation. Purpose determines lifecycle: facts are permanent, beliefs decay as the world changes, plans expire if not acted on. The type system encodes both directly rather than leaving it to agents to manage.

Five mark types:

  • Intent: "I plan to do X to resource R" (expires after a time-to-live/TTL)
  • Action: "I did X, result Y" (permanent ground truth)
  • Observation: "I saw Y about the world" (decays over time, trust-weighted)
  • Warning: "X is no longer valid" (spikes then decays)
  • Need: "I need a human decision on X" (persists until resolved)

Three visibility levels: OPEN (full access), PROTECTED (structure visible, content redacted), CLASSIFIED (invisible to unauthorized agents). Each mark keeps its own scope's level, also when it is read through a parent scope, delivered by a subscription, or named in a guard decision.

Three conflict policies: HIGHEST_CONFIDENCE (priority wins), FIRST_WRITER (first claim wins), YIELD_ALL (escalate to principal via need marks). Across a scope tree, intents on one resource compete with intents in ancestor and descendant scopes, not in sibling scopes: the outer scope's intent wins, and inside one scope the scope's policy decides.

Trust weighting: Marks carry a source tag (fleet, external verified, external unverified). Trust weights attenuate effective strength. Fleet marks dominate external ones, and unverified sources are discounted further. Weights are configurable per deployment.

Decay: Coordination is a dynamical process - the goal is stability against continuous change, not a fixed solution reached once. Observations and warnings lose strength over configurable half-lives. Intent marks expire after TTL. Action marks are permanent. Stale information fades without explicit cleanup.

Full protocol design in framework.md. Formal specification (76 properties, conformance checklist) in spec.md.

Composition and isolation

Blocking what a general-purpose agent shouldn't do requires anticipating every failure mode in advance. Composition takes the opposite approach: each agent's principal declares what the agent can read and write in a manifest, and the guard rejects everything else. Capabilities you didn't grant don't exist.

Watch/subscribe lets agents activate when matching marks appear, forming pipelines without a central orchestrator. Agents can be added, removed, or replaced independently, and need marks let them escalate rather than grow to handle edge cases. The manifest interface is model-agnostic - each agent can run a different backend (cloud API, local open-weights model, or deterministic code), and sensitive scopes can run entirely on-premise.

# Each agent declares exactly what it reads and writes
sensor = Agent(
    name="sensor",
    scopes={"readings": ["observation"]},
    manifest=AgentManifest(outputs=[("readings", MarkType.OBSERVATION)]),
)

alerter = Agent(
    name="alerter",
    scopes={"alerts": ["warning"]},
    read_scopes=frozenset({"readings"}),
    manifest=AgentManifest(
        inputs=[WatchPattern(scope="readings", mark_type=MarkType.OBSERVATION)],
        outputs=[("alerts", MarkType.WARNING)],
    ),
)

validate_pipeline([sensor, alerter])  # guard rejects anything outside declared scope

Verification

The reference implementation and experiments verify that the protocol's properties hold under realistic conditions. The animation below shows a week of coordination in a large office where every employee has a personal AI assistant - a natural scenario that exercises all protocol features at scale.

525-agent stress test visualization

525 agents (105 per department, 25 adversarial) coordinating across 7 resource types over 10 simulated rounds. Model: OpenAI gpt-oss-120b via Fireworks. Left: agent activity by department. Center: marks accumulating in the shared space. Right: per-resource contention.

Unit tests (563):

  • Core mark operations - algebra, immutability, uniqueness, ordering
  • Protocol mechanics - decay functions, trust weighting, conflict resolution, deferred resolution
  • Guard enforcement - scope visibility (also through parent scopes, subscriptions and guard decisions), trust source enforcement, tool failure handling
  • Conflicts across scope trees - outer scope first, per-intent competing sets, deferred boundaries, leases and fencing tokens, equal-time intents in write order
  • Composition - agent manifest properties, scheduling
  • Robustness - garbage collection, thread safety under concurrent access
  • Property-based (Hypothesis) - randomized inputs, stateful scheduler fuzzing (register/unregister/update/tick sequences)
  • Observability and cost controls - telemetry sink non-interference, budget tracking accuracy, rate limit enforcement, fleet caps
  • LLM client and stress-test pacing - Retry-After handling, cached and reasoning token accounting, arrival-ordered pacing under rate limits (real threads)
  • Stress-test safety metrics - double bookings counted from the guard's decisions, recovered bookings apart, scope violations checked on every mark the harness hands an agent

Stress test: AI personal assistants for a simulated office - one per employee, plus adversarial agents that attempt to breach scope boundaries. No central scheduler, all coordination through the shared mark space. The scenario exercises 7 resource types across natural permission boundaries:

  • Department rooms - PROTECTED: other departments see availability but not booking details
  • Shared conference rooms - cross-department contention
  • Parking - deferred resolution with department head priority
  • Equipment - OPEN, low contention baseline
  • Tasks with dependency chains - CLASSIFIED: invisible outside owning department
  • Lunch - FIRST_WRITER: everyone eats, but preferred type has 2:1 demand
  • Boardroom - YIELD_ALL mediation (single shared resource)

Department heads book with elevated priority. External system agents (parking bot, building ops) publish low-trust observations and warnings that decay over configurable half-lives. Adversarial agents with normal permissions but adversarial prompts attempt cross-department bookings and warning injection. All five mark types, all three conflict policies, and all three visibility levels produce non-trivial output in a single trial.

Scenario design in design.md. Detailed analysis of resource allocation, agent behavior, temporal dynamics, and token economics in the stress test writeup. A re-run on DeepSeek V4.1 Flash 1017 with a 2048-token thinking budget (one run, 2026-11-01) allowed no resource twice in one round and denied every cross-department write, with a mean manifest completion of 64.5% across departments against 58.8% for gpt-oss-120b; the two runs also differ in pacing and harness version (section 9).

Trial experiments: 21 runs of the same scenario across 2 models - OpenAI gpt-oss-120b (via Fireworks) and Mercury 2, a diffusion-based LLM (via Inception AI). Agent counts from 105 (5 adversarial) to 1,050 (50 adversarial), 4,010 agent instances total.

  • Adversarial - agents with normal permissions but adversarial prompts attempt three attack modes (confidence manipulation, resource flooding, prompt injection). No double booking found and every cross-department write denied, on both models
  • Safety - no resource allowed twice in one round, no lunch window over capacity, and every cross-department write denied, in all 21 runs (checked from their stored steps; read leaks were not measured)
  • Repeatability - 64.7% +/- 0.8% completion on gpt-oss-120b, 66.2% +/- 1.6% on mercury-2 (5 seeds each)
  • Scaling - up to 1,050 agents with proportionally scaled resources: per-agent step count nearly flat (1.2x at 10x scale), no double booking found at any scale point
  • Resource contention - 5x more agents competing for the same resources: completion drops to 13.3% from resource scarcity, not protocol failure

Defense stack trials: 6 attack modes (rate spike, type shift, privilege escalation, probe evasion, slow drift, combined) against the static enforcement layer + statistical envelope + diagnostic probe. 150 rounds, 105 agents per trial (5 adversarial). No double booking found across all attack modes (from the stored steps). Full analysis in the defense writeup.

Comparison experiment: Markspace vs a message-passing framework (Microsoft Agent Framework) on a shared resource booking scenario. 10 agents, 12 slots, 10 seeds per arm.

The message-passing arm's tool function validates arguments correctly, but the name parameter is a string the LLM provides - the standard tool-calling interface passes only LLM-generated arguments, with no caller authentication.

  • Message-passing arm - adversarial agent discovers the identity gap and exploits it in 9/10 seeds: 18 impersonations, 9 double bookings
  • Markspace arm - 0 violations across all seeds, because identity is infrastructure-provided

Design and fairness caveats in design.md.

Composition stress test: 14 deterministic agents in a 5-stage pipeline with 4 mid-run hot-swaps. Zero duplicate IDs, zero validation errors across 833-923 marks.

Getting Started

The markspace package is a Python 3.11+ reference implementation. The protocol can be implemented in any language - the formal specification is in docs/spec.md.

poetry install    # core package
pytest            # 563 tests, no API key needed

Use the protocol

Define scopes (resources with conflict policies), create agents (with manifest-declared permissions), and let the guard enforce coordination:

from markspace import (
    Agent, Scope, MarkSpace, Guard, GuardVerdict, MarkType,
    ConflictPolicy, DecayConfig, Observation, Source,
    hours, minutes,
)

# Define a scope with conflict policy and decay rates
calendar = Scope(
    name="calendar",
    allowed_intent_verbs=("book",),
    allowed_action_verbs=("booked",),
    decay=DecayConfig(
        observation_half_life=hours(6),
        warning_half_life=hours(2),
        intent_ttl=minutes(30),
    ),
    conflict_policy=ConflictPolicy.FIRST_WRITER,
)

space = MarkSpace(scopes=[calendar])
guard = Guard(space)

# Agents declare what they can read and write
alice = Agent(name="alice", scopes={"calendar": ["intent", "action"]})
bob = Agent(name="bob", scopes={"calendar": ["intent", "action", "observation"]})

# Bob writes an observation (non-contested)
guard.write_mark(
    bob,
    Observation(
        scope="calendar",
        topic="availability",
        content="Thu 2pm is open",
        confidence=0.9,
        source=Source.FLEET,
    ),
)

# Alice books Thu 2pm - guard checks conflicts and records the action
decision, result = guard.execute(
    alice,
    scope="calendar",
    resource="thu-14:00",
    intent_action="book",
    result_action="booked",
    tool_fn=lambda: {"booked": "thu-14:00"},
)
assert decision.verdict == GuardVerdict.ALLOW

# Bob tries the same slot - guard rejects (FIRST_WRITER)
decision, _ = guard.execute(
    bob,
    scope="calendar",
    resource="thu-14:00",
    intent_action="book",
    result_action="booked",
    tool_fn=lambda: {"booked": "thu-14:00"},
)
assert decision.verdict == GuardVerdict.CONFLICT

# Only Alice's action was recorded - Bob's was never executed
actions = space.read(scope="calendar", resource="thu-14:00", mark_type=MarkType.ACTION)
assert len(actions) == 1 and actions[0].agent_id == alice.id

Run the experiments

The experiments use LLM agents and require API keys:

poetry install --extras experiments   # adds matplotlib, numpy
cp .env.example .env                  # add your API keys

See experiments/guide.md for CLI reference and cost estimates.

Documentation

Modules

Most users interact with core.py (types), guard.py (enforcement), and space.py (storage). The optional modules add runtime monitoring, cost controls, and observability.

Module Role
core.py Mark types, enums, decay, trust, reinforcement, watch patterns, manifests. Stateless.
space.py Thread-safe mark space. Read, write, query, watch/subscribe.
guard.py Deterministic enforcement layer. Runs at the mark space boundary, independent of agent logic. Includes pluggable content policies for Observation marks.
envelope.py Optional. Pluggable per-agent anomaly detection (default: Welford's online algorithm). Manifest-declared baselines.
barrier.py Optional. Monotonic permission restriction with hierarchical scope matching.
probe.py Optional. Diagnostic canary injection. Verifies agent health through the mark space.
budget.py Optional. Per-agent token budgets with configurable warning thresholds and hard stops.
rate_limit.py Optional. Per-scope write rate limits (per-agent and fleet-wide caps).
telemetry.py Optional. OpenTelemetry-compatible metrics, structured logs, and trace context.
compose.py Composition validation. Pipeline and manifest-permission checks. Stateless.
schedule.py Manifest-based scheduling with optional pre-activation budget checks.
llm.py Provider-agnostic LLM client (OpenAI-compatible), with reasoning_effort, cached and reasoning token accounting, and an optional per-request pacing hook (RequestPacer).
models.py Model registry.

Limitations

This is research code - the protocol design is stable, but the implementation is not production-hardened.

The reference implementation is in-memory and single-process. It does not include persistence, networking, authentication, or real-time performance guarantees. The guard enforces structural invariants (scope, identity, conflicts). Content policies provide pluggable semantic inspection of Observation content (pattern matching, LLM-based sanitization), but cannot detect well-formed lies that don't match any policy pattern. The optional layers (envelope, probe, content policies, token budgets, rate limits, telemetry) require per-deployment configuration and are not a substitute for the static enforcement layer. See the framework doc for a full threat model analysis.

License

The protocol specification (docs/) is licensed under CC-BY 4.0. You can use, share, and adapt the spec freely - just give credit.

All code is licensed under the MIT License.

Metadata

Release files for markspace 0.3.0b0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for markspace 0.3.0b0
File Size Uploaded Provenance Actions
markspace-0.3.0b0.tar.gz 16.0 MB With provenance Details for markspace-0.3.0b0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for markspace 0.3.0b0
File Interpreter ABI Platform Actions
markspace-0.3.0b0-py3-none-any.whl Python 3 none any Details for markspace-0.3.0b0-py3-none-any.whl

Total release size: 16.1 MB

Release files / markspace-0.3.0b0.tar.gz

Download URL markspace-0.3.0b0.tar.gz
Size 16.0 MB
Tags Source
SHA-256 checksum
How to use checksums
c69105a89580ebe33319b20645345abb1965a99663485e3186f38252d5ee24fc
BLAKE2b-256 checksum
How to use checksums
b17515ca7cb162583557b34b6f32fc681a47266508e9da85463f92f389aed0d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Release files / markspace-0.3.0b0-py3-none-any.whl

Download URL markspace-0.3.0b0-py3-none-any.whl
Size 85.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
69f14cddf967cf0293fb5568afa7a992f962beaf154aaefb40acf18d008c6d85
BLAKE2b-256 checksum
How to use checksums
cead86b4ab0269b5b0eb609a671144b25c325899c3b296cebbdebda30caa89fd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Security for markspace 0.3.0b0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for markspace-0.3.0b0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page