Skip to content

Write scope

write_scope

WriteAccessDecision dataclass

Verdict for one attempted filesystem mutation.

Source code in packages/axm/src/axm/tools/write_scope.py
Python
@dataclass(frozen=True)
class WriteAccessDecision:
    """Verdict for one attempted filesystem mutation."""

    allowed: bool
    reason: str
    resolved_location: str | None = None
    consulted_prefixes: tuple[str, ...] = ()

WriteContract dataclass

Validated wire representation of a session filesystem write scope.

A prefix listed in markdown_only_prefixes carries a nature on top of its path: it grants Markdown sidecars only. Without it, a documentation prefix would have to be narrowed by whoever produces the contract, and every producer would reinvent that filter — the divergence this field exists to prevent. Such a prefix must also appear in allowed_prefixes; one that does not is dropped rather than silently granting a wider path.

Source code in packages/axm/src/axm/tools/write_scope.py
Python
@dataclass(frozen=True)
class WriteContract:
    """Validated wire representation of a session filesystem write scope.

    A prefix listed in ``markdown_only_prefixes`` carries a **nature** on top
    of its path: it grants Markdown sidecars only. Without it, a documentation
    prefix would have to be narrowed by whoever *produces* the contract, and
    every producer would reinvent that filter — the divergence this field
    exists to prevent. Such a prefix must also appear in ``allowed_prefixes``;
    one that does not is dropped rather than silently granting a wider path.
    """

    execution_root: str
    allowed_prefixes: tuple[str, ...] = ()
    markdown_only_prefixes: tuple[str, ...] = ()

    @classmethod
    def from_mapping(cls, raw: Mapping[str, object]) -> WriteContract:
        """Validate and normalize a transported contract mapping."""
        raw_root = raw.get("execution_root")
        if not isinstance(raw_root, str) or not raw_root.strip():
            raise ValueError("execution_root must be a non-empty string")
        root = os.path.realpath(raw_root.strip())
        prefixes = _normalized_prefixes(raw, "allowed_prefixes", root)
        markdown_only = _normalized_prefixes(raw, "markdown_only_prefixes", root)
        return cls(
            execution_root=root,
            allowed_prefixes=prefixes,
            markdown_only_prefixes=tuple(
                prefix for prefix in markdown_only if prefix in prefixes
            ),
        )

    @classmethod
    def from_json(cls, raw: str) -> WriteContract:
        """Decode, validate and normalize a JSON transport payload."""
        decoded = json.loads(raw)
        if not isinstance(decoded, Mapping):
            raise ValueError("write contract must be a JSON object")
        return cls.from_mapping(decoded)

    def resolve(self, base: str, candidate: str) -> str:
        """Resolve a candidate location relative to an explicit base."""
        return _absolute_location(base, candidate)

    def permits(self, location: str) -> bool:
        """Return whether a resolved location is under an allowed prefix.

        A location granted *only* by Markdown-restricted prefixes must itself
        be Markdown: those prefixes carry a nature, not merely a path. A
        location also covered by an unrestricted prefix keeps that grant.
        """
        granting = [
            prefix
            for prefix in self.allowed_prefixes
            if location == prefix or location.startswith(prefix + os.sep)
        ]
        if not granting:
            return False
        if any(prefix not in self.markdown_only_prefixes for prefix in granting):
            return True
        return location.casefold().endswith(_MARKDOWN_SUFFIXES)

    def contains(self, location: str) -> bool:
        """Return whether a resolved location is under the execution root."""
        root = self.execution_root
        return location == root or location.startswith(root + os.sep)
contains(location)

Return whether a resolved location is under the execution root.

Source code in packages/axm/src/axm/tools/write_scope.py
Python
def contains(self, location: str) -> bool:
    """Return whether a resolved location is under the execution root."""
    root = self.execution_root
    return location == root or location.startswith(root + os.sep)
from_json(raw) classmethod

Decode, validate and normalize a JSON transport payload.

Source code in packages/axm/src/axm/tools/write_scope.py
Python
@classmethod
def from_json(cls, raw: str) -> WriteContract:
    """Decode, validate and normalize a JSON transport payload."""
    decoded = json.loads(raw)
    if not isinstance(decoded, Mapping):
        raise ValueError("write contract must be a JSON object")
    return cls.from_mapping(decoded)
from_mapping(raw) classmethod

Validate and normalize a transported contract mapping.

Source code in packages/axm/src/axm/tools/write_scope.py
Python
@classmethod
def from_mapping(cls, raw: Mapping[str, object]) -> WriteContract:
    """Validate and normalize a transported contract mapping."""
    raw_root = raw.get("execution_root")
    if not isinstance(raw_root, str) or not raw_root.strip():
        raise ValueError("execution_root must be a non-empty string")
    root = os.path.realpath(raw_root.strip())
    prefixes = _normalized_prefixes(raw, "allowed_prefixes", root)
    markdown_only = _normalized_prefixes(raw, "markdown_only_prefixes", root)
    return cls(
        execution_root=root,
        allowed_prefixes=prefixes,
        markdown_only_prefixes=tuple(
            prefix for prefix in markdown_only if prefix in prefixes
        ),
    )
permits(location)

Return whether a resolved location is under an allowed prefix.

A location granted only by Markdown-restricted prefixes must itself be Markdown: those prefixes carry a nature, not merely a path. A location also covered by an unrestricted prefix keeps that grant.

Source code in packages/axm/src/axm/tools/write_scope.py
Python
def permits(self, location: str) -> bool:
    """Return whether a resolved location is under an allowed prefix.

    A location granted *only* by Markdown-restricted prefixes must itself
    be Markdown: those prefixes carry a nature, not merely a path. A
    location also covered by an unrestricted prefix keeps that grant.
    """
    granting = [
        prefix
        for prefix in self.allowed_prefixes
        if location == prefix or location.startswith(prefix + os.sep)
    ]
    if not granting:
        return False
    if any(prefix not in self.markdown_only_prefixes for prefix in granting):
        return True
    return location.casefold().endswith(_MARKDOWN_SUFFIXES)
resolve(base, candidate)

Resolve a candidate location relative to an explicit base.

Source code in packages/axm/src/axm/tools/write_scope.py
Python
def resolve(self, base: str, candidate: str) -> str:
    """Resolve a candidate location relative to an explicit base."""
    return _absolute_location(base, candidate)

decide_write_access(contract, tool_name, tool_input=None)

Decide whether an AXM call may write where its payload requests.

Source code in packages/axm/src/axm/tools/write_scope.py
Python
def decide_write_access(
    contract: WriteContract | Mapping[str, object] | None,
    tool_name: str,
    tool_input: Mapping[str, object] | None = None,
) -> WriteAccessDecision:
    """Decide whether an AXM call may write where its payload requests."""
    if contract is None:
        return WriteAccessDecision(allowed=True, reason="no write contract is in force")
    resolved_contract = (
        contract
        if isinstance(contract, WriteContract)
        else WriteContract.from_mapping(contract)
    )
    payload: Mapping[str, object] = tool_input or {}
    canonical, payload, facade_error = _canonical_call(tool_name, payload)
    if facade_error is not None:
        return WriteAccessDecision(
            allowed=False,
            reason=facade_error,
            consulted_prefixes=resolved_contract.allowed_prefixes,
        )
    shape = _MUTATION_TOOLS.get(canonical)
    if shape is None:
        return _unclassified_tool_decision(canonical, payload, resolved_contract)
    return _decide_declared_mutation(
        canonical,
        payload,
        shape,
        resolved_contract,
    )

write_contract_from_env(env=None)

Load the optional process-scoped contract, failing closed if malformed.

Source code in packages/axm/src/axm/tools/write_scope.py
Python
def write_contract_from_env(
    env: Mapping[str, str] | None = None,
) -> WriteContract | None:
    """Load the optional process-scoped contract, failing closed if malformed."""
    source = os.environ if env is None else env
    raw = source.get(WRITE_CONTRACT_ENV)
    if raw is None:
        return None
    try:
        return WriteContract.from_json(raw)
    except (TypeError, ValueError, json.JSONDecodeError) as exc:
        raise ValueError(f"invalid {WRITE_CONTRACT_ENV}: {exc}") from exc