{
  "name": "forge.auth",
  "language": "python",
  "version": "0.1.0",
  "description": "Python auth package; imports are explicit from this package.",
  "manifest": "forge-py/pyproject.toml",
  "manifestSha256": "7f96957378b21995bf2e583af2afd1b9e6fb3b0089ff3559d62c7e012a034696",
  "status": "source-reference",
  "registryPublicationVerified": false,
  "route": "/libraries/python/auth",
  "features": {},
  "files": [
    {
      "path": "forge-py/src/forge/auth/__init__.py",
      "sha256": "01e1b7ff5b47f19375cb7a70e0b429ce18b77f7679a1b73b52cf78d9ee6818ea",
      "artifactSha256": "9f5999a98d1018cf5fa48471f3b8cf9524e81e902a6ae3cb39d3efcfbbd19f0c",
      "url": "/reference/source/forge-py/src/forge/auth/__init__.py.txt",
      "declarations": []
    },
    {
      "path": "forge-py/src/forge/auth/capability.py",
      "sha256": "b1fa0b8a5b6c7ac5e489128e87acd81310973ca4415bd3ee5606a9c892b42c25",
      "artifactSha256": "a6567e7653638c8b5944954dc5d7df9ff9f72a6d88b97192931c1bbf51cc1e01",
      "url": "/reference/source/forge-py/src/forge/auth/capability.py.txt",
      "declarations": [
        {
          "name": "Scope",
          "line": 21,
          "signature": "class Scope()",
          "documentation": "A single capability scope in ``\"service:resource:action\"`` format.\n\nScopes follow the pattern ``service:resource:action`` where each component\nmay be a literal string or a wildcard (``*``). Wildcard scopes match any\nvalue at that position.\n\nANVIL Spec section 8.7.2 -- Scope matching on tool invocation.\n\nArgs:\n    service: The service component (e.g., ``\"forge\"``).\n    resource: The resource component (e.g., ``\"tool.web_search\"``).\n    action: The action component (e.g., ``\"execute\"``).\n\nExample:\n    >>> scope = Scope.parse(\"forge:tool.search:execute\")\n    >>> scope.service\n    'forge'\n    >>> scope.implies(Scope.parse(\"forge:tool.search:execute\"))\n    True"
        },
        {
          "name": "Scope.parse",
          "line": 48,
          "signature": "def parse(scope_str: str) -> Scope",
          "documentation": "Parse a scope from a ``\"service:resource:action\"`` string.\n\nArgs:\n    scope_str: The scope string to parse.\n\nReturns:\n    The parsed Scope.\n\nRaises:\n    InvalidTokenError: If the scope string is malformed.\n\nExample:\n    >>> s = Scope.parse(\"forge:tool.clock:execute\")\n    >>> s.service\n    'forge'"
        },
        {
          "name": "Scope.wildcard",
          "line": 74,
          "signature": "def wildcard() -> Scope",
          "documentation": "Create a global wildcard scope that matches everything.\n\nReturns:\n    A Scope with all components set to ``\"*\"``.\n\nExample:\n    >>> Scope.wildcard().implies(Scope.parse(\"any:thing:here\"))\n    True"
        },
        {
          "name": "Scope.implies",
          "line": 86,
          "signature": "def implies(self, other: Scope) -> bool",
          "documentation": "Check whether this scope implies (grants access to) another scope.\n\nA scope implies another if, for each component (service, resource, action),\neither the component matches exactly or this scope has a wildcard (``\"*\"``).\n\nArgs:\n    other: The scope to check against.\n\nReturns:\n    True if this scope implies the other.\n\nExample:\n    >>> Scope.parse(\"forge:*:*\").implies(Scope.parse(\"forge:tool.x:execute\"))\n    True\n    >>> Scope.parse(\"forge:tool.x:execute\").implies(Scope.parse(\"forge:tool.y:execute\"))\n    False"
        },
        {
          "name": "Scope.as_str",
          "line": 110,
          "signature": "def as_str(self) -> str",
          "documentation": "Return the scope as a ``\"service:resource:action\"`` string.\n\nReturns:\n    The scope string."
        },
        {
          "name": "ScopeSet",
          "line": 123,
          "signature": "class ScopeSet()",
          "documentation": "An ordered set of capability scopes.\n\nProvides methods for checking whether a scope is allowed (using\nwildcard matching) and for computing subset/superset relationships.\n\nANVIL Spec section 8.7.2 -- Scope matching uses ``Scope.implies``\nsemantics with wildcard support at each component position.\n\nExample:\n    >>> ss = ScopeSet.from_strings([\"forge:tool.clock:execute\", \"forge:tool.search:execute\"])\n    >>> ss.allows(Scope.parse(\"forge:tool.clock:execute\"))\n    True\n    >>> ss.allows(Scope.parse(\"forge:tool.admin:execute\"))\n    False"
        },
        {
          "name": "ScopeSet.__init__",
          "line": 140,
          "signature": "def __init__(self) -> None",
          "documentation": ""
        },
        {
          "name": "ScopeSet.from_strings",
          "line": 144,
          "signature": "def from_strings(scope_strs: list[str]) -> ScopeSet",
          "documentation": "Create a ScopeSet from a list of scope strings.\n\nArgs:\n    scope_strs: List of ``\"service:resource:action\"`` strings.\n\nReturns:\n    A ScopeSet containing the parsed scopes.\n\nRaises:\n    InvalidTokenError: If any scope string is malformed.\n\nExample:\n    >>> ss = ScopeSet.from_strings([\"a:b:c\", \"d:e:f\"])\n    >>> len(ss)\n    2"
        },
        {
          "name": "ScopeSet.add",
          "line": 166,
          "signature": "def add(self, scope: Scope) -> None",
          "documentation": "Add a scope to the set.\n\nDuplicates are silently ignored (checked by string comparison).\n\nArgs:\n    scope: The scope to add."
        },
        {
          "name": "ScopeSet.allows",
          "line": 180,
          "signature": "def allows(self, requested: Scope) -> bool",
          "documentation": "Check whether any scope in this set implies the requested scope.\n\nArgs:\n    requested: The scope to check.\n\nReturns:\n    True if any scope in this set implies the requested scope.\n\nExample:\n    >>> ss = ScopeSet.from_strings([\"forge:*:*\"])\n    >>> ss.allows(Scope.parse(\"forge:tool.search:execute\"))\n    True"
        },
        {
          "name": "ScopeSet.is_superset_of",
          "line": 196,
          "signature": "def is_superset_of(self, other: ScopeSet) -> bool",
          "documentation": "Check whether this set is a superset of another set.\n\nEvery scope in ``other`` must be implied by at least one scope in\n``self``.\n\nArgs:\n    other: The scope set to check against.\n\nReturns:\n    True if this set is a superset of ``other``.\n\nExample:\n    >>> parent = ScopeSet.from_strings([\"forge:*:*\"])\n    >>> child = ScopeSet.from_strings([\"forge:tool.clock:execute\"])\n    >>> parent.is_superset_of(child)\n    True"
        },
        {
          "name": "ScopeSet.to_strings",
          "line": 219,
          "signature": "def to_strings(self) -> list[str]",
          "documentation": "Return all scopes as a sorted list of strings.\n\nReturns:\n    Sorted list of scope strings."
        },
        {
          "name": "ArsenalACT",
          "line": 241,
          "signature": "class ArsenalACT()",
          "documentation": "An Arsenal Agent Capability Token (ACT).\n\nACTs define what capabilities an agent has. They contain a set of\nscopes (permissions), time validity constraints, and optional delegation\nconstraints.\n\nIn the Python SDK, ACTs are represented as data objects. Cryptographic\nsignature verification is delegated to the WASM bridge module.\n\nANVIL Spec section 8.7 -- Tool Authorization Gate.\n\nArgs:\n    token_id: Unique identifier for this token.\n    agent_did: The DID of the agent this token is issued to.\n    issuer: The entity that issued this token.\n    audience: The intended audience for this token.\n    scopes: The set of capability scopes granted by this token.\n    issued_at: When the token was issued (ISO 8601).\n    not_before: The earliest time the token is valid (ISO 8601).\n    expires_at: When the token expires (ISO 8601).\n    allow_delegation: Whether the token permits delegation to sub-agents.\n    max_delegation_depth: Maximum allowed delegation depth.\n    parent_token_id: The ID of the parent token if this was delegated.\n\nExample:\n    >>> act = ArsenalACT(\n    ...     token_id=\"tok-123\",\n    ...     agent_did=\"did:oas:l1fe:agent:bot\",\n    ...     issuer=\"forge-auth\",\n    ...     audience=\"forge-runtime\",\n    ...     scopes=ScopeSet.from_strings([\"forge:tool.clock:execute\"]),\n    ...     issued_at=\"2026-01-15T00:00:00+00:00\",\n    ...     not_before=\"2026-01-15T00:00:00+00:00\",\n    ...     expires_at=\"2026-01-15T01:00:00+00:00\",\n    ... )\n    >>> act.token_id\n    'tok-123'"
        },
        {
          "name": "ArsenalACT.is_expired",
          "line": 293,
          "signature": "def is_expired(self) -> bool",
          "documentation": "Check whether the token has expired.\n\nReturns:\n    True if the current time is past the token's expiration time.\n\nExample:\n    >>> from datetime import datetime, timezone, timedelta\n    >>> future = (datetime.now(tz=timezone.utc) + timedelta(hours=1)).isoformat()\n    >>> act = ArsenalACT(\n    ...     token_id=\"t\", agent_did=\"d\", issuer=\"i\", audience=\"a\",\n    ...     scopes=ScopeSet.from_strings([\"a:b:c\"]),\n    ...     issued_at=future, not_before=future, expires_at=future,\n    ... )\n    >>> # Note: will depend on exact timing"
        },
        {
          "name": "ArsenalACT.remaining_ttl_seconds",
          "line": 316,
          "signature": "def remaining_ttl_seconds(self) -> int",
          "documentation": "Return the remaining time-to-live in seconds.\n\nReturns:\n    Non-negative integer of remaining seconds. Returns 0 if expired."
        },
        {
          "name": "ArsenalACT.to_dict",
          "line": 330,
          "signature": "def to_dict(self) -> dict[str, Any]",
          "documentation": "Serialize the ACT to a dictionary.\n\nReturns:\n    Dictionary representation."
        },
        {
          "name": "ArsenalACT.from_dict",
          "line": 353,
          "signature": "def from_dict(data: dict[str, Any]) -> ArsenalACT",
          "documentation": "Deserialize an ACT from a dictionary.\n\nArgs:\n    data: Dictionary representation.\n\nReturns:\n    The deserialized ArsenalACT.\n\nRaises:\n    InvalidTokenError: If required fields are missing."
        },
        {
          "name": "ArsenalACT.to_json",
          "line": 382,
          "signature": "def to_json(self) -> str",
          "documentation": "Serialize to JSON string.\n\nReturns:\n    JSON string."
        },
        {
          "name": "ArsenalACT.from_json",
          "line": 391,
          "signature": "def from_json(data: str) -> ArsenalACT",
          "documentation": "Deserialize from JSON string.\n\nArgs:\n    data: JSON string.\n\nReturns:\n    The deserialized ArsenalACT."
        },
        {
          "name": "verify_act",
          "line": 403,
          "signature": "def verify_act(act: ArsenalACT) -> None",
          "documentation": "Verify that an Arsenal ACT is structurally valid and time-valid.\n\nThis function performs two checks:\n1. **Structural validation** -- Ensures the token has valid fields\n   (non-empty scopes, valid identifiers).\n2. **Time validity** -- Ensures the token is not expired.\n\nThis does NOT perform cryptographic signature verification. Signature\nverification is the responsibility of the WASM bridge / Arsenal crypto layer.\n\nANVIL Spec section 8.7.1.\n\nArgs:\n    act: The Arsenal ACT to verify.\n\nRaises:\n    TokenExpiredError: If the token's expiration time has passed.\n    InvalidTokenError: If the token fails structural validation.\n\nExample:\n    >>> from datetime import datetime, timezone, timedelta\n    >>> now = datetime.now(tz=timezone.utc)\n    >>> act = ArsenalACT(\n    ...     token_id=\"tok-1\", agent_did=\"did:oas:test:agent:x\",\n    ...     issuer=\"test\", audience=\"test\",\n    ...     scopes=ScopeSet.from_strings([\"a:b:c\"]),\n    ...     issued_at=now.isoformat(),\n    ...     not_before=now.isoformat(),\n    ...     expires_at=(now + timedelta(hours=1)).isoformat(),\n    ... )\n    >>> verify_act(act)  # No exception raised"
        },
        {
          "name": "extract_scopes",
          "line": 457,
          "signature": "def extract_scopes(act: ArsenalACT) -> list[str]",
          "documentation": "Extract all granted scope strings from an Arsenal ACT.\n\nReturns the scopes as a sorted list of strings in the\n``\"service:resource:action\"`` format.\n\nThis function does NOT validate the token. Call ``verify_act`` first\nto ensure the token is valid before relying on its scopes.\n\nArgs:\n    act: The Arsenal ACT from which to extract scopes.\n\nReturns:\n    A sorted list of scope strings.\n\nExample:\n    >>> act = ArsenalACT(\n    ...     token_id=\"t\", agent_did=\"d\", issuer=\"i\", audience=\"a\",\n    ...     scopes=ScopeSet.from_strings([\"z:z:z\", \"a:a:a\"]),\n    ...     issued_at=\"now\", not_before=\"now\", expires_at=\"later\",\n    ... )\n    >>> extract_scopes(act)\n    ['a:a:a', 'z:z:z']"
        },
        {
          "name": "act_allows_scope",
          "line": 484,
          "signature": "def act_allows_scope(act: ArsenalACT, scope_str: str) -> bool",
          "documentation": "Check whether an Arsenal ACT grants a specific scope.\n\nThis function first verifies the token is valid (not expired, structurally\nsound), then checks if any of the token's granted scopes imply the\nrequested scope. Wildcard scopes (e.g., ``\"forge:*:*\"``) will match\nspecific scopes (e.g., ``\"forge:tool.search:execute\"``).\n\nANVIL Spec section 8.7.2.\n\nArgs:\n    act: The Arsenal ACT to check.\n    scope_str: The scope string to check in ``\"service:resource:action\"`` format.\n\nReturns:\n    True if the scope is granted, False if not.\n\nRaises:\n    TokenExpiredError: If the token has expired.\n    InvalidTokenError: If the token is structurally invalid or the scope\n        string is malformed.\n\nExample:\n    >>> from datetime import datetime, timezone, timedelta\n    >>> now = datetime.now(tz=timezone.utc)\n    >>> act = ArsenalACT(\n    ...     token_id=\"tok-1\", agent_did=\"did:oas:test:agent:x\",\n    ...     issuer=\"test\", audience=\"test\",\n    ...     scopes=ScopeSet.from_strings([\"forge:tool.clock:execute\"]),\n    ...     issued_at=now.isoformat(),\n    ...     not_before=now.isoformat(),\n    ...     expires_at=(now + timedelta(hours=1)).isoformat(),\n    ... )\n    >>> act_allows_scope(act, \"forge:tool.clock:execute\")\n    True\n    >>> act_allows_scope(act, \"forge:tool.search:execute\")\n    False"
        }
      ]
    },
    {
      "path": "forge-py/src/forge/auth/delegation.py",
      "sha256": "5ecc85788de57160cb394be857bdef6aeff00285fa91c8e3372d44b9b7db861f",
      "artifactSha256": "2d7b726ad5106a8abfa1496f22b76975032ce85776e3274e0308cc10d5eaf337",
      "url": "/reference/source/forge-py/src/forge/auth/delegation.py.txt",
      "declarations": [
        {
          "name": "DelegationRequest",
          "line": 39,
          "signature": "class DelegationRequest()",
          "documentation": "A request to delegate capabilities from a parent agent to a child agent.\n\nANVIL Spec section 11.3.\n\nThe delegation request captures all information needed to create a\nchild ACT with narrowed capabilities.\n\nArgs:\n    parent_act: The parent agent's Arsenal ACT.\n    parent_did: The parent agent's OAS DID (for error messages).\n    child_did: The child agent's OAS DID (for error messages).\n    requested_scopes: The scopes requested for the child agent.\n        Must be a subset of the parent's scopes.\n    min_ttl_reduction: Minimum TTL reduction in seconds (default: 60).\n\nExample:\n    >>> from forge.auth.capability import ArsenalACT, ScopeSet\n    >>> from datetime import datetime, timezone, timedelta\n    >>> now = datetime.now(tz=timezone.utc)\n    >>> parent_act = ArsenalACT(\n    ...     token_id=\"tok-parent\", agent_did=\"did:oas:l1fe:agent:parent\",\n    ...     issuer=\"test\", audience=\"test\",\n    ...     scopes=ScopeSet.from_strings([\"forge:tool.search:execute\"]),\n    ...     issued_at=now.isoformat(), not_before=now.isoformat(),\n    ...     expires_at=(now + timedelta(hours=1)).isoformat(),\n    ... )\n    >>> req = DelegationRequest(\n    ...     parent_act=parent_act,\n    ...     parent_did=\"did:oas:l1fe:agent:parent\",\n    ...     child_did=\"did:oas:l1fe:agent:child\",\n    ...     requested_scopes=ScopeSet.from_strings([\"forge:tool.search:execute\"]),\n    ... )\n    >>> req.child_did\n    'did:oas:l1fe:agent:child'"
        },
        {
          "name": "delegate_capabilities",
          "line": 83,
          "signature": "def delegate_capabilities(request: DelegationRequest) -> ArsenalACT",
          "documentation": "Delegate capabilities from a parent agent to a child agent.\n\nThis function enforces all delegation constraints defined in ANVIL Spec section 11.3:\n\n1. **Parent ACT validity** -- The parent's token must be valid (not expired,\n   structurally sound).\n2. **Scope narrowing** -- The requested child scopes must be a subset of\n   the parent's scopes. Any scope in ``requested_scopes`` that is not implied\n   by the parent's scopes triggers a ``CapabilityEscalationError``.\n3. **Delegation permission** -- The parent's ACT must allow delegation.\n4. **TTL reduction** -- The child's TTL is the parent's remaining TTL\n   minus ``min_ttl_reduction``. If the result is below ``MIN_CHILD_TTL``,\n   delegation is denied.\n\nOn success, returns a new ``ArsenalACT`` for the child agent.\n\nArgs:\n    request: The delegation request.\n\nReturns:\n    A new ArsenalACT for the child agent.\n\nRaises:\n    TokenExpiredError: If the parent ACT has expired.\n    InvalidTokenError: If the parent ACT is structurally invalid.\n    CapabilityEscalationError: If the child requests scope not in the parent.\n    DelegationDeniedError: If delegation constraints prevent delegation.\n\nExample:\n    >>> from forge.auth.capability import ArsenalACT, ScopeSet\n    >>> from datetime import datetime, timezone, timedelta\n    >>> now = datetime.now(tz=timezone.utc)\n    >>> parent_act = ArsenalACT(\n    ...     token_id=\"tok-parent\", agent_did=\"did:oas:l1fe:agent:parent\",\n    ...     issuer=\"forge\", audience=\"forge-runtime\",\n    ...     scopes=ScopeSet.from_strings([\"forge:tool.search:execute\", \"forge:tool.clock:execute\"]),\n    ...     issued_at=now.isoformat(), not_before=now.isoformat(),\n    ...     expires_at=(now + timedelta(hours=1)).isoformat(),\n    ... )\n    >>> child_scopes = ScopeSet.from_strings([\"forge:tool.clock:execute\"])\n    >>> req = DelegationRequest(\n    ...     parent_act=parent_act,\n    ...     parent_did=\"did:oas:l1fe:agent:parent\",\n    ...     child_did=\"did:oas:l1fe:agent:child\",\n    ...     requested_scopes=child_scopes,\n    ... )\n    >>> child_act = delegate_capabilities(req)\n    >>> child_act.agent_did\n    'did:oas:l1fe:agent:child'"
        },
        {
          "name": "DelegationManager",
          "line": 187,
          "signature": "class DelegationManager()",
          "documentation": "Stateful delegation manager for creating sub-agent ACTs.\n\nProvides a convenient interface for delegating capabilities from a parent\nagent to child agents, tracking delegation history for audit purposes.\n\nANVIL Spec section 11.3 -- Capability Delegation.\n\nArgs:\n    parent_act: The parent agent's Arsenal ACT.\n    parent_did: The parent agent's OAS DID.\n\nExample:\n    >>> from forge.auth.capability import ArsenalACT, ScopeSet\n    >>> from datetime import datetime, timezone, timedelta\n    >>> now = datetime.now(tz=timezone.utc)\n    >>> parent_act = ArsenalACT(\n    ...     token_id=\"tok-parent\", agent_did=\"did:oas:l1fe:agent:parent\",\n    ...     issuer=\"test\", audience=\"test\",\n    ...     scopes=ScopeSet.from_strings([\"forge:tool.search:execute\"]),\n    ...     issued_at=now.isoformat(), not_before=now.isoformat(),\n    ...     expires_at=(now + timedelta(hours=1)).isoformat(),\n    ... )\n    >>> mgr = DelegationManager(parent_act=parent_act, parent_did=\"did:oas:l1fe:agent:parent\")\n    >>> mgr.delegation_count\n    0"
        },
        {
          "name": "DelegationManager.__init__",
          "line": 215,
          "signature": "def __init__(self, parent_act: ArsenalACT, parent_did: str) -> None",
          "documentation": ""
        },
        {
          "name": "DelegationManager.parent_act",
          "line": 221,
          "signature": "def parent_act(self) -> ArsenalACT",
          "documentation": "Return the parent's ACT.\n\nReturns:\n    The parent ArsenalACT."
        },
        {
          "name": "DelegationManager.parent_did",
          "line": 230,
          "signature": "def parent_did(self) -> str",
          "documentation": "Return the parent's DID.\n\nReturns:\n    The parent DID string."
        },
        {
          "name": "DelegationManager.delegation_count",
          "line": 239,
          "signature": "def delegation_count(self) -> int",
          "documentation": "Return the number of delegations performed.\n\nReturns:\n    The number of child ACTs created."
        },
        {
          "name": "DelegationManager.delegations",
          "line": 248,
          "signature": "def delegations(self) -> list[ArsenalACT]",
          "documentation": "Return the list of child ACTs created by delegation.\n\nReturns:\n    List of child ArsenalACTs."
        },
        {
          "name": "DelegationManager.delegate",
          "line": 256,
          "signature": "def delegate(self, child_did: str, requested_scopes: ScopeSet, *, min_ttl_reduction: int=DEFAULT_MIN_TTL_REDUCTION) -> ArsenalACT",
          "documentation": "Delegate capabilities to a child agent.\n\nArgs:\n    child_did: The child agent's OAS DID.\n    requested_scopes: The scopes to grant the child.\n        Must be a subset of the parent's scopes.\n    min_ttl_reduction: Minimum TTL reduction in seconds.\n\nReturns:\n    A new ArsenalACT for the child agent.\n\nRaises:\n    TokenExpiredError: If the parent ACT has expired.\n    InvalidTokenError: If the parent ACT is structurally invalid.\n    CapabilityEscalationError: If child requests scope not in parent.\n    DelegationDeniedError: If delegation constraints prevent delegation.\n\nExample:\n    >>> from forge.auth.capability import ArsenalACT, ScopeSet\n    >>> from datetime import datetime, timezone, timedelta\n    >>> now = datetime.now(tz=timezone.utc)\n    >>> parent_act = ArsenalACT(\n    ...     token_id=\"tok-parent\", agent_did=\"did:oas:l1fe:agent:parent\",\n    ...     issuer=\"test\", audience=\"test\",\n    ...     scopes=ScopeSet.from_strings([\"forge:tool.search:execute\"]),\n    ...     issued_at=now.isoformat(), not_before=now.isoformat(),\n    ...     expires_at=(now + timedelta(hours=1)).isoformat(),\n    ... )\n    >>> mgr = DelegationManager(parent_act=parent_act, parent_did=\"did:oas:l1fe:agent:parent\")\n    >>> child_act = mgr.delegate(\n    ...     \"did:oas:l1fe:agent:child\",\n    ...     ScopeSet.from_strings([\"forge:tool.search:execute\"]),\n    ... )\n    >>> child_act.agent_did\n    'did:oas:l1fe:agent:child'"
        }
      ]
    },
    {
      "path": "forge-py/src/forge/auth/error.py",
      "sha256": "e2b8cd3053e221c4aff2129b3b9e67071f33370f7695f57705ee024999791ea8",
      "artifactSha256": "95332ddd2382fb601456454e50f10cadefba5a03a82679838911e2d97bc2b665",
      "url": "/reference/source/forge-py/src/forge/auth/error.py.txt",
      "declarations": [
        {
          "name": "ForgeAuthError",
          "line": 16,
          "signature": "class ForgeAuthError(ForgeError)",
          "documentation": "Base exception for all forge-auth operations.\n\nEach subclass carries enough context for operators to diagnose the issue\nwithout access to internal state. Error messages never include private keys\nor raw token bytes."
        },
        {
          "name": "ForgeAuthError.error_code",
          "line": 24,
          "signature": "def error_code(self) -> str",
          "documentation": "Return a short error code string suitable for telemetry and logging.\n\nReturns:\n    A string identifying the error category."
        },
        {
          "name": "TokenExpiredError",
          "line": 33,
          "signature": "class TokenExpiredError(ForgeAuthError)",
          "documentation": "The Arsenal ACT has expired and is no longer valid.\n\nAgents must obtain a fresh token before retrying the operation.\n\nANVIL Spec section 8.7.1.\n\nArgs:\n    token_id: The unique identifier of the expired token.\n    agent_did: The DID of the agent that presented the token.\n    expired_at: The timestamp at which the token expired (ISO 8601).\n\nExample:\n    >>> err = TokenExpiredError(\"tok-123\", \"did:oas:l1fe:agent:bot\", \"2026-01-15T00:00:00Z\")\n    >>> \"tok-123\" in str(err)\n    True\n    >>> err.is_expired()\n    True"
        },
        {
          "name": "TokenExpiredError.__init__",
          "line": 53,
          "signature": "def __init__(self, token_id: str, agent_did: str, expired_at: str) -> None",
          "documentation": ""
        },
        {
          "name": "TokenExpiredError.is_expired",
          "line": 62,
          "signature": "def is_expired(self) -> bool",
          "documentation": "Return True. This is a token expiration error."
        },
        {
          "name": "TokenExpiredError.error_code",
          "line": 66,
          "signature": "def error_code(self) -> str",
          "documentation": "Return the error code for token expiration."
        },
        {
          "name": "InsufficientScopeError",
          "line": 71,
          "signature": "class InsufficientScopeError(ForgeAuthError)",
          "documentation": "The agent's ACT does not grant the required scope for the operation.\n\nThe agent must obtain a token with the missing capability, or the\noperation must be re-scoped to match the agent's granted permissions.\n\nANVIL Spec section 8.7.2.\n\nArgs:\n    agent_did: The DID of the agent whose token was checked.\n    required_scope: The scope string that was required but not granted.\n    available_scopes: The scopes that the agent's ACT actually grants.\n\nExample:\n    >>> err = InsufficientScopeError(\n    ...     \"did:oas:l1fe:agent:bot\",\n    ...     \"forge:tool.search:execute\",\n    ...     [\"forge:tool.clock:execute\"],\n    ... )\n    >>> \"search\" in str(err)\n    True"
        },
        {
          "name": "InsufficientScopeError.__init__",
          "line": 94,
          "signature": "def __init__(self, agent_did: str, required_scope: str, available_scopes: list[str]) -> None",
          "documentation": ""
        },
        {
          "name": "InsufficientScopeError.error_code",
          "line": 108,
          "signature": "def error_code(self) -> str",
          "documentation": "Return the error code for insufficient scope."
        },
        {
          "name": "CapabilityEscalationError",
          "line": 113,
          "signature": "class CapabilityEscalationError(ForgeAuthError)",
          "documentation": "A sub-agent delegation attempted to grant capabilities exceeding the parent's scope.\n\nChild agent capabilities must be a strict subset of the parent's. This is\na security invariant that prevents privilege escalation via delegation.\n\nANVIL Spec section 11.3.1.\n\nArgs:\n    parent_did: The DID of the parent agent.\n    child_did: The DID of the child agent.\n    requested: The scope string that was requested but exceeds the parent's grant.\n    available: The scopes available in the parent's ACT.\n\nExample:\n    >>> err = CapabilityEscalationError(\n    ...     \"did:oas:l1fe:agent:parent\",\n    ...     \"did:oas:l1fe:agent:child\",\n    ...     \"forge:tool.admin:execute\",\n    ...     [\"forge:tool.read:execute\"],\n    ... )\n    >>> \"escalation\" in str(err)\n    True"
        },
        {
          "name": "CapabilityEscalationError.__init__",
          "line": 138,
          "signature": "def __init__(self, parent_did: str, child_did: str, requested: str, available: list[str]) -> None",
          "documentation": ""
        },
        {
          "name": "CapabilityEscalationError.error_code",
          "line": 154,
          "signature": "def error_code(self) -> str",
          "documentation": "Return the error code for capability escalation."
        },
        {
          "name": "DelegationDeniedError",
          "line": 159,
          "signature": "class DelegationDeniedError(ForgeAuthError)",
          "documentation": "Delegation was denied due to constraint violations in the parent's ACT.\n\nThis covers cases where the parent's token does not permit delegation at all,\nor the target agent is not in the allowed delegates list, or the delegation\ndepth has been exceeded.\n\nANVIL Spec section 11.3.2.\n\nArgs:\n    parent_did: The DID of the parent agent attempting to delegate.\n    child_did: The DID of the intended child agent.\n    reason: Human-readable reason for the denial.\n\nExample:\n    >>> err = DelegationDeniedError(\n    ...     \"did:oas:l1fe:agent:root\",\n    ...     \"did:oas:l1fe:agent:sub\",\n    ...     \"delegation not allowed\",\n    ... )\n    >>> \"root\" in str(err) and \"sub\" in str(err)\n    True"
        },
        {
          "name": "DelegationDeniedError.__init__",
          "line": 183,
          "signature": "def __init__(self, parent_did: str, child_did: str, reason: str) -> None",
          "documentation": ""
        },
        {
          "name": "DelegationDeniedError.error_code",
          "line": 192,
          "signature": "def error_code(self) -> str",
          "documentation": "Return the error code for delegation denial."
        },
        {
          "name": "InvalidTokenError",
          "line": 197,
          "signature": "class InvalidTokenError(ForgeAuthError)",
          "documentation": "The ACT is structurally invalid or malformed.\n\nThis indicates the token could not be validated even before checking\nscopes or time validity. The token may be corrupted, incorrectly\nconstructed, or tampered with.\n\nANVIL Spec section 8.7.3.\n\nArgs:\n    reason: Human-readable explanation of why the token is invalid.\n\nExample:\n    >>> err = InvalidTokenError(\"missing required 'scope' field\")\n    >>> \"scope\" in str(err)\n    True"
        },
        {
          "name": "InvalidTokenError.__init__",
          "line": 215,
          "signature": "def __init__(self, reason: str) -> None",
          "documentation": ""
        },
        {
          "name": "InvalidTokenError.error_code",
          "line": 219,
          "signature": "def error_code(self) -> str",
          "documentation": "Return the error code for invalid token."
        }
      ]
    },
    {
      "path": "forge-py/src/forge/auth/tool_auth.py",
      "sha256": "b30acd4be7fb7f350dc0a546c20da34756956b084242088e684b142d6c4d335b",
      "artifactSha256": "e808e6a0b25e0b63d54f9a1ebfb0c7bbbb5716a653ed6976d8a16b4c96d2b587",
      "url": "/reference/source/forge-py/src/forge/auth/tool_auth.py.txt",
      "declarations": [
        {
          "name": "ToolAuthorizationDecision",
          "line": 31,
          "signature": "class ToolAuthorizationDecision(Enum)",
          "documentation": "The result of a tool authorization check.\n\nANVIL Spec section 8.7.\n\nThe three variants correspond to the three possible outcomes:\n\n- ``ALLOWED`` -- tool invocation proceeds.\n- ``DENIED`` -- tool invocation is blocked.\n- ``LEGACY_MODE`` -- no ACT was provided; tool executes without authorization.\n\nExample:\n    >>> ToolAuthorizationDecision.ALLOWED.is_allowed()\n    True\n    >>> ToolAuthorizationDecision.DENIED.is_allowed()\n    False\n    >>> ToolAuthorizationDecision.LEGACY_MODE.is_allowed()\n    True"
        },
        {
          "name": "ToolAuthorizationDecision.is_allowed",
          "line": 55,
          "signature": "def is_allowed(self) -> bool",
          "documentation": "Return True if the decision allows the tool invocation.\n\nBoth ``ALLOWED`` and ``LEGACY_MODE`` permit execution.\n\nReturns:\n    True if the tool may execute."
        },
        {
          "name": "ToolAuthorizationDecision.is_denied",
          "line": 65,
          "signature": "def is_denied(self) -> bool",
          "documentation": "Return True if the decision denies the tool invocation.\n\nReturns:\n    True if the tool is denied."
        },
        {
          "name": "ToolAuthorizationDecision.is_legacy_mode",
          "line": 73,
          "signature": "def is_legacy_mode(self) -> bool",
          "documentation": "Return True if operating in legacy mode (no ACT).\n\nReturns:\n    True if legacy mode."
        },
        {
          "name": "ToolAuthorizationRequest",
          "line": 83,
          "signature": "class ToolAuthorizationRequest()",
          "documentation": "A request to authorize a tool invocation.\n\nContains the agent's identity, the tool being invoked, its tier, and\nthe optional Arsenal ACT. When ``act`` is None, the system operates\nin legacy mode (no authorization enforcement).\n\nANVIL Spec section 8.7.\n\nArgs:\n    agent_did: The OAS DID of the agent requesting tool invocation.\n    tool_name: The name of the tool being invoked.\n    tool_tier: The tier classification of the tool.\n    act: The agent's Arsenal ACT, if available.\n\nExample:\n    >>> req = ToolAuthorizationRequest(\n    ...     agent_did=\"did:oas:l1fe:agent:bot\",\n    ...     tool_name=\"clock\",\n    ...     tool_tier=ToolTier.PLATFORM,\n    ...     act=None,\n    ... )\n    >>> req.tool_name\n    'clock'"
        },
        {
          "name": "ToolAuthorizationResult",
          "line": 116,
          "signature": "class ToolAuthorizationResult()",
          "documentation": "The full result of a tool authorization check.\n\nContains the decision and, if denied, a reason string.\n\nArgs:\n    decision: The authorization decision.\n    reason: The reason for denial (only set when decision is DENIED).\n\nExample:\n    >>> result = ToolAuthorizationResult(\n    ...     decision=ToolAuthorizationDecision.ALLOWED,\n    ...     reason=None,\n    ... )\n    >>> result.decision.is_allowed()\n    True"
        },
        {
          "name": "build_tool_scope",
          "line": 138,
          "signature": "def build_tool_scope(tool_name: str) -> str",
          "documentation": "Build the required scope string for a tool invocation.\n\nThe scope format is ``\"forge:tool.<tool_name>:execute\"``.\n\nArgs:\n    tool_name: The name of the tool.\n\nReturns:\n    The scope string.\n\nExample:\n    >>> build_tool_scope(\"web_search\")\n    'forge:tool.web_search:execute'"
        },
        {
          "name": "authorize_tool_invocation",
          "line": 156,
          "signature": "def authorize_tool_invocation(request: ToolAuthorizationRequest) -> ToolAuthorizationResult",
          "documentation": "Authorize a tool invocation per ANVIL Spec section 8.7.\n\nThis is the primary authorization gate for all tool invocations in the\nForge runtime. It enforces the three-tier model:\n\n- **Tier 1 (Platform)**: Always returns ``ALLOWED``. Platform tools (clock,\n  crypto, logging, random) are always available to agents.\n- **Tier 2 (Host)**: Requires an Arsenal ACT with a scope that implies\n  ``\"forge:tool.<tool_name>:execute\"``. Returns ``DENIED`` if the scope is\n  missing, or ``LEGACY_MODE`` if no ACT is provided.\n- **Tier 3 (Embedded)**: Always returns ``ALLOWED``. Embedded tools run\n  inside the WASM sandbox and are scoped to the module.\n\nArgs:\n    request: The authorization request containing agent DID, tool name,\n        tier, and optional ACT.\n\nReturns:\n    A ToolAuthorizationResult indicating whether the invocation is allowed,\n    denied, or operating in legacy mode.\n\nRaises:\n    TokenExpiredError: If the ACT has expired.\n    InvalidTokenError: If the ACT is structurally invalid.\n\nExample:\n    >>> from forge.core.tool import ToolTier\n    >>> req = ToolAuthorizationRequest(\n    ...     agent_did=\"did:oas:l1fe:agent:bot\",\n    ...     tool_name=\"clock\",\n    ...     tool_tier=ToolTier.PLATFORM,\n    ...     act=None,\n    ... )\n    >>> result = authorize_tool_invocation(req)\n    >>> result.decision.is_allowed()\n    True"
        },
        {
          "name": "ToolAuthorizer",
          "line": 232,
          "signature": "class ToolAuthorizer()",
          "documentation": "Stateful tool authorization manager.\n\nWraps an optional ``ArsenalACT`` and provides a convenient ``authorize``\nmethod for checking tool invocations. Used by the agent runtime to\ngate tool calls.\n\nANVIL Spec section 8.7 -- Tool Authorization Gate.\n\nArgs:\n    act: The agent's Arsenal ACT, if available.\n    agent_did: The agent's DID for error reporting.\n\nExample:\n    >>> authorizer = ToolAuthorizer(act=None, agent_did=\"did:oas:test:agent:bot\")\n    >>> result = authorizer.authorize(\"clock\", ToolTier.PLATFORM)\n    >>> result.decision.is_allowed()\n    True"
        },
        {
          "name": "ToolAuthorizer.__init__",
          "line": 252,
          "signature": "def __init__(self, act: ArsenalACT | None, agent_did: str) -> None",
          "documentation": ""
        },
        {
          "name": "ToolAuthorizer.act",
          "line": 257,
          "signature": "def act(self) -> ArsenalACT | None",
          "documentation": "Return the current ACT, if any.\n\nReturns:\n    The ArsenalACT or None."
        },
        {
          "name": "ToolAuthorizer.agent_did",
          "line": 266,
          "signature": "def agent_did(self) -> str",
          "documentation": "Return the agent's DID.\n\nReturns:\n    The DID string."
        },
        {
          "name": "ToolAuthorizer.is_legacy_mode",
          "line": 275,
          "signature": "def is_legacy_mode(self) -> bool",
          "documentation": "Return True if no ACT is loaded (legacy mode).\n\nReturns:\n    True if operating without ACT authorization."
        },
        {
          "name": "ToolAuthorizer.authorize",
          "line": 283,
          "signature": "def authorize(self, tool_name: str, tool_tier: ToolTier) -> ToolAuthorizationResult",
          "documentation": "Authorize a tool invocation.\n\nArgs:\n    tool_name: The name of the tool being invoked.\n    tool_tier: The tier classification of the tool.\n\nReturns:\n    A ToolAuthorizationResult.\n\nRaises:\n    TokenExpiredError: If the ACT has expired.\n    InvalidTokenError: If the ACT is structurally invalid.\n\nExample:\n    >>> authorizer = ToolAuthorizer(act=None, agent_did=\"d\")\n    >>> result = authorizer.authorize(\"clock\", ToolTier.PLATFORM)\n    >>> result.decision.is_allowed()\n    True"
        },
        {
          "name": "ToolAuthorizer.update_act",
          "line": 311,
          "signature": "def update_act(self, act: ArsenalACT) -> None",
          "documentation": "Update the stored ACT (e.g., after token refresh).\n\nArgs:\n    act: The new Arsenal ACT."
        }
      ]
    }
  ]
}
