Skip to content

API Reference — Actor Module

potpie.actor

Actor: who (user/system) and how (surface/client) submitted an event.

Threaded through every ingestion path (CLI, MCP, HTTP, webhook) so events, reconciliation runs, and graph episodes all retain a first-class answer to "who produced this".

ActorSurface = Literal['cli', 'mcp', 'http', 'webhook', 'system'] module-attribute

Inbound surface. http = direct API caller; cli / mcp are clients that go through HTTP but self-declare via X-Potpie-Client; webhook is an external provider; system is internal jobs (backfills, workers).

SYSTEM_ACTOR = Actor(user_id='system', surface='system', client_name='context-engine', auth_method='system') module-attribute

Fallback used by internal jobs (backfills, workers) that have no human actor.

Actor dataclass

The principal that produced an event.

user_id is the stable Potpie user id for authenticated humans, or a synthetic id for non-human actors (webhook:github:<delivery>, system:<job>). client_name identifies the concrete program, e.g. claude-code, cursor, potpie-cli — free-form metadata.

Source code in src/potpie/actor.py
@dataclass(frozen=True, slots=True)
class Actor:
    """The principal that produced an event.

    ``user_id`` is the stable Potpie user id for authenticated humans, or a
    synthetic id for non-human actors (``webhook:github:<delivery>``,
    ``system:<job>``). ``client_name`` identifies the concrete program, e.g.
    ``claude-code``, ``cursor``, ``potpie-cli`` — free-form metadata.
    """

    user_id: str
    surface: ActorSurface
    client_name: str | None = None
    auth_method: ActorAuthMethod = "api_key"

    def to_properties(self) -> dict[str, Any]:
        """Render as Neo4j ``actor_*`` properties (skip empties)."""
        out: dict[str, Any] = {
            "actor_user_id": self.user_id,
            "actor_surface": self.surface,
            "actor_auth_method": self.auth_method,
        }
        if self.client_name:
            out["actor_client_name"] = self.client_name
        return out

    def to_payload(self) -> dict[str, Any]:
        """JSON-serializable view for API responses."""
        return {
            "user_id": self.user_id,
            "surface": self.surface,
            "client_name": self.client_name,
            "auth_method": self.auth_method,
        }

to_properties()

Render as Neo4j actor_* properties (skip empties).

Source code in src/potpie/actor.py
def to_properties(self) -> dict[str, Any]:
    """Render as Neo4j ``actor_*`` properties (skip empties)."""
    out: dict[str, Any] = {
        "actor_user_id": self.user_id,
        "actor_surface": self.surface,
        "actor_auth_method": self.auth_method,
    }
    if self.client_name:
        out["actor_client_name"] = self.client_name
    return out

to_payload()

JSON-serializable view for API responses.

Source code in src/potpie/actor.py
def to_payload(self) -> dict[str, Any]:
    """JSON-serializable view for API responses."""
    return {
        "user_id": self.user_id,
        "surface": self.surface,
        "client_name": self.client_name,
        "auth_method": self.auth_method,
    }

normalize_surface(value)

Case-insensitive normalization; returns None for invalid/empty input.

Source code in src/potpie/actor.py
def normalize_surface(value: str | None) -> ActorSurface | None:
    """Case-insensitive normalization; returns None for invalid/empty input."""
    if not value:
        return None
    v = value.strip().lower()
    if v in VALID_SURFACES:
        return v  # type: ignore[return-value]
    return None