Repository: GraiaProject/Avilla (language: python)

Issue:
Implement `Context.wrap`



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/publish-spec-qq.yml b/.github/workflows/publish-spec-qq.yml
new file mode 100644
index 00000000..02a096fb
--- /dev/null
+++ b/.github/workflows/publish-spec-qq.yml
@@ -0,0 +1,24 @@
+name: Python package
+on:
+  push:
+    tags:
+      - "spec/qq-*.*.*"
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions/setup-python@v3
+        name: Ensure Python Runtime
+        with:
+          python-version: '3.x'
+          architecture: 'x64'
+      - name: Ensure PDM & twine
+        run: |
+          python3 -m pip install pdm twine pdm-mina mina-build
+      - name: Build Package
+        run: |
+          pdm mina build spec/qq
+      - name: Publish to PyPI
+        run: |
+          twine upload dist/* --non-interactive -u __token__ -p ${{ secrets.PYPI_TOKEN }}
\ No newline at end of file
diff --git a/README.md b/README.md
index 764eea83..d0a45b51 100644
--- a/README.md
+++ b/README.md
@@ -39,26 +39,27 @@ Avilla 是 `Graia Project` 的 "下一代" 框架实现,
 
 ```py
 from creart import create
-from graia.amnesia.builtins.aiohttp import AiohttpService
+from graia.amnesia.builtins.aiohttp import AiohttpClientService
 from graia.broadcast import Broadcast
 
-from avilla.core import Avilla, MessageReceived, Relationship, Selector
+from avilla.core import Avilla, Context, MessageReceived
 from avilla.elizabeth.connection.config import WebsocketClientConfig
 from avilla.elizabeth.protocol import ElizabethProtocol
 
 broadcast = create(Broadcast)
-avilla = Avilla(broadcast, [
-    ElizabethProtocol(
-        WebsocketClientConfig("bot-account", "mah-verify-code")
-    )
-], [AiohttpService()])
+avilla = Avilla(
+    broadcast, [ElizabethProtocol(WebsocketClientConfig("bot-account", "mah-verify-code"))], [AiohttpClientService()]
+)
+
 
 @broadcast.receiver(MessageReceived)
-async def on_message_received(event: MessageReceived, rs: Relationship):
-    if rs.ctx.follows("group.member(<master-account>)")
-        await rs.send_message("Hello, Avilla!")
+async def on_message_received(ctx: Context, event: MessageReceived):
+    if ctx.client.follows("group.member(<master-account>)"):
+        await ctx.scene.send_message("Hello, Avilla!")
+
 
 avilla.launch_manager.launch_blocking(loop=broadcast.loop)
+
 ```
 
 ## 部件发布情况
diff --git a/avilla/core/__init__.py b/avilla/core/__init__.py
index 9936c684..a54a37b8 100644
--- a/avilla/core/__init__.py
+++ b/avilla/core/__init__.py
@@ -1,92 +1,100 @@
 from graia.amnesia.message import MessageChain as MessageChain
 
-from .account import AbstractAccount as AbstractAccount
-from .application import Avilla as Avilla
-from .cell import Cell as Cell
-from .cell.cells import AnswerItem as AnswerItem
-from .cell.cells import Answers as Answers
-from .cell.cells import BanInfo as BanInfo
-from .cell.cells import Comment as Comment
-from .cell.cells import Count as Count
-from .cell.cells import MuteInfo as MuteInfo
-from .cell.cells import Nick as Nick
-from .cell.cells import Privilege as Privilege
-from .cell.cells import QuestionItem as QuestionItem
-from .cell.cells import Questions as Questions
-from .cell.cells import Reason as Reason
-from .cell.cells import Summary as Summary
-from .context import ctx_avilla as ctx_avilla
-from .context import ctx_protocol as ctx_protocol
-from .context import ctx_relationship as ctx_relationship
-from .context import get_current_avilla as get_current_avilla
-from .context import get_current_protocol as get_current_protocol
-from .context import get_current_relationship as get_current_relationship
-from .context import require_relationship as require_relationship
-from .dispatchers import AvillaBuiltinDispatcher as AvillaBuiltinDispatcher
-from .dispatchers import RelationshipDispatcher as RelationshipDispatcher
-from .elements import Audio as Audio
-from .elements import Notice as Notice
-from .elements import NoticeAll as NoticeAll
-from .elements import Picture as Picture
-from .elements import Text as Text
-from .elements import Unknown as Unknown
-from .elements import Video as Video
-from .event import AvillaEvent as AvillaEvent
-from .event import MetadataModified as MetadataModified
-from .event import RelationshipCreated as RelationshipCreated
-from .event import RelationshipDestroyed as RelationshipDestroyed
-from .event.lifecycle import AccountAvailable as AccountAvailable
-from .event.lifecycle import AccountStatusChanged as AccountStatusChanged
-from .event.lifecycle import AccountUnavailable as AccountUnavailable
-from .event.lifecycle import ApplicationClosed as ApplicationClosed
-from .event.lifecycle import ApplicationClosing as ApplicationClosing
-from .event.lifecycle import ApplicationPreparing as ApplicationPreparing
-from .event.lifecycle import ApplicationReady as ApplicationReady
-from .event.lifecycle import AvillaLifecycleEvent as AvillaLifecycleEvent
-from .event.message import MessageEdited as MessageEdited
-from .event.message import MessageReceived as MessageReceived
-from .event.message import MessageRevoked as MessageRevoked
-from .event.request import RequestAccepted as RequestAccepted
-from .event.request import RequestCancelled as RequestCancelled
-from .event.request import RequestEvent as RequestEvent
-from .event.request import RequestIgnored as RequestIgnored
-from .event.request import RequestReceived as RequestReceived
-from .event.request import RequestRejected as RequestRejected
-from .event.resource import ResourceAvailable as ResourceAvailable
-from .event.resource import ResourceUnavailable as ResourceUnavailable
-from .exceptions import AccountDeleted as AccountDeleted
-from .exceptions import AccountMuted as AccountMuted
-from .exceptions import ActionFailed as ActionFailed
-from .exceptions import ContextError as ContextError
-from .exceptions import DeprecatedError as DeprecatedError
-from .exceptions import HttpRequestError as HttpRequestError
-from .exceptions import InaccessibleInterface as InaccessibleInterface
-from .exceptions import InvalidAuthentication as InvalidAuthentication
-from .exceptions import InvalidOperation as InvalidOperation
-from .exceptions import NetworkError as NetworkError
-from .exceptions import ParserException as ParserException
-from .exceptions import RemoteError as RemoteError
-from .exceptions import TooLongMessage as TooLongMessage
-from .exceptions import UnknownError as UnknownError
-from .exceptions import UnknownTarget as UnknownTarget
-from .exceptions import UnsupportedOperation as UnsupportedOperation
-from .message import Message as Message
-from .platform import Abstract as Abstract
-from .platform import Branch as Branch
-from .platform import Land as Land
-from .platform import Maintainer as Maintainer
-from .platform import Platform as Platform
-from .platform import PlatformDescription as PlatformDescription
-from .platform import Version as Version
-from .protocol import BaseProtocol as BaseProtocol
-from .querier import AbstractQueryHandler as AbstractQueryHandler
-from .querier import ProtocolAbstractQueryHandler as ProtocolAbstractQueryHandler
-from .relationship import Relationship as Relationship
-from .request import Request as Request
-from .resource import LocalFileResource as LocalFileResource
-from .resource import Resource as Resource
-from .service import AvillaService as AvillaService
-from .typing import Ensureable as Ensureable
-from .utilles.selector import DynamicSelector as DynamicSelector
-from .utilles.selector import Selectable as Selectable
-from .utilles.selector import Selector as Selector
+from avilla.core.account import AbstractAccount as AbstractAccount
+from avilla.core.application import Avilla as Avilla
+from avilla.core.context import Context as Context
+from avilla.core.dispatchers import AvillaBuiltinDispatcher as AvillaBuiltinDispatcher
+from avilla.core.elements import Audio as Audio
+from avilla.core.elements import Notice as Notice
+from avilla.core.elements import NoticeAll as NoticeAll
+from avilla.core.elements import Picture as Picture
+from avilla.core.elements import Text as Text
+from avilla.core.elements import Unknown as Unknown
+from avilla.core.elements import Video as Video
+from avilla.core.exceptions import AccountDeleted as AccountDeleted
+from avilla.core.exceptions import AccountMuted as AccountMuted
+from avilla.core.exceptions import ActionFailed as ActionFailed
+from avilla.core.exceptions import ContextError as ContextError
+from avilla.core.exceptions import DeprecatedError as DeprecatedError
+from avilla.core.exceptions import HttpRequestError as HttpRequestError
+from avilla.core.exceptions import InaccessibleInterface as InaccessibleInterface
+from avilla.core.exceptions import InvalidAuthentication as InvalidAuthentication
+from avilla.core.exceptions import InvalidOperation as InvalidOperation
+from avilla.core.exceptions import NetworkError as NetworkError
+from avilla.core.exceptions import ParserException as ParserException
+from avilla.core.exceptions import RemoteError as RemoteError
+from avilla.core.exceptions import TooLongMessage as TooLongMessage
+from avilla.core.exceptions import UnknownError as UnknownError
+from avilla.core.exceptions import UnknownTarget as UnknownTarget
+from avilla.core.exceptions import UnsupportedOperation as UnsupportedOperation
+from avilla.core.message import Message as Message
+from avilla.core.metadata import Metadata as Metadata
+from avilla.core.platform import Abstract as Abstract
+from avilla.core.platform import Branch as Branch
+from avilla.core.platform import Land as Land
+from avilla.core.platform import Maintainer as Maintainer
+from avilla.core.platform import Platform as Platform
+from avilla.core.platform import PlatformDescription as PlatformDescription
+from avilla.core.platform import Version as Version
+from avilla.core.protocol import BaseProtocol as BaseProtocol
+from avilla.core.querier import AbstractQueryHandler as AbstractQueryHandler
+from avilla.core.querier import (
+    ProtocolAbstractQueryHandler as ProtocolAbstractQueryHandler,
+)
+from avilla.core.resource import BlobResource as BlobResource
+from avilla.core.resource import LocalFileResource as LocalFileResource
+from avilla.core.resource import Resource as Resource
+from avilla.core.selector import DynamicSelector as DynamicSelector
+from avilla.core.selector import Selectable as Selectable
+from avilla.core.selector import Selector as Selector
+from avilla.core.service import AvillaService as AvillaService
+from avilla.core.trait import Fn as Fn
+from avilla.core.trait import Trait as Trait
+from avilla.core.typing import Ensureable as Ensureable
+from avilla.spec.core.activity import ActivityAvailable as ActivityAvailable
+from avilla.spec.core.activity import ActivityEvent as ActivityEvent
+from avilla.spec.core.activity import ActivityTrigged as ActivityTrigged
+from avilla.spec.core.activity import ActivityUnavailable as ActivityUnavailable
+from avilla.spec.core.application import AccountAvailable as AccountAvailable
+from avilla.spec.core.application import AccountStatusChanged as AccountStatusChanged
+from avilla.spec.core.application import AccountUnavailable as AccountUnavailable
+from avilla.spec.core.application import ApplicationClosed as ApplicationClosed
+from avilla.spec.core.application import ApplicationClosing as ApplicationClosing
+from avilla.spec.core.application import ApplicationPreparing as ApplicationPreparing
+from avilla.spec.core.application import ApplicationReady as ApplicationReady
+from avilla.spec.core.application import AvillaLifecycleEvent as AvillaLifecycleEvent
+from avilla.spec.core.common import Count as Count
+from avilla.spec.core.message import MessageEdit as MessageEdit
+from avilla.spec.core.message import MessageEdited as MessageEdited
+from avilla.spec.core.message import MessageReceived as MessageReceived
+from avilla.spec.core.message import MessageRevoke as MessageRevoke
+from avilla.spec.core.message import MessageRevoked as MessageRevoked
+from avilla.spec.core.message import MessageSend as MessageSend
+from avilla.spec.core.privilege import BanInfo as BanInfo
+from avilla.spec.core.privilege import BanTrait as BanTrait
+from avilla.spec.core.privilege import MuteAllTrait as MuteAllTrait
+from avilla.spec.core.privilege import MuteInfo as MuteInfo
+from avilla.spec.core.privilege import MuteTrait as MuteTrait
+from avilla.spec.core.privilege import Privilege as Privilege
+from avilla.spec.core.privilege import PrivilegeTrait as PrivilegeTrait
+from avilla.spec.core.profile import Nick as Nick
+from avilla.spec.core.profile import NickTrait as NickTrait
+from avilla.spec.core.profile import Summary as Summary
+from avilla.spec.core.profile import SummaryTrait as SummaryTrait
+from avilla.spec.core.request import Answers as Answers
+from avilla.spec.core.request import Comment as Comment
+from avilla.spec.core.request import Questions as Questions
+from avilla.spec.core.request import Reason as Reason
+from avilla.spec.core.request import RequestAccepted as RequestAccepted
+from avilla.spec.core.request import RequestCancelled as RequestCancelled
+from avilla.spec.core.request import RequestEvent as RequestEvent
+from avilla.spec.core.request import RequestIgnored as RequestIgnored
+from avilla.spec.core.request import RequestReceived as RequestReceived
+from avilla.spec.core.request import RequestRejected as RequestRejected
+from avilla.spec.core.request import RequestTrait as RequestTrait
+from avilla.spec.core.resource import FileRemoved as FileRemoved
+from avilla.spec.core.resource import FileUploaded as FileUploaded
+from avilla.spec.core.resource import ResourceAvailable as ResourceAvailable
+from avilla.spec.core.resource import ResourceEvent as ResourceEvent
+from avilla.spec.core.resource import ResourceUnavailable as ResourceUnavailable
+from avilla.spec.core.scene import SceneTrait as SceneTrait
diff --git a/avilla/core/_runtime.py b/avilla/core/_runtime.py
new file mode 100644
index 00000000..fd580d91
--- /dev/null
+++ b/avilla/core/_runtime.py
@@ -0,0 +1,49 @@
+from __future__ import annotations
+
+import functools
+from typing import TYPE_CHECKING
+
+from graia.broadcast.utilles import Ctx
+
+if TYPE_CHECKING:
+    from avilla.core.application import Avilla
+    from avilla.core.context import Context
+    from avilla.core.protocol import BaseProtocol
+
+
+ctx_avilla: Ctx[Avilla] = Ctx("avilla")
+ctx_protocol: Ctx[BaseProtocol] = Ctx("protocol")
+ctx_context: Ctx[Context] = Ctx("context")
+
+
+def get_current_avilla() -> Avilla:
+    avilla = ctx_avilla.get(None)
+    if avilla:
+        return avilla
+    protocol = ctx_protocol.get(None)
+    if protocol:
+        return protocol.avilla
+    context = ctx_context.get(None)
+    if context:
+        return context.protocol.avilla
+    raise RuntimeError("no any current avilla")
+
+
+def get_current_protocol():
+    protocol = ctx_protocol.get(None)
+    if protocol:
+        return protocol
+    context = ctx_context.get(None)
+    if context:
+        return context.protocol
+    raise RuntimeError("no any current protocol")
+
+
+def require_context(func):
+    @functools.wraps(func)
+    async def wrapper(*args, **kwargs):
+        if ctx_context.get(None):
+            return await func(*args, **kwargs)
+        raise RuntimeError("no any current context")
+
+    return wrapper
diff --git a/avilla/core/account.py b/avilla/core/account.py
index 4fd53f1c..821e3ce1 100644
--- a/avilla/core/account.py
+++ b/avilla/core/account.py
@@ -5,11 +5,11 @@
 from typing import TYPE_CHECKING, Any
 
 from avilla.core.platform import Land
-from avilla.core.utilles.selector import Selector
+from avilla.core.selector import Selector
 
 if TYPE_CHECKING:
+    from avilla.core.context import Context
     from avilla.core.protocol import BaseProtocol
-    from avilla.core.relationship import Relationship
 
 
 @dataclass
@@ -24,17 +24,23 @@ def __init__(self, id: str, protocol: BaseProtocol, land: Land | None = None):
         self.protocol = protocol
 
     @abstractmethod
-    async def get_relationship(self, target: Selector, *, via: Selector | None = None) -> Relationship:
+    async def get_context(self, target: Selector, *, via: Selector | None = None) -> Context:
         ...
 
     @abstractmethod
     async def call(self, endpoint: str, params: dict[str, Any] | None = None) -> Any:
         ...
 
-    def get_self_relationship(self):
-        from avilla.core.relationship import Relationship
-        return Relationship(
-            self.protocol, self.to_selector(), Selector().land(self.land.name), self.to_selector(), self
+    def get_self_context(self):
+        from avilla.core.context import Context
+
+        selector = self.to_selector()
+        return Context(
+            self,
+            selector,
+            selector,
+            Selector().land(self.land.name),
+            selector,
         )
 
     @property
diff --git a/avilla/core/application.py b/avilla/core/application.py
index 1e201c09..6c0cef68 100644
--- a/avilla/core/application.py
+++ b/avilla/core/application.py
@@ -1,112 +1,60 @@
 from __future__ import annotations
 
-import importlib.metadata
-import re
-from inspect import cleandoc
-from typing import TYPE_CHECKING, Any, cast
+from typing import TYPE_CHECKING
 
 from graia.broadcast import Broadcast
-from launart import Launart, Service
-from loguru import logger
+from launart import Launart
 
+from avilla.core._runtime import get_current_avilla
 from avilla.core.account import AbstractAccount
-from avilla.core.context import get_current_avilla
-from avilla.core.dispatchers import AvillaBuiltinDispatcher, RelationshipDispatcher
+from avilla.core.dispatchers import AvillaBuiltinDispatcher
 from avilla.core.platform import Land
 from avilla.core.protocol import BaseProtocol
 from avilla.core.resource import LocalFileResource
+from avilla.core.selector import Selector
 from avilla.core.service import AvillaService
 from avilla.core.trait.signature import ResourceFetch
-from avilla.core.utilles.selector import Selector
+
+from .trait.context import wrap_artifacts
 
 if TYPE_CHECKING:
     from avilla.core.trait.signature import ArtifactSignature
 
-AVILLA_ASCII_LOGO = cleandoc(
-    r"""
-    [bold]Avilla[/]: a universal asynchronous message flow solution, powered by [blue]Graia Project[/].
-        _        _ _ _
-       / \__   _(_) | | __ _
-      / _ \ \ / / | | |/ _` |
-     / ___ \ V /| | | | (_| |
-    /_/   \_\_/ |_|_|_|\__,_|
-    """
-)
-AVILLA_ASCII_RAW_LOGO = re.sub(r"\[.*?\]", "", AVILLA_ASCII_LOGO)
-
-
-GRAIA_PROJECT_REPOS = [
-    "avilla-core",
-    "graia-broadcast",
-    "graia-saya",
-    "graia-scheduler",
-    "graia-ariadne",
-    "statv",
-    "launart",
-    "creart",
-    "creart-graia",
-    "kayaku",
-]
-
-
-def _log_telemetry():
-    for telemetry in GRAIA_PROJECT_REPOS:
-        try:
-            version = importlib.metadata.version(telemetry)
-        except Exception:
-            version = "unknown / not-installed"
-        logger.info(
-            f"{telemetry} version: {version}",
-            alt=f"[b cornflower_blue]{telemetry}[/] version: [cyan3]{version}[/]",
-        )
-
 
 class Avilla:
     broadcast: Broadcast
     launch_manager: Launart
     protocols: list[BaseProtocol]
-    # action_middlewares: list[ActionMiddleware]
-    # resource_providers: dict[str, ResourceProvider]
-    # extension_impls: dict[type[ActionExtension], ActionExtensionImpl]
     accounts: list[AbstractAccount]
     service: AvillaService
-    global_artifacts: dict[ArtifactSignature, Any]
 
-    # NOTE: configuration is done by kayaku.
+    with wrap_artifacts() as global_artifacts:
+        import avilla.core.builtins.resource_fetch as _
+
     def __init__(
         self,
         broadcast: Broadcast,
+        launch_manager: Launart,
         protocols: list[BaseProtocol],
-        services: list[Service],
-        # middlewares: list[ActionMiddleware] | None = None,
-        launch_manager: Launart | None = None,
     ):
         if len({type(i) for i in protocols}) != len(protocols):
             raise ValueError("protocol must be unique, and the config should be passed by config.")
 
         self.broadcast = broadcast
-        self.launch_manager = launch_manager or Launart()
+        self.launch_manager = launch_manager
         self.protocols = protocols
         self._protocol_map = {type(i): i for i in protocols}
-        # self.action_middlewares = middlewares or []
         self.accounts = []
-        # self.resource_providers = {}
-        # self.extension_impls = {}
         self.global_artifacts = {}
         self.service = AvillaService(self)
 
-        for service in services:
-            self.launch_manager.add_service(service)
-
         self.launch_manager.add_service(self.service)
 
         for protocol in self.protocols:
-            # Ensureable 用于注册各种东西, 包括 Service, ResourceProvider 等.
+            # Ensureable 用于注册各种东西，包括 Service, ResourceProvider 等。
             protocol.ensure(self)
 
-        # self.broadcast.finale_dispatchers.append(MetadataDispatcher())
         self.broadcast.finale_dispatchers.append(AvillaBuiltinDispatcher(self))
-        self.broadcast.finale_dispatchers.append(RelationshipDispatcher())
 
         @self.register_global_artifact(ResourceFetch(LocalFileResource))
         async def _fetch_local_file(_, res: LocalFileResource):
@@ -121,32 +69,11 @@ def loop(self):
         return self.broadcast.loop
 
     def register_global_artifact(self, signature: ArtifactSignature):
-        def warpper(v):
+        def wrapper(v):
             self.global_artifacts[signature] = v
             return v
 
-        return warpper
-
-    """
-    def add_action_middleware(self, middleware: ActionMiddleware):
-        self.action_middlewares.append(middleware)
-
-    def remove_action_middleware(self, middleware: ActionMiddleware):
-        self.action_middlewares.remove(middleware)
-
-    def get_resource_provider(self, resource: Selector) -> ResourceProvider | None:
-        return self.resource_providers.get(cast(str, resource.latest_key))
-
-    def add_resource_provider(self, provider: ResourceProvider, *resource_types: str):
-        for resource_type in resource_types:
-            self.resource_providers[resource_type] = provider
-
-    def remove_resource_provider(self, provider: ResourceProvider):
-        for resource_type in self.resource_providers:
-            if self.resource_providers[resource_type] is provider:
-                del self.resource_providers[resource_type]
-
-    """
+        return wrapper
 
     def add_account(self, account: AbstractAccount):
         if account in self.accounts:
@@ -164,7 +91,7 @@ def get_account(
         for account in self.accounts:
             if account_id is not None and account.id != account_id:
                 continue
-            if selector is not None and not selector.match(account.to_selector()):
+            if selector is not None and not selector.matches(account.to_selector()):
                 continue
             if land is not None and account.land != land:
                 continue
@@ -177,21 +104,9 @@ def get_accounts(
         for account in self.accounts:
             if account_id is not None and account.id != account_id:
                 continue
-            if selector is not None and not selector.match(account.to_selector()):
+            if selector is not None and not selector.matches(account.to_selector()):
                 continue
             if land is not None and account.land != land:
                 continue
             result.append(account)
         return result
-
-    async def launch(self):
-        logger.info(AVILLA_ASCII_RAW_LOGO, alt=AVILLA_ASCII_LOGO)
-        _log_telemetry()
-
-        for protocol in self.protocols:
-            logger.info(
-                f"Using platform: {protocol.__class__.platform}",
-                alt=f"[magenta]Using platform: [/][dark_orange]{protocol.__class__.platform}[/]",
-            )
-
-        await self.launch_manager.launch()
diff --git a/avilla/core/builtins/resource_fetch.py b/avilla/core/builtins/resource_fetch.py
new file mode 100644
index 00000000..77f54cd2
--- /dev/null
+++ b/avilla/core/builtins/resource_fetch.py
@@ -0,0 +1,14 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from ..resource import LocalFileResource
+from ..trait.context import fetch
+
+if TYPE_CHECKING:
+    from ..context import Context
+
+
+@fetch(LocalFileResource)
+async def fetch_localfile(ctx: Context, res: LocalFileResource):
+    return res.file.read_bytes()
diff --git a/avilla/core/cell/__init__.py b/avilla/core/cell/__init__.py
deleted file mode 100644
index bb5da651..00000000
--- a/avilla/core/cell/__init__.py
+++ /dev/null
@@ -1,134 +0,0 @@
-from __future__ import annotations
-
-from contextvars import ContextVar
-from dataclasses import dataclass
-from typing import TYPE_CHECKING, Any, Generic, TypeVar, overload
-from weakref import WeakKeyDictionary
-
-from typing_extensions import Self, TypeVarTuple, Unpack
-
-if TYPE_CHECKING:
-    from avilla.core.relationship import Relationship
-    from avilla.core.utilles.selector import Selector
-
-T = TypeVar("T")  # 返回值
-
-_Meta_A = TypeVar("_Meta_A", bound="Cell")
-
-_Meta_B = TypeVar("_Meta_B", bound="Cell")
-
-TVT = TypeVarTuple("TVT")
-
-
-class CellMeta(type):
-    @overload
-    def __rshift__(cls: type[_Meta_A], other: type[_Meta_B]) -> CellOf[_Meta_A, _Meta_B]:
-        # sourcery skip: instance-method-first-arg-name
-        ...
-
-    @overload
-    def __rshift__(cls: type[_Meta_A], other: CellOf[Unpack[TVT]]) -> CellOf[_Meta_A, Unpack[TVT]]:
-        # sourcery skip: instance-method-first-arg-name
-        ...
-
-    def __rshift__(cls: Any, other: type[Cell] | CellOf) -> CellOf:
-        # sourcery skip: instance-method-first-arg-name
-        cells = (cls, other) if isinstance(other, type) else (cls, *other.cells)
-        return CellOf(cells)
-
-    """
-    def __repr__(cls) -> str:
-        # sourcery skip: instance-method-first-arg-name
-        return cls.__name__
-    """
-
-
-METACELL_PARAMS_CTX: WeakKeyDictionary[type[Cell], ContextVar[dict[str, Any] | None]] = WeakKeyDictionary()
-
-
-@dataclass
-class Cell(Generic[T], metaclass=CellMeta):
-    describe: type[Self] | CellOf  # CellCompose 的行为和单次的行为一样.
-
-    @classmethod
-    @property
-    def _param_ctx(cls):
-        return METACELL_PARAMS_CTX[cls]
-
-    def __init_subclass__(cls) -> None:
-        METACELL_PARAMS_CTX[cls] = ContextVar(f"$MetadataParam${cls.__module__}::{cls.__qualname__}", default=None)
-
-    @classmethod
-    def get_default_target(cls, relationship: Relationship) -> Selector | None:
-        return relationship.ctx.to_selector()
-
-    @classmethod
-    def get_params(cls) -> dict[str, Any] | None:
-        return cls._param_ctx.get()
-
-    @classmethod
-    def set_params(cls, params: dict[str, Any]):
-        target = cls._param_ctx.get()
-        if target is None:
-            target = {}
-            cls._param_ctx.set(target)
-        target.update(params)
-
-    @classmethod
-    def clear_params(cls) -> None:
-        cls._param_ctx.set(None)
-
-    @classmethod
-    def has_params(cls) -> bool:
-        return cls._param_ctx.get() is not None
-
-
-Ts = TypeVarTuple("Ts")
-
-_M = TypeVar("_M", bound=Cell)
-
-_M_k = TypeVar("_M_k", bound=Cell)
-
-
-class CellOf(Generic[Unpack[TVT]]):
-    cells: tuple[type[Cell], ...]
-
-    def __init__(self, cells: tuple[type[Cell], ...]) -> None:
-        self.cells = cells
-
-    def get_default_target(self, relationship: Relationship) -> Selector | None:
-        return self.cells[0].get_default_target(relationship)
-
-    @overload
-    def __rshift__(self: CellOf[Unpack[TVT]], other: type[_M]) -> CellOf[Unpack[TVT], _M]:
-        ...
-
-    @overload
-    def __rshift__(self: CellOf[Unpack[TVT]], other: CellOf[Unpack[Ts]]) -> CellOf[Unpack[TVT], Unpack[Ts]]:
-        ...
-
-    def __rshift__(self, other: type[Cell] | CellOf) -> CellOf:
-        if not isinstance(other, (type, CellOf)):
-            raise TypeError(f"{other.__class__} is not allowed.")
-        cells = (*self.cells, other) if isinstance(other, type) else (*self.cells, *other.cells)
-        return CellOf(cells)
-
-    def __repr__(self) -> str:
-        cells_repr = " >> ".join(cell.__name__ for cell in self.cells)
-        return f"CellOf[{cells_repr}]"
-
-    def __hash__(self) -> int:
-        return hash(self.cells) + hash("CellOf")
-
-    def __eq__(self, o: object) -> bool:
-        return isinstance(o, CellOf) and o.cells == self.cells
-
-    def clear_params(self) -> None:
-        for cell in self.cells:
-            cell.clear_params()
-
-    def has_params(self) -> bool:
-        return any(cell.has_params() for cell in self.cells)
-
-
-_DeriveBack = CellOf[Unpack[tuple[Any, ...]], _M_k]
diff --git a/avilla/core/cell/cells.py b/avilla/core/cell/cells.py
deleted file mode 100644
index 87c428b0..00000000
--- a/avilla/core/cell/cells.py
+++ /dev/null
@@ -1,75 +0,0 @@
-from __future__ import annotations
-
-from dataclasses import dataclass
-from datetime import timedelta
-
-from . import Cell
-
-
-@dataclass
-class Count(Cell):
-    current: int
-    max: int
-
-
-@dataclass
-class Summary(Cell):
-    name: str
-    description: str | None
-
-
-@dataclass
-class MuteInfo(Cell):
-    muted: bool
-    duration: timedelta
-
-
-@dataclass
-class BanInfo(Cell):
-    banned: bool
-    duration: timedelta
-
-
-@dataclass
-class Privilege(Cell):
-    available: bool
-    effective: bool
-
-
-@dataclass
-class Nick(Cell):
-    name: str
-    nickname: str
-    badge: str | None
-
-
-@dataclass
-class Reason(Cell):
-    content: str
-
-
-@dataclass
-class Comment(Cell):
-    content: str
-
-
-@dataclass
-class QuestionItem:
-    id: str
-    content: str
-
-
-@dataclass
-class Questions(Cell):
-    items: list[QuestionItem]
-
-
-@dataclass
-class AnswerItem:
-    id: str
-    content: str
-
-
-@dataclass
-class Answers(Cell):
-    items: list[AnswerItem]
diff --git a/avilla/core/context.py b/avilla/core/context.py
deleted file mode 100644
index 753a3f5c..00000000
--- a/avilla/core/context.py
+++ /dev/null
@@ -1,58 +0,0 @@
-from __future__ import annotations
-
-import functools
-from typing import TYPE_CHECKING, Any
-
-from graia.broadcast.utilles import Ctx
-
-if TYPE_CHECKING:
-    from graia.broadcast.entities.event import Dispatchable
-
-    from avilla.core.application import Avilla
-    from avilla.core.protocol import BaseProtocol
-    from avilla.core.relationship import Relationship
-
-
-ctx_avilla: Ctx[Avilla] = Ctx("avilla")
-ctx_protocol: Ctx[BaseProtocol] = Ctx("protocol")
-ctx_relationship: Ctx[Relationship] = Ctx("relationship")
-
-
-def get_current_avilla() -> Avilla:
-    avilla = ctx_avilla.get()
-    if avilla:
-        return avilla
-    protocol = ctx_protocol.get()
-    if protocol:
-        return protocol.avilla
-    relationship = ctx_relationship.get()
-    if relationship:
-        return relationship.protocol.avilla
-    raise RuntimeError("no any current avilla")
-
-
-def get_current_protocol():
-    protocol = ctx_protocol.get()
-    if protocol:
-        return protocol
-    relationship = ctx_relationship.get()
-    if relationship:
-        return relationship.protocol
-    raise RuntimeError("no any current protocol")
-
-
-def get_current_relationship():
-    relationship = ctx_relationship.get()
-    if relationship:
-        return relationship
-    raise RuntimeError("no any current relationship")
-
-
-def require_relationship(func):
-    @functools.wraps(func)
-    async def wrapper(*args, **kwargs):
-        if ctx_relationship.get():
-            return await func(*args, **kwargs)
-        raise RuntimeError("no any current relationship")
-
-    return wrapper
diff --git a/avilla/core/context/__init__.py b/avilla/core/context/__init__.py
new file mode 100644
index 00000000..8edebe6f
--- /dev/null
+++ b/avilla/core/context/__init__.py
@@ -0,0 +1,243 @@
+from __future__ import annotations
+
+from collections import ChainMap
+from collections.abc import AsyncGenerator, Awaitable, Callable
+from functools import cached_property
+from typing import Any, TypedDict, TypeVar, cast, overload
+
+from graia.amnesia.message import __message_chain_class__
+from typing_extensions import TypeAlias, Unpack
+
+from avilla.core._runtime import ctx_context
+from avilla.core.account import AbstractAccount
+from avilla.core.metadata import Metadata, MetadataBound, MetadataOf, MetadataRoute
+from avilla.core.resource import Resource
+from avilla.core.selector import Selectable, Selector
+from avilla.core.trait import Trait
+from avilla.core.trait.context import Artifacts
+from avilla.core.trait.signature import Bounds, Pull, Query, ResourceFetch, VisibleConf
+from avilla.core.utilles import classproperty
+
+from ._query import find_querier_steps as _find_querier_steps
+from ._query import query_depth_generator as _query_depth_generator
+from ._selector import (
+    ContextClientSelector,
+    ContextEndpointSelector,
+    ContextMedium,
+    ContextRequestSelector,
+    ContextSceneSelector,
+    ContextSelector,
+    ContextWrappedMetadataOf,
+)
+
+_T = TypeVar("_T")
+_MetadataT = TypeVar("_MetadataT", bound=Metadata)
+_DescribeT = TypeVar("_DescribeT", bound="type[Metadata] | MetadataRoute")
+_TraitT = TypeVar("_TraitT", bound=Trait)
+
+_Querier: TypeAlias = Callable[["Context", Selector | None, Selector], AsyncGenerator[Selector, None]]
+_Describe: TypeAlias = type[_MetadataT] | MetadataRoute[Unpack[tuple[Unpack[tuple[Any, ...]], _MetadataT]]]
+
+
+class ContextCache(TypedDict):
+    meta: dict[Selector, dict[type[Metadata] | MetadataRoute, Metadata]]
+
+
+class Context:
+    account: AbstractAccount
+
+    client: ContextClientSelector
+    endpoint: ContextEndpointSelector
+    scene: ContextSceneSelector
+    self: Selector
+    mediums: list[ContextMedium]
+
+    cache: ContextCache | dict[str, Any]
+
+    def __init__(
+        self,
+        account: AbstractAccount,
+        client: Selector,
+        endpoint: Selector,
+        scene: Selector,
+        selft: Selector,
+        mediums: list[Selector] | None = None,
+        prelude_metadatas: dict[Selector, dict[type[Metadata] | MetadataRoute, Metadata]] | None = None,
+    ) -> None:
+        self.account = account
+
+        self.client = ContextClientSelector.from_selector(self, client)
+        self.endpoint = ContextEndpointSelector.from_selector(self, endpoint)
+        self.scene = ContextSceneSelector.from_selector(self, scene)
+        self.self = selft
+        self.mediums = [ContextMedium(ContextSelector.from_selector(self, medium)) for medium in mediums or []]
+
+        self.cache = {"meta": prelude_metadatas or {}}
+
+    @property
+    def protocol(self):
+        return self.account.protocol
+
+    @property
+    def avilla(self):
+        return self.protocol.avilla
+
+    @property
+    def land(self):
+        return self.protocol.land
+
+    @cached_property
+    def _impl_artifacts(self) -> Artifacts:
+        m = [
+            self.protocol.implementations,
+            *[v for k, v in self.protocol.implementations.items() if isinstance(k, VisibleConf) and k.checker(self)],
+        ]
+        return ChainMap(*m[::-1], self.avilla.global_artifacts)
+
+    @property
+    def request(self) -> ContextRequestSelector:
+        return self.endpoint.expects_request()
+
+    @property
+    def is_resource(self) -> bool:
+        return any(isinstance(i, Resource) for i in self.cache["meta"].get(self.endpoint, {}).values())
+
+    def _collect_metadatas(self, target: Selector | Selectable, *metadatas: Metadata):
+        scope = self.cache["meta"].setdefault(target.to_selector(), {})
+        scope.update({type(i): i for i in metadatas})
+
+    def _get_entity_bound_scope(self, target: Selector):
+        return next(
+            (
+                v
+                for k, v in self._impl_artifacts.items()
+                if isinstance(k, Bounds) and isinstance(k.bound, str) and target.follows(k.bound)
+            ),
+            {},
+        )
+
+    def _get_metadata_bound_scope(self, reference: MetadataOf):
+        return next(
+            (
+                v
+                for k, v in self._impl_artifacts.items()
+                if isinstance(k, Bounds)
+                and isinstance(k.bound, MetadataBound)
+                and reference.target.follows(k.bound.target)
+                and reference.describe == k.bound.describe
+            ),
+            {},
+        )
+
+    """
+    @property
+    def _ext_handler(self):
+        return ExtensionHandler(self)
+    """
+
+    @classproperty
+    @classmethod
+    def current(cls) -> Context:
+        return ctx_context.get()
+
+    async def query(self, pattern: Selector, with_land: bool = False):
+        querier_steps: list[Query] | None = _find_querier_steps(
+            self._impl_artifacts, pattern.path if with_land else pattern.path_without_land
+        )
+
+        if querier_steps is None:
+            raise NotImplementedError(f'cannot query "{pattern.path_without_land}" due to unknown step calc.')
+
+        querier = cast("dict[Query, _Querier]", {i: self._impl_artifacts[i] for i in querier_steps})
+        generators: list[AsyncGenerator[Selector, None]] = []
+
+        past = []
+        for k, v in querier.items():
+            past.append(k.target)
+            pred = pattern.mixin(".".join(past))
+            current = _query_depth_generator(self, v, pred, generators[-1] if generators else None)
+            generators.append(current)
+
+        async for i in generators[-1]:
+            if with_land:
+                yield Selector({"land": self.land.name, **i.pattern})
+            else:
+                yield i
+
+    # TODO: GraiaProject/Avilla#66
+    # TODO: redesign Context.complete
+
+    """
+    def complete(self, selector: Selector, with_land: bool = False):
+        output_rule = self._impl_artifacts.get(CompleteRule(selector.path_without_land))
+        if output_rule is not None:
+            output_rule = cast(str, output_rule)
+            selector = Selector().mixin(output_rule, selector, self.endpoint, self.scene)
+        if with_land and list(selector.pattern.keys())[0] != "land":
+            selector.pattern = {"land": self.land.name, **selector.pattern}
+        return selector
+    """
+
+    async def fetch(self, resource: Resource[_T]) -> _T:
+        fetcher = self._impl_artifacts.get(ResourceFetch(type(resource)))
+        if fetcher is None:
+            raise NotImplementedError(
+                f'cannot fetch "{resource}" because no available fetch implement found in "{self.protocol.__class__.__name__}"'
+            )
+        return await fetcher(self, resource)
+
+    async def pull(
+        self,
+        route: type[_MetadataT] | MetadataRoute[Unpack[tuple[Any, ...]], _MetadataT],
+        target: Selector | Selectable,
+        *,
+        flush: bool = False,
+    ) -> _MetadataT:
+        if isinstance(target, Selectable):
+            target = target.to_selector()
+
+        cached = self.cache["meta"].get(target)
+        if cached is not None and route in cached:
+            if flush:
+                del cached[route]
+            elif not route.has_params():
+                return cast("_MetadataT", cached[route])
+
+        pull_implement = self._impl_artifacts.get(Bounds(target.path_without_land), {}).get(Pull(route))
+        if pull_implement is None:
+            raise NotImplementedError(
+                f'cannot pull "{route}"'
+                + (f' for "{target.path_without_land}"' if target is not None else "")
+                + f' because no available implement found in "{self.protocol.__class__.__name__}"'
+            )
+        pull_implement = cast(Callable[[Context, "Selector | None"], Awaitable[_MetadataT]], pull_implement)
+        result = await pull_implement(self, target)
+        if target is not None and not route.has_params():
+            cached = self.cache["meta"].setdefault(target, {})
+            cached[route] = result
+        return result
+
+    @overload
+    def wrap(self, closure: Selector) -> ContextSelector:
+        ...
+
+    @overload
+    def wrap(self, closure: MetadataOf[_Describe]) -> ContextWrappedMetadataOf[_Describe]:
+        ...
+
+    @overload
+    def wrap(self, closure: type[_TraitT]) -> type[_TraitT]:
+        ...
+
+    def wrap(
+        self,
+        closure: Selector | MetadataOf[_DescribeT] | type[_TraitT],
+    ) -> ContextSelector | ContextWrappedMetadataOf[_Describe] | type[_TraitT]:
+        if isinstance(closure, type) and issubclass(closure, Trait):
+            return type(closure.__name__, (closure,), {"context": self})  # type: ignore
+        elif isinstance(closure, Selector):
+            return ContextSelector.from_selector(self, closure)
+        elif isinstance(closure, MetadataOf):
+            return ContextWrappedMetadataOf(closure.target, closure.describe, self)
+
+        raise TypeError(f"cannot wrap {closure!r}")
diff --git a/avilla/core/context/_query.py b/avilla/core/context/_query.py
new file mode 100644
index 00000000..54172948
--- /dev/null
+++ b/avilla/core/context/_query.py
@@ -0,0 +1,67 @@
+from __future__ import annotations
+
+from collections import deque
+from collections.abc import AsyncGenerator, Callable
+from dataclasses import dataclass
+from typing import TYPE_CHECKING
+
+from graia.amnesia.message import __message_chain_class__
+from typing_extensions import TypeAlias
+
+from avilla.core.selector import Selector
+from avilla.core.trait.context import Artifacts
+from avilla.core.trait.signature import Query
+
+if TYPE_CHECKING:
+    from . import Context
+
+_Querier: TypeAlias = Callable[["Context", Selector | None, Selector], AsyncGenerator[Selector, None]]
+
+
+async def query_depth_generator(
+    context: Context,
+    current: _Querier,
+    predicate: Selector,
+    upper_generator: AsyncGenerator[Selector, None] | None = None,
+):
+    if upper_generator is not None:
+        async for i in upper_generator:
+            async for j in current(context, i, predicate):
+                yield j
+    else:
+        async for j in current(context, None, predicate):
+            yield j
+
+
+@dataclass
+class _MatchStep:
+    upper: str
+    start: int
+    history: tuple[Query, ...]
+
+
+def find_querier_steps(artifacts: Artifacts, query_path: str) -> list[Query] | None:
+    result: list[Query] | None = None
+    frags: list[str] = query_path.split(".")
+    queue: deque[_MatchStep] = deque([_MatchStep("", 0, ())])
+    while queue:
+        head: _MatchStep = queue.popleft()
+        current_steps: list[str] = []
+        for curr_frag in frags[head.start :]:
+            current_steps.append(curr_frag)
+            steps = ".".join(current_steps)
+            full_path = f"{head.upper}.{steps}" if head.upper else steps
+            head.start += 1
+            if (query := Query(head.upper or None, steps)) in artifacts:
+                if full_path == query_path:
+                    if result is None or len(result) > len(head.history) + 1:
+                        result = [*head.history, query]
+                else:
+                    queue.append(
+                        _MatchStep(
+                            full_path,
+                            head.start,
+                            head.history + (query,),
+                        )
+                    )
+    return result
diff --git a/avilla/core/context/_selector.py b/avilla/core/context/_selector.py
new file mode 100644
index 00000000..5c30dd06
--- /dev/null
+++ b/avilla/core/context/_selector.py
@@ -0,0 +1,116 @@
+from __future__ import annotations
+
+from collections.abc import Awaitable, Iterable, Mapping
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, Any, TypeVar
+
+from graia.amnesia.message import Element, Text, __message_chain_class__
+from typing_extensions import Self, TypeAlias, Unpack
+
+from avilla.core.message import Message
+from avilla.core.metadata import Metadata, MetadataOf, MetadataRoute
+from avilla.core.selector import EMPTY_MAP, Selector
+from avilla.core.trait import Trait
+from avilla.spec.core.message import MessageSend
+from avilla.spec.core.request import RequestTrait
+from avilla.spec.core.scene import SceneTrait
+
+if TYPE_CHECKING:
+    from . import Context
+
+_MetadataT = TypeVar("_MetadataT", bound=Metadata)
+_DescribeT = TypeVar("_DescribeT", bound="type[Metadata] | MetadataRoute")
+_TraitT = TypeVar("_TraitT", bound=Trait)
+
+_Describe: TypeAlias = type[_MetadataT] | MetadataRoute[Unpack[tuple[Unpack[tuple[Any, ...]], _MetadataT]]]
+
+
+class ContextSelector(Selector):
+    context: Context
+
+    def __init__(self, ctx: Context, pattern: Mapping[str, str] = EMPTY_MAP) -> None:
+        super().__init__(pattern)
+        self.context = ctx
+
+    @classmethod
+    def from_selector(cls, ctx: Context, selector: Selector) -> Self:
+        return cls(ctx, selector.pattern)
+
+    def pull(self, metadata: _Describe[_MetadataT]) -> Awaitable[_MetadataT]:
+        return self.context.pull(metadata, self)
+
+    def wrap(self, trait: type[_TraitT]) -> _TraitT:
+        return trait(self.context, self)
+
+
+class ContextClientSelector(ContextSelector):
+    ...
+
+
+class ContextEndpointSelector(ContextSelector):
+    def expects_request(self) -> ContextRequestSelector:
+        if "request" in self.pattern:
+            return ContextRequestSelector.from_selector(self.context, self)
+
+        raise ValueError(f"endpoint {self!r} is not a request endpoint")
+
+
+class ContextSceneSelector(ContextSelector):
+    def leave_scene(self):
+        return self.wrap(SceneTrait).leave()
+
+    def disband_scene(self):
+        return self.wrap(SceneTrait).disband()
+
+    def send_message(
+        self,
+        message: __message_chain_class__ | str | Iterable[str | Element],
+        *,
+        reply: Message | Selector | str | None = None,
+    ):
+        if isinstance(message, str):
+            message = __message_chain_class__([Text(message)])
+        elif not isinstance(message, __message_chain_class__):
+            message = __message_chain_class__([]).extend(list(message))
+        else:
+            message = __message_chain_class__([i if isinstance(i, Element) else Text(i) for i in message])
+
+        if isinstance(reply, Message):
+            reply = reply.to_selector()
+        elif isinstance(reply, str):
+            reply = self.message(reply)
+
+        return self.wrap(MessageSend).send(message, reply=reply)
+
+    def remove_member(self, target: Selector, reason: str | None = None):
+        return self.wrap(SceneTrait).remove_member(reason)
+
+
+class ContextRequestSelector(ContextEndpointSelector):
+    def accept_request(self):
+        return self.wrap(RequestTrait).accept()
+
+    def reject_request(self, reason: str | None = None, forever: bool = False):
+        return self.wrap(RequestTrait).reject(reason, forever)
+
+    def cancel_request(self):
+        return self.wrap(RequestTrait).cancel()
+
+    def ignore_request(self):
+        return self.wrap(RequestTrait).ignore()
+
+
+@dataclass
+class ContextMedium:
+    selector: ContextSelector
+
+
+@dataclass
+class ContextWrappedMetadataOf(MetadataOf[_DescribeT]):
+    context: Context
+
+    def pull(self) -> Awaitable[_DescribeT]:
+        return self.context.pull(self.describe, self.target)
+
+    def wrap(self, trait: type[_TraitT]) -> _TraitT:
+        return trait(self.context, self)
diff --git a/avilla/core/dispatchers.py b/avilla/core/dispatchers.py
index c63ad030..e0a7f8c0 100644
--- a/avilla/core/dispatchers.py
+++ b/avilla/core/dispatchers.py
@@ -1,16 +1,15 @@
 from __future__ import annotations
 
 from inspect import isclass
-from types import TracebackType
 from typing import TYPE_CHECKING
 
 from graia.broadcast.entities.dispatcher import BaseDispatcher
 
+from avilla.core._runtime import ctx_protocol
 from avilla.core.account import AbstractAccount
-from avilla.core.cell import Cell
-from avilla.core.context import ctx_protocol, ctx_relationship
+from avilla.core.context import Context
 from avilla.core.event import AvillaEvent
-from avilla.core.relationship import Relationship
+from avilla.core.protocol import BaseProtocol
 
 if TYPE_CHECKING:
     from graia.broadcast.interfaces.dispatcher import DispatcherInterface
@@ -29,46 +28,18 @@ async def catch(self, interface: DispatcherInterface[AvillaEvent]):
 
         if interface.annotation is Avilla:
             return self.avilla
-        elif interface.annotation in self.avilla._protocol_map:
+        if interface.annotation in self.avilla._protocol_map:
             return self.avilla._protocol_map[interface.annotation]
-        elif isinstance(interface.event, AvillaEvent):
-            if isclass(interface.annotation) and issubclass(interface.annotation, AbstractAccount):
-                rs: Relationship = interface.local_storage["relationship"]
-                return interface.event.account
-
-
-class RelationshipDispatcher(BaseDispatcher):
-    @staticmethod
-    async def beforeExecution(interface: DispatcherInterface[AvillaEvent]):
-        protocol = ctx_protocol.get()
-        if protocol is not None:
-            rs = await interface.event.account.get_relationship(interface.event.ctx, via=interface.event.get_via())
-            token = ctx_relationship.set(rs)
-            rs.cache["meta"] = interface.event.extra.get("meta", {})
-            interface.local_storage["relationship"] = rs
-            interface.local_storage["_ctxtoken_rs"] = token
-
-    @staticmethod
-    async def afterExecution(
-        interface: DispatcherInterface[AvillaEvent],
-        exception: Exception | None,
-        tb: TracebackType | None,
-    ):
-        ctx_relationship.reset(interface.local_storage["_ctxtoken_rs"])
-
-    @staticmethod
-    async def catch(interface: DispatcherInterface[AvillaEvent]):
-        if isinstance(interface.event, AvillaEvent):
-            if interface.annotation is Relationship:
-                return interface.local_storage["relationship"]
-
-
-"""
-class MetadataDispatcher(BaseDispatcher):
-    @staticmethod
-    async def catch(interface: DispatcherInterface[AvillaEvent]):
-        if isinstance(interface.event, AvillaEvent):
-            if isinstance(interface.annotation, type) and issubclass(interface.annotation, Cell):
-                relationship: Relationship = interface.local_storage["relationship"]
-                return await relationship.meta(interface.annotation)
-"""
+        if (
+            isclass(interface.annotation)
+            and issubclass(interface.annotation, BaseProtocol)
+            and isinstance(ctx_protocol.get(None), interface.annotation)
+        ):
+            return ctx_protocol.get(None)
+        if (
+            isinstance(interface.event, AvillaEvent)
+            and isclass(interface.annotation)
+            and issubclass(interface.annotation, AbstractAccount)
+        ):
+            ctx: Context = interface.local_storage["avilla_context"]
+            return ctx.account
diff --git a/avilla/core/elements.py b/avilla/core/elements.py
index e05e68bb..7674334e 100644
--- a/avilla/core/elements.py
+++ b/avilla/core/elements.py
@@ -7,7 +7,7 @@
 from graia.amnesia.message.element import Text as Text
 
 from avilla.core.resource import LocalFileResource, Resource
-from avilla.core.utilles.selector import Selector
+from avilla.core.selector import Selector
 
 
 class Notice(Element):
@@ -16,7 +16,7 @@ class Notice(Element):
     target: Selector
 
     def __init__(self, target: Selector) -> None:
-        """实例化一个 Notice 消息元素, 用于承载消息中用于提醒/呼唤特定用户的部分.
+        """实例化一个 Notice 消息元素，用于承载消息中用于提醒/呼唤特定用户的部分。
 
         Args:
             target (str): 需要提醒/呼唤的特定用户的 ID.
diff --git a/avilla/core/event.py b/avilla/core/event.py
new file mode 100644
index 00000000..1739b67e
--- /dev/null
+++ b/avilla/core/event.py
@@ -0,0 +1,89 @@
+from __future__ import annotations
+
+from abc import ABCMeta
+from dataclasses import dataclass, field
+from datetime import datetime
+from typing import TYPE_CHECKING, Any
+
+from graia.broadcast.entities.dispatcher import BaseDispatcher
+from graia.broadcast.entities.event import Dispatchable
+
+from ._runtime import ctx_context
+
+if TYPE_CHECKING:
+    from graia.broadcast.interfaces.dispatcher import DispatcherInterface
+
+    from avilla.core.selector import Selector
+
+    from .context import Context
+    from .metadata import MetadataOf
+
+
+@dataclass
+class AvillaEvent(Dispatchable, metaclass=ABCMeta):
+    context: Context
+    time: datetime = field(init=False, default_factory=datetime.now)
+
+    class Dispatcher(BaseDispatcher):
+        @staticmethod
+        async def beforeExecution(interface: DispatcherInterface[AvillaEvent]):
+            interface.local_storage["avilla_context"] = interface.event.context
+            interface.local_storage["_context_token"] = ctx_context.set(interface.event.context)
+
+        @staticmethod
+        async def catch(interface: DispatcherInterface[AvillaEvent]):
+            from .context import Context
+
+            if interface.annotation is Context:
+                return interface.event.context
+
+        @staticmethod
+        async def afterExecution(interface: DispatcherInterface[AvillaEvent]):
+            ctx_context.reset(interface.local_storage["_context_token"])
+
+
+@dataclass
+class MetadataModify:
+    bound: Selector | MetadataOf
+    field: str
+    action: str
+    past: Any
+    present: Any
+
+
+@dataclass
+class MetadataModified(AvillaEvent):
+    endpoint: Selector
+    modifies: list[MetadataModify]
+    operator: Selector | None = None
+
+    class Dispatcher(AvillaEvent.Dispatcher):
+        @staticmethod
+        async def catch(interface: DispatcherInterface["MetadataModified"]):
+            return await super().catch(interface)
+
+
+@dataclass
+class RelationshipCreated(AvillaEvent):
+    client: Selector
+    scene: Selector
+    self: Selector
+    mediums: list[Selector] = field(default_factory=list)
+
+    class Dispatcher(AvillaEvent.Dispatcher):
+        @staticmethod
+        async def catch(interface: DispatcherInterface["RelationshipCreated"]):
+            return await super().catch(interface)
+
+
+@dataclass
+class RelationshipDestroyed(AvillaEvent):
+    client: Selector
+    scene: Selector
+    self: Selector
+    mediums: list[Selector] = field(default_factory=list)
+
+    class Dispatcher(AvillaEvent.Dispatcher):
+        @staticmethod
+        async def catch(interface: DispatcherInterface["RelationshipDestroyed"]):
+            return await super().catch(interface)
diff --git a/avilla/core/event/__init__.py b/avilla/core/event/__init__.py
deleted file mode 100644
index 2929d477..00000000
--- a/avilla/core/event/__init__.py
+++ /dev/null
@@ -1,123 +0,0 @@
-from __future__ import annotations
-
-from abc import ABCMeta, abstractmethod
-from dataclasses import dataclass
-from datetime import datetime
-from typing import TYPE_CHECKING, Any, get_args, get_origin
-
-from graia.broadcast.entities.dispatcher import BaseDispatcher
-from graia.broadcast.entities.event import Dispatchable
-
-if TYPE_CHECKING:
-    from graia.broadcast.interfaces.dispatcher import DispatcherInterface
-
-    from avilla.core.account import AbstractAccount
-    from avilla.core.utilles.selector import Selector
-
-    from ..cell import Cell, CellOf
-
-
-class AvillaEvent(Dispatchable, metaclass=ABCMeta):
-    account: AbstractAccount
-    time: datetime
-
-    extra: dict[Any, Any]
-
-    def __init__(
-        self, account: AbstractAccount, *, extra: dict[Any, Any] | None = None, time: datetime | None = None
-    ) -> None:
-        self.account = account
-        self.extra = extra or {}
-        self.time = time or datetime.now()
-
-    @property
-    @abstractmethod
-    def ctx(self) -> Selector:
-        ...
-
-    def get_via(self) -> Selector | None:
-        ...
-
-
-@dataclass
-class MetadataModify:
-    describe: type[Cell] | CellOf
-    field: str
-    current: Any
-    past: Any | None = None
-
-
-class MetadataModified(AvillaEvent):
-    ctx: Selector
-    modifies: list[MetadataModify]
-    operator: Selector | None = None
-
-    def __init__(
-        self,
-        ctx: Selector,
-        modifies: list[MetadataModify],
-        account: AbstractAccount,
-        operator: Selector | None = None,
-        time: datetime | None = None,
-        extra: dict[Any, Any] | None = None,
-    ):
-        self.ctx = ctx
-        self.modifies = modifies
-        self.operator = operator
-        super().__init__(account, time=time, extra=extra)
-
-    class Dispatcher(BaseDispatcher):
-        @staticmethod
-        async def catch(interface: DispatcherInterface["MetadataModified"]):
-            if get_origin(interface.annotation) is list and get_args(interface.annotation)[0] is MetadataModify:
-                return interface.event.modifies
-
-
-class RelationshipCreated(AvillaEvent):
-    ctx: Selector
-    via: Selector | None
-    # 用 via 同时表示两个方向的关系.(自发行为和被动行为)
-    # 自发行为就是 None, 被动行为反之
-
-    def __init__(
-        self,
-        ctx: Selector,
-        account: AbstractAccount,
-        time: datetime | None = None,
-        via: Selector | None = None,
-    ):
-        self.ctx = ctx
-        self.via = via
-        super().__init__(account, time=time)
-
-    def get_via(self) -> Selector | None:
-        return self.via
-
-    class Dispatcher(BaseDispatcher):
-        @staticmethod
-        async def catch(interface: DispatcherInterface["RelationshipCreated"]):
-            ...
-
-
-class RelationshipDestroyed(AvillaEvent):
-    ctx: Selector
-    via: Selector | None
-
-    def __init__(
-        self,
-        ctx: Selector,
-        account: AbstractAccount,
-        time: datetime | None = None,
-        via: Selector | None = None,
-    ):
-        self.ctx = ctx
-        self.via = via
-        super().__init__(account, time=time)
-
-    def get_via(self) -> Selector | None:
-        return self.via
-
-    class Dispatcher(BaseDispatcher):
-        @staticmethod
-        async def catch(interface: DispatcherInterface["RelationshipDestroyed"]):
-            ...
diff --git a/avilla/core/event/message.py b/avilla/core/event/message.py
deleted file mode 100644
index 5e9d5835..00000000
--- a/avilla/core/event/message.py
+++ /dev/null
@@ -1,95 +0,0 @@
-from __future__ import annotations
-
-from datetime import datetime
-from typing import TYPE_CHECKING
-
-from graia.amnesia.message import MessageChain
-from graia.broadcast.entities.dispatcher import BaseDispatcher
-
-from avilla.core.event import AvillaEvent
-from avilla.core.message import Message
-from avilla.core.utilles.selector import Selector
-
-if TYPE_CHECKING:
-    from graia.broadcast.interfaces.dispatcher import DispatcherInterface
-
-    from avilla.core.account import AbstractAccount
-
-
-class MessageReceived(AvillaEvent):
-    message: Message
-
-    @property
-    def ctx(self) -> Selector:
-        return self.message.sender
-
-    def __init__(self, message: Message, account: AbstractAccount, time: datetime | None = None) -> None:
-        self.message = message
-        super().__init__(account, time=time)
-
-    class Dispatcher(BaseDispatcher):
-        @staticmethod
-        async def catch(interface: DispatcherInterface["MessageReceived"]):
-            if interface.annotation is Message:
-                return interface.event.message
-            elif interface.annotation is MessageChain:
-                return interface.event.message.content
-
-
-class MessageEdited(AvillaEvent):
-    message: Message
-    operator: Selector
-    past: MessageChain
-    current: MessageChain
-
-    @property
-    def ctx(self):
-        return self.operator
-
-    def __init__(
-        self,
-        message: Message,
-        operator: Selector,
-        past: MessageChain,
-        current: MessageChain,
-        account: AbstractAccount,
-        time: datetime | None = None,
-    ) -> None:
-        self.message = message
-        self.operator = operator
-        self.past = past
-        self.current = current
-        super().__init__(account, time=time)
-
-    class Dispatcher(BaseDispatcher):
-        @staticmethod
-        async def catch(interface: DispatcherInterface["MessageEdited"]):
-            if interface.annotation is Message:
-                return interface.event.message
-            elif interface.annotation is MessageChain:
-                return interface.event.current
-
-
-class MessageRevoked(AvillaEvent):
-    message: Selector
-    operator: Selector
-
-    @property
-    def ctx(self):
-        return self.operator
-
-    def __init__(
-        self,
-        message: Selector,
-        operator: Selector,
-        account: AbstractAccount,
-        time: datetime | None = None,
-    ) -> None:
-        self.message = message
-        self.operator = operator
-        super().__init__(account, time=time)
-
-    class Dispatcher(BaseDispatcher):
-        @staticmethod
-        async def catch(interface: DispatcherInterface["MessageRevoked"]):
-            ...
diff --git a/avilla/core/event/resource.py b/avilla/core/event/resource.py
deleted file mode 100644
index 5747c3cc..00000000
--- a/avilla/core/event/resource.py
+++ /dev/null
@@ -1,81 +0,0 @@
-from __future__ import annotations
-
-from datetime import datetime
-from typing import TYPE_CHECKING
-
-from graia.broadcast.entities.dispatcher import BaseDispatcher
-from typing_extensions import get_origin
-
-from avilla.core.event import AvillaEvent
-from avilla.core.resource import BlobResource, Resource
-from avilla.core.utilles.selector import Selector
-
-if TYPE_CHECKING:
-    from graia.broadcast.interfaces.dispatcher import DispatcherInterface
-
-    from avilla.core.account import AbstractAccount
-
-
-class ResourceEvent(AvillaEvent):
-    resource: BlobResource
-
-    @property
-    def ctx(self):
-        return self.resource.selector
-
-    def __init__(
-            self,
-            resource: BlobResource,
-            account: AbstractAccount,
-            time: datetime | None = None,
-    ):
-        self.resource = resource
-        super().__init__(account, time=time)
-
-    class Dispatcher(BaseDispatcher):
-        @staticmethod
-        async def catch(interface: 'DispatcherInterface[ResourceEvent]'):
-            if issubclass((get_origin(interface.annotation)) or interface.annotation, Resource):
-                return interface.event.resource
-
-
-class ResourceAvailable(ResourceEvent):
-    pass
-
-
-class ResourceUnavailable(ResourceEvent):
-    pass
-
-
-class FileUploaded(ResourceAvailable):
-    uploader: Selector
-    mainline: Selector
-
-    def __init__(
-        self,
-        resource: BlobResource,
-        uploader: Selector,
-        mainline: Selector,
-        account: AbstractAccount,
-        time: datetime | None = None,
-    ):
-        self.uploader = uploader
-        self.mainline = mainline
-        super().__init__(resource, account, time)
-
-
-class FileRemoved(ResourceUnavailable):
-    uploader: Selector
-    mainline: Selector
-
-    def __init__(
-        self,
-        resource: BlobResource,
-        uploader: Selector,
-        mainline: Selector,
-        account: AbstractAccount,
-        time: datetime | None = None,
-    ):
-        self.uploader = uploader
-        self.mainline = mainline
-        super().__init__(resource, account, time)
diff --git a/avilla/core/exceptions.py b/avilla/core/exceptions.py
index 823182b2..4b113ed7 100644
--- a/avilla/core/exceptions.py
+++ b/avilla/core/exceptions.py
@@ -72,7 +72,7 @@ class DeprecatedError(Exception):
 
 def permission_error_message(operator: str, current: str, required: list[str]):
     return (
-        f'missing permission: {operator} required ' +
-        " or ".join(f'"{i}"' for i in required) +
-        f" but current is {current}"
-    )
\ No newline at end of file
+        f"missing permission: {operator} required "
+        + " or ".join(f'"{i}"' for i in required)
+        + f" but current is {current}"
+    )
diff --git a/avilla/core/graia.py b/avilla/core/graia.py
new file mode 100644
index 00000000..fc612f2b
--- /dev/null
+++ b/avilla/core/graia.py
@@ -0,0 +1,52 @@
+import importlib.metadata
+import re
+from inspect import cleandoc
+
+from loguru import logger
+
+AVILLA_ASCII_LOGO = cleandoc(
+    r"""
+    [bold]Avilla[/]: a universal backend/framework for effective im development, powered by [blue]Graia Project[/].
+        _        _ _ _
+       / \__   _(_) | | __ _
+      / _ \ \ / / | | |/ _` |
+     / ___ \ V /| | | | (_| |
+    /_/   \_\_/ |_|_|_|\__,_|
+    """
+)
+AVILLA_ASCII_RAW_LOGO = re.sub(r"\[.*?\]", "", AVILLA_ASCII_LOGO)
+
+
+import random
+
+if random.choice((True, False)):
+    AVILLA_ASCII_LOGO += "\n"
+    AVILLA_ASCII_LOGO += "[dim]when will I be able to find a place that can be my second hometown...?[/]"
+
+    # but no matter what, the most important thing for me is always to be with my only loved one, so that the journey will not be lonely.
+
+
+GRAIA_PROJECT_REPOS = [
+    "avilla-core",
+    "graia-broadcast",
+    "graia-saya",
+    "graia-scheduler",
+    "graia-ariadne",
+    "statv",
+    "launart",
+    "creart",
+    "creart-graia",
+    "kayaku",
+]
+
+
+def log_telemetry():
+    for telemetry in GRAIA_PROJECT_REPOS:
+        try:
+            version = importlib.metadata.version(telemetry)
+        except Exception:
+            version = "unknown / not-installed"
+        logger.info(
+            f"{telemetry} version: {version}",
+            alt=f"[b cornflower_blue]{telemetry}[/] version: [cyan3]{version}[/]",
+        )
diff --git a/avilla/core/message.py b/avilla/core/message.py
index a9edafe6..70807fc5 100644
--- a/avilla/core/message.py
+++ b/avilla/core/message.py
@@ -3,28 +3,36 @@
 from dataclasses import dataclass
 from typing import TYPE_CHECKING, cast
 
-from graia.amnesia.message import MessageChain
+from graia.amnesia.message import __message_chain_class__
 
-from avilla.core.cell import Cell
 from avilla.core.platform import Land
-from avilla.core.utilles.selector import Selector
+from avilla.core.selector import Selector
+
+from ..spec.core.message.skeleton import MessageRevoke
+from .metadata import Metadata
 
 if TYPE_CHECKING:
     from datetime import datetime
 
 
 @dataclass
-class Message(Cell):
+class Message(Metadata):
     id: str
-    mainline: Selector
+    scene: Selector
     sender: Selector
-    content: MessageChain
+    content: __message_chain_class__
     time: datetime
     reply: Selector | None = None
 
     @property
     def land(self):
-        return Land(cast(str, self.mainline.pattern.get("land")))
+        return Land(cast(str, self.scene.pattern.get("land")))
 
     def to_selector(self) -> Selector:
-        return self.mainline.copy().message(self.id)
+        return self.scene.message(self.id)
+
+    def rev(self):
+        return self.to_selector().rev()
+
+    async def revoke(self):
+        return await self.rev().wrap(MessageRevoke).revoke()
diff --git a/avilla/core/metadata.py b/avilla/core/metadata.py
new file mode 100644
index 00000000..439ed5b6
--- /dev/null
+++ b/avilla/core/metadata.py
@@ -0,0 +1,154 @@
+from __future__ import annotations
+
+from contextvars import ContextVar
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, Any, Generic, TypeVar, overload
+from weakref import WeakKeyDictionary
+
+from typing_extensions import Self, TypeVarTuple, Unpack
+
+from avilla.core.utilles import classproperty
+
+if TYPE_CHECKING:
+    from avilla.core.context import Context
+    from avilla.core.selector import Selector
+
+T = TypeVar("T")
+
+_MetadataT1 = TypeVar("_MetadataT1", bound="Metadata")
+_MetadataT2 = TypeVar("_MetadataT2", bound="Metadata")
+
+_DescribeT = TypeVar("_DescribeT", bound="type[Metadata] | MetadataRoute")
+
+_TVT1 = TypeVarTuple("_TVT1")
+_TVT2 = TypeVarTuple("_TVT2")
+
+
+@dataclass
+class MetadataOf(Generic[_DescribeT]):
+    target: Selector
+    describe: _DescribeT
+
+    def to_bounding(self):
+        return MetadataBound(self.target.path_without_land, self.describe)
+
+
+@dataclass
+class MetadataBound(Generic[_DescribeT]):
+    target: str
+    describe: _DescribeT
+
+
+class MetadataMeta(type):
+    @overload
+    def __rshift__(cls: type[_MetadataT1], other: type[_MetadataT2]) -> MetadataRoute[_MetadataT1, _MetadataT2]:
+        ...
+
+    @overload
+    def __rshift__(
+        cls: type[_MetadataT1], other: MetadataRoute[Unpack[_TVT1]]
+    ) -> MetadataRoute[_MetadataT1, Unpack[_TVT1]]:
+        ...
+
+    def __rshift__(cls: Any, other: type[Metadata] | MetadataRoute) -> MetadataRoute:
+        # sourcery skip: instance-method-first-arg-name
+        cells = (cls, other) if isinstance(other, type) else (cls, *other.cells)
+        return MetadataRoute(cells)
+
+    """
+    def __repr__(cls) -> str:
+        # sourcery skip: instance-method-first-arg-name
+        return cls.__name__
+    """
+
+
+METACELL_PARAMS_CTX: WeakKeyDictionary[type[Metadata], ContextVar[dict[str, Any] | None]] = WeakKeyDictionary()
+
+
+@dataclass
+class Metadata(Generic[T], metaclass=MetadataMeta):
+    describe: type[Self] | MetadataRoute  # CellCompose 的行为和单次的行为一样。
+
+    @classmethod
+    def of(cls, target: Selector) -> MetadataOf[type[Self]]:
+        return MetadataOf(target, cls)
+
+    @classproperty
+    @classmethod
+    def _param_ctx(cls):
+        return METACELL_PARAMS_CTX[cls]
+
+    def __init_subclass__(cls) -> None:
+        METACELL_PARAMS_CTX[cls] = ContextVar(f"$MetadataParam${cls.__module__}::{cls.__qualname__}", default=None)
+
+    @classmethod
+    def get_default_target(cls, ctx: Context) -> Selector | None:
+        return ctx.client.to_selector()
+
+    @classmethod
+    def get_params(cls) -> dict[str, Any] | None:
+        return cls._param_ctx.get()
+
+    @classmethod
+    def set_params(cls, params: dict[str, Any]):
+        target = cls._param_ctx.get()
+        if target is None:
+            target = {}
+            cls._param_ctx.set(target)
+        target.update(params)
+
+    @classmethod
+    def clear_params(cls) -> None:
+        cls._param_ctx.set(None)
+
+    @classmethod
+    def has_params(cls) -> bool:
+        return cls._param_ctx.get() is not None
+
+
+class MetadataRoute(Generic[Unpack[_TVT1]]):
+    cells: tuple[type[Metadata], ...]
+
+    def __init__(self, cells: tuple[type[Metadata], ...]) -> None:
+        self.cells = cells
+
+    def of(self, target: Selector) -> MetadataOf[Self]:
+        return MetadataOf(target, self)
+
+    def get_default_target(self, ctx: Context) -> Selector | None:
+        return self.cells[0].get_default_target(ctx)
+
+    @overload
+    def __rshift__(
+        self: MetadataRoute[Unpack[_TVT1]], other: type[_MetadataT1]
+    ) -> MetadataRoute[Unpack[_TVT1], _MetadataT1]:
+        ...
+
+    @overload
+    def __rshift__(
+        self: MetadataRoute[Unpack[_TVT1]], other: MetadataRoute[Unpack[_TVT2]]
+    ) -> MetadataRoute[Unpack[_TVT1], Unpack[_TVT2]]:
+        ...
+
+    def __rshift__(self, other: type[Metadata] | MetadataRoute) -> MetadataRoute:
+        if not isinstance(other, (type, MetadataRoute)):
+            raise TypeError(f"{other.__class__} is not allowed.")
+        cells = (*self.cells, other) if isinstance(other, type) else (*self.cells, *other.cells)
+        return MetadataRoute(cells)
+
+    def __repr__(self) -> str:
+        cells_repr = " >> ".join(cell.__name__ for cell in self.cells)
+        return f"MetadataRoute[{cells_repr}]"
+
+    def __hash__(self) -> int:
+        return hash(self.cells) + hash("MetadataRoute")
+
+    def __eq__(self, o: object) -> bool:
+        return isinstance(o, MetadataRoute) and o.cells == self.cells
+
+    def clear_params(self) -> None:
+        for cell in self.cells:
+            cell.clear_params()
+
+    def has_params(self) -> bool:
+        return any(cell.has_params() for cell in self.cells)
diff --git a/avilla/core/platform.py b/avilla/core/platform.py
index 26f18ec1..3dae7b30 100644
--- a/avilla/core/platform.py
+++ b/avilla/core/platform.py
@@ -24,6 +24,9 @@ def __init__(self, land: Land, abstract: Abstract, *description: PlatformDescrip
     def __getitem__(self, item: type[PD]) -> PD:
         return self.description[item]  # type: ignore
 
+    def __str__(self):
+        return f"<Platform {' '.join([str(i) for i in self.description.values()])}>"
+
 
 class Maintainer(TypedDict):
     name: str
diff --git a/avilla/core/protocol.py b/avilla/core/protocol.py
index 81f5caec..31c9b8f4 100644
--- a/avilla/core/protocol.py
+++ b/avilla/core/protocol.py
@@ -1,44 +1,26 @@
 from __future__ import annotations
 
 from abc import ABCMeta, abstractmethod
-from typing import TYPE_CHECKING, Any, ClassVar, cast
-
-from graia.amnesia.message import MessageChain
+from contextlib import nullcontext
+from typing import TYPE_CHECKING, Any, ClassVar
 
+from avilla.core._runtime import ctx_avilla, ctx_context, ctx_protocol
 from avilla.core.account import AbstractAccount
-
-# from avilla.core.action.extension import ActionExtension
-# from avilla.core.action.middleware import ActionMiddleware
-from avilla.core.context import ctx_avilla, ctx_protocol
 from avilla.core.event import AvillaEvent
 from avilla.core.platform import Abstract, Land, Platform
-from avilla.core.querier import ProtocolAbstractQueryHandler
-from avilla.core.trait.context import Namespace
-from avilla.core.utilles.event_parser import AbstractEventParser
-from avilla.core.utilles.message_deserializer import MessageDeserializer
-from avilla.core.utilles.message_serializer import MessageSerializer
-from avilla.core.utilles.selector import Selector
+from avilla.core.selector import Selector
+from avilla.core.trait.context import Artifacts
 
 if TYPE_CHECKING:
     from avilla.core.application import Avilla
+    from avilla.core.context import Context
 
 
 class BaseProtocol(metaclass=ABCMeta):
     avilla: Avilla
     platform: ClassVar[Platform]
-    message_serializer: MessageSerializer
-    message_deserializer: MessageDeserializer
-
-    # completion_rules: ClassVar[dict[str, dict[str, str]]] = cast(dict, MappingProxyType({}))
-    # action_middlewares: list[ActionMiddleware] = []
-
-    event_parser: ClassVar[AbstractEventParser]
-    # action_executors: ClassVar[list[type[ProtocolActionExecutor]]] = cast(list, ())
-    # resource_providers: ClassVar[dict[str, type[ProtocolResourceProvider]]] = cast(dict, MappingProxyType({}))
-    # query_handlers: ClassVar[list[type[ProtocolAbstractQueryHandler]]] = cast(list, ())
-    # extension_impls: ClassVar[dict[type[ActionExtension], ActionExtensionImpl]] = cast(dict, MappingProxyType({}))
 
-    impl_namespace: ClassVar[Namespace]
+    implementations: ClassVar[Artifacts]
 
     def __init__(self):
         ...
@@ -51,12 +33,6 @@ def land(self):
     def abstract(self):
         return self.platform[Abstract]
 
-    """
-    @property
-    def resource_labels(self) -> set[str]:
-        return {pattern.path_without_land for pattern in self.resource_providers.keys()}
-    """
-
     @abstractmethod
     def ensure(self, avilla: Avilla) -> Any:
         ...
@@ -67,12 +43,8 @@ def get_accounts(self, selector: Selector | None = None) -> list[AbstractAccount
     def get_account(self, selector: Selector) -> AbstractAccount | None:
         return self.avilla.get_account(selector=selector, land=self.platform[Land])
 
-    async def parse_message(self, data: Any) -> MessageChain:
-        return MessageChain(await self.message_deserializer.parse_sentence(self, data))
-
-    async def serialize_message(self, message: MessageChain) -> Any:
-        return await self.message_serializer.serialize_chain(self, message)
-
-    def post_event(self, event: AvillaEvent):
-        with ctx_avilla.use(self.avilla), ctx_protocol.use(self):
-            self.avilla.broadcast.postEvent(event)
+    def post_event(self, event: AvillaEvent, context: Context | None = None):
+        with ctx_avilla.use(self.avilla), ctx_protocol.use(self), (
+            ctx_context.use(context) if context is not None else nullcontext()
+        ):
+            return self.avilla.broadcast.postEvent(event)
diff --git a/avilla/core/querier.py b/avilla/core/querier.py
index 2b87a834..6411c92b 100644
--- a/avilla/core/querier.py
+++ b/avilla/core/querier.py
@@ -1,23 +1,16 @@
 from __future__ import annotations
 
 import inspect
-from typing import (
-    TYPE_CHECKING,
-    AsyncGenerator,
-    AsyncIterator,
-    Callable,
-    ClassVar,
-    Generic,
-    TypeVar,
-)
+from collections.abc import AsyncGenerator, Callable
+from typing import TYPE_CHECKING, ClassVar, Generic, TypeVar
 
 from typing_extensions import Self
 
-from avilla.core.utilles.selector import Selector
+from avilla.core.selector import Selector
 
 if TYPE_CHECKING:
+    from avilla.core.context import Context
     from avilla.core.protocol import BaseProtocol
-    from avilla.core.relationship import Relationship
 
 
 def query(target: str):
@@ -33,7 +26,7 @@ class AbstractQueryHandler:
     queriers: ClassVar[
         dict[
             str,
-            Callable[[Self, Relationship, Selector, Callable[[Selector], bool]], AsyncGenerator[Selector, None]],
+            Callable[[Self, Context, Selector, Callable[[Selector], bool]], AsyncGenerator[Selector, None]],
         ]
     ] = {}
 
@@ -43,11 +36,11 @@ def __init_subclass__(cls, prefix: str | None = None):
         cls.prefix = prefix
         for mro in reversed(inspect.getmro(cls)):
             if issubclass(mro, AbstractQueryHandler):
-                cls.queriers.update(mro.queriers)
+                cls.queriers |= mro.queriers
         members = inspect.getmembers(cls, predicate=inspect.isfunction)
         for _, value in members:
-            if hasattr(value, "__query_key__"):
-                cls.queriers[value.__query_key__] = value
+            if query_key := getattr(value, "__query_key__", None):
+                cls.queriers[query_key] = value
 
 
 TProtocol = TypeVar("TProtocol", bound="BaseProtocol")
@@ -58,6 +51,3 @@ class ProtocolAbstractQueryHandler(AbstractQueryHandler, Generic[TProtocol]):
 
     def __init__(self, protocol: TProtocol) -> None:
         self.protocol = protocol
-
-    def __init_subclass__(cls, prefix: str | None = None):
-        super().__init_subclass__(prefix)
diff --git a/avilla/core/relationship.py b/avilla/core/relationship.py
deleted file mode 100644
index 5c06ac83..00000000
--- a/avilla/core/relationship.py
+++ /dev/null
@@ -1,336 +0,0 @@
-from __future__ import annotations
-
-from collections import ChainMap, deque
-from dataclasses import dataclass
-from typing import (
-    TYPE_CHECKING,
-    Any,
-    AsyncGenerator,
-    Awaitable,
-    Callable,
-    Iterable,
-    TypeVar,
-    cast,
-    overload,
-)
-
-from graia.amnesia.message import Element, MessageChain, Text
-from typing_extensions import Unpack
-
-from avilla.core.account import AbstractAccount
-
-# from avilla.core.action.middleware import ActionMiddleware
-from avilla.core.cell import Cell, CellOf
-from avilla.core.context import ctx_relationship
-from avilla.core.message import Message
-from avilla.core.request import Request
-from avilla.core.resource import Resource
-from avilla.core.skeleton.message import MessageEdit, MessageRevoke, MessageSend
-from avilla.core.skeleton.request import RequestTrait
-from avilla.core.skeleton.scene import SceneTrait
-from avilla.core.trait import Trait
-from avilla.core.trait.context import GLOBAL_SCOPE, Scope
-from avilla.core.trait.extension import ExtensionHandler
-from avilla.core.trait.recorder import Querier
-from avilla.core.trait.signature import (
-    ArtifactSignature,
-    CastAllow,
-    Check,
-    CompleteRule,
-    Pull,
-    Query,
-    ResourceFetch,
-)
-from avilla.core.utilles.selector import Selectable, Selector
-
-if TYPE_CHECKING:
-    from avilla.core.protocol import BaseProtocol
-
-_T = TypeVar("_T")
-_M = TypeVar("_M", bound=Cell)
-_TboundTrait = TypeVar("_TboundTrait", bound=Trait)
-
-
-async def _query_depth_generator(
-    rs: Relationship,
-    current: Querier,
-    predicate: Selector,
-    upper_generator: AsyncGenerator[Selector, None] | None = None,
-):
-    if upper_generator is not None:
-        async for i in upper_generator:
-            async for j in current(rs, i, predicate):
-                yield j
-    else:
-        async for j in current(rs, None, predicate):
-            yield j
-
-
-@dataclass
-class _MatchStep:
-    upper: str
-    start: int
-    history: tuple[Query, ...]
-
-
-def _find_querier_steps(artifacts: ChainMap[ArtifactSignature, Any], query_path: str) -> list[Query] | None:
-    result: list[Query] | None = None
-    frags: list[str] = query_path.split(".")
-    queue: deque[_MatchStep] = deque([_MatchStep("", 0, ())])
-    while queue:
-        head: _MatchStep = queue.popleft()
-        current_steps: list[str] = []
-        for curr_frag in frags[head.start :]:
-            current_steps.append(curr_frag)
-            steps = ".".join(current_steps)
-            full_path = f"{head.upper}.{steps}" if head.upper else steps
-            head.start += 1
-            if (query := Query(head.upper or None, steps)) in artifacts:
-                if full_path == query_path:
-                    if result is None or len(result) > len(head.history) + 1:
-                        result = [*head.history, query]
-                else:
-                    queue.append(
-                        _MatchStep(
-                            full_path,
-                            head.start,
-                            head.history + (query,),
-                        )
-                    )
-    return result
-
-
-class Relationship:
-    ctx: Selector
-    mainline: Selector
-    self: Selector
-    via: Selector | None = None
-
-    account: AbstractAccount
-    cache: dict[str, Any]
-
-    protocol: "BaseProtocol"
-
-    _artifacts: ChainMap[ArtifactSignature, Any]
-    # _middlewares: list[ActionMiddleware]
-
-    def __init__(
-        self,
-        protocol: "BaseProtocol",
-        ctx: Selector,
-        mainline: Selector,
-        selft: Selector,
-        account: AbstractAccount,
-        via: Selector | None = None,
-        # middlewares: list[ActionMiddleware] | None = None,
-    ) -> None:
-        self.ctx = ctx
-        self.mainline = mainline
-        self.self = selft
-        self.via = via
-        self.account = account
-        self.protocol = protocol
-        # self._middlewares = middlewares or []
-        self.cache = {"meta": {}}
-        self._artifacts = ChainMap(
-            self.protocol.impl_namespace.get(Scope(self.land.name, self.mainline.path_without_land, self.self.path_without_land), {}),
-            self.protocol.impl_namespace.get(Scope(self.land.name, self.mainline.path_without_land), {}),
-            self.protocol.impl_namespace.get(Scope(self.land.name, self=self.self.path_without_land), {}),
-            self.protocol.impl_namespace.get(Scope(self.land.name), {}),
-            self.protocol.impl_namespace.get(GLOBAL_SCOPE, {}),
-            self.avilla.global_artifacts,
-        )
-
-    @property
-    def avilla(self):
-        return self.protocol.avilla
-
-    @property
-    def land(self):
-        return self.protocol.land
-
-    @property
-    def is_resource(self) -> bool:
-        # TODO: Auto inference for implementations of a "ctx"
-        ...
-
-    @property
-    def _ext_handler(self):
-        return ExtensionHandler(self)
-
-    @property
-    def app_current(self) -> Relationship | None:
-        return ctx_relationship.get(None)
-
-    async def query(self, pattern: Selector, with_land: bool = False):
-        querier_steps: list[Query] | None = _find_querier_steps(
-            self._artifacts, pattern.path if with_land else pattern.path_without_land
-        )
-
-        if querier_steps is None:
-            raise NotImplementedError(f'cannot query "{pattern.path_without_land}" due to unknown step calc.')
-
-        querier = cast("dict[Query, Querier]", {i: self._artifacts[i] for i in querier_steps})
-        generators: list[AsyncGenerator[Selector, None]] = []
-
-        past = []
-        for k, v in querier.items():
-            past.append(k.target)
-            pred = pattern.mixin(".".join(past))
-            current = _query_depth_generator(self, v, pred, generators[-1] if generators else None)
-            generators.append(current)
-
-        async for i in generators[-1]:
-            if with_land:
-                yield Selector.from_dict({"land": self.land.name, **i.pattern})
-            else:
-                yield i
-
-    @overload
-    async def check(self, *, check_via: bool = True) -> None:
-        # 检查 Relationship 的存在性.
-        # 如 Relationship 的存在性无法被验证为真, 则 Relationship 不成立, 抛出错误.
-        ...
-
-    @overload
-    async def check(self, target: Selector, *, strict: bool = False, check_via: bool = True) -> bool:
-        # 检查 target 相对于当前关系 Relationship 的存在性.
-        # 注意, 这里是 "相对于当前关系", 如 Github 的项目若为 Private, 则对于外界/Amonymous来说是不存在的, 即使他从客观上是存在的.
-        # 注意, target 不仅需要相对于当前关系是存在的, 由于关系本身处在一个 mainline 之中,
-        # mainline 相当于工作目录或者是 docker 那样的应用容器, 后者是更严谨的比喻,
-        # 因为有些操作**只能**在处于一个特定的 mainline 中才能完成, 这其中包含了访问并操作某些 target.
-        # 在 strict 模式下, target 被视作包含 "仅在当前 mainline 中才能完成的操作" 的集合中,
-        # 表示其访问或是操作必须以当前 mainline 甚至是 current(account) 为基础.
-        # 如果存在可能的 via, 则会先检查 via 的存在性, 因为 via 是维系这段关系的基础.
-        ...
-
-    async def check(self, target: Selector | None = None, *, strict: bool = False, check_via: bool = True) -> bool | None:
-        # FIXME: check this sentence again
-        if check_via and self.via is not None:
-            await self.check(self.via, strict=True, check_via=False)
-        checker = self._artifacts.get(Check((target or self.ctx).path_without_land))
-        if checker is None:
-            raise NotImplementedError(
-                f'cannot check existence & accessible of "{(target or self.ctx).path_without_land}" due to notimplemented checker'
-            )
-        result = checker(self, target)
-        if strict and not result:
-            raise ValueError(f"check failed on {target or self.ctx!r}")
-        return result
-
-    def complete(self, selector: Selector, with_land: bool = False):
-        output_rule = self._artifacts.get(CompleteRule(selector.path_without_land))
-        if output_rule is not None:
-            output_rule = cast(str, output_rule)
-            selector = Selector().mixin(output_rule, selector, self.ctx, self.mainline)
-        if with_land and list(selector.pattern.keys())[0] != "land":
-            selector.pattern = {"land": self.land.name, **selector.pattern}
-        return selector
-
-    async def fetch(self, resource: Resource[_T]) -> _T:
-        fetcher = self._artifacts.get(ResourceFetch(type(resource)))
-        if fetcher is None:
-            raise NotImplementedError(
-                f'cannot fetch "{resource.selector}" '
-                + f' because no available fetch implement found in "{self.protocol.__class__.__name__}"'
-            )
-        return await fetcher(self, resource)
-
-    async def pull(
-        self,
-        path: type[_M] | CellOf[Unpack[tuple[Any, ...]], _M],
-        target: Selector | Selectable | None = None,
-        *,
-        flush: bool = False,
-    ) -> _M:
-        if isinstance(target, Selectable):
-            target = target.to_selector()
-        if target is not None:
-            cached = self.cache["meta"].get(target)
-            if cached is not None and path in cached:
-                if flush:
-                    del cached[path]
-                elif not path.has_params():
-                    return cached[path]
-
-        puller = self._artifacts.get(Pull(target.path_without_land if target is not None else None, path))
-        if puller is None:
-            raise NotImplementedError(
-                f'cannot pull "{path}"'
-                + (f' for "{target.path_without_land}"' if target is not None else "")
-                + f' because no available implement found in "{self.protocol.__class__.__name__}"'
-            )
-        puller = cast("Callable[[Relationship, Selector | None], Awaitable[_M]]", puller)
-        result = await puller(self, target)
-        if target is not None and not path.has_params():
-            cached = self.cache["meta"].setdefault(target, {})
-            cached[path] = result
-        return result
-
-    def cast(
-        self,
-        trait: type[_TboundTrait],
-        path: type[Cell] | CellOf[Unpack[tuple[Any, ...]], Cell] | None = None,
-        target: Selector | Selectable | None = None,
-    ) -> _TboundTrait:
-        if isinstance(target, Selectable):
-            target = target.to_selector()
-        if CastAllow(trait) not in self._artifacts:
-            raise NotImplementedError(f"trait {trait.__name__} is not allow to cast in current context.")
-        return trait(self, path, target)
-
-    def send_message(
-        self, message: MessageChain | str | Iterable[str | Element], *, reply: Message | Selector | str | None = None
-    ):
-        if isinstance(message, str):
-            message = MessageChain([Text(message)])
-        elif not isinstance(message, MessageChain):
-            message = MessageChain([]).extend(list(message))
-        else:
-            message = MessageChain([i if isinstance(i, Element) else Text(i) for i in message])
-
-        if isinstance(reply, Message):
-            reply = reply.to_selector()
-        elif isinstance(reply, str):
-            reply = self.mainline.copy().message(reply)
-
-        return self.cast(MessageSend).send(message, reply=reply)
-
-    # TODO: more shortcuts, like `accept_request` etc.
-
-    async def accept_request(self, request: Request | Selector):
-        if isinstance(request, Request):
-            request = request.to_selector()
-        return await self.cast(RequestTrait, target=request).accept()
-
-    async def reject_request(self, request: Request | Selector, reason: str | None = None, forever: bool = False):
-        if isinstance(request, Request):
-            request = request.to_selector()
-        return await self.cast(RequestTrait, target=request).reject(reason, forever)
-
-    async def cancel_request(self, request: Request | Selector):
-        if isinstance(request, Request):
-            request = request.to_selector()
-        return await self.cast(RequestTrait, target=request).cancel()
-
-    async def ignore_request(self, request: Request | Selector):
-        if isinstance(request, Request):
-            request = request.to_selector()
-        return await self.cast(RequestTrait, target=request).ignore()
-
-    async def leave_scene(self, scene: Selectable | Selector | None = None):
-        if isinstance(scene, Selectable):
-            scene = scene.to_selector()
-        return await self.cast(SceneTrait, target=scene or self.mainline).leave()
-
-    async def disband_scene(self, scene: Selectable | Selector | None = None):
-        if isinstance(scene, Selectable):
-            scene = scene.to_selector()
-        return await self.cast(SceneTrait, target=scene or self.mainline).disband()
-
-    async def remove_member(
-        self, target: Selector, reason: str | None = None, scene: Selectable | Selector | None = None
-    ):
-        if isinstance(scene, Selectable):
-            scene = scene.to_selector()
-        return await self.cast(SceneTrait, target=scene or self.mainline).remove_member(target, reason)
diff --git a/avilla/core/request.py b/avilla/core/request.py
index 9ecdedbb..f57823eb 100644
--- a/avilla/core/request.py
+++ b/avilla/core/request.py
@@ -4,19 +4,21 @@
 from datetime import datetime
 from typing import TYPE_CHECKING
 
-from avilla.core.cell import Cell
 from avilla.core.platform import Land
 
+from ..spec.core.request.skeleton import RequestTrait
+from .metadata import Metadata
+
 if TYPE_CHECKING:
     from avilla.core.account import AbstractAccount
-    from avilla.core.utilles.selector import Selector
+    from avilla.core.selector import Selector
 
 
 @dataclass
-class Request(Cell):
+class Request(Metadata):
     id: str
     land: Land
-    mainline: Selector
+    scene: Selector
     sender: Selector
     account: AbstractAccount
     time: datetime
@@ -53,4 +55,22 @@ def to_selector(self) -> Selector:
         request_id = self.id
         if self.request_type is not None:
             request_id = f"{self.request_type}:{request_id}"
-        return self.mainline.copy().request(request_id)
+        return self.scene.request(request_id)
+
+    def rev(self):
+        return self.to_selector().rev()
+
+    def rev_trait(self):
+        return self.rev().wrap(RequestTrait)
+
+    async def accept(self):
+        return await self.rev_trait().accept()
+
+    async def reject(self, reason: str | None = None, forever: bool = False):
+        return await self.rev_trait().reject(reason, forever)
+
+    async def cancel(self):
+        return await self.rev_trait().cancel()
+
+    async def ignore(self):
+        return await self.rev_trait().ignore()
diff --git a/avilla/core/resource.py b/avilla/core/resource.py
index 4e86cdfe..07c2d885 100644
--- a/avilla/core/resource.py
+++ b/avilla/core/resource.py
@@ -5,13 +5,14 @@
 
 from typing_extensions import TypeAlias
 
-from avilla.core.cell import Cell
-from avilla.core.utilles.selector import Selector
+from avilla.core.selector import Selector
+
+from .metadata import Metadata
 
 T = TypeVar("T")
 
 
-class Resource(Cell, Generic[T]):
+class Resource(Metadata, Generic[T]):
     selector: Selector
 
     def __init__(self, selector: Selector):
diff --git a/avilla/core/utilles/selector.py b/avilla/core/selector.py
similarity index 71%
rename from avilla/core/utilles/selector.py
rename to avilla/core/selector.py
index cd841acd..29f2000a 100644
--- a/avilla/core/utilles/selector.py
+++ b/avilla/core/selector.py
@@ -1,43 +1,32 @@
 from __future__ import annotations
 
-from collections import ChainMap
+from collections.abc import Callable, Mapping
 from itertools import filterfalse
-from typing import (
-    TYPE_CHECKING,
-    Any,
-    Callable,
-    Literal,
-    Protocol,
-    Union,
-    runtime_checkable,
-)
+from types import MappingProxyType
+from typing import TYPE_CHECKING, Literal, Protocol, Union, runtime_checkable
 
 from typing_extensions import Self
 
+from avilla.core._runtime import ctx_context
 from avilla.core.platform import Land
 
 if TYPE_CHECKING:
-    ...
+    from .context import ContextSelector
 
 MatchRule = Literal["any", "exact", "exist", "fragment", "startswith"]
 Pattern = Union[str, Callable[[str], bool]]
+EMPTY_MAP = MappingProxyType({})
 
 
 class Selector:
-    mode: MatchRule = "exact"
-    pattern: dict[str, str]
-    path_excludes: frozenset[str]
-    referent: Any = None
+    pattern: Mapping[str, str]
 
-    def __init__(self, *, mode: MatchRule = "exact", path_excludes: frozenset[str] = frozenset()) -> None:
-        self.mode = mode
-        self.path_excludes = path_excludes
-        self.pattern = {}
+    def __init__(self, pattern: Mapping[str, str] = EMPTY_MAP) -> None:
+        self.pattern = MappingProxyType({**pattern})
 
     def __getattr__(self, name: str) -> Callable[[str], Self]:
         def wrapper(content: str) -> Self:
-            self.pattern[name] = content
-            return self
+            return Selector(pattern={**self.pattern, name: content})
 
         return wrapper
 
@@ -54,7 +43,7 @@ def __getitem__(self, key: str) -> str:
         return self.pattern[key]
 
     def __repr__(self) -> str:
-        return f"{self.__class__.__name__}(mode={self.mode}).{'.'.join(f'{k}({v})' for k, v in self.pattern.items())}"
+        return f"{self.__class__.__name__}().{'.'.join(f'{k}({v})' for k, v in self.pattern.items())}"
 
     @property
     def empty(self) -> bool:
@@ -62,44 +51,31 @@ def empty(self) -> bool:
 
     @property
     def path(self) -> str:
-        return ".".join(filterfalse(self.path_excludes.__contains__, self.pattern))
+        return ".".join(self.pattern)
 
     @property
     def path_without_land(self) -> str:
-        return ".".join(filterfalse((self.path_excludes | {"land"}).__contains__, self.pattern))
-
-    @classmethod
-    def exist(cls) -> Self:
-        return cls(mode="exist")
-
-    @classmethod
-    def any(cls) -> Self:
-        return cls(mode="any")
-
-    @classmethod
-    def fragment(cls, *path_excludes: str) -> Self:
-        return cls(mode="fragment", path_excludes=frozenset(path_excludes))
+        return ".".join(filterfalse(lambda x: x == "land", self.pattern))
 
-    @classmethod
-    def from_dict(cls, pattern: dict) -> Self:
-        instance = cls()
-        instance.pattern = pattern
-        return instance
+    @property
+    def last_key(self) -> str:
+        return next(reversed(self.pattern.keys()))
 
     @property
-    def latest_key(self) -> str:
-        return list(self.pattern.keys())[-1]
+    def last_value(self) -> str:
+        return next(reversed(self.pattern.values()))
+
+    def appendix(self, key: str, value: str):
+        return Selector(pattern={**self.pattern, key: value})
 
     def land(self, land: Land | str):
         if isinstance(land, Land):
             land = land.name
-        self.pattern["land"] = land
-        return self
 
-    def match(self, other: Selectable) -> bool:
+        return Selector({"land": land, **self.pattern})
+
+    def matches(self, other: Selectable, *, mode: MatchRule = "exact") -> bool:
         if not isinstance(other, Selector):
-            if not isinstance(other, Selectable):
-                return False
             other = other.to_selector()
         try:
             match = {
@@ -108,9 +84,9 @@ def match(self, other: Selectable) -> bool:
                 "exist": self._match_exist,
                 "fragment": self._match_fragment,
                 "startswith": self._match_startswith,
-            }[self.mode]
+            }[mode]
         except KeyError:
-            raise ValueError(f"Unknown match rule: {self.mode}") from None
+            raise ValueError(f"Unknown match rule: {mode}") from None
 
         return match(other)
 
@@ -142,34 +118,8 @@ def _match_startswith(self, other: Selector) -> bool:
 
         return all(fragment[i] == full[i] for i in range(len(fragment)))
 
-    def mix(self, path: str, **pattern: str) -> Self:
-        pattern = self.pattern | pattern
-        instance = self.__class__(mode=self.mode, path_excludes=self.path_excludes)
-
-        try:
-            instance.pattern = {each: pattern[each] for each in path.split(".")}
-        except KeyError:
-            raise ValueError(f"given information cannot mix with {path}") from None
-
-        return instance
-
-    def mixin(self, path: str, *selectors: Self) -> Self:
-        return self.mix(path, **ChainMap(*(x.pattern for x in selectors)))
-
-    def appendix(self, key: str, value: str) -> Self:
-        self.pattern[key] = value
-        return self
-
-    def copy(self) -> Self:
-        instance = self.__class__(mode=self.mode, path_excludes=self.path_excludes)
-        instance.pattern = self.pattern.copy()
-        return instance
-
     def as_dyn(self) -> DynamicSelector:
-        instance = DynamicSelector(mode=self.mode, path_excludes=self.path_excludes)
-        for k, v in self.pattern.items():
-            getattr(instance, k)(v)
-        return instance
+        return DynamicSelector(self.pattern)
 
     def to_selector(self):
         return self
@@ -210,9 +160,11 @@ def expects(self, pattern: str) -> Self:
 
         return self
 
-    def set_referent(self, referent: Any) -> Self:
-        self.referent = referent
-        return self
+    def rev(self) -> ContextSelector:
+        ctx = ctx_context.get(None)
+        if ctx is None:
+            raise LookupError
+        return ctx.wrap(self)
 
 
 class DynamicSelector(Selector):
diff --git a/avilla/core/service.py b/avilla/core/service.py
index d19a0da8..82195150 100644
--- a/avilla/core/service.py
+++ b/avilla/core/service.py
@@ -3,14 +3,17 @@
 from typing import TYPE_CHECKING
 
 from launart import Launart, Service
+from loguru import logger
 
-from avilla.core.event.lifecycle import (
+from avilla.spec.core.application import (
     ApplicationClosed,
     ApplicationClosing,
     ApplicationPreparing,
     ApplicationReady,
 )
 
+from .graia import AVILLA_ASCII_LOGO, AVILLA_ASCII_RAW_LOGO, log_telemetry
+
 if TYPE_CHECKING:
     from .application import Avilla
 
@@ -40,6 +43,15 @@ async def launch(self, manager: Launart):
         async with self.stage("preparing"):
             await self.avilla.broadcast.postEvent(ApplicationPreparing(self.avilla))
 
+            logger.info(AVILLA_ASCII_RAW_LOGO, alt=AVILLA_ASCII_LOGO)
+            log_telemetry()
+
+            for protocol in self.avilla.protocols:
+                logger.info(
+                    f"Using platform: {protocol.__class__.platform}",
+                    # alt=f"[magenta]Using platform: [/][dark_orange]{protocol.__class__.platform}[/]",
+                )
+
         await self.avilla.broadcast.postEvent(ApplicationReady(self.avilla))
 
         async with self.stage("blocking"):
diff --git a/avilla/core/skeleton/message.py b/avilla/core/skeleton/message.py
deleted file mode 100644
index c2677718..00000000
--- a/avilla/core/skeleton/message.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from __future__ import annotations
-
-from graia.amnesia.message import MessageChain
-
-from avilla.core.trait import DirectFn, Fn, Trait
-from avilla.core.utilles.selector import Selector
-
-
-# MessageFetch => rs.pull(Message, target=...)
-class MessageSend(Trait):
-    @DirectFn
-    async def send(self, message: MessageChain, *, reply: Selector | None = None) -> Selector:
-        ...
-
-
-class MessageRevoke(Trait):
-    @Fn
-    async def revoke(self, message: Selector) -> None:
-        ...
-
-
-class MessageEdit(Trait):
-    @Fn
-    async def edit(self, message: Selector, content: MessageChain) -> None:
-        ...
diff --git a/avilla/core/skeleton/nick.py b/avilla/core/skeleton/nick.py
deleted file mode 100644
index c1ecc74c..00000000
--- a/avilla/core/skeleton/nick.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from __future__ import annotations
-
-from avilla.core.trait import Fn, OrientedFn, Trait
-from avilla.core.utilles.selector import Selector
-
-
-class NickTrait(Trait):
-    @OrientedFn
-    async def set_name(self, name: str) -> None:
-        ...
-
-    @OrientedFn
-    async def set_nickname(self, nickname: str) -> None:
-        ...
-
-    @OrientedFn
-    async def unset_nickname(self) -> None:
-        ...
-
-    # TODO: recheck badge operators
-
-    @Fn
-    async def set_badge(self, target: Selector, badge: str) -> None:
-        ...
-
-    @Fn
-    async def unset_badge(self, target: Selector) -> None:
-        ...
diff --git a/avilla/core/skeleton/privilege.py b/avilla/core/skeleton/privilege.py
deleted file mode 100644
index 0122b7d6..00000000
--- a/avilla/core/skeleton/privilege.py
+++ /dev/null
@@ -1,47 +0,0 @@
-from __future__ import annotations
-
-from datetime import timedelta
-
-from avilla.core.trait import Fn, Trait
-from avilla.core.utilles.selector import Selector
-
-
-class PrivilegeTrait(Trait):
-    @Fn
-    async def upgrade(self, target: Selector, dest: str | None = None) -> None:
-        ...
-
-    @Fn
-    async def downgrade(self, target: Selector, dest: str | None = None) -> None:
-        ...
-
-
-class MuteTrait(Trait):
-    @Fn
-    async def mute(self, target: Selector, duration: timedelta) -> None:
-        ...
-
-    @Fn
-    async def unmute(self, target: Selector) -> None:
-        ...
-
-class MuteAllTrait(Trait):
-    @Fn
-    async def mute_all(self, target: Selector) -> None:
-        ...
-    
-    @Fn
-    async def unmute_all(self, target: Selector) -> None:
-        ...
-
-    # Fetch => rs.pull(MuteInfo, target=...)
-
-
-class BanTrait(Trait):
-    @Fn
-    async def ban(self, target: Selector, duration: timedelta | None = None) -> None:
-        ...
-
-    @Fn
-    async def unban(self, target: Selector) -> None:
-        ...
diff --git a/avilla/core/skeleton/scene.py b/avilla/core/skeleton/scene.py
deleted file mode 100644
index 323ac483..00000000
--- a/avilla/core/skeleton/scene.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from __future__ import annotations
-
-from avilla.core.trait import Fn, OrientedFn, Trait
-from avilla.core.utilles.selector import Selector
-
-
-class SceneTrait(Trait):
-    @OrientedFn
-    async def leave(self) -> None:
-        ...
-
-    @OrientedFn
-    async def disband(self) -> None:
-        ...
-
-    @Fn
-    async def remove_member(self, target: Selector, reason: str | None = None) -> None:
-        ...
-
-    # TODO: join, invite etc.
diff --git a/avilla/core/skeleton/summary.py b/avilla/core/skeleton/summary.py
deleted file mode 100644
index 9c669d43..00000000
--- a/avilla/core/skeleton/summary.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from __future__ import annotations
-
-from avilla.core.trait import OrientedFn, Trait
-
-
-class SummaryTrait(Trait):
-    @OrientedFn
-    async def set_name(self, name: str) -> None:
-        ...
-
-    @OrientedFn
-    async def unset_name(self) -> None:
-        ...
-
-    @OrientedFn
-    async def set_description(self, description: str) -> None:
-        ...
-
-    @OrientedFn
-    async def unset_description(self) -> None:
-        ...
diff --git a/avilla/core/tools/filter.py b/avilla/core/tools/filter.py
index e0079d53..3ac206dc 100644
--- a/avilla/core/tools/filter.py
+++ b/avilla/core/tools/filter.py
@@ -1,17 +1,18 @@
 from __future__ import annotations
 
-from collections.abc import Callable, Container, Iterable
+from collections.abc import Awaitable, Callable, Container, Iterable
 from functools import partial
 from inspect import isawaitable
 from operator import contains, eq, is_, is_not, ne
-from typing import Any, Awaitable, Generic, TypeVar
+from typing import Any, Generic, TypeVar
 
 from graia.broadcast import BaseDispatcher, DispatcherInterface, ExecutionStop
 from typing_extensions import ParamSpec, Self
 
 from avilla.core.account import AbstractAccount
-from avilla.core.relationship import Relationship
-from avilla.core.utilles.selector import Selectable, Selector
+from avilla.core.context import Context
+from avilla.core.selector import Selectable, Selector
+from avilla.core.utilles import classproperty
 
 T = TypeVar("T")
 R = TypeVar("R")
@@ -86,46 +87,46 @@ def all(self, funcs: Iterable[Callable[[T], Any]]) -> Self:
         return self.assert_true(lambda result: all(func(result) for func in funcs))
 
     def match(self: Filter[Selectable], pattern: Selector) -> Filter[Selectable]:
-        return self.assert_true(lambda result: pattern.match(result))
+        return self.assert_true(lambda result: pattern.matches(result))
 
     def mismatch(self: Filter[Selectable], pattern: Selector) -> Filter[Selectable]:
-        return self.assert_false(lambda result: pattern.match(result))
+        return self.assert_false(lambda result: pattern.matches(result))
 
     def match_any(self: Filter[Selectable], patterns: Iterable[Selector]) -> Filter[Selectable]:
-        return self.any(lambda result: pattern.match(result) for pattern in patterns)
+        return self.any(lambda result: pattern.matches(result) for pattern in patterns)
 
     def match_all(self: Filter[Selectable], patterns: Iterable[Selector]) -> Filter[Selectable]:
-        return self.all(lambda result: pattern.match(result) for pattern in patterns)
+        return self.all(lambda result: pattern.matches(result) for pattern in patterns)
 
     def mismatch_any(self: Filter[Selectable], patterns: Iterable[Selector]) -> Filter[Selectable]:
-        return self.any(lambda result: not pattern.match(result) for pattern in patterns)
+        return self.any(lambda result: not pattern.matches(result) for pattern in patterns)
 
     def mismatch_all(self: Filter[Selectable], patterns: Iterable[Selector]) -> Filter[Selectable]:
-        return self.any(lambda result: not pattern.match(result) for pattern in patterns)
+        return self.any(lambda result: not pattern.matches(result) for pattern in patterns)
 
     def follows(self: Filter[Selectable], *patterns: str) -> Filter[Selectable]:
         return self.any(lambda result: result.to_selector().follows(pattern) for pattern in patterns)
 
+    @classproperty
     @classmethod
-    @property
-    def rs(cls) -> Filter[Relationship]:
-        return cls().fetch(Relationship)
+    def ctx(cls) -> Filter[Context]:
+        return cls().fetch(Context)
 
     @property
-    def ctx(self: Filter[Relationship]) -> Filter[Selectable]:
-        return self.rs.step(lambda rs: rs.ctx)
+    def client(self: Filter[Context]) -> Filter[Selectable]:
+        return self.ctx.step(lambda ctx: ctx.client)
 
     @property
-    def mainline(self: Filter[Relationship]) -> Filter[Selector]:
-        return self.rs.step(lambda rs: rs.mainline)
+    def scene(self: Filter[Context]) -> Filter[Selector]:
+        return self.ctx.step(lambda ctx: ctx.scene)
 
     @property
-    def current(self: Filter[Relationship]) -> Filter[AbstractAccount]:
-        return self.rs.step(lambda rs: rs.account)
+    def account(self: Filter[Context]) -> Filter[AbstractAccount]:
+        return self.ctx.step(lambda ctx: ctx.account)
 
     @property
-    def via(self: Filter[Relationship]) -> Filter[Selector | None]:
-        return self.rs.step(lambda rs: rs.via)
+    def mediums_first(self: Filter[Context]) -> Filter[Selector | None]:
+        return self.ctx.step(lambda ctx: ctx.mediums[0].selector if ctx.mediums else None)
 
     async def beforeExecution(self, interface: DispatcherInterface):
         result: Awaitable[Any] | Any = interface  # type: ignore
diff --git a/avilla/core/trait/__init__.py b/avilla/core/trait/__init__.py
index 458ee521..60ffab6a 100644
--- a/avilla/core/trait/__init__.py
+++ b/avilla/core/trait/__init__.py
@@ -1,41 +1,20 @@
 from __future__ import annotations
 
-from typing import (
-    TYPE_CHECKING,
-    Any,
-    Awaitable,
-    Callable,
-    Generic,
-    TypeVar,
-    cast,
-    overload,
-)
+import inspect
+from collections.abc import Awaitable, Callable
+from functools import partial
+from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast, overload
 
 from typing_extensions import Concatenate, ParamSpec, Self
 
+from avilla.core.selector import Selector
 from avilla.core.utilles import identity
-from avilla.core.utilles.selector import Selector
 
-from ..cell import Cell, CellOf
-from .signature import Impl, ImplDefaultTarget
+from ..metadata import MetadataOf
+from .signature import Bounds, Impl
 
 if TYPE_CHECKING:
-    from avilla.core.relationship import Relationship
-
-from devtools import debug
-
-
-class Trait:
-    relationship: Relationship
-    path: type[Cell] | CellOf | None
-    target: Selector | None = None
-
-    def __init__(
-        self, relationship: Relationship, path: type[Cell] | CellOf | None = None, target: Selector | None = None
-    ) -> None:
-        self.relationship = relationship
-        self.path = path
-        self.target = target
+    from avilla.core.context import Context
 
 
 _P = ParamSpec("_P")
@@ -44,218 +23,285 @@ def __init__(
 _P1 = ParamSpec("_P1")
 _T1 = TypeVar("_T1")
 
-_TboundTrait = TypeVar("_TboundTrait", bound=Trait)
+_TboundTrait = TypeVar("_TboundTrait", bound="Trait")
+
+
+class Trait:
+    context: Context
+    bound: Selector | MetadataOf
+
+    def __init__(self, context: Context, bound: Selector | MetadataOf) -> None:
+        self.context = context
+        self.bound = bound
+
+    @classmethod
+    def fn(cls) -> list[Fn]:
+        return [fn for _, fn in inspect.getmembers(cls, lambda a: isinstance(a, Fn))]
 
 
 class Fn(Generic[_P, _T]):
-    __attr__: str
+    trait: type[Trait]
+    identity: str
     schema: Callable[_P, Awaitable[_T]]
 
-    @overload
-    def __new__(cls, schema: Callable[Concatenate[_TboundTrait, _P1], Awaitable[_T1]]) -> Fn[_P1, _T1]:
-        ...
+    def __init__(self, schema: Callable[_P, Awaitable[_T]]):
+        self.schema = schema
 
-    @overload
-    def __new__(cls, schema: Callable[_P1, Awaitable[_T1]]) -> Fn[_P1, _T1]:
-        ...
+    def __set_name__(self, owner: type[Trait], attr: str):
+        self.trait = owner
+        self.identity = attr
 
-    def __new__(cls, schema: ...) -> ...:
-        instance = super().__new__(cls)
-        instance.schema = schema
-        return instance
+    def __repr__(self) -> str:
+        return f"<Fn async {self.trait.__name__}::{self.identity} {inspect.signature(self.schema)}>"
 
-    def __set_name__(self, owner: type[Trait], attr: str):
-        self.__attr__ = attr
+    @overload
+    def __get__(self, instance: Trait, owner: type[Trait]) -> FnCall[_P, _T]:
+        ...
 
     @overload
-    def __get__(self, instance: Trait, owner: type[Trait]) -> FnWrapper[_P, _T]:
+    def __get__(self, instance: Any, owner: type[Trait]) -> FnCall[_P, _T]:
         ...
 
     @overload
-    def __get__(self, instance: Any, owner: type[Trait] | None) -> Self:
+    def __get__(self, instance: Any, owner: type) -> Self:
         ...
 
-    def __get__(self, instance: ..., owner: ...) -> Self | FnWrapper[_P, _T]:
-        # sourcery skip: assign-if-exp, reintroduce-else, swap-if-expression
-        if not isinstance(instance, Trait):
-            return self
-        return FnWrapper(instance, self)
+    def __get__(self, instance: Any, owner: type) -> Self | FnCall[_P, _T]:
+        return FnCall(instance, self) if issubclass(owner, Trait) else self
+
+    @classmethod
+    def configure(cls, **kwargs):
+        return partial(cls.__new__, **kwargs)
+
+    @classmethod
+    def bound_entity(cls, schema: Callable[Concatenate[_TboundTrait, _P1], Awaitable[_T1]]) -> BoundEntityFn[_P1, _T1]:
+        return BoundEntityFn(schema)
+
+    @classmethod
+    def bound_metadata(
+        cls, schema: Callable[Concatenate[_TboundTrait, _P1], Awaitable[_T1]]
+    ) -> BoundMetadataFn[_P1, _T1]:
+        return BoundMetadataFn(schema)
+
+    @classmethod
+    def bound_universal(
+        cls, schema: Callable[Concatenate[_TboundTrait, _P1], Awaitable[_T1]]
+    ) -> BoundUniversalFn[_P1, _T1]:
+        return BoundUniversalFn(schema)
 
 
-class FnWrapper(Generic[_P, _T]):
-    _args: tuple[Any, ...] | None = None
-    _kwargs: dict[str, Any] | None = None
+class FnCall(Generic[_P, _T]):
     trait: Trait
+    fn: Fn[_P, _T]
 
     def __init__(self, trait: Trait, fn: Fn[_P, _T]):
         self.trait = trait
         self.fn = fn
 
-    async def __call__(self, *args: _P.args, **kwargs: _P.kwargs):
-        self._args = args
-        self._kwargs = kwargs
-        return self
-
-    def __await__(self):
-        return self.__await_impl__().__await__()
+    def __repr__(self) -> str:
+        return f"<FnCall async {identity(self.trait)}::{self.fn.identity} {inspect.signature(self.fn.schema)}>"
 
-    async def __await_impl__(self) -> _T:
-        if self._args is None or self._kwargs is None:
-            raise ValueError("cannot call without param in shape of schema")
-
-        impl = self.trait.relationship._artifacts.get(
-            Impl(
-                self.fn,
-                None,
-                self.trait.path,
-            )
-        )
+    async def __call__(self, *args: _P.args, **kwargs: _P.kwargs):
+        impl = self.trait.context._impl_artifacts.get(Impl(self.fn))
         if impl is None:
             raise NotImplementedError(
-                f'"{identity(self.trait)}::{self.fn.__attr__}" '
-                f'in "{identity(self.trait.relationship.protocol)}" '
-                + (f'for target "{self.trait.target.path_without_land}"' if self.trait.target is not None else "")
-                + "is not implemented"
+                f'"{identity(self.trait)}::{self.fn.identity}" '
+                f'in "{identity(self.trait.context.protocol)}" '
+                "is not implemented."
             )
-        impl = cast("Callable[Concatenate[Relationship, _P], Awaitable[_T]]", impl)
-        return await impl(self.trait.relationship, *self._args, **self._kwargs)  # type: ignore
-
+        impl = cast(Callable[Concatenate["Context", _P], Awaitable[_T]], impl)
+        return await impl(self.trait.context, *args, **kwargs)
 
-class OrientedFn(Fn[_P, _T]):
-    # 要求 Trait 里面要设置对象
 
+class BoundFnCommon(Fn[_P, _T]):
     @overload
-    def __new__(cls, schema: Callable[Concatenate[_TboundTrait, _P1], Awaitable[_T1]]) -> OrientedFn[_P1, _T1]:
+    def __init__(self, schema: Callable[Concatenate[_TboundTrait, _P], Awaitable[_T]]):
         ...
 
     @overload
-    def __new__(cls, schema: Callable[_P1, Awaitable[_T1]]) -> OrientedFn[_P1, _T1]:
+    def __init__(self, schema: Callable[_P, Awaitable[_T]]):
         ...
 
-    def __new__(cls, schema: ...) -> ...:
-        return super().__new__(cls, schema)
+    def __init__(self, schema: Any):
+        self.schema = schema
+
+
+class BoundEntityFn(BoundFnCommon[_P, _T]):
+    def __repr__(self) -> str:
+        return (
+            f"<Fn bound-required entity async {self.trait.__name__}::{self.identity} {inspect.signature(self.schema)}>"
+        )
+
+    @overload
+    def __get__(self, instance: Trait, owner: type[Trait]) -> AppliedEntityFnCall[_P, _T]:
+        ...
 
     @overload
-    def __get__(self, instance: Trait, owner: type[Trait]) -> OrientedFnWrapper[_P, _T]:
+    def __get__(self, instance: Any, owner: type[Trait]) -> UnappliedEntityFnCall[_P, _T]:
         ...
 
     @overload
-    def __get__(self, instance: Any, owner: type[Trait] | None) -> Self:
+    def __get__(self, instance: Any, owner: type) -> Self:
         ...
 
-    def __get__(self, instance: ..., owner: ...) -> ...:
-        # sourcery skip: assign-if-exp, reintroduce-else
-        if instance is None:
-            return self
-        return DirectFnWrapper(instance, self)
-
-
-class OrientedFnWrapper(FnWrapper[_P, _T]):
-    _args: tuple[Any, ...] | None = None
-    _kwargs: dict[str, Any] | None = None
-
-    async def __await_impl__(self) -> _T:
-        if self._args is None or self._kwargs is None:
-            raise ValueError("cannot call without param in shape of schema")
-
-        target = self.trait.target
-        if target is None:
-            raise ValueError(f'cannot call "{identity(self.trait)}::{self.fn.__attr__}" without target on cast')
-        impl = self.trait.relationship._artifacts.get(
-            Impl(
-                self.fn,
-                target.path_without_land,
-                self.trait.path,
-            )
-        )
-        if impl is None:
-            debug(
-                self.trait.relationship._artifacts,
-                Impl(
-                    self.fn,
-                    target.path_without_land,
-                    self.trait.path,
-                ),
-            )
-            raise NotImplementedError(
-                f'"{identity(self.trait)}::{self.fn.__attr__}" '
-                f'in "{identity(self.trait.relationship.protocol)}" '
-                f'for target "{target.path_without_land}" '
-                "is not implemented"
-            )
-        impl = cast("Callable[Concatenate[Relationship, Selector, _P], Awaitable[_T]]", impl)
-        return await impl(self.trait.relationship, target, *self._args, **self._kwargs)  # type: ignore
+    def __get__(self, instance: Any, owner: type):
+        if issubclass(owner, Trait):
+            if isinstance(instance, Trait):
+                return AppliedEntityFnCall(instance, self)
+            return UnappliedEntityFnCall(instance, self)
+        return self
+
 
+class BoundMetadataFn(BoundFnCommon[_P, _T]):
+    def __repr__(self) -> str:
+        return f"<Fn bound-required metadata async {self.trait.__name__}::{self.identity} {inspect.signature(self.schema)}>"
 
-class DirectFn(Fn[_P, _T]):
     @overload
-    def __new__(cls, schema: Callable[Concatenate[_TboundTrait, _P1], Awaitable[_T1]]) -> DirectFn[_P1, _T1]:
+    def __get__(self, instance: Trait, owner: type[Trait]) -> AppliedMetadataFnCall[_P, _T]:
         ...
 
     @overload
-    def __new__(cls, schema: Callable[_P1, Awaitable[_T1]]) -> DirectFn[_P1, _T1]:
+    def __get__(self, instance: Any, owner: type[Trait]) -> UnappliedMetadataFnCall[_P, _T]:
         ...
 
-    def __new__(cls, schema: ...) -> ...:
-        return super().__new__(cls, schema)
+    @overload
+    def __get__(self, instance: Any, owner: type) -> Self:
+        ...
+
+    def __get__(self, instance: Any, owner: type):
+        if issubclass(owner, Trait):
+            if isinstance(instance, Trait):
+                return AppliedMetadataFnCall(instance, self)
+            return UnappliedMetadataFnCall(instance, self)
+        return self
+
+
+class BoundUniversalFn(BoundFnCommon[_P, _T]):
+    def __repr__(self) -> str:
+        return f"<Fn bound-required universal async {self.trait.__name__}::{self.identity} {inspect.signature(self.schema)}>"
 
     @overload
-    def __get__(self, instance: Trait, owner: type[Trait]) -> DirectFnWrapper[_P, _T]:
+    def __get__(self, instance: Trait, owner: type[Trait]) -> AppliedUniversalFnCall[_P, _T]:
         ...
 
     @overload
-    def __get__(self, instance: Any, owner: type[Trait] | None) -> Self:
+    def __get__(self, instance: Any, owner: type[Trait]) -> UnappliedUniversalFnCall[_P, _T]:
         ...
 
-    def __get__(self, instance: ..., owner: ...) -> ...:
-        # sourcery skip: assign-if-exp, reintroduce-else
-        if instance is None:
-            return self
-        return DirectFnWrapper(instance, self)
+    @overload
+    def __get__(self, instance: Any, owner: type) -> Self:
+        ...
 
+    def __get__(self, instance: Any, owner: type):
+        if issubclass(owner, Trait):
+            if isinstance(instance, Trait):
+                return AppliedUniversalFnCall(instance, self)
+            return UnappliedUniversalFnCall(instance, self)
+        return self
 
-class DirectFnWrapper(FnWrapper[_P, _T]):
-    target: Selector | None = None
 
-    def to(self, target: Selector):
-        self.target = target
-        return self
+class UnappliedEntityFnCall(FnCall[_P, _T]):
+    def __repr__(self) -> str:
+        return f"<FnCall unbounded entity async {self.trait.__class__.__name__}::{self.fn.identity} {inspect.signature(self.fn.schema)}>"
+
+    async def __call__(self, target: Selector, *args: _P.args, **kwargs: _P.kwargs):
+        impl = self.trait.context._get_entity_bound_scope(target).get(Impl(self.fn))
+        if impl is None:
+            raise NotImplementedError(
+                f'"{identity(self.trait)}::{self.fn.identity}" for target "{target!r}" is not implemented.'
+            )
+        impl = cast(Callable[Concatenate["Context", Selector, _P], Awaitable[_T]], impl)
+        return await impl(self.trait.context, target, *args, **kwargs)
 
-    async def __await_impl__(self) -> _T:
-        if self._args is None or self._kwargs is None:
-            raise ValueError("cannot call without param in shape of schema")
-
-        target = self.target or self.trait.target
-        if target is None:
-            targetter = self.trait.relationship._artifacts.get(ImplDefaultTarget(self.trait.path, self.fn))
-            if targetter is None:
-                raise NotImplementedError(
-                    f'"{self.trait.__class__.__name__}::{self.fn.__attr__}" '
-                    "required a target, but no target given and no default getter implemented."
-                )
-            targetter = cast("Callable[[Relationship], Selector]", targetter)
-            target = targetter(self.trait.relationship)
-        impl = self.trait.relationship._artifacts.get(
-            Impl(
-                self.fn,
-                target.path_without_land,
-                self.trait.path,
+
+class UnappliedMetadataFnCall(FnCall[_P, _T]):
+    def __repr__(self) -> str:
+        return f"<FnCall unbounded metadata async {self.trait.__class__.__name__}::{self.fn.identity} {inspect.signature(self.fn.schema)}>"
+
+    async def __call__(self, target: MetadataOf, *args: _P.args, **kwargs: _P.kwargs):
+        impl = self.trait.context._get_metadata_bound_scope(target).get(Impl(self.fn))
+        if impl is None:
+            raise NotImplementedError(
+                f'"{identity(self.trait)}::{self.fn.identity}" for target "{target!r}" is not implemented.'
             )
-        )
+        impl = cast(Callable[Concatenate["Context", MetadataOf, _P], Awaitable[_T]], impl)
+        return await impl(self.trait.context, target, *args, **kwargs)
+
+
+class UnappliedUniversalFnCall(FnCall[_P, _T]):
+    def __repr__(self) -> str:
+        return f"<FnCall unbounded universal async {self.trait.__class__.__name__}::{self.fn.identity} {inspect.signature(self.fn.schema)}>"
+
+    async def __call__(self, target: Selector | MetadataOf, *args: _P.args, **kwargs: _P.kwargs):
+        if isinstance(target, Selector):
+            scope = self.trait.context._get_entity_bound_scope(target)
+        else:
+            scope = self.trait.context._get_metadata_bound_scope(target)
+        impl = scope.get(Impl(self.fn))
         if impl is None:
-            debug(
-                self.trait.relationship._artifacts,
-                Impl(
-                    self.fn,
-                    target.path_without_land,
-                    self.trait.path,
-                ),
+            raise NotImplementedError(
+                f'"{identity(self.trait)}::{self.fn.identity}" for target "{target!r}" is not implemented.'
+            )
+        impl = cast(Callable[Concatenate["Context", "Selector | MetadataOf", _P], Awaitable[_T]], impl)
+        return await impl(self.trait.context, target, *args, **kwargs)
+
+    def assert_entity(self, target: Selector | MetadataOf):
+        if not isinstance(target, Selector):
+            raise TypeError(f'"{identity(self.trait)}::{self.fn.identity}" expected bounds with a entity.')
+
+    def assert_metadata(self, target: Selector | MetadataOf):
+        if not isinstance(target, MetadataOf):
+            raise TypeError(f'"{identity(self.trait)}::{self.fn.identity}" expected bounds with a metadata referring.')
+
+
+class AppliedEntityFnCall(FnCall[_P, _T]):
+    def __repr__(self) -> str:
+        return f"<FnCall bounded entity async {self.trait.__class__.__name__}::{self.fn.identity} {inspect.signature(self.fn.schema)}>"
+
+    async def __call__(self, *args: _P.args, **kwargs: _P.kwargs):
+        target = self.trait.bound
+        if not isinstance(target, Selector):
+            raise TypeError(f'"{identity(self.trait)}::{self.fn.identity}" expected bounds with a entity.')
+        impl = self.trait.context._get_entity_bound_scope(target).get(Impl(self.fn))
+        if impl is None:
+            raise NotImplementedError(
+                f'"{identity(self.trait)}::{self.fn.identity}" for target "{target!r}" is not implemented.'
+            )
+        impl = cast(Callable[Concatenate["Context", Selector, _P], Awaitable[_T]], impl)
+        return await impl(self.trait.context, target, *args, **kwargs)
+
+
+class AppliedMetadataFnCall(FnCall[_P, _T]):
+    def __repr__(self) -> str:
+        return f"<FnCall bounded metadata async {self.trait.__class__.__name__}::{self.fn.identity} {inspect.signature(self.fn.schema)}>"
+
+    async def __call__(self, *args: _P.args, **kwargs: _P.kwargs):
+        target = self.trait.bound
+        if not isinstance(target, MetadataOf):
+            raise TypeError(f'"{identity(self.trait)}::{self.fn.identity}" expected bounds with a metadata referring.')
+        impl = self.trait.context._get_metadata_bound_scope(target).get(Impl(self.fn))
+        if impl is None:
+            raise NotImplementedError(
+                f'"{identity(self.trait)}::{self.fn.identity}" for target "{target!r}" is not implemented.'
             )
+        impl = cast(Callable[Concatenate["Context", MetadataOf, _P], Awaitable[_T]], impl)
+        return await impl(self.trait.context, target, *args, **kwargs)
+
+
+class AppliedUniversalFnCall(FnCall[_P, _T]):
+    def __repr__(self) -> str:
+        return f"<FnCall bounded universal async {self.trait.__class__.__name__}::{self.fn.identity} {inspect.signature(self.fn.schema)}>"
+
+    async def __call__(self, *args: _P.args, **kwargs: _P.kwargs):
+        target = self.trait.bound
+        if isinstance(target, Selector):
+            scope = self.trait.context._get_entity_bound_scope(target)
+        else:
+            scope = self.trait.context._get_metadata_bound_scope(target)
+        impl = scope.get(Impl(self.fn))
+        if impl is None:
             raise NotImplementedError(
-                f'"{self.trait.__class__.__name__}::{self.fn.__attr__}" '
-                f'in "{self.trait.relationship.protocol.__class__.__name__}" '
-                f'for target "{target.path_without_land}" '
-                "is not implemented"
+                f'"{identity(self.trait)}::{self.fn.identity}" for target "{target!r}" is not implemented.'
             )
-        impl = cast("Callable[Concatenate[Relationship, Selector, _P], Awaitable[_T]]", impl)
-        return await impl(self.trait.relationship, target, *self._args, **self._kwargs)  # type: ignore
+        impl = cast(Callable[Concatenate["Context", "Selector | MetadataOf", _P], Awaitable[_T]], impl)
+        return await impl(self.trait.context, target, *args, **kwargs)
diff --git a/avilla/core/trait/context.py b/avilla/core/trait/context.py
index 5a7eaa83..9f621b77 100644
--- a/avilla/core/trait/context.py
+++ b/avilla/core/trait/context.py
@@ -1,66 +1,159 @@
 from __future__ import annotations
 
+from collections.abc import Awaitable, Callable
 from contextlib import contextmanager
 from contextvars import ContextVar
-from dataclasses import dataclass
-from typing import Any
+from itertools import chain
+from typing import TYPE_CHECKING, Any, MutableMapping, TypeVar, overload
 
-from typing_extensions import TypeAlias
+from typing_extensions import Concatenate, ParamSpec, TypeAlias, Unpack
 
-from avilla.core.trait.signature import ArtifactSignature
+from ..metadata import Metadata, MetadataBound, MetadataOf, MetadataRoute
+from ..resource import Resource
+from ..selector import Selector
+from . import (
+    Fn,
+    FnCall,
+    Trait,
+    UnappliedEntityFnCall,
+    UnappliedMetadataFnCall,
+    UnappliedUniversalFnCall,
+)
+from .signature import ArtifactSignature, Bounds, Impl, Pull, ResourceFetch, VisibleConf
 
+if TYPE_CHECKING:
+    from ..context import Context
+Artifacts: TypeAlias = MutableMapping[ArtifactSignature, Any]
 
-@dataclass(unsafe_hash=True)
-class Scope:
-    land: str
-    mainline: str | None = None
-    self: str | None = None
+ctx_artifacts: ContextVar[Artifacts] = ContextVar("artifacts")
 
 
-Namespace: TypeAlias = "dict[Scope | None, dict[ArtifactSignature, Any]]"
-
-ctx_namespace: ContextVar[Namespace] = ContextVar("ctx_namespace")
+@contextmanager
+def wrap_artifacts(*upstream_artifacts: Artifacts):
+    artifacts = {}
+    for upstream in upstream_artifacts:
+        artifacts |= upstream
+    token = ctx_artifacts.set(artifacts)
+    yield artifacts
+    ctx_artifacts.reset(token)
 
-GLOBAL_SCOPE = Scope(land="avilla")
 
-ctx_scope: ContextVar[Scope] = ContextVar("ctx_scope", default=GLOBAL_SCOPE)
-ctx_prefix: ContextVar[str] = ContextVar("ctx_prefix", default="")
+def get_artifacts() -> Artifacts:
+    try:
+        return ctx_artifacts.get()
+    except LookupError:
+        raise ValueError("cannot access artifacts due to undefined") from None
 
 
 @contextmanager
-def scope(land: str, mainline: str | None = None, self: str | None = None):
-    token = ctx_scope.set(Scope(land, mainline, self))
+def bounds(bound: str | MetadataBound, check: bool = True):
+    parent = get_artifacts()
+    override_artifacts = {}
+    token = ctx_artifacts.set(override_artifacts)
+
     yield
-    ctx_scope.reset(token)
 
+    ctx_artifacts.reset(token)
+
+    if check:
+        referred_traits: dict[type[Trait], set[Fn]] = {}
+        implemented_trait_fns: dict[type[Trait], set[Fn]] = {}
 
-def eval_dotpath(path: str, env: str = "") -> str:
-    if path.startswith("."):
-        if env:
-            return ".".join(i for i in env.split(".") + path.split(".") if i)
-        raise ValueError("cannot parse relative path without env pattern")
-    return path
+        for k in override_artifacts:
+            if isinstance(k, Impl):
+                implemented_trait_fns.setdefault(k.fn.trait, set()).add(k.fn)
+                if k.fn.trait not in referred_traits:
+                    referred_traits[k.fn.trait] = set(k.fn.trait.fn())
+
+        if unimplemented := list(
+            chain.from_iterable(
+                fn_definations - implemented_trait_fns[trait] for trait, fn_definations in referred_traits.items()
+            )
+        ):
+            raise NotImplementedError(f"missing required implements {unimplemented!r}")
+
+    parent[Bounds(bound)] = override_artifacts
 
 
 @contextmanager
-def prefix(pattern: str):
-    token = ctx_prefix.set(eval_dotpath(pattern, ctx_prefix.get()))
+def visible(checker: Callable[[Context], bool]):
+    parent = get_artifacts()
+    override_artifacts = {}
+    token = ctx_artifacts.set(override_artifacts)
+
     yield
-    ctx_prefix.reset(token)
 
+    parent[VisibleConf(checker)] = override_artifacts
+    ctx_artifacts.reset(token)
+
+
+_P = ParamSpec("_P")
+_T = TypeVar("_T")
+_T_co = TypeVar("_T_co", covariant=True)
+
+RecordCallable = Callable[[_T], _T]
+
+
+@overload
+def implement(
+    fn_call: UnappliedEntityFnCall[_P, _T_co]
+) -> RecordCallable[Callable[Concatenate[Context, Selector, _P], Awaitable[_T_co]]]:
+    ...
+
+
+@overload
+def implement(
+    fn_call: UnappliedMetadataFnCall[_P, _T_co]
+) -> RecordCallable[Callable[Concatenate[Context, MetadataOf, _P], Awaitable[_T_co]]]:
+    ...
+
+
+@overload
+def implement(
+    fn_call: UnappliedUniversalFnCall[_P, _T_co]
+) -> RecordCallable[Callable[Concatenate[Context, Selector | MetadataOf, _P], Awaitable[_T_co]]]:
+    ...
+
+
+@overload
+def implement(fn_call: FnCall[_P, _T_co]) -> RecordCallable[Callable[Concatenate[Context, _P], Awaitable[_T_co]]]:
+    ...
+
+
+def implement(fn_call: FnCall) -> ...:
+    def wrapper(artifact):
+        artifacts = get_artifacts()
+        artifacts[Impl(fn_call.fn)] = artifact
+        return artifact
+
+    return wrapper
+
+
+_MetadataT = TypeVar("_MetadataT", bound=Metadata)
+
+
+def pull(
+    route: type[_MetadataT] | MetadataRoute[Unpack[tuple[Any, ...]], _MetadataT]
+) -> RecordCallable[Callable[[Context, Selector], Awaitable[_MetadataT]]]:
+    def wrapper(artifact):
+        artifacts = get_artifacts()
+        artifacts[Pull(route)] = artifact
+        return artifact
+
+    return wrapper
+
+
+_ResourceT = TypeVar("_ResourceT", bound=Resource)
 
-@contextmanager
-def wrap_namespace(initial: Namespace | None = None):
-    namespace: Namespace = initial or {}
-    token = ctx_namespace.set(namespace)
-    yield namespace
-    ctx_namespace.reset(token)
 
+def fetch(resource: type[_ResourceT]) -> RecordCallable[Callable[[Context, _ResourceT], Awaitable[Any]]]:
+    def wrapper(artifact):
+        artifacts = get_artifacts()
+        artifacts[ResourceFetch(resource)] = artifact
+        return artifact
 
-def raise_for_no_namespace(exception: type[Exception] = LookupError):
-    if ctx_namespace.get(None) is None:
-        raise exception("required available namespace to initize")
+    return wrapper
 
 
-def get_current_namespace() -> dict[ArtifactSignature, Any]:
-    return ctx_namespace.get().setdefault(ctx_scope.get(), {})
+def complete_rule():
+    ...  # TODO
diff --git a/avilla/core/trait/recorder.py b/avilla/core/trait/recorder.py
deleted file mode 100644
index 0294d74d..00000000
--- a/avilla/core/trait/recorder.py
+++ /dev/null
@@ -1,209 +0,0 @@
-from __future__ import annotations
-
-import abc
-from typing import (
-    TYPE_CHECKING,
-    Any,
-    AsyncGenerator,
-    Awaitable,
-    Callable,
-    Generic,
-    TypeVar,
-    overload,
-)
-
-from typing_extensions import Concatenate, ParamSpec, TypeAlias, Unpack
-
-from avilla.core.resource import Resource
-from avilla.core.trait import DirectFn, OrientedFn, Trait
-from avilla.core.trait.signature import CastAllow, CompleteRule
-from avilla.core.trait.signature import Impl as _Impl
-from avilla.core.trait.signature import ImplDefaultTarget
-from avilla.core.trait.signature import Pull as _Pull
-from avilla.core.trait.signature import Query
-from avilla.core.trait.signature import ResourceFetch as _ResourceFatch
-from avilla.core.utilles.selector import Selector
-
-from .context import ctx_prefix, eval_dotpath, get_current_namespace
-
-if TYPE_CHECKING:
-    from avilla.core.cell import Cell, CellOf
-    from avilla.core.relationship import Relationship
-    from avilla.core.trait.signature import ArtifactSignature
-
-    from . import Fn
-
-
-class Recorder(abc.ABC):
-    @abc.abstractmethod
-    def signature(self) -> ArtifactSignature:
-        ...
-
-    def __call__(self, content: Any):
-        sig = self.signature()
-        r = get_current_namespace()
-        r[sig] = content
-        return content
-
-class AlterRecorder(Recorder):
-    @abc.abstractmethod
-    def signature(self) -> ArtifactSignature:
-        ...
-
-    def __call__(self, content: Any):
-        sig = self.signature()
-        r = get_current_namespace()
-        r.setdefault(sig, []).append(content)
-        return content
-
-
-_P = ParamSpec("_P")
-_T = TypeVar("_T")
-
-
-class ImplRecorder(Recorder, Generic[_P, _T]):
-    trait_call: Fn
-    path: type[Cell] | CellOf | None = None
-    target: str | None = None
-
-    @overload
-    def __new__(cls, trait_call: OrientedFn[_P, _T]) -> ImplRecorder[Concatenate[Selector, _P], _T]:
-        ...
-
-    @overload
-    def __new__(cls, trait_call: DirectFn[_P, _T]) -> ImplRecorder[Concatenate[Selector, _P], _T]:
-        ...
-
-    @overload
-    def __new__(cls, trait_call: Fn[_P, _T]) -> ImplRecorder[_P, _T]:
-        ...
-
-    def __new__(cls, trait_call: Fn[_P, _T]) -> ImplRecorder[_P, _T] | ImplRecorder[Concatenate[Selector, _P], _T]:
-        return super(ImplRecorder, cls).__new__(cls)
-
-    def __init__(self, trait_call: Fn[_P, _T]):
-        self.trait_call = trait_call
-
-    def of(self, path: type[Cell] | CellOf):
-        self.path = path
-        return self
-
-    def pin(self, target: str):
-        self.target = eval_dotpath(target, ctx_prefix.get())
-        return self
-
-    def signature(self):
-        if isinstance(self.trait_call, DirectFn):  # type: ignore
-            target = eval_dotpath(".", ctx_prefix.get())
-        else:
-            target = self.target
-        return _Impl(target=target, path=self.path, trait_call=self.trait_call)  # type: ignore
-
-    def __call__(self, content: Callable[Concatenate[Relationship, _P], Awaitable[_T]]):
-        return super().__call__(content)
-
-
-impl = ImplRecorder
-
-_R = TypeVar("_R", bound=Resource)
-
-
-class FetchRecorder(Recorder, Generic[_R]):
-    resource: type[_R]
-
-    def __init__(self, resource: type[_R]):
-        self.resource = resource
-
-    def signature(self):
-        return _ResourceFatch(self.resource)
-
-    def __call__(self, content: Callable[[Relationship, _R], Awaitable[Any]]):
-        return super().__call__(content)
-
-
-fetch = FetchRecorder
-
-_C = TypeVar("_C", bound="Cell")
-
-
-class PullRecorder(Recorder, Generic[_C]):
-    target: str | None = None
-    path: type[Cell] | CellOf
-
-    def __init__(self, path: type[_C] | CellOf[Unpack[tuple[Any, ...]], _C]):
-        self.path = path
-
-    def of(self, target: str):
-        self.target = target
-        return self
-
-    def signature(self):
-        return _Pull(eval_dotpath(self.target, ctx_prefix.get()) if self.target is not None else None, self.path)
-
-    def __call__(self, content: Callable[[Relationship, Selector | None], Awaitable[_C]]):
-        return super().__call__(content)
-
-
-pull = PullRecorder
-
-
-def completes(relative: str, output: str):
-    r = get_current_namespace()
-    r[CompleteRule(eval_dotpath(relative, ctx_prefix.get()))] = eval_dotpath(output, ctx_prefix.get())
-
-
-Querier: TypeAlias = "Callable[[Relationship, Selector | None, Selector], AsyncGenerator[Selector, None]]"
-
-
-@overload
-def query(
-    upper: None, target: str
-) -> Callable[
-    [Callable[["Relationship", None, Selector], AsyncGenerator[Selector, None]]],
-    Callable[["Relationship", None, Selector], AsyncGenerator[Selector, None]],
-]:
-    ...
-
-
-@overload
-def query(
-    upper: str, target: str
-) -> Callable[
-    [Callable[["Relationship", Selector, Selector], AsyncGenerator[Selector, None]]],
-    Callable[["Relationship", Selector, Selector], AsyncGenerator[Selector, None]],
-]:
-    ...
-
-
-def query(upper: str | None, target: str) -> ...:
-    def wrapper(querier):
-        r = get_current_namespace()
-        r[Query(upper, target)] = querier
-        return querier
-
-    return wrapper
-
-
-def casts(trait_type: type[Trait], target: str | None = None):
-    r: dict[ArtifactSignature, Any] = get_current_namespace()
-    r[CastAllow(trait_type, target)] = True
-
-class ImplDefaultTargetRecorder(Recorder):
-    # trait_call: TraitCall
-    path: type[Cell] | CellOf | None = None
-
-    def __init__(self, trait_call: Fn):
-        self.trait_call = trait_call
-
-    def of(self, path: type[Cell] | CellOf):
-        self.path = path
-        return self
-
-    def signature(self):
-        return ImplDefaultTarget(self.path, self.trait_call)
-
-    def __call__(self, content: Callable[[Relationship], Selector]):
-        return super().__call__(content)
-
-
-default_target = ImplDefaultTargetRecorder
diff --git a/avilla/core/trait/signature.py b/avilla/core/trait/signature.py
index af3cff36..d66fc0f4 100644
--- a/avilla/core/trait/signature.py
+++ b/avilla/core/trait/signature.py
@@ -1,30 +1,33 @@
 from __future__ import annotations
 
+from collections.abc import Callable
 from dataclasses import dataclass
-from typing import TYPE_CHECKING, Generic, Hashable, TypeVar
+from typing import TYPE_CHECKING
 
 if TYPE_CHECKING:
-    from avilla.core.cell import Cell, CellOf
-    from avilla.core.resource import Resource
-    from avilla.core.trait import Fn, Trait
-    from avilla.core.trait.extension import FnExtension
+    from ..context import Context
+    from ..metadata import Metadata, MetadataBound, MetadataRoute
+    from ..resource import Resource
+    from ..trait import Fn
 
 
 class ArtifactSignature:
     pass
 
 
+@dataclass(unsafe_hash=True)
+class Bounds(ArtifactSignature):
+    bound: str | MetadataBound
+
+
 @dataclass(unsafe_hash=True)
 class Impl(ArtifactSignature):
-    trait_call: Fn
-    target: str | None
-    path: type[Cell] | CellOf | None
+    fn: Fn
 
 
 @dataclass(unsafe_hash=True)
 class Pull(ArtifactSignature):
-    target: str | None
-    path: type[Cell] | CellOf
+    route: type[Metadata] | MetadataRoute
 
 
 @dataclass(unsafe_hash=True)
@@ -32,39 +35,27 @@ class ResourceFetch(ArtifactSignature):
     target: type[Resource]
 
 
-@dataclass(unsafe_hash=True)
-class Allow(ArtifactSignature):
-    content: Hashable
-
-
 @dataclass(unsafe_hash=True)
 class CompleteRule(ArtifactSignature):
     relative: str
 
 
-@dataclass(unsafe_hash=True)
-class ImplDefaultTarget(ArtifactSignature):
-    path: type[Cell] | CellOf | None
-    trait_call: Fn
-
-
 @dataclass(unsafe_hash=True)
 class Query(ArtifactSignature):
     upper: str | None
     target: str
 
+
 @dataclass(unsafe_hash=True)
-class Check(ArtifactSignature):
-    target: str
+class VisibleConf(ArtifactSignature):
+    checker: Callable[[Context], bool]
 
 
+"""
 E = TypeVar("E", bound="FnExtension")
 
+
 @dataclass(unsafe_hash=True)
 class ExtensionImpl(ArtifactSignature, Generic[E]):
     ext: type[E]
-
-@dataclass(unsafe_hash=True)
-class CastAllow(ArtifactSignature):
-    trait: type[Trait]
-    target: str | None = None
\ No newline at end of file
+"""
diff --git a/avilla/core/typing.py b/avilla/core/typing.py
index 000e71d7..69bba4e8 100644
--- a/avilla/core/typing.py
+++ b/avilla/core/typing.py
@@ -1,13 +1,4 @@
-from typing import (
-    TYPE_CHECKING,
-    Any,
-    Callable,
-    Coroutine,
-    Generic,
-    Protocol,
-    TypeVar,
-    runtime_checkable,
-)
+from typing import TYPE_CHECKING, Any, Generic, Protocol, TypeVar, runtime_checkable
 
 if TYPE_CHECKING:
     from avilla.core.protocol import BaseProtocol
diff --git a/avilla/core/utilles/__init__.py b/avilla/core/utilles/__init__.py
index fbd1baff..08173d6b 100644
--- a/avilla/core/utilles/__init__.py
+++ b/avilla/core/utilles/__init__.py
@@ -1,30 +1,24 @@
-import inspect
-from typing import Any, Awaitable, Callable, Coroutine, TypeVar, overload
+from __future__ import annotations
 
-T = TypeVar("T")
+from collections.abc import Callable
+from typing import Any, Generic, TypeVar
 
+_T = TypeVar("_T")
+_R_co = TypeVar("_R_co", covariant=True)
 
-@overload
-async def run_always_await(callable: Callable[..., T], *args, **kwargs) -> T:
-    ...
-
-
-@overload
-async def run_always_await(callable: Callable[..., Awaitable[T]], *args, **kwargs) -> T:
-    ...
 
+def identity(obj: Any) -> str:
+    return obj.__name__ if isinstance(obj, type) else obj.__class__.__name__
 
-@overload
-async def run_always_await(callable: Callable[..., Coroutine[None, None, T]], *args, **kwargs) -> T:
-    ...
 
+class classproperty(Generic[_R_co]):
+    fget: classmethod[_R_co]
 
-async def run_always_await(callable, *args, **kwargs):
-    obj = callable(*args, **kwargs)
-    while inspect.isawaitable(obj):
-        obj = await obj
-    return obj
+    def __init__(self, fget: Callable[[Any], _R_co] | classmethod[_R_co]) -> None:
+        if not isinstance(fget, classmethod):
+            fget = classmethod(fget)
 
+        self.fget = fget
 
-def identity(obj: Any) -> str:
-    return obj.__name__ if isinstance(obj, type) else obj.__class__.__name__
+    def __get__(self, __obj: _T, __type: type[_T] | None = None, /) -> _R_co:
+        return self.fget.__get__(__obj, __type)()
diff --git a/avilla/core/utilles/event_parser.py b/avilla/core/utilles/event_parser.py
deleted file mode 100644
index 54c9ff4f..00000000
--- a/avilla/core/utilles/event_parser.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from __future__ import annotations
-
-import inspect
-from abc import ABC, abstractmethod
-from typing import TYPE_CHECKING, Callable, Coroutine, Generic, TypeVar
-
-from graia.amnesia.message.element import Element
-from graia.broadcast.utilles import run_always_await
-from loguru import logger
-from typing_extensions import Self
-
-from avilla.core.account import AbstractAccount
-from avilla.core.event import AvillaEvent
-
-if TYPE_CHECKING:
-    from avilla.core.account import AbstractAccount
-    from avilla.core.protocol import BaseProtocol
-
-
-def event(event_type: str):
-    def wrapper(func):
-        func.__event_parser__ = event_type
-        return func
-
-    return wrapper
-
-
-_P = TypeVar("_P", bound="BaseProtocol")
-
-
-class AbstractEventParser(ABC, Generic[_P]):
-    event_parser: dict[str, Callable[[Self, _P, AbstractAccount, dict], Coroutine[None, None, AvillaEvent | None]]] = {}
-
-    def __init_subclass__(cls) -> None:
-        super().__init_subclass__()
-        cls.event_parser = {}
-        for mro in reversed(inspect.getmro(cls)):
-            if issubclass(mro, AbstractEventParser):
-                cls.event_parser.update(mro.event_parser)
-        members = inspect.getmembers(cls)
-        for _, value in members:
-            if callable(value) and getattr(value, "__event_parser__", False):
-                cls.event_parser[value.__event_parser__] = value
-
-    @abstractmethod
-    def get_event_type(self, raw: dict) -> str:
-        ...
-
-    async def parse_event(
-        self, protocol: _P, account: AbstractAccount, raw: dict, *, error: bool = False
-    ) -> AvillaEvent | None:
-        event_type = self.get_event_type(raw)
-        deserializer = self.event_parser.get(event_type)
-        if deserializer is None:
-            if error:
-                raise NotImplementedError(f"Event type {event_type} is not supported.")
-            logger.warning(f"Event type {event_type} is not supported by {self.__class__.__name__}", raw)
-            return
-        return await deserializer(self, protocol, account, raw)
diff --git a/avilla/core/utilles/message_deserializer.py b/avilla/core/utilles/message_deserializer.py
deleted file mode 100644
index b7e4e224..00000000
--- a/avilla/core/utilles/message_deserializer.py
+++ /dev/null
@@ -1,64 +0,0 @@
-from __future__ import annotations
-
-import inspect
-from abc import ABC, abstractmethod
-from typing import TYPE_CHECKING, Any, Callable, Coroutine, Generic, Iterable, TypeVar
-
-from graia.amnesia.message.element import Element
-from typing_extensions import Self
-
-from avilla.core.elements import Unknown
-from avilla.core.utilles import run_always_await
-
-if TYPE_CHECKING:
-    from avilla.core.protocol import BaseProtocol
-
-
-def deserializer(element_type: str):
-    def wrapper(func):
-        func.__element_deserializer__ = element_type
-        return func
-
-    return wrapper
-
-
-_P = TypeVar("_P", bound="BaseProtocol")
-
-
-class MessageDeserializer(ABC, Generic[_P]):
-    element_deserializer: dict[
-        str, Callable[[Self, _P, dict], Coroutine[None, None, Element]] | Callable[[Self, _P, dict], Element]
-    ] = {}
-    ignored_types: set[str] = set()
-
-    def __init_subclass__(cls) -> None:
-        super().__init_subclass__()
-        cls.element_deserializer = {}
-        for mro in reversed(inspect.getmro(cls)):
-            if issubclass(mro, MessageDeserializer):
-                cls.element_deserializer.update(mro.element_deserializer)
-        members = inspect.getmembers(cls)
-        for _, value in members:
-            if callable(value) and getattr(value, "__element_deserializer__", False):
-                cls.element_deserializer[value.__element_deserializer__] = value
-
-    def split_message(self, data: list) -> Iterable[dict]:
-        yield from data
-
-    @abstractmethod
-    def get_element_type(self, raw: dict) -> str:
-        ...
-
-    async def parse_element(self, protocol: _P, raw: dict) -> Element:
-        element_type = self.get_element_type(raw)
-        deserializer = self.element_deserializer.get(element_type)
-        if deserializer is None:
-            return Unknown(type=element_type, raw_data=raw)
-        return await run_always_await(deserializer, self, protocol, raw)  # type: ignore
-
-    async def parse_sentence(self, protocol: _P, data: list) -> list[Any]:
-        return [
-            await self.parse_element(protocol, raw)
-            for raw in self.split_message(data)
-            if self.get_element_type(raw) not in self.ignored_types
-        ]
diff --git a/avilla/core/utilles/message_serializer.py b/avilla/core/utilles/message_serializer.py
deleted file mode 100644
index 7c466062..00000000
--- a/avilla/core/utilles/message_serializer.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from __future__ import annotations
-
-import inspect
-from typing import TYPE_CHECKING, Any, Callable, Coroutine, Generic, TypeVar
-
-from graia.amnesia.message import MessageChain
-from graia.amnesia.message.element import Element
-from graia.broadcast.utilles import run_always_await
-from typing_extensions import Self
-
-if TYPE_CHECKING:
-    from avilla.core.protocol import BaseProtocol
-
-
-def element(element_type: type[Element]):
-    def wrapper(func: Callable):
-        func.__element_serializer__ = element_type
-        return func
-
-    return wrapper
-
-
-_P = TypeVar("_P", bound="BaseProtocol")
-
-
-class MessageSerializer(Generic[_P]):
-    element_serializer: dict[type[Element], Callable[[Self, _P, Any], dict | Coroutine[None, None, dict]]] = {}
-
-    def __init_subclass__(cls) -> None:
-        super().__init_subclass__()
-        cls.element_serializer = {}
-        for mro in reversed(inspect.getmro(cls)):
-            if issubclass(mro, MessageSerializer):
-                cls.element_serializer.update(mro.element_serializer)
-        members = inspect.getmembers(cls)
-        for _, value in members:
-            if callable(value) and getattr(value, "__element_serializer__", False):
-                cls.element_serializer[value.__element_serializer__] = value
-
-    async def serialize_element(self, protocol: _P, element: Element) -> dict:
-        if type(element) not in self.element_serializer:
-            raise NotImplementedError(f"Element type {type(element)} is not supported.")
-        return await run_always_await(self.element_serializer[type(element)], self, protocol, element)  # type: ignore
-
-    async def serialize_chain(self, protocol: _P, message: MessageChain):
-        return [await self.serialize_element(protocol, element) for element in message.content]
diff --git a/avilla/core/utilles/promise.py b/avilla/core/utilles/promise.py
deleted file mode 100644
index 194372e1..00000000
--- a/avilla/core/utilles/promise.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from __future__ import annotations
-
-from asyncio import Future
-from contextlib import suppress
-from typing import Generic, TypeVar
-
-T = TypeVar("T")
-
-class Promise(Generic[T]):
-    _futures: list[Future[T]]
-    done: bool = False
-
-    def __init__(self) -> None:
-        self._futures = []
-
-    def __await__(self):
-        return self.__await_impl__().__await__()
-    
-    async def __await_impl__(self):
-        future = Future()
-        try:
-            self._futures.append(future)
-            return await future
-        finally:
-            with suppress(ValueError):
-                self._futures.remove(future)
-
-    def resolve(self, value: T):
-        for future in self._futures:
-            if not future.done() and not future.cancelled():
-                future.set_result(value)
-    
-    def reject(self, exception: Exception):
-        for future in self._futures:
-            if not future.done() and not future.cancelled():
-                future.set_exception(exception)
-    
-    def cancel(self):
-        for future in self._futures:
-            if not future.done() and not future.cancelled():
-                future.cancel()
diff --git a/avilla/core/utilles/stream.py b/avilla/core/utilles/stream.py
deleted file mode 100644
index d61a4a7c..00000000
--- a/avilla/core/utilles/stream.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from __future__ import annotations
-
-from asyncio import Future
-from contextlib import suppress
-from typing import Generic, TypeVar
-
-T = TypeVar("T")
-
-class Stream(Generic[T]):
-    _receivers: list[Future[T]]
-    closed: bool = False
-
-    def __init__(self) -> None:
-        self._receivers = []
-
-    async def __iter__(self):
-        if self.closed:
-            raise RuntimeError("stream was closed.")
-        while not self.closed:
-            future = Future()
-            self._receivers.append(future)
-            try:
-                yield await future
-            finally:
-                with suppress(ValueError):
-                    self._receivers.remove(future)
-
-    def push(self, value: T):
-        for receiver in self._receivers:
-            if not receiver.done() and not receiver.cancelled():
-                receiver.set_result(value)
-
-    def close(self):
-        self.closed = True
-        for receiver in self._receivers:
-            if not receiver.done() and not receiver.cancelled():
-                receiver.cancel()
diff --git a/avilla/elizabeth/_query.py b/avilla/elizabeth/_query.py
index 8424c6c1..984ddb5a 100644
--- a/avilla/elizabeth/_query.py
+++ b/avilla/elizabeth/_query.py
@@ -3,16 +3,16 @@
 from typing import TYPE_CHECKING, Callable
 
 from avilla.core.querier import ProtocolAbstractQueryHandler, query
-from avilla.core.utilles.selector import Selector
+from avilla.core.selector import Selector
 from avilla.elizabeth.account import ElizabethAccount
 
 if TYPE_CHECKING:
-    from avilla.core.relationship import Relationship
+    from avilla.core.context import Context
 
 
 class ElizabethRootQuery(ProtocolAbstractQueryHandler):
     @query("group")
-    async def query_group(self, rs: Relationship, prefix: Selector, checker: Callable[[Selector], bool]):
+    async def query_group(self, rs: Context, prefix: Selector, checker: Callable[[Selector], bool]):
         account = rs.account
         assert isinstance(account, ElizabethAccount)
         result: list[dict] = await account.call("groupList", {"__method__": "get"})
@@ -24,7 +24,7 @@ async def query_group(self, rs: Relationship, prefix: Selector, checker: Callabl
 
 class ElizabethGroupQuery(ProtocolAbstractQueryHandler, prefix="group"):
     @query("member")
-    async def query_member(self, rs: Relationship, prefix: Selector, checker: Callable[[Selector], bool]):
+    async def query_member(self, rs: Context, prefix: Selector, checker: Callable[[Selector], bool]):
         account = rs.account
         assert isinstance(account, ElizabethAccount)
         result: list[dict] = await account.call(
diff --git a/avilla/elizabeth/account.py b/avilla/elizabeth/account.py
index ea0d208c..afc084d5 100644
--- a/avilla/elizabeth/account.py
+++ b/avilla/elizabeth/account.py
@@ -3,8 +3,8 @@
 from typing import TYPE_CHECKING, Any
 
 from avilla.core.account import AbstractAccount
-from avilla.core.relationship import Relationship
-from avilla.core.utilles.selector import Selector
+from avilla.core.context import Context
+from avilla.core.selector import Selector
 from avilla.elizabeth.connection import ElizabethConnection
 from avilla.elizabeth.connection.util import CallMethod
 
@@ -15,21 +15,21 @@
 class ElizabethAccount(AbstractAccount):
     protocol: ElizabethProtocol
 
-    async def get_relationship(self, target: Selector, *, via: Selector | None = None) -> Relationship:
+    async def get_context(self, target: Selector, *, via: Selector | None = None) -> Context:
         # TODO: 对象存在性检查
         if "land" not in target:
-            target = Selector().mixin(f"land.{target.path}", target)
+            target = target.land(self.protocol.land)
         if target.path == "land.group":
-            return Relationship(self.protocol, target, target, target.copy().member(self.id), self)
+            return Context(self, target, target, target.member(self.id), self.to_selector())
         elif target.path == "land.friend":
-            return Relationship(self.protocol, target, target, self.to_selector(), self)
+            return Context(self, target, target, self.to_selector(), self.to_selector())
         elif target.path == "land.group.member":
-            return Relationship(
-                self.protocol,
+            return Context(
+                self,
                 target,
                 Selector().land(self.land.name).group(target.pattern["group"]),
                 Selector().land(self.land.name).group(target.pattern["group"]).member(self.id),
-                self,
+                self.to_selector(),
             )
         else:
             raise NotImplementedError()
diff --git a/avilla/elizabeth/connection/__init__.py b/avilla/elizabeth/connection/__init__.py
index 846a5447..28a13ff0 100644
--- a/avilla/elizabeth/connection/__init__.py
+++ b/avilla/elizabeth/connection/__init__.py
@@ -1,15 +1,15 @@
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Any, Generic, Optional, Set, Type
+from typing import TYPE_CHECKING, Any, Generic, Optional
 
 from graia.amnesia.transport.common.status import (
     ConnectionStatus as BaseConnectionStatus,
 )
-from launart import Launchable, LaunchableStatus
+from launart import ExportInterface, Launchable, LaunchableStatus
 from loguru import logger
 from statv import Stats
 
-from avilla.core.event.lifecycle import AccountAvailable, AccountUnavailable
+from avilla.spec.core.application import AccountAvailable, AccountUnavailable
 
 from .config import HttpClientConfig, HttpServerConfig, T_Config
 from .config import U_Config as U_Config
@@ -59,12 +59,12 @@ class ElizabethConnection(Launchable, Generic[T_Config]):
     status: ConnectionStatus
     protocol: ElizabethProtocol
     config: T_Config
-    dependencies: frozenset[str]
+    dependencies: frozenset[str | type[ExportInterface]]
 
     http_conn: Optional["HttpClientConnection"]
 
     @property
-    def required(self) -> Set[str]:
+    def required(self):
         return set(self.dependencies)
 
     @property
@@ -84,7 +84,7 @@ def register_account(self):
 
     def on_connected_update(self, statv: ConnectionStatus, stats: Stats[bool], past: bool, current: bool) -> None:
         if past != current:
-            logger.warning(f"Account: {'Connected' if current else 'Disconnected'}")
+            logger.warning(f"Account({self.account.id}): {'Connected' if current else 'Disconnected'}")
             proto = self.account.protocol
             proto.avilla.broadcast.postEvent(
                 (AccountAvailable if current else AccountUnavailable)(proto.avilla, self.account)
diff --git a/avilla/elizabeth/connection/http.py b/avilla/elizabeth/connection/http.py
index b84c80f3..9e5da216 100644
--- a/avilla/elizabeth/connection/http.py
+++ b/avilla/elizabeth/connection/http.py
@@ -9,6 +9,7 @@
 from graia.amnesia.transport import Transport
 from graia.amnesia.transport.common.http import AbstractServerRequestIO, HttpEndpoint
 from graia.amnesia.transport.common.http.extra import HttpRequest
+from graia.amnesia.transport.common.server import AbstractRouter
 from launart import Launart
 from launart.utilles import wait_fut
 from loguru import logger
@@ -25,7 +26,7 @@
 class HttpServerConnection(ElizabethConnection[HttpServerConfig], Transport):
     """HTTP 服务器连接"""
 
-    dependencies = frozenset(["http.universal_server"])
+    dependencies = frozenset([AbstractRouter])
 
     def __init__(self, protocol: ElizabethProtocol, config: HttpServerConfig) -> None:
         super().__init__(protocol, config)
@@ -43,9 +44,11 @@ async def handle_request(self, io: AbstractServerRequestIO):
         self.status.connected = True
         self.status.alive = True
         self.register_account()  # LINK: hot registration
-        event = await self.protocol.event_parser.parse_event(self.protocol, self.account, data)
-        if event is not None:
-            self.protocol.post_event(event)
+        try:
+            event, context = await self.protocol.parse_event(self.account, data)
+            self.protocol.post_event(event, context)
+        except Exception:
+            logger.exception("error on parsing event: ", data)
         return {"command": "", "data": {}}
 
     async def launch(self, mgr: Launart) -> None:
@@ -56,7 +59,7 @@ async def launch(self, mgr: Launart) -> None:
 class HttpClientConnection(ElizabethConnection[HttpClientConfig]):
     """HTTP 客户端连接"""
 
-    dependencies = frozenset(["http.universal_client"])
+    dependencies = frozenset([AiohttpClientInterface])
     http_interface: AiohttpClientInterface
 
     def __init__(self, protocol: ElizabethProtocol, config: HttpClientConfig) -> None:
@@ -141,9 +144,11 @@ async def launch(self, mgr: Launart) -> None:
                     continue
                 assert isinstance(data, list)
                 for event_data in data:
-                    event = await self.protocol.event_parser.parse_event(self.protocol, self.account, event_data)
-                    if event is not None:
-                        self.protocol.post_event(event)
+                    try:
+                        event, context = await self.protocol.parse_event(self.account, event_data)
+                        self.protocol.post_event(event, context)
+                    except Exception:
+                        logger.exception("error on parsing event: ", event_data)
                 await wait_fut(
                     [asyncio.sleep(0.5), mgr.status.wait_for_sigexit()],
                     return_when=asyncio.FIRST_COMPLETED,
diff --git a/avilla/elizabeth/connection/ws.py b/avilla/elizabeth/connection/ws.py
index cfb066a7..d0a09605 100644
--- a/avilla/elizabeth/connection/ws.py
+++ b/avilla/elizabeth/connection/ws.py
@@ -7,6 +7,7 @@
 
 from graia.amnesia.builtins.aiohttp import AiohttpClientInterface
 from graia.amnesia.transport import Transport
+from graia.amnesia.transport.common.client import AbstractClientInterface
 from graia.amnesia.transport.common.http.extra import HttpRequest
 from graia.amnesia.transport.common.websocket import (
     AbstractWebsocketIO,
@@ -70,9 +71,11 @@ async def _(self, _: AbstractWebsocketIO, raw: Any) -> None:  # event pass and c
             self.futures[sync_id].set_result(data)
         elif "type" in data:
             self.status.alive = True
-            event = await self.protocol.event_parser.parse_event(self.protocol, self.account, data)
-            if event:
-                self.protocol.post_event(event)
+            try:
+                event, context = await self.protocol.parse_event(self.account, data)
+                self.protocol.post_event(event, context)
+            except Exception:
+                logger.exception("error on parsing event: ", data)
         else:
             logger.warning(f"Got unknown data: {raw}")
 
@@ -118,7 +121,7 @@ async def call(self, command: str, method: CallMethod, params: Optional[dict] =
 class WebsocketServerConnection(BaseWebsocketConnection[WebsocketServerConfig]):
     """Websocket 服务器连接"""
 
-    dependencies = frozenset(["http.universal_server"])
+    dependencies = frozenset([AbstractClientInterface])
 
     config: WebsocketServerConfig
 
@@ -162,7 +165,7 @@ async def _(self, io: AbstractWebsocketIO) -> None:
 class WebsocketClientConnection(BaseWebsocketConnection[WebsocketClientConfig]):
     """Websocket 客户端连接"""
 
-    dependencies = frozenset(["http.universal_client"])
+    dependencies = frozenset([AbstractClientInterface])
     http_interface: AiohttpClientInterface
     config: WebsocketClientConfig
 
diff --git a/avilla/core/skeleton/__init__.py b/avilla/elizabeth/event/__init__.py
similarity index 100%
rename from avilla/core/skeleton/__init__.py
rename to avilla/elizabeth/event/__init__.py
diff --git a/avilla/elizabeth/event/message.py b/avilla/elizabeth/event/message.py
new file mode 100644
index 00000000..6eedd68c
--- /dev/null
+++ b/avilla/elizabeth/event/message.py
@@ -0,0 +1,90 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from graia.amnesia.message import __message_chain_class__
+
+from avilla.core.message import Message
+from avilla.elizabeth.util import event
+from avilla.spec.core.message import MessageReceived
+
+from ...core.context import Context
+from ...core.selector import Selector
+
+if TYPE_CHECKING:
+    from ..account import ElizabethAccount
+    from ..protocol import ElizabethProtocol
+
+
+@event("GroupMessage")
+async def group_message(protocol: ElizabethProtocol, account: ElizabethAccount, raw: dict):
+    group = Selector().land(protocol.land.name).group(str(raw["sender"]["group"]["id"]))
+    member = group.member(str(raw["sender"]["id"]))
+    context = Context(
+        account=account,
+        client=member,
+        endpoint=group,
+        scene=group,
+        selft=group.member(account.id),
+    )
+    message_result = await protocol.deserialize_message(context, raw["messageChain"])
+    message = Message(
+        describe=Message,
+        id=message_result["source"],
+        scene=group,
+        sender=member,
+        content=__message_chain_class__(message_result["content"]),
+        time=message_result["time"],
+    )
+    context._collect_metadatas(message, message)
+    event = MessageReceived(context, message)
+    return event, context
+
+
+@event("FriendMessage")
+async def friend_message(protocol: ElizabethProtocol, account: ElizabethAccount, raw: dict):
+    friend = Selector().land(protocol.land.name).friend(str(raw["sender"]["id"]))
+    context = Context(
+        account=account,
+        client=friend,
+        endpoint=friend,
+        scene=friend,
+        selft=account.to_selector(),
+    )
+    message_result = await protocol.deserialize_message(context, raw["messageChain"])
+    message = Message(
+        describe=Message,
+        id=message_result["source"],
+        scene=friend,
+        sender=friend,
+        content=__message_chain_class__(message_result["content"]),
+        time=message_result["time"],
+    )
+    context._collect_metadatas(message, message)
+    event = MessageReceived(context, message)
+    return event, context
+
+
+@event("TempMessage")
+async def temp_message(protocol: ElizabethProtocol, account: ElizabethAccount, raw: dict):
+    group = Selector().land(protocol.land.name).group(str(raw["sender"]["group"]["id"]))
+    member = group.member(str(raw["sender"]["id"]))
+    context = Context(
+        account=account,
+        client=member,
+        endpoint=member,
+        scene=member,
+        selft=group.member(account.id),
+    )
+    message_result = await protocol.deserialize_message(context, raw["messageChain"])
+    message = Message(
+        describe=Message,
+        id=message_result["source"],
+        scene=member,
+        sender=member,
+        content=__message_chain_class__(message_result["content"]),
+        time=message_result["time"],
+    )
+    context._collect_metadatas(message, message)
+    event = MessageReceived(context, message)
+    return event, context
diff --git a/avilla/elizabeth/event_parser.py b/avilla/elizabeth/event_parser.py
deleted file mode 100644
index f03e112a..00000000
--- a/avilla/elizabeth/event_parser.py
+++ /dev/null
@@ -1,134 +0,0 @@
-from __future__ import annotations
-
-from dataclasses import dataclass
-from datetime import datetime
-from typing import TYPE_CHECKING
-
-from graia.amnesia.message import MessageChain
-
-from avilla.core.event.message import MessageReceived
-from avilla.core.message import Message
-from avilla.core.utilles.event_parser import AbstractEventParser, event
-from avilla.core.utilles.selector import Selector
-
-if TYPE_CHECKING:
-    from avilla.elizabeth.account import ElizabethAccount
-
-    from .protocol import ElizabethProtocol
-
-
-@dataclass
-class _Source:
-    id: int
-    time: int
-
-
-@dataclass
-class _Quote:
-    id: int
-    group_id: int
-    sender_id: int
-    target_id: int
-    origin: list
-
-
-class ElizabethEventParser(AbstractEventParser["ElizabethProtocol"]):
-    def get_event_type(self, raw: dict) -> str:
-        return raw["type"]
-
-    @event("GroupMessage")
-    async def group_message(self, protocol: ElizabethProtocol, account: ElizabethAccount, raw: dict):
-        message_chain = raw["messageChain"]
-        source = None
-        quote = None
-        for i in message_chain:
-            if i["type"] == "Source":
-                source = _Source(i["id"], i["time"])
-            elif i["type"] == "Quote":
-                quote = _Quote(i["id"], i["groupId"], i["senderId"], i["targetId"], i["origin"])
-        if source is None:
-            raise ValueError("Source not found.")
-        return MessageReceived(
-            message=Message(
-                describe=Message,
-                id=str(source.id),
-                mainline=Selector().land(protocol.land.name).group(str(raw["sender"]["group"]["id"])),
-                sender=Selector()
-                .land(protocol.land.name)
-                .group(str(raw["sender"]["group"]["id"]))
-                .member(str(raw["sender"]["id"])),
-                content=MessageChain(await protocol.message_deserializer.parse_sentence(protocol, message_chain)),
-                time=datetime.fromtimestamp(source.time),
-                reply=Selector()
-                .land(protocol.land.name)
-                .group(str(raw["sender"]["group"]["id"]))
-                .message(str(quote.id))
-                if quote is not None
-                else None,
-            ),
-            account=account,
-        )
-
-    @event("FriendMessage")
-    async def friend_message(self, protocol: ElizabethProtocol, account: ElizabethAccount, raw: dict):
-        message_chain = raw["messageChain"]
-        source = None
-        quote = None
-        for i in message_chain:
-            if i["type"] == "Source":
-                source = _Source(i["id"], i["time"])
-            elif i["type"] == "Quote":
-                quote = _Quote(i["id"], i["groupId"], i["senderId"], i["targetId"], i["origin"])
-        if source is None:
-            raise ValueError("Source not found.")
-        return MessageReceived(
-            message=Message(
-                describe=Message,
-                id=str(source.id),
-                mainline=Selector().land(protocol.land.name).friend(str(raw["sender"]["id"])),
-                sender=Selector().land(protocol.land.name).friend(str(raw["sender"]["id"])),
-                content=MessageChain(await protocol.message_deserializer.parse_sentence(protocol, message_chain)),
-                time=datetime.fromtimestamp(source.time),
-                reply=Selector().land(protocol.land.name).friend(str(raw["sender"]["id"])).message(str(quote.id))
-                if quote is not None
-                else None,
-            ),
-            account=account,
-        )
-
-    @event("TempMessage")
-    async def temp_message(self, protocol: ElizabethProtocol, account: ElizabethAccount, raw: dict):
-        message_chain = raw["messageChain"]
-        source = None
-        quote = None
-        for i in message_chain:
-            if i["type"] == "Source":
-                source = _Source(i["id"], i["time"])
-            elif i["type"] == "Quote":
-                quote = _Quote(i["id"], i["groupId"], i["senderId"], i["targetId"], i["origin"])
-        if source is None:
-            raise ValueError("Source not found.")
-        return MessageReceived(
-            message=Message(
-                describe=Message,
-                id=str(source.id),
-                mainline=Selector()
-                .land(protocol.land.name)
-                .group(str(raw["sender"]["group"]["id"]))
-                .member(str(raw["sender"]["id"])),
-                sender=Selector()
-                .land(protocol.land.name)
-                .group(str(raw["sender"]["group"]["id"]))
-                .member(str(raw["sender"]["id"])),
-                content=MessageChain(await protocol.message_deserializer.parse_sentence(protocol, message_chain)),
-                time=datetime.fromtimestamp(source.time),
-                reply=Selector()
-                .land(protocol.land.name)
-                .group(str(raw["sender"]["group"]["id"]))
-                .member(str(raw["sender"]["id"]))
-                .message(str(quote.id))
-                if quote is not None
-                else None,
-            ),
-            account=account,
-        )
diff --git a/avilla/elizabeth/impl/__init__.py b/avilla/elizabeth/impl/__init__.py
index 7f9c39c3..2928f366 100644
--- a/avilla/elizabeth/impl/__init__.py
+++ b/avilla/elizabeth/impl/__init__.py
@@ -4,31 +4,36 @@
 
 from graia.amnesia.builtins.aiohttp import AiohttpClientInterface
 
-from avilla.core.trait.context import prefix, raise_for_no_namespace, scope
-from avilla.core.trait.recorder import completes, default_target, fetch, impl, pull
-from avilla.core.utilles.selector import Selector
-from avilla.elizabeth.resource import ElizabethAudioResource, ElizabethImageResource
+from avilla.core.trait.context import bounds, fetch, get_artifacts
+from avilla.core.trait.signature import CompleteRule
+from avilla.elizabeth.resource import (
+    ElizabethAudioResource,
+    ElizabethImageResource,
+    ElizabethResource,
+)
 
 # from graia.amnesia.transport.common.http import AbstractClientInterface
 
 
 if TYPE_CHECKING:
-    from avilla.core.relationship import Relationship
+    from avilla.core.context import Context
 
-raise_for_no_namespace()
+# raise_for_no_namespace()
 
 # Relationship Complete
 
-with scope("group"), prefix("group"):
-    completes("member", "group.member")
+# with scope("group"), prefix("group"):
+#     completes("member", "group.member")
+with bounds("group"):
+    get_artifacts().setdefault(CompleteRule("member"), "group.member")
 
 
-@fetch(ElizabethImageResource)
+@fetch(ElizabethImageResource)  # type: ignore
 @fetch(ElizabethAudioResource)
-async def fetch_from_url(rs: Relationship, res: ElizabethAudioResource | ElizabethImageResource) -> bytes:
+async def fetch_from_url(ctx: Context, res: ElizabethResource) -> bytes:
     if not res.url:
         raise NotImplementedError
-    print(rs.avilla.launch_manager._service_bind)
-    client = rs.avilla.launch_manager.get_interface(AiohttpClientInterface)
+    # print(ctx.avilla.launch_manager._service_bind)
+    client = ctx.avilla.launch_manager.get_interface(AiohttpClientInterface)
     # NOTE: wait for amnesia's fix on this.
     return await (await client.request("GET", res.url)).io().read()
diff --git a/avilla/elizabeth/impl/friend.py b/avilla/elizabeth/impl/friend.py
index 3fec0dab..96c0cc81 100644
--- a/avilla/elizabeth/impl/friend.py
+++ b/avilla/elizabeth/impl/friend.py
@@ -1,36 +1,35 @@
 from __future__ import annotations
 
+from datetime import datetime
 from typing import TYPE_CHECKING
 
-from avilla.core.message import Message
-from avilla.core.skeleton.message import MessageRevoke, MessageSend
-from avilla.core.trait.context import prefix, raise_for_no_namespace, scope
-from avilla.core.trait.recorder import casts, default_target, impl, pull
-from avilla.core.utilles.selector import Selector
+from avilla.core.selector import Selector
+from avilla.core.trait.context import bounds, implement
+from avilla.spec.core.message import MessageRevoke, MessageSend
 
-if TYPE_CHECKING:
-    from graia.amnesia.message import MessageChain
+from ...core.message import Message
 
-    from avilla.core.relationship import Relationship
+if TYPE_CHECKING:
+    from graia.amnesia.message import __message_chain_class__
 
+    from avilla.core.context import Context
 
-raise_for_no_namespace()
+    from ..protocol import ElizabethProtocol
 
-with scope("qq", "friend"), prefix("friend"):
 
-    casts(MessageSend)
-    casts(MessageRevoke)
+with bounds("friend"):
 
-    @default_target(MessageSend.send)
-    def send_friend_message_default_target(rs: Relationship):
-        return rs.ctx
+    # casts(MessageSend)
+    # casts(MessageRevoke)
 
-    @impl(MessageSend.send)
+    @implement(MessageSend.send)
     async def send_friend_message(
-        rs: Relationship, target: Selector, message: MessageChain, *, reply: Selector | None = None
+        ctx: Context, target: Selector, message: __message_chain_class__, *, reply: Selector | None = None
     ) -> Selector:
-        serialized_msg = await rs.protocol.serialize_message(message)
-        result = await rs.account.call(
+        if TYPE_CHECKING:
+            assert isinstance(ctx.protocol, ElizabethProtocol)
+        serialized_msg = await ctx.protocol.serialize_message(message)
+        result = await ctx.account.call(
             "sendFriendMessage",
             {
                 "__method__": "post",
@@ -39,11 +38,21 @@ async def send_friend_message(
                 **({"quote": reply.pattern["message"]} if reply is not None else {}),
             },
         )
-        return Selector().land(rs.land).group(target.pattern["friend"]).message(result["messageId"])
+        message_metadata = Message(
+            describe=Message,
+            id=str(result["messageId"]),
+            scene=Selector().land(ctx.land).friend(str(target.pattern["friend"])),
+            content=message,
+            time=datetime.now(),
+            sender=ctx.account.to_selector(),
+        )
+        message_selector = message_metadata.to_selector()
+        ctx._collect_metadatas(message_selector, message_metadata)
+        return message_selector
 
-    @impl(MessageRevoke.revoke)
-    async def revoke_friend_message(rs: Relationship, message: Selector):
-        await rs.account.call(
+    @implement(MessageRevoke.revoke)
+    async def revoke_friend_message(ctx: Context, message: Selector):
+        await ctx.account.call(
             "recall",
             {
                 "__method__": "post",
diff --git a/avilla/elizabeth/impl/group.py b/avilla/elizabeth/impl/group.py
index 5e536386..f8df1746 100644
--- a/avilla/elizabeth/impl/group.py
+++ b/avilla/elizabeth/impl/group.py
@@ -1,46 +1,45 @@
 from __future__ import annotations
 
 from collections import defaultdict
-from datetime import timedelta
+from datetime import datetime, timedelta
 from typing import TYPE_CHECKING
 
-from avilla.core.cell.cells import Nick, Privilege, Summary
 from avilla.core.exceptions import permission_error_message
 from avilla.core.message import Message
-from avilla.core.skeleton.message import MessageRevoke, MessageSend
-from avilla.core.skeleton.privilege import MuteAllTrait, MuteTrait
-from avilla.core.skeleton.scene import SceneTrait
-from avilla.core.skeleton.summary import SummaryTrait
-from avilla.core.trait.context import prefix, raise_for_no_namespace, scope
-from avilla.core.trait.recorder import casts, default_target, impl, pull, query
-from avilla.core.utilles.selector import Selector
+from avilla.core.selector import Selector
+from avilla.core.trait.context import bounds, implement, pull
+from avilla.spec.core.message import MessageRevoke, MessageSend
+from avilla.spec.core.privilege import MuteAllTrait, MuteTrait, Privilege
+from avilla.spec.core.profile import Nick, Summary, SummaryTrait
+from avilla.spec.core.scene import SceneTrait
+
+from ...core.metadata import MetadataOf
 
 if TYPE_CHECKING:
-    from graia.amnesia.message import MessageChain
+    from graia.amnesia.message import __message_chain_class__
 
-    from avilla.core.relationship import Relationship
+    from avilla.core.context import Context
 
-raise_for_no_namespace()
+    from ..protocol import ElizabethProtocol
 
-with scope("qq", "group"), prefix("group"):
 
-    casts(MessageSend)
-    casts(MessageRevoke)
-    casts(MuteTrait)
-    casts(MuteAllTrait)
-    casts(SceneTrait)
-    casts(SummaryTrait)
+with bounds("group"):
 
-    @default_target(MessageSend.send)
-    def send_group_message_default_target(rs: Relationship):
-        return rs.mainline
+    # casts(MessageSend)
+    # casts(MessageRevoke)
+    # casts(MuteTrait)
+    # casts(MuteAllTrait)
+    # casts(SceneTrait)
+    # casts(SummaryTrait)
 
-    @impl(MessageSend.send)
+    @implement(MessageSend.send)
     async def send_group_message(
-        rs: Relationship, target: Selector, message: MessageChain, *, reply: Selector | None = None
+        ctx: Context, target: Selector, message: __message_chain_class__, *, reply: Selector | None = None
     ) -> Selector:
-        serialized_msg = await rs.protocol.serialize_message(message)
-        result = await rs.account.call(
+        if TYPE_CHECKING:
+            assert isinstance(ctx.protocol, ElizabethProtocol)
+        serialized_msg = await ctx.protocol.serialize_message(message)
+        result = await ctx.account.call(
             "sendGroupMessage",
             {
                 "__method__": "update",
@@ -49,11 +48,21 @@ async def send_group_message(
                 **({"quote": reply.pattern["message"]} if reply is not None else {}),
             },
         )
-        return Selector().land(rs.land).group(target.pattern["group"]).message(result["messageId"])
+        message_metadata = Message(
+            describe=Message,
+            id=str(result["messageId"]),
+            scene=Selector().land(ctx.land).group(str(target.pattern["group"])),
+            content=message,
+            time=datetime.now(),
+            sender=Selector().land(ctx.land).group(str(target.pattern["group"])).member(ctx.account.id),
+        )
+        message_selector = message_metadata.to_selector()
+        ctx._collect_metadatas(message_selector, message_metadata)
+        return message_selector
 
-    @impl(MessageRevoke.revoke)
-    async def revoke_group_message(rs: Relationship, message: Selector):
-        await rs.account.call(
+    @implement(MessageRevoke.revoke)
+    async def revoke_group_message(ctx: Context, message: Selector):
+        await ctx.account.call(
             "recall",
             {
                 "__method__": "update",
@@ -62,11 +71,11 @@ async def revoke_group_message(rs: Relationship, message: Selector):
             },
         )
 
-    @impl(MuteTrait.mute)
-    async def mute_member(rs: Relationship, target: Selector, duration: timedelta):
-        privilege_info = await rs.pull(Privilege, target)
+    @implement(MuteTrait.mute)
+    async def mute_member(ctx: Context, target: Selector, duration: timedelta):
+        privilege_info = await ctx.pull(Privilege, target)
         if not privilege_info.effective:
-            self_privilege_info = await rs.pull(Privilege >> Summary, rs.self)
+            self_privilege_info = await ctx.pull(Privilege >> Summary, ctx.self)
             raise PermissionError(
                 permission_error_message(
                     f"Mute.mute@{target.path}", self_privilege_info.name, ["group_owner", "group_admin"]
@@ -75,7 +84,7 @@ async def mute_member(rs: Relationship, target: Selector, duration: timedelta):
         time = max(0, min(int(duration.total_seconds()), 2592000))  # Fix time parameter
         if not time:
             return
-        await rs.account.call(
+        await ctx.account.call(
             "mute",
             {
                 "__method__": "update",
@@ -85,17 +94,17 @@ async def mute_member(rs: Relationship, target: Selector, duration: timedelta):
             },
         )
 
-    @impl(MuteTrait.unmute)
-    async def unmute_member(rs: Relationship, target: Selector):
-        privilege_info = await rs.pull(Privilege, target)
+    @implement(MuteTrait.unmute)
+    async def unmute_member(ctx: Context, target: Selector):
+        privilege_info = await ctx.pull(Privilege, target)
         if not privilege_info.effective:
-            self_privilege_info = await rs.pull(Privilege >> Summary, rs.self)
+            self_privilege_info = await ctx.pull(Privilege >> Summary, ctx.self)
             raise PermissionError(
                 permission_error_message(
                     f"Mute.unmute@{target.path}", self_privilege_info.name, ["group_owner", "group_admin"]
                 )
             )
-        await rs.account.call(
+        await ctx.account.call(
             "unmute",
             {
                 "__method__": "update",
@@ -104,9 +113,9 @@ async def unmute_member(rs: Relationship, target: Selector):
             },
         )
 
-    @impl(MuteAllTrait.mute_all)
-    async def group_mute_all(rs: Relationship, target: Selector):
-        await rs.account.call(
+    @implement(MuteAllTrait.mute_all)
+    async def group_mute_all(ctx: Context, target: Selector):
+        await ctx.account.call(
             "muteAll",
             {
                 "__method__": "update",
@@ -114,9 +123,9 @@ async def group_mute_all(rs: Relationship, target: Selector):
             },
         )
 
-    @impl(MuteAllTrait.unmute_all)
-    async def group_unmute_all(rs: Relationship, target: Selector):
-        await rs.account.call(
+    @implement(MuteAllTrait.unmute_all)
+    async def group_unmute_all(ctx: Context, target: Selector):
+        await ctx.account.call(
             "unmuteAll",
             {
                 "__method__": "update",
@@ -124,44 +133,47 @@ async def group_unmute_all(rs: Relationship, target: Selector):
             },
         )
 
-    @impl(SceneTrait.leave).pin("group")
-    async def leave(rs: Relationship, target: Selector):
-        await rs.account.call("quit", {"__method__": "update", "target": int(target.pattern["group"])})
+    @implement(SceneTrait.leave)
+    async def leave(ctx: Context, target: Selector):
+        await ctx.account.call("quit", {"__method__": "update", "target": int(target.pattern["group"])})
 
-    @impl(SceneTrait.remove_member)
-    async def remove_member(rs: Relationship, target: Selector, reason: str | None = None):
-        privilege_info = await rs.pull(Privilege, target)
+    @implement(SceneTrait.remove_member)
+    async def remove_member(ctx: Context, target: Selector, reason: str | None = None):
+        privilege_info = await ctx.pull(Privilege, target)
         if not privilege_info.effective:
             raise PermissionError()  # TODO: error message, including Summary info
-        await rs.account.call(
+        await ctx.account.call(
             "kick",
             {"__method__": "update", "target": int(target.pattern["group"]), "memberId": int(target.pattern["member"])},
         )
 
-    @pull(Summary).of("group")
-    async def get_summary(rs: Relationship, target: Selector | None) -> Summary:
+    @pull(Summary)
+    async def get_summary(ctx: Context, target: Selector | None) -> Summary:
         assert target is not None
-        result = await rs.account.call(
+        result = await ctx.account.call(
             "groupConfig",
             {"__method__": "fetch", "target": int(target.pattern["group"])},
         )
         return Summary(describe=Summary, name=result["name"], description=None)
 
-    @impl(SummaryTrait.set_name).pin("group")
-    async def group_set_name(rs: Relationship, target: Selector, name: str):
-        await rs.account.call(
+    @implement(SummaryTrait.set_name)
+    async def group_set_name(ctx: Context, target: Selector | MetadataOf, name: str):
+        SummaryTrait.set_name.assert_entity(target)
+        if TYPE_CHECKING:
+            assert isinstance(target, Selector)
+        await ctx.account.call(
             "groupConfig",
             {"__method__": "update", "target": int(target.pattern["group"]), "config": {"name": name}},
         )
 
-    @pull(Privilege).of("group.member")
-    async def group_get_privilege_info(rs: Relationship, target: Selector | None) -> Privilege:
-        self_info = await rs.account.call(
+    @pull(Privilege)
+    async def group_get_privilege_info(ctx: Context, target: Selector | None) -> Privilege:
+        self_info = await ctx.account.call(
             "memberInfo",
             {
                 "__method__": "fetch",
-                "target": int(rs.self.pattern["group"]),
-                "memberId": int(rs.self.pattern["member"]),
+                "target": int(ctx.self.pattern["group"]),
+                "memberId": int(ctx.self.pattern["member"]),
             },
         )
         if target is None:
@@ -170,7 +182,7 @@ async def group_get_privilege_info(rs: Relationship, target: Selector | None) ->
                 self_info["permission"] in {"OWNER", "ADMINISTRATOR"},
                 self_info["permission"] in {"OWNER", "ADMINISTRATOR"},
             )
-        target_info = await rs.account.call(
+        target_info = await ctx.account.call(
             "memberInfo",
             {"__method__": "fetch", "target": int(target.pattern["group"]), "memberId": int(target.pattern["member"])},
         )
@@ -184,17 +196,20 @@ async def group_get_privilege_info(rs: Relationship, target: Selector | None) ->
             ),
         )
 
-    @pull(Privilege >> Summary).of("group.member")
-    async def group_get_privilege_summary_info(rs: Relationship, target: Selector | None) -> Summary:
+
+with bounds("group.member"):
+
+    @pull(Privilege >> Summary)
+    async def group_get_privilege_summary_info(ctx: Context, target: Selector | None) -> Summary:
         privilege_trans = defaultdict(lambda: "group_member", {"OWNER": "group_owner", "ADMINISTRATOR": "group_admin"})
 
         if target is None:
-            self_info = await rs.account.call(
+            self_info = await ctx.account.call(
                 "memberInfo",
                 {
                     "__method__": "fetch",
-                    "target": int(rs.self.pattern["group"]),
-                    "memberId": int(rs.self.pattern["member"]),
+                    "target": int(ctx.self.pattern["group"]),
+                    "memberId": int(ctx.self.pattern["member"]),
                 },
             )
             return Summary(
@@ -202,7 +217,7 @@ async def group_get_privilege_summary_info(rs: Relationship, target: Selector |
                 privilege_trans[self_info["permission"]],
                 "the permission info of current account in the group",
             )
-        target_info = await rs.account.call(
+        target_info = await ctx.account.call(
             "memberInfo",
             {"__method__": "fetch", "target": int(target.pattern["group"]), "memberId": int(target.pattern["member"])},
         )
@@ -212,29 +227,32 @@ async def group_get_privilege_summary_info(rs: Relationship, target: Selector |
             "the permission info of current account in the group",
         )
 
-    @pull(Nick).of("group.member")
-    async def get_member_nick(rs: Relationship, target: Selector | None) -> Nick:
+    @pull(Nick)
+    async def get_member_nick(ctx: Context, target: Selector | None) -> Nick:
         assert target is not None
-        result = await rs.account.call(
+        result = await ctx.account.call(
             "memberInfo",
             {"__method__": "fetch", "target": int(target.pattern["group"]), "memberId": int(target.pattern["member"])},
         )
         return Nick(Nick, result["memberName"], result["memberName"], result["specialTitle"])
 
+
+"""
     @query(None, "group")
-    async def get_groups(rs: Relationship, upper: None, predicate: Selector):
-        result: list[dict] = await rs.account.call("groupList", {"__method__": "fetch"})
+    async def get_groups(ctx: Context, upper: None, predicate: Selector):
+        result: list[dict] = await ctx.account.call("groupList", {"__method__": "fetch"})
         for i in result:
             group = Selector().group(str(i["id"]))
             if predicate.match(group):
                 yield group
 
     @query("group", "member")
-    async def get_group_members(rs: Relationship, upper: Selector, predicate: Selector):
-        result: list[dict] = await rs.account.call(
+    async def get_group_members(ctx: Context, upper: Selector, predicate: Selector):
+        result: list[dict] = await ctx.account.call(
             "memberList", {"__method__": "fetch", "target": int(upper.pattern["group"])}
         )
         for i in result:
             member = Selector().group(str(i["group"]["id"])).member(str(i["id"]))
             if predicate.match(member):
                 yield member
+"""
diff --git a/avilla/elizabeth/message_deserializer.py b/avilla/elizabeth/message_deserializer.py
deleted file mode 100644
index 39262806..00000000
--- a/avilla/elizabeth/message_deserializer.py
+++ /dev/null
@@ -1,48 +0,0 @@
-from __future__ import annotations
-
-from typing import TYPE_CHECKING
-
-from graia.amnesia.message.element import Text
-
-from avilla.core.elements import Audio, Notice, NoticeAll, Picture
-from avilla.core.utilles.message_deserializer import MessageDeserializer, deserializer
-from avilla.core.utilles.selector import Selector
-from avilla.elizabeth.element import FlashImage
-from avilla.elizabeth.resource import ElizabethAudioResource, ElizabethImageResource
-
-if TYPE_CHECKING:
-    from .protocol import ElizabethProtocol
-
-
-class ElizabethMessageDeserializer(MessageDeserializer["ElizabethProtocol"]):
-    ignored_types: set[str] = {"Source", "Quote"}
-
-    def get_element_type(self, raw: dict) -> str:
-        return raw["type"]
-
-    @deserializer("Plain")
-    def plain(self, protocol: "ElizabethProtocol", raw: dict):
-        return Text(raw["text"])
-
-    @deserializer("At")
-    def at(self, protocol: "ElizabethProtocol", raw: dict):
-        return Notice(Selector().contact(raw["target"]))  # 请使用 rs.complete.
-
-    @deserializer("AtAll")
-    def at_all(self, protocol: "ElizabethProtocol", raw: dict):
-        return NoticeAll()
-
-    @deserializer("Image")
-    def image(self, protocol: "ElizabethProtocol", raw: dict):
-        # mainline 后续修饰
-        return Picture(ElizabethImageResource(raw["imageId"], raw["url"], raw["path"], raw["base64"]))
-
-    @deserializer("FlashImage")
-    def flash_image(self, protocol: "ElizabethProtocol", raw: dict):
-        return FlashImage(ElizabethImageResource(raw["imageId"], raw["url"], raw["path"], raw["base64"]))
-
-    @deserializer("Voice")
-    def voice(self, protocol: "ElizabethProtocol", raw: dict):
-        return Audio(ElizabethAudioResource(raw["voiceId"], raw["url"], raw["path"], raw["base64"], raw["length"]))
-
-    # TODO: 更多的消息元素支持
diff --git a/avilla/elizabeth/message_parse.py b/avilla/elizabeth/message_parse.py
new file mode 100644
index 00000000..6e1952c0
--- /dev/null
+++ b/avilla/elizabeth/message_parse.py
@@ -0,0 +1,42 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from graia.amnesia.message.element import Text
+
+from avilla.core.elements import Audio, Notice, NoticeAll, Picture
+
+from .resource import ElizabethAudioResource, ElizabethImageResource
+from .util import element
+
+if TYPE_CHECKING:
+    from avilla.core.context import Context
+
+
+@element("Plain")
+async def plain(context: Context, raw: dict):
+    return Text(raw["text"])
+
+
+@element("At")
+async def at(context: Context, raw: dict):
+    if not context.scene.follows("group"):
+        raise ValueError(f"At(Notice) element expected used in group scene, which currently {context.scene}")
+    return Notice(context.scene.member(raw["target"]))
+
+
+@element("AtAll")
+async def at_all(context: Context, raw: dict):
+    return NoticeAll()
+
+
+@element("Image")
+async def image(context: Context, raw: dict):
+    return Picture(ElizabethImageResource(raw["imageId"], raw["url"], raw["path"], raw["base64"], context.scene))
+
+
+@element("Voice")
+async def voice(context: Context, raw: dict):
+    return Audio(
+        ElizabethAudioResource(raw["voiceId"], raw["url"], raw["path"], raw["base64"], raw["length"], context.scene)
+    )
diff --git a/avilla/elizabeth/message_serializer.py b/avilla/elizabeth/message_serializer.py
deleted file mode 100644
index b8bf3750..00000000
--- a/avilla/elizabeth/message_serializer.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from __future__ import annotations
-
-import base64
-from typing import TYPE_CHECKING
-
-from graia.amnesia.message.element import Text
-
-from avilla.core.context import ctx_relationship
-from avilla.core.elements import Audio, Notice, NoticeAll, Picture
-from avilla.core.utilles.message_serializer import MessageSerializer, element
-from avilla.elizabeth.element import FlashImage
-
-if TYPE_CHECKING:
-    from .protocol import ElizabethProtocol
-
-
-class ElizabethMessageSerializer(MessageSerializer["ElizabethProtocol"]):
-    @element(Text)
-    def plain(self, protocol: "ElizabethProtocol", element: Text):
-        return {"type": "Plain", "text": element.text}
-
-    @element(Notice)
-    def at(self, protocol: "ElizabethProtocol", element: Notice):
-        return {"type": "At", "target": element.target.id}
-
-    @element(NoticeAll)
-    def at_all(self, protocol: "ElizabethProtocol", element: NoticeAll):
-        return {"type": "AtAll"}
-
-    @element(Picture)
-    async def image(self, protocol: "ElizabethProtocol", element: Picture):
-        raw = await ctx_relationship.get().fetch(element.resource)
-        return {
-            "type": "Image",
-            "base64": base64.b64encode(raw).decode("utf-8"),
-        }
-
-    @element(FlashImage)
-    async def flash_image(self, protocol: "ElizabethProtocol", element: FlashImage):
-        raw = await ctx_relationship.get().fetch(element.resource)
-        return {
-            "type": "FlashImage",
-            "base64": base64.b64encode(raw).decode("utf-8"),
-        }
-
-    @element(Audio)
-    async def voice(self, protocol: "ElizabethProtocol", element: Audio):
-        raw = await ctx_relationship.get().fetch(element.resource)
-        return {"type": "Voice", "base64": base64.b64encode(raw).decode("utf-8")}
diff --git a/avilla/elizabeth/protocol.py b/avilla/elizabeth/protocol.py
index 2b69e71c..e0129ec3 100644
--- a/avilla/elizabeth/protocol.py
+++ b/avilla/elizabeth/protocol.py
@@ -1,18 +1,33 @@
 from __future__ import annotations
 
-from typing import ClassVar
+import base64
+from datetime import datetime
+from typing import Any, TypedDict, cast
+
+from graia.amnesia.message import __message_chain_class__
+from graia.amnesia.message.element import Element, Text
 
 from avilla.core.application import Avilla
+from avilla.core.elements import Audio, Notice, NoticeAll, Picture
 from avilla.core.platform import Abstract, Land, Platform
 from avilla.core.protocol import BaseProtocol
-from avilla.core.trait.context import wrap_namespace
-from avilla.core.utilles.selector import Selector
+from avilla.core.trait.context import wrap_artifacts
 from avilla.elizabeth.connection.config import U_Config
-from avilla.elizabeth.event_parser import ElizabethEventParser
-from avilla.elizabeth.message_deserializer import ElizabethMessageDeserializer
-from avilla.elizabeth.message_serializer import ElizabethMessageSerializer
 from avilla.elizabeth.service import ElizabethService
 
+from ..core.context import Context
+from ..core.event import AvillaEvent
+from ..spec.qq.elements import FlashImage
+from .account import ElizabethAccount
+from .util import ElementParse, ElementParser, EventParse, EventParser
+
+
+class MessageDeserializeResult(TypedDict):
+    content: list[Element]
+    source: str
+    time: datetime
+    reply: str | None
+
 
 class ElizabethProtocol(BaseProtocol):
     platform = Platform(
@@ -32,21 +47,18 @@ class ElizabethProtocol(BaseProtocol):
             humanized_name="Elizabeth - mirai-api-http for avilla",
         ),
     )
-    event_parser = ElizabethEventParser()
-    message_serializer = ElizabethMessageSerializer()
-    message_deserializer = ElizabethMessageDeserializer()
-    """
-    query_handlers: ClassVar[list[type[ProtocolAbstractQueryHandler]]] = [
-        ElizabethGroupQuery,
-        ElizabethRootQuery,
-    ]
-    """
-
-    with wrap_namespace() as impl_namespace:
+
+    with wrap_artifacts() as implementations:
         import avilla.elizabeth.impl as _
         import avilla.elizabeth.impl.friend as _
         import avilla.elizabeth.impl.group as _
 
+    with wrap_artifacts() as event_parsers:
+        import avilla.elizabeth.event.message as _
+
+    with wrap_artifacts() as message_parsers:
+        import avilla.elizabeth.message_parse as _
+
     service: ElizabethService
 
     def __init__(self, *config: U_Config):
@@ -64,3 +76,67 @@ def ensure(self, avilla: Avilla):
             avilla.launch_manager.add_launchable(connection)
 
             # LINK: see avilla.elizabeth.connection.{http|ws} for hot registration
+
+    async def serialize_message(self, message: __message_chain_class__, context: Context | None = None):
+        result = []
+        for element in message.content:
+            if isinstance(element, Text):
+                result.append({"type": "Plain", "text": element.text})
+            elif isinstance(element, Notice):
+                result.append({"type": "At", "target": int(element.target.last_value)})
+            elif isinstance(element, NoticeAll):
+                result.append({"type": "AtAll"})
+            elif isinstance(element, Picture):
+                raw = await (context or Context.current).fetch(element.resource)
+                result.append(
+                    {
+                        "type": "Image",
+                        "base64": base64.b64encode(raw).decode("utf-8"),
+                    }
+                )
+            elif isinstance(element, FlashImage):
+                raw = await (context or Context.current).fetch(element.resource)
+                result.append(
+                    {
+                        "type": "FlashImage",
+                        "base64": base64.b64encode(raw).decode("utf-8"),
+                    }
+                )
+            elif isinstance(element, Audio):
+                raw = await (context or Context.current).fetch(element.resource)
+                result.append(
+                    {
+                        "type": "Voice",
+                        "base64": base64.b64encode(raw).decode("utf-8"),
+                    }
+                )
+        return result
+
+    async def deserialize_message(self, context: Context, message: list[dict]):
+        serialized: list[Element] = []
+        result: dict[str, Any] = {
+            "content": serialized,
+            "source": str(message[0]["id"]),
+            "time": datetime.fromtimestamp(message[0]["time"]),
+        }
+        for raw_element in message[1:]:
+            if "type" not in raw_element:
+                raise KeyError(f'expected "type" exists for {raw_element}')
+            element_type = raw_element["type"]
+            if element_type == "Quote":
+                result["reply"] = str(raw_element["id"])
+                continue
+            parser: ElementParser | None = self.message_parsers.get(ElementParse(element_type))
+            if parser is None:
+                raise NotImplementedError(f'expected element "{element_type}" implemented for {raw_element}')
+            serialized.append(await parser(context, raw_element))
+        return cast("MessageDeserializeResult", result)
+
+    async def parse_event(self, account: ElizabethAccount, event: dict) -> tuple[AvillaEvent, Context]:
+        if "type" not in event:
+            raise KeyError(f'expected "type" exists for {event}')
+        event_type = event["type"]
+        parser: EventParser | None = self.event_parsers.get(EventParse(event_type))
+        if parser is None:
+            raise NotImplementedError(f'expected event "{event_type}" implemented for {event}')
+        return await parser(self, account, event)
diff --git a/avilla/elizabeth/resource.py b/avilla/elizabeth/resource.py
index f27a5097..afe0f12e 100644
--- a/avilla/elizabeth/resource.py
+++ b/avilla/elizabeth/resource.py
@@ -1,14 +1,14 @@
 from __future__ import annotations
 
 from avilla.core.resource import Resource
-from avilla.core.utilles.selector import Selector
+from avilla.core.selector import Selector
 
 
 class ElizabethResource(Resource[bytes]):
     url: str | None = None
     path: str | None = None
     base64: str | None = None
-    mainline: Selector | None = None
+    scene: Selector | None = None
 
     def __init__(
         self,
@@ -16,13 +16,13 @@ def __init__(
         url: str | None = None,
         path: str | None = None,
         base64: str | None = None,
-        mainline: Selector | None = None,
+        scene: Selector | None = None,
     ) -> None:
         self.id = id
         self.url = url
         self.path = path
         self.base64 = base64
-        self.mainline = mainline
+        self.scene = scene
 
     @property
     def type(self) -> str:
@@ -30,7 +30,7 @@ def type(self) -> str:
 
     @property
     def selector(self) -> Selector:
-        return (self.mainline.copy() if self.mainline is not None else Selector()).appendix(self.type, self.id)
+        return (self.scene or Selector()).appendix(self.type, self.id)
 
 
 class ElizabethImageResource(ElizabethResource):
@@ -48,10 +48,10 @@ def __init__(
         url: str | None = None,
         path: str | None = None,
         base64: str | None = None,
-        mainline: Selector | None = None,
         length: int | None = None,
+        scene: Selector | None = None,
     ) -> None:
-        super().__init__(id, url, path, base64, mainline)
+        super().__init__(id, url, path, base64, scene)
         self.length = length
 
     @property
diff --git a/avilla/elizabeth/service.py b/avilla/elizabeth/service.py
index ee0a4a5e..9e6ba599 100644
--- a/avilla/elizabeth/service.py
+++ b/avilla/elizabeth/service.py
@@ -3,10 +3,9 @@
 import asyncio
 from typing import TYPE_CHECKING
 
+from graia.amnesia.transport.common.client import AbstractClientInterface
 from launart import Launart, Service
 
-from avilla.elizabeth.account import ElizabethAccount
-
 from .connection import ElizabethConnection
 from .connection.config import U_Config
 
@@ -38,7 +37,7 @@ def get_connection(self, account_id: str):
     async def launch(self, manager: Launart):
         async with self.stage("preparing"):
             # TODO: lifecycle event for account
-            # 主要有几点 - 配置的读取, 应用; 子任务(Launchable) 的堵塞 - 这个交给 blocking;
+            # 主要有几点 - 配置的读取，应用; 子任务 (Launchable) 的堵塞 - 这个交给 blocking;
             ...
 
         async with self.stage("blocking"):
@@ -54,8 +53,8 @@ async def launch(self, manager: Launart):
             ...  # TODO
 
     @property
-    def required(self) -> set[str]:
-        return {"http.universal_client"}
+    def required(self):
+        return {AbstractClientInterface}
 
     @property
     def stages(self):
diff --git a/avilla/elizabeth/util/__init__.py b/avilla/elizabeth/util/__init__.py
new file mode 100644
index 00000000..39179c44
--- /dev/null
+++ b/avilla/elizabeth/util/__init__.py
@@ -0,0 +1,51 @@
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, Awaitable, Callable
+
+from graia.amnesia.message.element import Element
+from typing_extensions import TypeAlias
+
+from avilla.core.context import Context
+from avilla.core.event import AvillaEvent
+
+from ...core.trait.context import get_artifacts
+from ...core.trait.signature import ArtifactSignature
+
+if TYPE_CHECKING:
+    from ..account import ElizabethAccount
+    from ..protocol import ElizabethProtocol
+
+
+@dataclass(unsafe_hash=True)
+class EventParse(ArtifactSignature):
+    event_type: str
+
+
+EventParser: TypeAlias = Callable[
+    ["ElizabethProtocol", "ElizabethAccount", dict], Awaitable[tuple[AvillaEvent, Context]]
+]
+
+
+def event(event_type: str):
+    def wrapper(handler: EventParser):
+        artifacts = get_artifacts()
+        artifacts[EventParse(event_type)] = handler
+        return handler
+
+    return wrapper
+
+
+@dataclass(unsafe_hash=True)
+class ElementParse(ArtifactSignature):
+    element_type: str
+
+
+ElementParser: TypeAlias = Callable[[Context, dict], Awaitable[Element]]
+
+
+def element(element_type: str):
+    def wrapper(handler: ElementParser):
+        artifacts = get_artifacts()
+        artifacts[ElementParse(element_type)] = handler
+        return handler
+
+    return wrapper
diff --git a/avilla/core/builtins/extension.py b/avilla/spec/core/account/__init__.py
similarity index 100%
rename from avilla/core/builtins/extension.py
rename to avilla/spec/core/account/__init__.py
diff --git a/avilla/spec/core/activity/__init__.py b/avilla/spec/core/activity/__init__.py
new file mode 100644
index 00000000..abde8285
--- /dev/null
+++ b/avilla/spec/core/activity/__init__.py
@@ -0,0 +1,4 @@
+from .event import ActivityAvailable as ActivityAvailable
+from .event import ActivityEvent as ActivityEvent
+from .event import ActivityTrigged as ActivityTrigged
+from .event import ActivityUnavailable as ActivityUnavailable
diff --git a/avilla/core/event/activity.py b/avilla/spec/core/activity/event.py
similarity index 60%
rename from avilla/core/event/activity.py
rename to avilla/spec/core/activity/event.py
index 9f9f84dd..d2c2f7ee 100644
--- a/avilla/core/event/activity.py
+++ b/avilla/spec/core/activity/event.py
@@ -1,27 +1,23 @@
 from __future__ import annotations
 
+from dataclasses import dataclass
 from typing import TYPE_CHECKING
 
-from graia.broadcast.entities.dispatcher import BaseDispatcher
-
 from avilla.core.event import AvillaEvent
-from avilla.core.utilles.selector import Selector
+from avilla.core.selector import Selector
 
 if TYPE_CHECKING:
     from graia.broadcast.interfaces.dispatcher import DispatcherInterface
 
 
+@dataclass
 class ActivityEvent(AvillaEvent):
     id: Selector  # eg. [...].activity("button_clicked")
     activity: Selector  # eg. [...].button("#1")
 
-    @property
-    def ctx(self):
-        return self.activity
-
-    class Dispatcher(BaseDispatcher):
+    class Dispatcher(AvillaEvent.Dispatcher):
         @staticmethod
-        async def catch(interface: 'DispatcherInterface[ActivityEvent]'):
+        async def catch(interface: DispatcherInterface[ActivityEvent]):
             ...
 
 
@@ -35,8 +31,4 @@ class ActivityUnavailable(ActivityEvent):
 
 class ActivityTrigged(ActivityEvent):
     trigger: Selector  # who trigged the activity
-    mainline: Selector
-
-    @property
-    def ctx(self):
-        return self.trigger
+    scene: Selector
diff --git a/avilla/spec/core/application/__init__.py b/avilla/spec/core/application/__init__.py
new file mode 100644
index 00000000..71544572
--- /dev/null
+++ b/avilla/spec/core/application/__init__.py
@@ -0,0 +1,8 @@
+from .event import AccountAvailable as AccountAvailable
+from .event import AccountStatusChanged as AccountStatusChanged
+from .event import AccountUnavailable as AccountUnavailable
+from .event import ApplicationClosed as ApplicationClosed
+from .event import ApplicationClosing as ApplicationClosing
+from .event import ApplicationPreparing as ApplicationPreparing
+from .event import ApplicationReady as ApplicationReady
+from .event import AvillaLifecycleEvent as AvillaLifecycleEvent
diff --git a/avilla/core/event/lifecycle.py b/avilla/spec/core/application/event.py
similarity index 79%
rename from avilla/core/event/lifecycle.py
rename to avilla/spec/core/application/event.py
index 58f04e36..52867875 100644
--- a/avilla/core/event/lifecycle.py
+++ b/avilla/spec/core/application/event.py
@@ -8,8 +8,8 @@
 from graia.broadcast.interfaces.dispatcher import DispatcherInterface
 
 if TYPE_CHECKING:
-    from ..account import AbstractAccount
-    from ..application import Avilla
+    from avilla.core.account import AbstractAccount
+    from avilla.core.application import Avilla
 
 
 @dataclass
@@ -20,8 +20,8 @@ class AvillaLifecycleEvent(Dispatchable):
 
     class Dispatcher(BaseDispatcher):
         @classmethod
-        async def catch(cls, interface: "DispatcherInterface[AvillaLifecycleEvent]"):
-            from ..application import Avilla
+        async def catch(cls, interface: DispatcherInterface[AvillaLifecycleEvent]):
+            from avilla.core.application import Avilla
 
             if interface.annotation is Avilla:
                 return interface.event.avilla
@@ -51,8 +51,8 @@ class AccountStatusChanged(AvillaLifecycleEvent):
 
     class Dispatcher(BaseDispatcher):
         @classmethod
-        async def catch(cls, interface: "DispatcherInterface[AccountStatusChanged]"):
-            from ..account import AbstractAccount
+        async def catch(cls, interface: DispatcherInterface[AccountStatusChanged]):
+            from avilla.core.account import AbstractAccount
 
             if issubclass(interface.annotation, AbstractAccount):
                 return interface.event.account
diff --git a/avilla/spec/core/common/__init__.py b/avilla/spec/core/common/__init__.py
new file mode 100644
index 00000000..1b2f7791
--- /dev/null
+++ b/avilla/spec/core/common/__init__.py
@@ -0,0 +1,1 @@
+from .metadata import Count as Count
diff --git a/avilla/spec/core/common/metadata.py b/avilla/spec/core/common/metadata.py
new file mode 100644
index 00000000..decfd25f
--- /dev/null
+++ b/avilla/spec/core/common/metadata.py
@@ -0,0 +1,11 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+from avilla.core.metadata import Metadata
+
+
+@dataclass
+class Count(Metadata):
+    current: int
+    max: int
diff --git a/avilla/spec/core/common/skeletion.py b/avilla/spec/core/common/skeletion.py
new file mode 100644
index 00000000..e69de29b
diff --git a/avilla/spec/core/message/__init__.py b/avilla/spec/core/message/__init__.py
new file mode 100644
index 00000000..24111ddf
--- /dev/null
+++ b/avilla/spec/core/message/__init__.py
@@ -0,0 +1,6 @@
+from .event import MessageEdited as MessageEdited
+from .event import MessageReceived as MessageReceived
+from .event import MessageRevoked as MessageRevoked
+from .skeleton import MessageEdit as MessageEdit
+from .skeleton import MessageRevoke as MessageRevoke
+from .skeleton import MessageSend as MessageSend
diff --git a/avilla/spec/core/message/event.py b/avilla/spec/core/message/event.py
new file mode 100644
index 00000000..8db6d886
--- /dev/null
+++ b/avilla/spec/core/message/event.py
@@ -0,0 +1,56 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import TYPE_CHECKING
+
+from graia.amnesia.message import __message_chain_class__
+
+from avilla.core.event import AvillaEvent
+
+if TYPE_CHECKING:
+    from graia.broadcast.interfaces.dispatcher import DispatcherInterface
+
+    from avilla.core.message import Message
+    from avilla.core.selector import Selector
+
+
+@dataclass
+class MessageReceived(AvillaEvent):
+    message: Message
+
+    class Dispatcher(AvillaEvent.Dispatcher):
+        @classmethod
+        async def catch(cls, interface: DispatcherInterface[MessageReceived]):
+            if interface.annotation is interface.event.message.__class__:
+                return interface.event.message
+            elif interface.annotation is __message_chain_class__:
+                return interface.event.message.content
+            return await super().catch(interface)
+
+
+@dataclass
+class MessageEdited(AvillaEvent):
+    message: Message
+    operator: Selector
+    past: __message_chain_class__
+    current: __message_chain_class__
+
+    class Dispatcher(AvillaEvent.Dispatcher):
+        @classmethod
+        async def catch(cls, interface: DispatcherInterface[MessageEdited]):
+            if interface.annotation is Message:
+                return interface.event.message
+            elif interface.annotation is __message_chain_class__:
+                return interface.event.current
+            return await super().catch(interface)
+
+
+@dataclass
+class MessageRevoked(AvillaEvent):
+    message: Selector
+    operator: Selector
+
+    class Dispatcher(AvillaEvent.Dispatcher):
+        @classmethod
+        async def catch(cls, interface: DispatcherInterface[MessageRevoked]):
+            return await super().catch(interface)
diff --git a/avilla/spec/core/message/skeleton.py b/avilla/spec/core/message/skeleton.py
new file mode 100644
index 00000000..e356cf85
--- /dev/null
+++ b/avilla/spec/core/message/skeleton.py
@@ -0,0 +1,26 @@
+from __future__ import annotations
+
+from graia.amnesia.message import __message_chain_class__
+
+from avilla.core.selector import Selector
+from avilla.core.trait import Fn, Trait
+
+# MessageFetch => rs.pull(Message, target=...)
+
+
+class MessageSend(Trait):
+    @Fn.bound_entity
+    async def send(self, message: __message_chain_class__, *, reply: Selector | None = None) -> Selector:
+        ...
+
+
+class MessageRevoke(Trait):
+    @Fn.bound_entity
+    async def revoke(self) -> None:
+        ...
+
+
+class MessageEdit(Trait):
+    @Fn
+    async def edit(self, message: Selector, content: __message_chain_class__) -> None:
+        ...
diff --git a/avilla/spec/core/privilege/__init__.py b/avilla/spec/core/privilege/__init__.py
new file mode 100644
index 00000000..be7e7b0a
--- /dev/null
+++ b/avilla/spec/core/privilege/__init__.py
@@ -0,0 +1,7 @@
+from .metadata import BanInfo as BanInfo
+from .metadata import MuteInfo as MuteInfo
+from .metadata import Privilege as Privilege
+from .skeleton import BanTrait as BanTrait
+from .skeleton import MuteAllTrait as MuteAllTrait
+from .skeleton import MuteTrait as MuteTrait
+from .skeleton import PrivilegeTrait as PrivilegeTrait
diff --git a/avilla/spec/core/privilege/metadata.py b/avilla/spec/core/privilege/metadata.py
new file mode 100644
index 00000000..91db3663
--- /dev/null
+++ b/avilla/spec/core/privilege/metadata.py
@@ -0,0 +1,28 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+from datetime import datetime, timedelta
+
+from avilla.core.metadata import Metadata
+
+
+@dataclass
+class MuteInfo(Metadata):
+    muted: bool
+    duration: timedelta
+    time: datetime | None = None
+
+
+@dataclass
+class BanInfo(Metadata):
+    banned: bool
+    duration: timedelta
+    time: datetime | None = None
+
+
+@dataclass
+class Privilege(Metadata):
+    available: bool
+    effective: bool
+
+    duration: timedelta | None = None
diff --git a/avilla/spec/core/privilege/skeleton.py b/avilla/spec/core/privilege/skeleton.py
new file mode 100644
index 00000000..1d72dae3
--- /dev/null
+++ b/avilla/spec/core/privilege/skeleton.py
@@ -0,0 +1,47 @@
+from __future__ import annotations
+
+from datetime import timedelta
+
+from avilla.core.trait import Fn, Trait
+
+
+class PrivilegeTrait(Trait):
+    @Fn.bound_entity
+    async def upgrade(self, dest: str | None = None) -> None:
+        ...
+
+    @Fn.bound_entity
+    async def downgrade(self, dest: str | None = None) -> None:
+        ...
+
+
+class MuteTrait(Trait):
+    @Fn.bound_entity
+    async def mute(self, duration: timedelta) -> None:
+        ...
+
+    @Fn.bound_entity
+    async def unmute(self) -> None:
+        ...
+
+
+class MuteAllTrait(Trait):
+    @Fn.bound_entity
+    async def mute_all(self) -> None:
+        ...
+
+    @Fn.bound_entity
+    async def unmute_all(self) -> None:
+        ...
+
+    # Fetch => rs.pull(MuteInfo, target=...)
+
+
+class BanTrait(Trait):
+    @Fn.bound_entity
+    async def ban(self, duration: timedelta | None = None) -> None:
+        ...
+
+    @Fn.bound_entity
+    async def unban(self) -> None:
+        ...
diff --git a/avilla/spec/core/profile/__init__.py b/avilla/spec/core/profile/__init__.py
new file mode 100644
index 00000000..6d0278dd
--- /dev/null
+++ b/avilla/spec/core/profile/__init__.py
@@ -0,0 +1,4 @@
+from .metadata import Nick as Nick
+from .metadata import Summary as Summary
+from .skeleton import NickTrait as NickTrait
+from .skeleton import SummaryTrait as SummaryTrait
diff --git a/avilla/spec/core/profile/metadata.py b/avilla/spec/core/profile/metadata.py
new file mode 100644
index 00000000..bf3dbe10
--- /dev/null
+++ b/avilla/spec/core/profile/metadata.py
@@ -0,0 +1,18 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+from avilla.core.metadata import Metadata
+
+
+@dataclass
+class Summary(Metadata):
+    name: str
+    description: str | None
+
+
+@dataclass
+class Nick(Metadata):
+    name: str
+    nickname: str
+    badge: str | None
diff --git a/avilla/spec/core/profile/skeleton.py b/avilla/spec/core/profile/skeleton.py
new file mode 100644
index 00000000..19349cb6
--- /dev/null
+++ b/avilla/spec/core/profile/skeleton.py
@@ -0,0 +1,43 @@
+from __future__ import annotations
+
+from avilla.core.trait import Fn, Trait
+
+
+class SummaryTrait(Trait):
+    @Fn.bound_universal
+    async def set_name(self, name: str) -> None:
+        ...
+
+    @Fn.bound_universal
+    async def unset_name(self) -> None:
+        ...
+
+    @Fn.bound_universal
+    async def set_description(self, description: str) -> None:
+        ...
+
+    @Fn.bound_universal
+    async def unset_description(self) -> None:
+        ...
+
+
+class NickTrait(Trait):
+    @Fn.bound_universal
+    async def set_name(self, name: str) -> None:
+        ...
+
+    @Fn.bound_entity
+    async def set_nickname(self, nickname: str) -> None:
+        ...
+
+    @Fn.bound_entity
+    async def unset_nickname(self) -> None:
+        ...
+
+    @Fn.bound_entity
+    async def set_badge(self, badge: str) -> None:
+        ...
+
+    @Fn.bound_entity
+    async def unset_badge(self) -> None:
+        ...
diff --git a/avilla/spec/core/request/__init__.py b/avilla/spec/core/request/__init__.py
new file mode 100644
index 00000000..bee06ea9
--- /dev/null
+++ b/avilla/spec/core/request/__init__.py
@@ -0,0 +1,11 @@
+from .event import RequestAccepted as RequestAccepted
+from .event import RequestCancelled as RequestCancelled
+from .event import RequestEvent as RequestEvent
+from .event import RequestIgnored as RequestIgnored
+from .event import RequestReceived as RequestReceived
+from .event import RequestRejected as RequestRejected
+from .metadata import Answers as Answers
+from .metadata import Comment as Comment
+from .metadata import Questions as Questions
+from .metadata import Reason as Reason
+from .skeleton import RequestTrait as RequestTrait
diff --git a/avilla/core/event/request.py b/avilla/spec/core/request/event.py
similarity index 53%
rename from avilla/core/event/request.py
rename to avilla/spec/core/request/event.py
index 6c28e9d2..f76cc722 100644
--- a/avilla/core/event/request.py
+++ b/avilla/spec/core/request/event.py
@@ -1,42 +1,23 @@
 from __future__ import annotations
 
-from typing import TYPE_CHECKING
+from dataclasses import dataclass
 
-from graia.broadcast.entities.dispatcher import BaseDispatcher
 from graia.broadcast.interfaces.dispatcher import DispatcherInterface
 
+from avilla.core.event import AvillaEvent
 from avilla.core.request import Request
 
-from . import AvillaEvent
-
-if TYPE_CHECKING:
-    from datetime import datetime
-
 
+@dataclass
 class RequestEvent(AvillaEvent):
     request: Request
 
-    @property
-    def mainline(self):
-        return self.request.mainline
-
-    @property
-    def ctx(self):
-        return self.request.sender
-
-    def __init__(
-        self,
-        request: Request,
-        time: datetime | None = None,
-    ):
-        self.request = request
-        super().__init__(request.account, time=time)
-
-    class Dispatcher(BaseDispatcher):
+    class Dispatcher(AvillaEvent.Dispatcher):
         @staticmethod
         async def catch(interface: DispatcherInterface[RequestEvent]):
             if interface.annotation is Request:
                 return interface.event.request
+            return await super().catch(interface)
 
 
 class RequestReceived(RequestEvent):
diff --git a/avilla/spec/core/request/metadata.py b/avilla/spec/core/request/metadata.py
new file mode 100644
index 00000000..285db2ec
--- /dev/null
+++ b/avilla/spec/core/request/metadata.py
@@ -0,0 +1,37 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+from avilla.core.metadata import Metadata
+
+
+@dataclass
+class Reason(Metadata):
+    content: str
+
+
+@dataclass
+class Comment(Metadata):
+    content: str
+
+
+@dataclass
+class QuestionItem:
+    id: str
+    content: str
+
+
+@dataclass
+class Questions(Metadata):
+    items: list[QuestionItem]
+
+
+@dataclass
+class AnswerItem:
+    id: str
+    content: str
+
+
+@dataclass
+class Answers(Metadata):
+    items: list[AnswerItem]
diff --git a/avilla/core/skeleton/request.py b/avilla/spec/core/request/skeleton.py
similarity index 69%
rename from avilla/core/skeleton/request.py
rename to avilla/spec/core/request/skeleton.py
index e48535ea..e6f9e90b 100644
--- a/avilla/core/skeleton/request.py
+++ b/avilla/spec/core/request/skeleton.py
@@ -1,21 +1,21 @@
 from __future__ import annotations
 
-from avilla.core.trait import OrientedFn, Trait
+from avilla.core.trait import Fn, Trait
 
 
 class RequestTrait(Trait):
-    @OrientedFn
+    @Fn.bound_entity
     async def accept(self):
         ...
 
-    @OrientedFn
+    @Fn.bound_entity
     async def reject(self, reason: str | None = None, forever: bool = False):
         ...
 
-    @OrientedFn
+    @Fn.bound_entity
     async def cancel(self):
         ...
 
-    @OrientedFn
+    @Fn.bound_entity
     async def ignore(self):
         ...
diff --git a/avilla/spec/core/resource/__init__.py b/avilla/spec/core/resource/__init__.py
new file mode 100644
index 00000000..50e3efaa
--- /dev/null
+++ b/avilla/spec/core/resource/__init__.py
@@ -0,0 +1,5 @@
+from .event import FileRemoved as FileRemoved
+from .event import FileUploaded as FileUploaded
+from .event import ResourceAvailable as ResourceAvailable
+from .event import ResourceEvent as ResourceEvent
+from .event import ResourceUnavailable as ResourceUnavailable
diff --git a/avilla/spec/core/resource/event.py b/avilla/spec/core/resource/event.py
new file mode 100644
index 00000000..5e2199f2
--- /dev/null
+++ b/avilla/spec/core/resource/event.py
@@ -0,0 +1,45 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import TYPE_CHECKING
+
+from typing_extensions import get_origin
+
+from avilla.core.event import AvillaEvent
+from avilla.core.resource import Resource
+from avilla.core.selector import Selector
+
+if TYPE_CHECKING:
+    from graia.broadcast.interfaces.dispatcher import DispatcherInterface
+
+
+@dataclass
+class ResourceEvent(AvillaEvent):
+    resource: Resource
+
+    class Dispatcher(AvillaEvent.Dispatcher):
+        @staticmethod
+        async def catch(interface: DispatcherInterface[ResourceEvent]):
+            if issubclass((get_origin(interface.annotation)) or interface.annotation, Resource):
+                return interface.event.resource
+            return await super().catch(interface)
+
+
+class ResourceAvailable(ResourceEvent):
+    pass
+
+
+class ResourceUnavailable(ResourceEvent):
+    pass
+
+
+@dataclass
+class FileUploaded(ResourceAvailable):
+    uploader: Selector
+    scene: Selector
+
+
+@dataclass
+class FileRemoved(ResourceUnavailable):
+    uploader: Selector
+    scene: Selector
diff --git a/avilla/spec/core/scene/__init__.py b/avilla/spec/core/scene/__init__.py
new file mode 100644
index 00000000..89954ef9
--- /dev/null
+++ b/avilla/spec/core/scene/__init__.py
@@ -0,0 +1,1 @@
+from .skeleton import SceneTrait as SceneTrait
diff --git a/avilla/spec/core/scene/skeleton.py b/avilla/spec/core/scene/skeleton.py
new file mode 100644
index 00000000..899f138c
--- /dev/null
+++ b/avilla/spec/core/scene/skeleton.py
@@ -0,0 +1,19 @@
+from __future__ import annotations
+
+from avilla.core.trait import Fn, Trait
+
+
+class SceneTrait(Trait):
+    @Fn.bound_entity
+    async def leave(self) -> None:
+        ...
+
+    @Fn.bound_entity
+    async def disband(self) -> None:
+        ...
+
+    @Fn.bound_entity
+    async def remove_member(self, reason: str | None = None) -> None:
+        ...
+
+    # TODO: join, invite etc.
diff --git a/avilla/elizabeth/element.py b/avilla/spec/qq/elements.py
similarity index 100%
rename from avilla/elizabeth/element.py
rename to avilla/spec/qq/elements.py
diff --git a/pdm.lock b/pdm.lock
index e4426302..c0f0d229 100644
--- a/pdm.lock
+++ b/pdm.lock
@@ -44,7 +44,7 @@ summary = "Classes Without Boilerplate"
 
 [[package]]
 name = "black"
-version = "22.10.0"
+version = "22.12.0"
 requires_python = ">=3.7"
 summary = "The uncompromising code formatter."
 dependencies = [
@@ -117,12 +117,12 @@ dependencies = [
 
 [[package]]
 name = "devtools"
-version = "0.9.0"
+version = "0.10.0"
 requires_python = ">=3.7"
 summary = "Python's missing debug print command, and more."
 dependencies = [
     "asttokens<3.0.0,>=2.0.0",
-    "executing<1.0.0,>=0.8.0",
+    "executing>=1.1.1",
 ]
 
 [[package]]
@@ -132,7 +132,7 @@ summary = "Distribution utilities"
 
 [[package]]
 name = "executing"
-version = "0.10.0"
+version = "1.2.0"
 summary = "Get the currently executing AST node of a frame, and other information"
 
 [[package]]
@@ -143,13 +143,13 @@ summary = "A platform independent file lock."
 
 [[package]]
 name = "flake8"
-version = "5.0.4"
-requires_python = ">=3.6.1"
+version = "6.0.0"
+requires_python = ">=3.8.1"
 summary = "the modular source code checker: pep8 pyflakes and co"
 dependencies = [
     "mccabe<0.8.0,>=0.7.0",
-    "pycodestyle<2.10.0,>=2.9.0",
-    "pyflakes<2.6.0,>=2.5.0",
+    "pycodestyle<2.11.0,>=2.10.0",
+    "pyflakes<3.1.0,>=3.0.0",
 ]
 
 [[package]]
@@ -160,7 +160,7 @@ summary = "A list-like structure which implements collections.abc.MutableSequenc
 
 [[package]]
 name = "graia-amnesia"
-version = "0.6.0"
+version = "0.7.1"
 requires_python = ">=3.8,<4.0"
 summary = "a collection of shared components for graia"
 dependencies = [
@@ -173,7 +173,7 @@ dependencies = [
 
 [[package]]
 name = "graia-broadcast"
-version = "0.19.0"
+version = "0.19.1"
 requires_python = ">=3.7,<4.0"
 summary = "a highly customizable, elegantly designed event system based on asyncio"
 
@@ -210,8 +210,8 @@ dependencies = [
 
 [[package]]
 name = "isort"
-version = "5.10.1"
-requires_python = ">=3.6.1,<4.0"
+version = "5.11.3"
+requires_python = ">=3.7.0"
 summary = "A Python utility / library to sort Python imports."
 
 [[package]]
@@ -303,13 +303,13 @@ dependencies = [
 
 [[package]]
 name = "pycodestyle"
-version = "2.9.1"
+version = "2.10.0"
 requires_python = ">=3.6"
 summary = "Python style guide checker"
 
 [[package]]
 name = "pyflakes"
-version = "2.5.0"
+version = "3.0.1"
 requires_python = ">=3.6"
 summary = "passive checker of Python programs"
 
@@ -409,7 +409,7 @@ summary = "A small Python utility to set file creation time on Windows"
 
 [[package]]
 name = "yarl"
-version = "1.8.1"
+version = "1.8.2"
 requires_python = ">=3.7"
 summary = "Yet another URL library"
 dependencies = [
@@ -533,28 +533,19 @@ content_hash = "sha256:7e8b30f52f9b926770365d713c5e091457b3919b19b4109009fd7d387
     {url = "https://files.pythonhosted.org/packages/1a/cb/c4ffeb41e7137b23755a45e1bfec9cbb76ecf51874c6f1d113984ecaa32c/attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
     {url = "https://files.pythonhosted.org/packages/f2/bc/d817287d1aa01878af07c19505fafd1165cd6a119e9d0821ca1d1c20312d/attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
 ]
-"black 22.10.0" = [
-    {url = "https://files.pythonhosted.org/packages/2c/11/f2737cd3b458d91401801e83a014e87c63e8904dc063200f77826c352f54/black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"},
-    {url = "https://files.pythonhosted.org/packages/3d/c5/b3ab9b563f35fb284d37ab2b14acaed9a27d8cdea9c31364766eb54946a7/black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"},
-    {url = "https://files.pythonhosted.org/packages/56/df/913d71817c7034edba25d596c54f782c2f809b6af30367d2f00309e8890a/black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"},
-    {url = "https://files.pythonhosted.org/packages/69/21/846c95710cc6561ba980bd6c72479dbcdde742e927ff5ef7340916d003ac/black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"},
-    {url = "https://files.pythonhosted.org/packages/69/84/903cdf41514088d5a716538cb189c471ab34e56ae9a1c2da6b8bfe8e4dbf/black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"},
-    {url = "https://files.pythonhosted.org/packages/71/f8/57e47ea67f59613c4368a952062bc3429131249920cffbb8362fd404b733/black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"},
-    {url = "https://files.pythonhosted.org/packages/86/da/edebcc6c13441d91eff6761e50512bc6d6886a556dc5357b399694122b4f/black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"},
-    {url = "https://files.pythonhosted.org/packages/91/e6/d9b78987d7d903369ba1a0b795bce4de06f0155be6609f15e8950aef8f7e/black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"},
-    {url = "https://files.pythonhosted.org/packages/a3/89/629fca2eea0899c06befaa58dc0f49d56807d454202bb2e54bd0d98c77f3/black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"},
-    {url = "https://files.pythonhosted.org/packages/a5/5f/9cfc6dd95965f8df30194472543e6f0515a10d78ea5378426ef1546735c7/black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"},
-    {url = "https://files.pythonhosted.org/packages/a6/84/5c3f3ffc4143fa7e208d745d2239d915e74d3709fdbc64c3e98d3fd27e56/black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"},
-    {url = "https://files.pythonhosted.org/packages/ab/15/61119d166a44699827c112d7c4726421f14323c2cb7aa9f4c26628f237f9/black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"},
-    {url = "https://files.pythonhosted.org/packages/ae/49/ea03c318a25be359b8e5178a359d47e2da8f7524e1522c74b8f74c66b6f8/black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"},
-    {url = "https://files.pythonhosted.org/packages/b0/9e/fa912c5ae4b8eb6d36982fc8ac2d779cf944dbd7c3c1fe7a28acf462c1ed/black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"},
-    {url = "https://files.pythonhosted.org/packages/b9/51/403b0b0eb9fb412ca02b79dc38472469f2f88c9aacc6bb5262143e4ff0bc/black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"},
-    {url = "https://files.pythonhosted.org/packages/ce/6f/74492b8852ee4f2ad2178178f6b65bc8fc80ad539abe56c1c23eab6732e2/black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"},
-    {url = "https://files.pythonhosted.org/packages/d0/5a/5f31494e3acbb6319ee60c3a3a09d3e536a3fd2353f76af9cbff799c4999/black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"},
-    {url = "https://files.pythonhosted.org/packages/e2/2f/a8406a9e337a213802aa90a3e9fbf90c86f3edce92f527255fd381309b77/black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"},
-    {url = "https://files.pythonhosted.org/packages/e3/b4/9203f1a0c99aa30389b61fa8cb54bc9f4bf16ac3aa74630c6b974ed3f3b0/black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"},
-    {url = "https://files.pythonhosted.org/packages/f2/23/f4278377cabf882298b4766e977fd04377f288d1ccef706953076a1e0598/black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"},
-    {url = "https://files.pythonhosted.org/packages/ff/ce/22281871536b3d79474fd44d48dad48f7cbc5c3982bddf6a7495e7079d00/black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"},
+"black 22.12.0" = [
+    {url = "https://files.pythonhosted.org/packages/0c/51/1f7f93c0555eaf4cbb628e26ba026e3256174a45bd9397ff1ea7cf96bad5/black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"},
+    {url = "https://files.pythonhosted.org/packages/4c/49/420dcfccba3215dc4e5790fa47572ef14129df1c5e95dd87b5ad30211b01/black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"},
+    {url = "https://files.pythonhosted.org/packages/4c/dd/cdb4e62a58e229ee757110a9dfb914a44e9d41be8becb41e085cb5df5d5b/black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"},
+    {url = "https://files.pythonhosted.org/packages/54/44/6d5f9af3c14da013754021e28eacc873e6ecbe877b2540e37346579398c8/black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"},
+    {url = "https://files.pythonhosted.org/packages/71/57/975782465cc6b514f2c972421e29b933dfbb51d4a95948a4e0e94f36ea38/black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"},
+    {url = "https://files.pythonhosted.org/packages/79/d9/60852a6fc2f85374db20a9767dacfe50c2172eb8388f46018c8daf836995/black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"},
+    {url = "https://files.pythonhosted.org/packages/a6/59/e873cc6807fb62c11131e5258ca15577a3b7452abad08dc49286cf8245e8/black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"},
+    {url = "https://files.pythonhosted.org/packages/ba/32/954bcc56b2b3b4ef52a086e3c0bdbad88a38c9e739feb19dd2e6294cda42/black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"},
+    {url = "https://files.pythonhosted.org/packages/e9/e0/6aa02d14785c4039b38bfed6f9ee28a952b2d101c64fc97b15811fa8bd04/black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"},
+    {url = "https://files.pythonhosted.org/packages/eb/91/e0ccc36f8e1a00ed3c343741ca7ffe954e33cd2be0cada039845ff9e0539/black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"},
+    {url = "https://files.pythonhosted.org/packages/f1/b7/6de002378cfe0b83beba72f0a7875dfb6005b2a214ac9f9ca689583069ef/black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"},
+    {url = "https://files.pythonhosted.org/packages/f2/b9/06fe2dd83a2104d83c2b737f41aa5679f5a4395630005443ba4fa6fece8b/black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"},
 ]
 "cfgv 3.3.1" = [
     {url = "https://files.pythonhosted.org/packages/6d/82/0a0ebd35bae9981dea55c06f8e6aaf44a49171ad798795c72c6f64cba4c2/cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
@@ -588,25 +579,25 @@ content_hash = "sha256:7e8b30f52f9b926770365d713c5e091457b3919b19b4109009fd7d387
     {url = "https://files.pythonhosted.org/packages/80/12/4cf1fa220d521702db5b4e3a06603cac89ecd233ad69b050aa98f08e52ce/croniter-1.3.7-py2.py3-none-any.whl", hash = "sha256:12369c67e231c8ce5f98958d76ea6e8cb5b157fda4da7429d245a931e4ed411e"},
     {url = "https://files.pythonhosted.org/packages/bc/75/71b7d4b9b364570f8a307bcfd79c89941e929ea803dcf5d0e355725f5316/croniter-1.3.7.tar.gz", hash = "sha256:72ef78d0f8337eb35393b8893ebfbfbeb340f2d2ae47e0d2d78130e34b0dd8b9"},
 ]
-"devtools 0.9.0" = [
-    {url = "https://files.pythonhosted.org/packages/2d/e2/a1e80801b195539f552a2a369691e09ecc27648f5c5c0c0cab0256f4f098/devtools-0.9.0.tar.gz", hash = "sha256:86ede6e0273e023db766344d14098228785b48a80f31716f28e8b9453d52fa1e"},
-    {url = "https://files.pythonhosted.org/packages/8e/3a/741773833ee8f1d18d5ce377c3b062f0d63b951fb9e4bec25f994c7f4631/devtools-0.9.0-py3-none-any.whl", hash = "sha256:689cf4e7c75024237c42093ba19f4fa9cf15980269f02463aeab4d97d4b0a215"},
+"devtools 0.10.0" = [
+    {url = "https://files.pythonhosted.org/packages/50/ac/705b4de745ca0aa4d42f563b790465870b5fb24255d16c31d3d2e74b640c/devtools-0.10.0-py3-none-any.whl", hash = "sha256:b0bc02043bb032cdfb93e227226e2fea1aaea8f5a31fca25fabc4eadca22f228"},
+    {url = "https://files.pythonhosted.org/packages/e4/d5/a16445a372eea5730cc9051905d938c3530e2c5f91034701ca30fa6c4481/devtools-0.10.0.tar.gz", hash = "sha256:6eb7c4fa7c4b90e5cfe623537a9961d1dc3199d8be0981802c6931cd8f02418f"},
 ]
 "distlib 0.3.6" = [
     {url = "https://files.pythonhosted.org/packages/58/07/815476ae605bcc5f95c87a62b95e74a1bce0878bc7a3119bc2bf4178f175/distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"},
     {url = "https://files.pythonhosted.org/packages/76/cb/6bbd2b10170ed991cf64e8c8b85e01f2fb38f95d1bc77617569e0b0b26ac/distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"},
 ]
-"executing 0.10.0" = [
-    {url = "https://files.pythonhosted.org/packages/14/ab/82fbfcc5d1888770aeec5b7a17ad5ef0215ff3962c52a38f4429f7c9220b/executing-0.10.0-py2.py3-none-any.whl", hash = "sha256:9c745f80cda11eb22b62cbecf21156491a794eb56ab06f9d286a44e62822b24e"},
-    {url = "https://files.pythonhosted.org/packages/e3/a7/6380f9bc4367ea010de6297540f69433e9a6070b8b7c1f283ff250b48e60/executing-0.10.0.tar.gz", hash = "sha256:d1cd87c2e371e9966261410c5b3769d6df2f9e4a79a83eebd2662dd3388f9833"},
+"executing 1.2.0" = [
+    {url = "https://files.pythonhosted.org/packages/28/3c/bc3819dd8b1a1588c9215a87271b6178cc5498acaa83885211f5d4d9e693/executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"},
+    {url = "https://files.pythonhosted.org/packages/8f/ac/89ff37d8594b0eef176b7cec742ac868fef853b8e18df0309e3def9f480b/executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"},
 ]
 "filelock 3.8.0" = [
     {url = "https://files.pythonhosted.org/packages/94/b3/ff2845971788613e646e667043fdb5f128e2e540aefa09a3c55be8290d6d/filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"},
     {url = "https://files.pythonhosted.org/packages/95/55/b897882bffb8213456363e646bf9e9fa704ffda5a7d140edf935a9e02c7b/filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"},
 ]
-"flake8 5.0.4" = [
-    {url = "https://files.pythonhosted.org/packages/ad/00/9808c62b2d529cefc69ce4e4a1ea42c0f855effa55817b7327ec5b75e60a/flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"},
-    {url = "https://files.pythonhosted.org/packages/cf/a0/b881b63a17a59d9d07f5c0cc91a29182c8e8a9aa2bde5b3b2b16519c02f4/flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"},
+"flake8 6.0.0" = [
+    {url = "https://files.pythonhosted.org/packages/66/53/3ad4a3b74d609b3b9008a10075c40e7c8909eae60af53623c3888f7a529a/flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"},
+    {url = "https://files.pythonhosted.org/packages/d9/6a/bb0122ebe280476c924470779d2595f1403878cafe3c8a343ac56a5a9c0e/flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"},
 ]
 "frozenlist 1.3.1" = [
     {url = "https://files.pythonhosted.org/packages/04/a6/7d83ee70d9e4d5e4423fae9d0d6821359df0313f754eb4db4c79f779c624/frozenlist-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:625d8472c67f2d96f9a4302a947f92a7adbc1e20bedb6aff8dbc8ff039ca6189"},
@@ -669,13 +660,13 @@ content_hash = "sha256:7e8b30f52f9b926770365d713c5e091457b3919b19b4109009fd7d387
     {url = "https://files.pythonhosted.org/packages/f4/98/0dc010eff663f2b75feb35b7a908cda585c87b402b198a34e3b1161e20f2/frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:53b2b45052e7149ee8b96067793db8ecc1ae1111f2f96fe1f88ea5ad5fd92d10"},
     {url = "https://files.pythonhosted.org/packages/f8/16/addcabc0c2483fba353f5818b56e593c363e00c83eb9c9132a42aa3c740d/frozenlist-1.3.1-cp310-cp310-win32.whl", hash = "sha256:fabb953ab913dadc1ff9dcc3a7a7d3dc6a92efab3a0373989b8063347f8705be"},
 ]
-"graia-amnesia 0.6.0" = [
-    {url = "https://files.pythonhosted.org/packages/4f/0d/434bae97145de0e5bda33e4757c5def19e034fdb12a32ea2dd7d0d4d1c70/graia_amnesia-0.6.0-py3-none-any.whl", hash = "sha256:c1e347171cd42d81b10dea4fb6afef4bed4e836fa9c698ecf595ccaa5c2d1939"},
-    {url = "https://files.pythonhosted.org/packages/e4/17/23accd9a4466a7cebc4cd6f74821197ad1e74b23cd5395acee7ccd19ce1f/graia-amnesia-0.6.0.tar.gz", hash = "sha256:9f4ed226ebd2ccfe5e09489e4afffd9e58ae28c3fa93211dda72c3c6b9a439f0"},
+"graia-amnesia 0.7.1" = [
+    {url = "https://files.pythonhosted.org/packages/49/6c/9f6c4f5badfd04e0f3118ef1509a684101dade8124031e2fe90297d3dda8/graia-amnesia-0.7.1.tar.gz", hash = "sha256:d93efde0a36b6c4463401d9f142d03e49d14d37b5d005161cf3468136aba931d"},
+    {url = "https://files.pythonhosted.org/packages/9c/16/3afcf0811a9a81352633bf24705974e8122e0031bf00ce6c1b3c1b3da500/graia_amnesia-0.7.1-py3-none-any.whl", hash = "sha256:7292c43d3caa9884bf60e827d1fd2190b076b00210a4881a907d63ba2e5bfa6d"},
 ]
-"graia-broadcast 0.19.0" = [
-    {url = "https://files.pythonhosted.org/packages/18/88/c87afe3d5f6cfa0a8befc8491a5e4a648966325421fbaa0a355ac61704d2/graia_broadcast-0.19.0-py3-none-any.whl", hash = "sha256:16a6cb0eaa7e405f243d5380a7e9acdf563000e2b8158dc3bc5c2b984d1b4411"},
-    {url = "https://files.pythonhosted.org/packages/46/19/749976aada206042fa677242d034f7b0951ba75a7351601393a9f8cf5d09/graia-broadcast-0.19.0.tar.gz", hash = "sha256:bd12fda9a4ae0251ed875aca5ad70cc15ec8184248e7ab4dd6fdfd8b4dd1aa7a"},
+"graia-broadcast 0.19.1" = [
+    {url = "https://files.pythonhosted.org/packages/2d/74/479522bf0643121b6bd967ee26410faa0129b35ef3339e0d9a513dfc3057/graia_broadcast-0.19.1-py3-none-any.whl", hash = "sha256:94ba3a53b3dda292e95f6be2ae964d975e34d5f6fb973df31016bd34089e2c47"},
+    {url = "https://files.pythonhosted.org/packages/3c/a0/6baa89337a9fde73e5a0715d32cad8bb37925e30e42fcae71d6046deb1e6/graia-broadcast-0.19.1.tar.gz", hash = "sha256:bd0d3b9891e6ff3b86948d94fbac52ff187056389556aecc0251c261a7806ba0"},
 ]
 "graia-scheduler 0.0.10" = [
     {url = "https://files.pythonhosted.org/packages/4c/58/0171da0e922bc07fe2216cb014d72d64b6cd38bdb7170ed046544d24a906/graia_scheduler-0.0.10-py3-none-any.whl", hash = "sha256:9e725b83aeb36c9f95754c979fe01a4b6e23eea0ae6c527e3d3bb7ca388e02aa"},
@@ -693,9 +684,9 @@ content_hash = "sha256:7e8b30f52f9b926770365d713c5e091457b3919b19b4109009fd7d387
     {url = "https://files.pythonhosted.org/packages/7e/ec/97f2ce958b62961fddd7258e0ceede844953606ad09b672fa03b86c453d3/importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"},
     {url = "https://files.pythonhosted.org/packages/b5/64/ef29a63cf08f047bb7fb22ab0f1f774b87eed0bb46d067a5a524798a4af8/importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"},
 ]
-"isort 5.10.1" = [
-    {url = "https://files.pythonhosted.org/packages/ab/e9/964cb0b2eedd80c92f5172f1f8ae0443781a9d461c1372a3ce5762489593/isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
-    {url = "https://files.pythonhosted.org/packages/b8/5b/f18e227df38b94b4ee30d2502fd531bebac23946a2497e5595067a561274/isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
+"isort 5.11.3" = [
+    {url = "https://files.pythonhosted.org/packages/cd/11/7bf65b28548c7cb626e4a70807cee496361b3c789cce57bd48ce4008d1e4/isort-5.11.3-py3-none-any.whl", hash = "sha256:83155ffa936239d986b0f190347a3f2285f42a9b9e1725c89d865b27dd0627e5"},
+    {url = "https://files.pythonhosted.org/packages/e2/43/d99899bfa24a3914f0318536918ab8c91c09350b5482e4e9bb7291840ae3/isort-5.11.3.tar.gz", hash = "sha256:a8ca25fbfad0f7d5d8447a4314837298d9f6b23aed8618584c894574f626b64b"},
 ]
 "launart 0.6.1" = [
     {url = "https://files.pythonhosted.org/packages/14/47/33a21e34b66f36b51a02bb550f039b6278fa84fcf2fb5e53cf1a98218a68/launart-0.6.1.tar.gz", hash = "sha256:630d5582c3f5e7b68df0b2bde46f5bdfef69557fdade2af8414172e4c862dd15"},
@@ -798,13 +789,13 @@ content_hash = "sha256:7e8b30f52f9b926770365d713c5e091457b3919b19b4109009fd7d387
     {url = "https://files.pythonhosted.org/packages/1e/ba/8cf8b88d0e07588818de46877effc9971305541d9421bc6377b06639d135/pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"},
     {url = "https://files.pythonhosted.org/packages/b2/6c/9ccb5213a3d9fd3f8c0fd69d207951901eaef86b7a1a69bcc478364d3072/pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"},
 ]
-"pycodestyle 2.9.1" = [
-    {url = "https://files.pythonhosted.org/packages/67/e4/fc77f1039c34b3612c4867b69cbb2b8a4e569720b1f19b0637002ee03aff/pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"},
-    {url = "https://files.pythonhosted.org/packages/b6/83/5bcaedba1f47200f0665ceb07bcb00e2be123192742ee0edfb66b600e5fd/pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"},
+"pycodestyle 2.10.0" = [
+    {url = "https://files.pythonhosted.org/packages/06/6b/5ca0d12ef7dcf7d20dfa35287d02297f3e0f9e515da5183654c03a9636ce/pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"},
+    {url = "https://files.pythonhosted.org/packages/a2/54/001fdc0d69e8d0bb86c3423a6fa6dfada8cc26317c2635ab543e9ac411bd/pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"},
 ]
-"pyflakes 2.5.0" = [
-    {url = "https://files.pythonhosted.org/packages/07/92/f0cb5381f752e89a598dd2850941e7f570ac3cb8ea4a344854de486db152/pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"},
-    {url = "https://files.pythonhosted.org/packages/dc/13/63178f59f74e53acc2165aee4b002619a3cfa7eeaeac989a9eb41edf364e/pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"},
+"pyflakes 3.0.1" = [
+    {url = "https://files.pythonhosted.org/packages/af/4c/b1c7008aa7788b3e26c06c60aa18da7d3aa1f00e344aa3f18ac92768854b/pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"},
+    {url = "https://files.pythonhosted.org/packages/f2/51/506ddcfab10d708e8460554cc1cf37c727a6a2cccbad8dfe57766cfce33c/pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"},
 ]
 "pygments 2.13.0" = [
     {url = "https://files.pythonhosted.org/packages/4f/82/672cd382e5b39ab1cd422a672382f08a1fb3d08d9e0c0f3707f33a52063b/Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"},
@@ -896,66 +887,81 @@ content_hash = "sha256:7e8b30f52f9b926770365d713c5e091457b3919b19b4109009fd7d387
     {url = "https://files.pythonhosted.org/packages/0a/e6/a7d828fef907843b2a5773ebff47fb79ac0c1c88d60c0ca9530ee941e248/win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"},
     {url = "https://files.pythonhosted.org/packages/6b/dd/f95a13d2b235a28d613ba23ebad55191514550debb968b46aab99f2e3a30/win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"},
 ]
-"yarl 1.8.1" = [
-    {url = "https://files.pythonhosted.org/packages/02/83/af04c6a34e9011e1620ae918e223869adcc5de855ae2e89fd77fabfee626/yarl-1.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:85cba594433915d5c9a0d14b24cfba0339f57a2fff203a5d4fd070e593307d0b"},
-    {url = "https://files.pythonhosted.org/packages/02/df/0d3ae329942cb26c96ac5a4e9164a1d440ffd067331c6886b5ce0729b17a/yarl-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:de49d77e968de6626ba7ef4472323f9d2e5a56c1d85b7c0e2a190b2173d3b9be"},
-    {url = "https://files.pythonhosted.org/packages/05/3d/df4502e29f8153e15c417f75b864cc46af4440be75fd6be16445e3fbb6f7/yarl-1.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6347f1a58e658b97b0a0d1ff7658a03cb79bdbda0331603bed24dd7054a6dea1"},
-    {url = "https://files.pythonhosted.org/packages/07/1d/1088411450c0213ee932a87fadff8448d2f77f95ad92c8386efddb7301c6/yarl-1.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:12768232751689c1a89b0376a96a32bc7633c08da45ad985d0c49ede691f5c0d"},
-    {url = "https://files.pythonhosted.org/packages/0c/a9/9feec07388320ece07b9d706070a67a99858158c0d66cf5e580fdbdbc435/yarl-1.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5587bba41399854703212b87071c6d8638fa6e61656385875f8c6dff92b2e461"},
-    {url = "https://files.pythonhosted.org/packages/10/39/493c2c771e2e71d519992251c565c293801ecc6de0441334a16171d01db5/yarl-1.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0fb2cb4204ddb456a8e32381f9a90000429489a25f64e817e6ff94879d432fc"},
-    {url = "https://files.pythonhosted.org/packages/14/3c/3aaabeaf84b2b05243cb0995dbf76595dd4901470173f4000c23e6fb2a7b/yarl-1.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e4808f996ca39a6463f45182e2af2fae55e2560be586d447ce8016f389f626f"},
-    {url = "https://files.pythonhosted.org/packages/17/72/8720b7fe90b35f7e75caa22bba1dd679ef2e0374e6907d4d584c939e20a0/yarl-1.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:07b21e274de4c637f3e3b7104694e53260b5fc10d51fb3ec5fed1da8e0f754e3"},
-    {url = "https://files.pythonhosted.org/packages/18/2a/cac0cdcb727f0eb4fdbe624d26c0d6a3585e20967ca04002745d4ff324b1/yarl-1.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6c8148e0b52bf9535c40c48faebb00cb294ee577ca069d21bd5c48d302a83780"},
-    {url = "https://files.pythonhosted.org/packages/1c/6f/314fef68b9973b445d469b0890f2d5a872f65f4e18477e0e56bc68dc1a69/yarl-1.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2d800b9c2eaf0684c08be5f50e52bfa2aa920e7163c2ea43f4f431e829b4f0fd"},
-    {url = "https://files.pythonhosted.org/packages/1e/7d/97972e1238f710cf157ddbb92f52af5dce684862137443b81d0f821a25ba/yarl-1.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a88510731cd8d4befaba5fbd734a7dd914de5ab8132a5b3dde0bbd6c9476c64"},
-    {url = "https://files.pythonhosted.org/packages/21/38/64c88eef7ae656a2cc221c10497c25bf09193186e9f77e6dd84b32483d67/yarl-1.8.1-cp38-cp38-win32.whl", hash = "sha256:c1445a0c562ed561d06d8cbc5c8916c6008a31c60bc3655cdd2de1d3bf5174a0"},
-    {url = "https://files.pythonhosted.org/packages/22/72/50a451e82bc86e435509a83c4f358a921b58ee6879438bbc6c190f30c62b/yarl-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:56c11efb0a89700987d05597b08a1efcd78d74c52febe530126785e1b1a285f4"},
-    {url = "https://files.pythonhosted.org/packages/23/fa/30da7a36cf5199781002acfe602105bcce1adcb14afb324f7090ddd1e76d/yarl-1.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20df6ff4089bc86e4a66e3b1380460f864df3dd9dccaf88d6b3385d24405893b"},
-    {url = "https://files.pythonhosted.org/packages/25/8f/8e534ed3093c2fe4d4a2fe5f42cf569904b1f56e07aafafd488e6e9c915b/yarl-1.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6628d750041550c5d9da50bb40b5cf28a2e63b9388bac10fedd4f19236ef4957"},
-    {url = "https://files.pythonhosted.org/packages/28/c9/b4cc0b0841fc171ac830e27237da036a5085691f47135122481824bc9c5d/yarl-1.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fae37373155f5ef9b403ab48af5136ae9851151f7aacd9926251ab26b953118b"},
-    {url = "https://files.pythonhosted.org/packages/2b/89/36a50cab1be3d5099ec66a41212cf0c11507c343074e97e907a2f5f1a569/yarl-1.8.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0f77539733e0ec2475ddcd4e26777d08996f8cd55d2aef82ec4d3896687abda"},
-    {url = "https://files.pythonhosted.org/packages/37/13/a50fb36f9b38be69354bab7e67a702759f05c5190315265310056f334e73/yarl-1.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a165442348c211b5dea67c0206fc61366212d7082ba8118c8c5c1c853ea4d82e"},
-    {url = "https://files.pythonhosted.org/packages/39/91/d8073e858f887f0574894cb514206502c8ceb8544d5821ba5baf871bfed2/yarl-1.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:99449cd5366fe4608e7226c6cae80873296dfa0cde45d9b498fefa1de315a09e"},
-    {url = "https://files.pythonhosted.org/packages/3f/73/463ea4d2655c90f979419f65027252fe99fe9b4f9654782a8a5d69d3fd27/yarl-1.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:205904cffd69ae972a1707a1bd3ea7cded594b1d773a0ce66714edf17833cdae"},
-    {url = "https://files.pythonhosted.org/packages/53/33/2b672d8793f875f6096fbb178be5e4456fffbe3bb48fd592e00f0869ef57/yarl-1.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:21ac44b763e0eec15746a3d440f5e09ad2ecc8b5f6dcd3ea8cb4773d6d4703e3"},
-    {url = "https://files.pythonhosted.org/packages/56/e8/e3a8a499eafd892b4fa2cd665aff51192c8f43475a33cc3c708b7f82adb9/yarl-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed19b74e81b10b592084a5ad1e70f845f0aacb57577018d31de064e71ffa267a"},
-    {url = "https://files.pythonhosted.org/packages/59/4d/5d2cd47d05bd6928ead354feb78f22b73a18dc2b3aa97e09425274cd8fd5/yarl-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:9130ddf1ae9978abe63808b6b60a897e41fccb834408cde79522feb37fb72fb0"},
-    {url = "https://files.pythonhosted.org/packages/5b/6a/80a42dbdd433f9856ebda43963af6f4c671f2f565535991d13dffedeeec7/yarl-1.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:abc06b97407868ef38f3d172762f4069323de52f2b70d133d096a48d72215d28"},
-    {url = "https://files.pythonhosted.org/packages/5e/6b/012f4874880fb40f09c794f62b79fc32291837797a5929914832ced2cdb3/yarl-1.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c322cbaa4ed78a8aac89b2174a6df398faf50e5fc12c4c191c40c59d5e28357"},
-    {url = "https://files.pythonhosted.org/packages/5f/fb/edeb230634491f9222dd494687ee05910f7f26add9bb049b640a7ae2727d/yarl-1.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9de955d98e02fab288c7718662afb33aab64212ecb368c5dc866d9a57bf48880"},
-    {url = "https://files.pythonhosted.org/packages/61/9c/17c739a0f6f454c5873048fb463dc9344ea7cb2a0e9d233d6b334ce497df/yarl-1.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:59ddd85a1214862ce7c7c66457f05543b6a275b70a65de366030d56159a979f0"},
-    {url = "https://files.pythonhosted.org/packages/67/29/52d35348cfcc38251d64fe5e8c75d2d7096fc10d15467e7ca308367b3965/yarl-1.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5999c4662631cb798496535afbd837a102859568adc67d75d2045e31ec3ac497"},
-    {url = "https://files.pythonhosted.org/packages/72/5e/96610128f06a47090b93708978ce96029f02291a62ddc63c786f4de45ed4/yarl-1.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ec362167e2c9fd178f82f252b6d97669d7245695dc057ee182118042026da40"},
-    {url = "https://files.pythonhosted.org/packages/83/ac/2a9e5d5a2347be5a19bfe8d1eb5b59d3582db11f0b92c2b26f0e220a7ca5/yarl-1.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31a9a04ecccd6b03e2b0e12e82131f1488dea5555a13a4d32f064e22a6003cfe"},
-    {url = "https://files.pythonhosted.org/packages/87/27/f99c22607862ae77d76b31e2fcf72f88c5c97aa342beaac12963844b9f34/yarl-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d1a50e461615747dd93c099f297c1994d472b0f4d2db8a64e55b1edf704ec1c"},
-    {url = "https://files.pythonhosted.org/packages/90/fc/5fb6ad9196322efddc7e3779e00ecab01b3073f90852906fb44118e5e82b/yarl-1.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7de89c8456525650ffa2bb56a3eee6af891e98f498babd43ae307bd42dca98f6"},
-    {url = "https://files.pythonhosted.org/packages/97/d9/e37a639c8ead053e5cb00d217edd451ab0504f961f71e2dea898889b65a8/yarl-1.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:19cd801d6f983918a3f3a39f3a45b553c015c5aac92ccd1fac619bd74beece4a"},
-    {url = "https://files.pythonhosted.org/packages/9a/f4/496a1f6c33ad274ac8fbd813aad80a6e19dd058848427f3b0fa0e3ac8704/yarl-1.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b3ded839a5c5608eec8b6f9ae9a62cb22cd037ea97c627f38ae0841a48f09eae"},
-    {url = "https://files.pythonhosted.org/packages/9f/cd/b815be9e7302e45e18e3109a73a4aedeb32964f2fec6ac7c334b63b7b280/yarl-1.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c0da7e44d0c9108d8b98469338705e07f4bb7dab96dbd8fa4e91b337db42548"},
-    {url = "https://files.pythonhosted.org/packages/a6/c4/4b92d3832d18fda62e396eaf15c27b564ae2bb6fbb93515512a297f6c16d/yarl-1.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29e256649f42771829974e742061c3501cc50cf16e63f91ed8d1bf98242e5507"},
-    {url = "https://files.pythonhosted.org/packages/b4/f8/d807818f2648c85c29abc7ccdc63c8ca5b136f03a2bb7828086f6fd4929d/yarl-1.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e80ed5a9939ceb6fda42811542f31c8602be336b1fb977bccb012e83da7e4936"},
-    {url = "https://files.pythonhosted.org/packages/bc/2b/9dd8299ef8d57a78295d5f2f9d14dc3e29dafcc306507de7a4bf0b24a301/yarl-1.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c03f456522d1ec815893d85fccb5def01ffaa74c1b16ff30f8aaa03eb21e453"},
-    {url = "https://files.pythonhosted.org/packages/c1/01/6e6f4100b4bc20935bc9e1d22225be43e0d299fb8a08a33c999a55b43309/yarl-1.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5395da939ffa959974577eff2cbfc24b004a2fb6c346918f39966a5786874e54"},
-    {url = "https://files.pythonhosted.org/packages/c8/44/ef8610a40656bb404b350402b426a1b9a242478c4b35ba3e3893264aae63/yarl-1.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ab2a60d57ca88e1d4ca34a10e9fb4ab2ac5ad315543351de3a612bbb0560bead"},
-    {url = "https://files.pythonhosted.org/packages/c8/a7/1a92f1049acd7f8fe122b5c78bd135b1a606414109b6cd43de696a5c4dfc/yarl-1.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6afb336e23a793cd3b6476c30f030a0d4c7539cd81649683b5e0c1b0ab0bf350"},
-    {url = "https://files.pythonhosted.org/packages/ca/db/706a8f5da17b42cc50bfca2cc5e5b2b0c2ae7bbacb8138cb5ac49456ecc0/yarl-1.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2b8f245dad9e331540c350285910b20dd913dc86d4ee410c11d48523c4fd546"},
-    {url = "https://files.pythonhosted.org/packages/ce/54/7527c4d474fbc36af1b2e1977ae1d5d0150563e72e360fa82ba0b12e31d4/yarl-1.8.1-cp310-cp310-win32.whl", hash = "sha256:ea30a42dc94d42f2ba4d0f7c0ffb4f4f9baa1b23045910c0c32df9c9902cb272"},
-    {url = "https://files.pythonhosted.org/packages/d1/4a/294168151f8bb9eb2c9ae0192b01a274f1a98056bfe08b80ce96f39bfb04/yarl-1.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:dd032e8422a52e5a4860e062eb84ac94ea08861d334a4bcaf142a63ce8ad4802"},
-    {url = "https://files.pythonhosted.org/packages/d2/20/74ba44eb5bf298997d8bc7c1a57fd3c15c677df13f21daee31b5ebf150b8/yarl-1.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:b19255dde4b4f4c32e012038f2c169bb72e7f081552bea4641cab4d88bc409dd"},
-    {url = "https://files.pythonhosted.org/packages/d4/f8/c6a73a7d8d8207720bbe197fb653c4faeae35d5a2281d5385d2613d46309/yarl-1.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7fce6cbc6c170ede0221cc8c91b285f7f3c8b9fe28283b51885ff621bbe0f8ee"},
-    {url = "https://files.pythonhosted.org/packages/d6/04/255c68974ec47fa754564c4abba8f61f9ed68b869bbbb854198d6259c4f7/yarl-1.8.1.tar.gz", hash = "sha256:af887845b8c2e060eb5605ff72b6f2dd2aab7a761379373fd89d314f4752abbf"},
-    {url = "https://files.pythonhosted.org/packages/dc/36/a3ddf9d3997d418a6b7ebb51a0bad474c4bb0f94a139d981242b653ce5fb/yarl-1.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:449c957ffc6bc2309e1fbe67ab7d2c1efca89d3f4912baeb8ead207bb3cc1cd4"},
-    {url = "https://files.pythonhosted.org/packages/dd/cf/5e7d506b9b5add77548252d6938380e08caf59ba808ac3cf0f0635629d1a/yarl-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea513a25976d21733bff523e0ca836ef1679630ef4ad22d46987d04b372d57fc"},
-    {url = "https://files.pythonhosted.org/packages/e5/95/e9257227d69a6e5fc9d542dbaa78798441bf9c3b7253c5868bda358991f3/yarl-1.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0ab5a138211c1c366404d912824bdcf5545ccba5b3ff52c42c4af4cbdc2c5035"},
-    {url = "https://files.pythonhosted.org/packages/e6/e0/1e778d018d5c5540b6cc7f77917102687bf23b850a9ab6236df1f558f1c0/yarl-1.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:076eede537ab978b605f41db79a56cad2e7efeea2aa6e0fa8f05a26c24a034fb"},
-    {url = "https://files.pythonhosted.org/packages/ec/ce/3dd8b79342c789d169cfb953f720213b9180163f6eb7fa254b0a2f702e2d/yarl-1.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:76577f13333b4fe345c3704811ac7509b31499132ff0181f25ee26619de2c843"},
-    {url = "https://files.pythonhosted.org/packages/f7/78/d78cffcf58a447a397b2554799b6d2415f968af2660a0dc39e2ef1aac660/yarl-1.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ca7e596c55bd675432b11320b4eacc62310c2145d6801a1f8e9ad160685a231"},
-    {url = "https://files.pythonhosted.org/packages/f9/6d/66b56ab2b8db30a5a24ec9a38684dec1c962741d8f0a0e6123c0fb2dc455/yarl-1.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f5af52738e225fcc526ae64071b7e5342abe03f42e0e8918227b38c9aa711e28"},
-    {url = "https://files.pythonhosted.org/packages/fc/1a/9840ca805e4a5f2d976fa2eb36dd78541c6f6fb15f7e6a1e225cfeceebc4/yarl-1.8.1-cp37-cp37m-win32.whl", hash = "sha256:de839c3a1826a909fdbfe05f6fe2167c4ab033f1133757b5936efe2f84904c07"},
-    {url = "https://files.pythonhosted.org/packages/fd/d0/9a3cd7b15bfa9f7b37f30364b16c654b01cccb222b34fbc93055bbca1fd3/yarl-1.8.1-cp39-cp39-win32.whl", hash = "sha256:8b0af1cf36b93cee99a31a545fe91d08223e64390c5ecc5e94c39511832a4bb6"},
-    {url = "https://files.pythonhosted.org/packages/fe/cb/ae0def686041d2da7dd631934f9f961123b597f9aa99c09917f67810cf6f/yarl-1.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d0272228fabe78ce00a3365ffffd6f643f57a91043e119c289aaba202f4095b0"},
-    {url = "https://files.pythonhosted.org/packages/ff/44/52161d5de9fc136e78e2e0663f2b386807f128b246f397817f4d4ae2e4f2/yarl-1.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0b51530877d3ad7a8d47b2fff0c8df3b8f3b8deddf057379ba50b13df2a5eae"},
-    {url = "https://files.pythonhosted.org/packages/ff/c0/ddcd9c883887a67c2d241fc807111fc2be840dcc5513067ddd59abfed933/yarl-1.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2d93a049d29df172f48bcb09acf9226318e712ce67374f893b460b42cc1380ae"},
+"yarl 1.8.2" = [
+    {url = "https://files.pythonhosted.org/packages/02/51/c33498373d2e0ff5d7f3e76038b7057003927d481405780d22f140906b24/yarl-1.8.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a1fca9588f360036242f379bfea2b8b44cae2721859b1c56d033adfd5893634"},
+    {url = "https://files.pythonhosted.org/packages/02/c6/13751bb69244e4835fa8192a20d1d1110091f717f1e1b0168320ed1a29c9/yarl-1.8.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3adeef150d528ded2a8e734ebf9ae2e658f4c49bf413f5f157a470e17a4a2e89"},
+    {url = "https://files.pythonhosted.org/packages/04/d8/2d1d9941715076b4585a054ad2e500ac7ea309c050c60c39a89caa3d50d8/yarl-1.8.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a783cd344113cb88c5ff7ca32f1f16532a6f2142185147822187913eb989f739"},
+    {url = "https://files.pythonhosted.org/packages/05/b8/db3ee364931d959c62ad4c5f636a36eff7b388e3a310d425f91269bf8f0c/yarl-1.8.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:728be34f70a190566d20aa13dc1f01dc44b6aa74580e10a3fb159691bc76909d"},
+    {url = "https://files.pythonhosted.org/packages/06/04/add788ffdf590fd8d7aa93bd0add24d369fbf864548adf80bab8c8587bd3/yarl-1.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cfa2bbca929aa742b5084fd4663dd4b87c191c844326fcb21c3afd2d11497f80"},
+    {url = "https://files.pythonhosted.org/packages/0d/88/90457ba43e9d4424ee58a1adfa04c717569ab31456480958576ac3e8cfff/yarl-1.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3fc056e35fa6fba63248d93ff6e672c096f95f7836938241ebc8260e062832fe"},
+    {url = "https://files.pythonhosted.org/packages/11/ea/c5487522577f3b029a39da71bbe81d7b13303894bde26c88046b2a180e79/yarl-1.8.2-cp311-cp311-win32.whl", hash = "sha256:fb742dcdd5eec9f26b61224c23baea46c9055cf16f62475e11b9b15dfd5c117b"},
+    {url = "https://files.pythonhosted.org/packages/13/69/714c371c8efee12a110e9a6775bf15a41755d41408f974731856f8bfe89b/yarl-1.8.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1684a9bd9077e922300ecd48003ddae7a7474e0412bea38d4631443a91d61077"},
+    {url = "https://files.pythonhosted.org/packages/14/9c/80ccfc199679bea8fa6982a49c88ac54a1ec0c8c033bede70fa84fcd13ca/yarl-1.8.2-cp39-cp39-win32.whl", hash = "sha256:cb6d48d80a41f68de41212f3dfd1a9d9898d7841c8f7ce6696cf2fd9cb57ef83"},
+    {url = "https://files.pythonhosted.org/packages/18/76/c0516fab27d4e9c7d4364418430fcf63cb0b0437d7470ae226aba948f568/yarl-1.8.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:34c09b43bd538bf6c4b891ecce94b6fa4f1f10663a8d4ca589a079a5018f6ed7"},
+    {url = "https://files.pythonhosted.org/packages/20/23/9ed12660f860962f179bca719b1d8a895c572c5dbb75098d35d074d35703/yarl-1.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0978f29222e649c351b173da2b9b4665ad1feb8d1daa9d971eb90df08702668a"},
+    {url = "https://files.pythonhosted.org/packages/21/47/47ef6563db61f6ecf9b23ac1b76682ec92b94cdd41fe645525411c127608/yarl-1.8.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da65c3f263729e47351261351b8679c6429151ef9649bba08ef2528ff2c423b2"},
+    {url = "https://files.pythonhosted.org/packages/21/9c/d3b5976d5de5ece14e50a8452d573ac1746fa377346f1bb099fcc3900c61/yarl-1.8.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f8ca8ad414c85bbc50f49c0a106f951613dfa5f948ab69c10ce9b128d368baf8"},
+    {url = "https://files.pythonhosted.org/packages/22/85/be8df871b9294272129306359d30f69c046fcc9a5df8528c2ff35af32735/yarl-1.8.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57a7c87927a468e5a1dc60c17caf9597161d66457a34273ab1760219953f7f4c"},
+    {url = "https://files.pythonhosted.org/packages/2e/dd/f1b1d3ddbc2f37f9cad188c984ac3ed0b3726b152b78d91ae7b24c49d3b5/yarl-1.8.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a48f4f7fea9a51098b02209d90297ac324241bf37ff6be6d2b0149ab2bd51b37"},
+    {url = "https://files.pythonhosted.org/packages/3c/82/badd5416e11351a9fb513a0ce8573f3abd8581aed8db595601023645b575/yarl-1.8.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93202666046d9edadfe9f2e7bf5e0782ea0d497b6d63da322e541665d65a044e"},
+    {url = "https://files.pythonhosted.org/packages/3e/da/942a19605c385e887a0ed784429d95a608a54cd0aa8dc9b44396bc8b57f5/yarl-1.8.2-cp310-cp310-win32.whl", hash = "sha256:b05df9ea7496df11b710081bd90ecc3a3db6adb4fee36f6a411e7bc91a18aa42"},
+    {url = "https://files.pythonhosted.org/packages/42/37/d8eae7ce26f39d0115375e3b654714c550933ffefa4d07104f85d0d37b41/yarl-1.8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:47d49ac96156f0928f002e2424299b2c91d9db73e08c4cd6742923a086f1c863"},
+    {url = "https://files.pythonhosted.org/packages/4c/8a/4ebd7bbee5fc9a77a2d382ef8c6d1d6bff77362df4fbd0efe4c810c3a155/yarl-1.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcd7bb1e5c45274af9a1dd7494d3c52b2be5e6bd8d7e49c612705fd45420b12d"},
+    {url = "https://files.pythonhosted.org/packages/4f/1a/043606ef5e785efede363552c002e53bd2ce3bbea7fdf5ada8cbe9b39b2f/yarl-1.8.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b372aad2b5f81db66ee7ec085cbad72c4da660d994e8e590c997e9b01e44901"},
+    {url = "https://files.pythonhosted.org/packages/52/e4/7bcabff7bc7b8421bef266bc955367f586d48667eb0a6ae812852feb51e8/yarl-1.8.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4d04acba75c72e6eb90745447d69f84e6c9056390f7a9724605ca9c56b4afcc6"},
+    {url = "https://files.pythonhosted.org/packages/53/4a/379701b5373a47b49d2a590fd2a7f8502fb4f7da79eb187ee3f25e8fd84c/yarl-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef8fb25e52663a1c85d608f6dd72e19bd390e2ecaf29c17fb08f730226e3a08"},
+    {url = "https://files.pythonhosted.org/packages/54/e9/5ec82331620403dfc1b76f1c97771375e1ec1725e95c6906998c9b7eea26/yarl-1.8.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e6f3515aafe0209dd17fb9bdd3b4e892963370b3de781f53e1746a521fb39fc0"},
+    {url = "https://files.pythonhosted.org/packages/5c/2c/8a41574a0afd95f4b4e8eb3477361ec3515ca8daddba441b49c2be70b7d5/yarl-1.8.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e59399dda559688461762800d7fb34d9e8a6a7444fd76ec33220a926c8be1516"},
+    {url = "https://files.pythonhosted.org/packages/5e/81/6691d7dd1c6ca607a4d6804557e6e0bf43dd52ad8ae2bf8bdca2e5cce54d/yarl-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:24ad1d10c9db1953291f56b5fe76203977f1ed05f82d09ec97acb623a7976574"},
+    {url = "https://files.pythonhosted.org/packages/5f/3c/59d045a4094f11dea659b69bfca8338803f6cb161da5b039d35cb415a84d/yarl-1.8.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:75c16b2a900b3536dfc7014905a128a2bea8fb01f9ee26d2d7d8db0a08e7cb2c"},
+    {url = "https://files.pythonhosted.org/packages/64/cd/b246a3d8dcbddd8bb3eeb83a4dda9b416d076ca93d48fe9364f533f74b2f/yarl-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:d881d152ae0007809c2c02e22aa534e702f12071e6b285e90945aa3c376463c5"},
+    {url = "https://files.pythonhosted.org/packages/67/69/129bf73c5fe35a8c0ad1500bf4e1145e610ef956316784911fee41a7fae7/yarl-1.8.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5df5e3d04101c1e5c3b1d69710b0574171cc02fddc4b23d1b2813e75f35a30b1"},
+    {url = "https://files.pythonhosted.org/packages/6a/de/90a6baeb12f8a09f4b17c2cb274fbadcb6469f5b66993f36d08c1bbb095d/yarl-1.8.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e21fb44e1eff06dd6ef971d4bdc611807d6bd3691223d9c01a18cec3677939e"},
+    {url = "https://files.pythonhosted.org/packages/6f/3e/a9fc9c32ba8788758af0bb95edc0e75853561259dabd47920a6ef820c242/yarl-1.8.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3edac5d74bb3209c418805bda77f973117836e1de7c000e9755e572c1f7850d0"},
+    {url = "https://files.pythonhosted.org/packages/7a/a5/b0e5ec63f806465381df8db27690757e072bcdca21aebb9419ea72e12d7b/yarl-1.8.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:efff27bd8cbe1f9bd127e7894942ccc20c857aa8b5a0327874f30201e5ce83d0"},
+    {url = "https://files.pythonhosted.org/packages/7c/9a/6f2039a5578f2af2d36f22173abf22c957970e908617b90e12552f7dfc9a/yarl-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42430ff511571940d51e75cf42f1e4dbdded477e71c1b7a17f4da76c1da8ea76"},
+    {url = "https://files.pythonhosted.org/packages/7f/13/a4b6ffff8f3278c020d6b7c42fee53133f6165d347db94bdd9ae394ba4f8/yarl-1.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6d88056a04860a98341a0cf53e950e3ac9f4e51d1b6f61a53b0609df342cc8b2"},
+    {url = "https://files.pythonhosted.org/packages/81/e5/d2b70c55a217697629fd653b33e9ac209bb465dbbad44dadb0a009900ec8/yarl-1.8.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dfef7350ee369197106805e193d420b75467b6cceac646ea5ed3049fcc950a05"},
+    {url = "https://files.pythonhosted.org/packages/83/15/6a532d39772d24e0383b83bccb252ddc97da7943fca96c1e1696af834e48/yarl-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ceff9722e0df2e0a9e8a79c610842004fa54e5b309fe6d218e47cd52f791d7ef"},
+    {url = "https://files.pythonhosted.org/packages/88/59/fd28cddd2fe1806cde775c61b43dfe824b672bef1d214383fd86ead3db93/yarl-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:8c46d3d89902c393a1d1e243ac847e0442d0196bbd81aecc94fcebbc2fd5857c"},
+    {url = "https://files.pythonhosted.org/packages/88/6f/6ed536b68a754fe337f6d8b7686d6c28d7474c5326087eb76dd1a9975675/yarl-1.8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bb81f753c815f6b8e2ddd2eef3c855cf7da193b82396ac013c661aaa6cc6b0a5"},
+    {url = "https://files.pythonhosted.org/packages/8b/cc/340f4cbea79da7462c5033108b674b42b7e0c1bcf7b0177da839e27a4afb/yarl-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:418857f837347e8aaef682679f41e36c24250097f9e2f315d39bae3a99a34cbf"},
+    {url = "https://files.pythonhosted.org/packages/97/bb/c03ef39330f6d302863746c80094f566e5ff9949bc267062d4dcdc8e2264/yarl-1.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44ceac0450e648de86da8e42674f9b7077d763ea80c8ceb9d1c3e41f0f0a9951"},
+    {url = "https://files.pythonhosted.org/packages/99/4f/e756d7569e3999bd7493be53a66b2e59caa97c70fec4f6fd17ea3315c0ef/yarl-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:6604711362f2dbf7160df21c416f81fac0de6dbcf0b5445a2ef25478ecc4c778"},
+    {url = "https://files.pythonhosted.org/packages/9b/d2/7813ebb6fe192e568c78ba56658f7a26caeceff6302a96808512f5ee40fd/yarl-1.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c15163b6125db87c8f53c98baa5e785782078fbd2dbeaa04c6141935eb6dab7a"},
+    {url = "https://files.pythonhosted.org/packages/9f/f0/63ceb39bb191f7559bfe53afcd919c105d503fbf7712d0fb10d92db879e6/yarl-1.8.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f6b4aca43b602ba0f1459de647af954769919c4714706be36af670a5f44c9c1"},
+    {url = "https://files.pythonhosted.org/packages/a1/be/fb772a7a6fa8246cea3499fdf558b81a0a269b7cf6b5ff2bdaf180104c2b/yarl-1.8.2-cp38-cp38-win32.whl", hash = "sha256:272b4f1599f1b621bf2aabe4e5b54f39a933971f4e7c9aa311d6d7dc06965165"},
+    {url = "https://files.pythonhosted.org/packages/a6/39/ac5344a9490f1484b1098f5285c34691ba77e32662f8e4600b4c40980ea6/yarl-1.8.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ff205b58dc2929191f68162633d5e10e8044398d7a45265f90a0f1d51f85f72c"},
+    {url = "https://files.pythonhosted.org/packages/b2/73/78372b24715d2b34348445ef501430d9d60ab11dcc2e20fd94cf2d086fcc/yarl-1.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae0eec05ab49e91a78700761777f284c2df119376e391db42c38ab46fd662b77"},
+    {url = "https://files.pythonhosted.org/packages/b3/0d/0ba1f2022b9a36ae670c1f3c579ed08d0958398cb6beaf4687e606ad33d4/yarl-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dd68a92cab699a233641f5929a40f02a4ede8c009068ca8aa1fe87b8c20ae3"},
+    {url = "https://files.pythonhosted.org/packages/b5/e0/6ea3832faed10de6a06cd407c660e6978d5538fe7489e934fb9967c8bb8b/yarl-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c4fcfa71e2c6a3cb568cf81aadc12768b9995323186a10827beccf5fa23d4f8"},
+    {url = "https://files.pythonhosted.org/packages/b8/53/ceec5140e3cb51c904bb87fca5cf6a3ba5d98b0ea13991dd21833d90662e/yarl-1.8.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:48dd18adcf98ea9cd721a25313aef49d70d413a999d7d89df44f469edfb38a06"},
+    {url = "https://files.pythonhosted.org/packages/b9/bd/42b39f09ed7b26ed810900f513cd579d5918e3ca39de22f5c5f401a7c102/yarl-1.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae4d7ff1049f36accde9e1ef7301912a751e5bae0a9d142459646114c70ecba6"},
+    {url = "https://files.pythonhosted.org/packages/b9/e4/66e2f32179075d2b5e1c0046b7cd23b1a4c71584765255fed51b89b6efe3/yarl-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7a66c506ec67eb3159eea5096acd05f5e788ceec7b96087d30c7d2865a243918"},
+    {url = "https://files.pythonhosted.org/packages/ba/85/f9e3350daa31161d1f4dfb10e195951df4ac22d8f201603cf894b37510c8/yarl-1.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3150078118f62371375e1e69b13b48288e44f6691c1069340081c3fd12c94d5b"},
+    {url = "https://files.pythonhosted.org/packages/ba/c2/8760e6df148cb9d092894decfd9fcf07593bfff26f6716f992d5a1ca7a5c/yarl-1.8.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:74dece2bfc60f0f70907c34b857ee98f2c6dd0f75185db133770cd67300d505f"},
+    {url = "https://files.pythonhosted.org/packages/be/d8/fcf074e9c246a0d22241f94d474794c876c073a3191d1608a64492d7ea4f/yarl-1.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58a3c13d1c3005dbbac5c9f0d3210b60220a65a999b1833aa46bd6677c69b08e"},
+    {url = "https://files.pythonhosted.org/packages/c0/fd/2f7a640dc157cc2d111114106e3036a69ba3408460d38580f681377c122d/yarl-1.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388a45dc77198b2460eac0aca1efd6a7c09e976ee768b0d5109173e521a19daf"},
+    {url = "https://files.pythonhosted.org/packages/c1/a7/7a1b5dfdc8d86784d3f0a5769721aaa0dec1633236f0ee237264cb515cdb/yarl-1.8.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc77086ce244453e074e445104f0ecb27530d6fd3a46698e33f6c38951d5a0f1"},
+    {url = "https://files.pythonhosted.org/packages/c2/4d/2d0cd4867b4699291479f329c8cfd3943edafe5ba7c250c31f7a65af2196/yarl-1.8.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:97209cc91189b48e7cfe777237c04af8e7cc51eb369004e061809bcdf4e55220"},
+    {url = "https://files.pythonhosted.org/packages/c4/1e/1b204050c601d5cd82b45d5c8f439cb6f744a2ce0c0a6f83be0ddf0dc7b2/yarl-1.8.2.tar.gz", hash = "sha256:49d43402c6e3013ad0978602bf6bf5328535c48d192304b91b97a3c6790b1562"},
+    {url = "https://files.pythonhosted.org/packages/c6/1c/4a992306ad86a8ae5a1fb4745bd76c590e7bcdb01ce2203dfd38dc830dfe/yarl-1.8.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e7fd20d6576c10306dea2d6a5765f46f0ac5d6f53436217913e952d19237efc4"},
+    {url = "https://files.pythonhosted.org/packages/c6/dc/50fe7fdcf3d27828a5922aaa1c4cbdf2d03827cd5ca6ace2757289e5ee18/yarl-1.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bf071f797aec5b96abfc735ab97da9fd8f8768b43ce2abd85356a3127909d146"},
+    {url = "https://files.pythonhosted.org/packages/c8/29/388508ba25f7cf777fac774c01cfb4ebf805efa3a567c4e2da570983e13a/yarl-1.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d617c241c8c3ad5c4e78a08429fa49e4b04bedfc507b34b4d8dceb83b4af3588"},
+    {url = "https://files.pythonhosted.org/packages/c8/b1/79645f117946e9d6fbc4880d5703393891f1ad7520dceb425754e6d93a62/yarl-1.8.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebb78745273e51b9832ef90c0898501006670d6e059f2cdb0e999494eb1450c2"},
+    {url = "https://files.pythonhosted.org/packages/ca/f3/2ef9870409b3ea57a5890e4e49b6bfd6e347a45fe92f6b2e9567abfefb59/yarl-1.8.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f37db05c6051eff17bc832914fe46869f8849de5b92dc4a3466cd63095d23dfd"},
+    {url = "https://files.pythonhosted.org/packages/cb/82/91f74496b653ac9a6220ee499510377c03a4ff768c5bd945f6759b23ebb8/yarl-1.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2305517e332a862ef75be8fad3606ea10108662bc6fe08509d5ca99503ac2aee"},
+    {url = "https://files.pythonhosted.org/packages/cf/4c/4d0d1a5c50fab50ae368b9a8af1e1e6437fe1dc28ff8a04a06a90136af63/yarl-1.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10b08293cda921157f1e7c2790999d903b3fd28cd5c208cf8826b3b508026996"},
+    {url = "https://files.pythonhosted.org/packages/d3/50/a9a7e280bb94def4a7497d27dd0c9fc87c6feb2ef9cf7639df15b2d0a1e1/yarl-1.8.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:df60a94d332158b444301c7f569659c926168e4d4aad2cfbf4bce0e8fb8be826"},
+    {url = "https://files.pythonhosted.org/packages/d7/56/3e792cef8ad8a904d11850101a7b4f3f0a1364c77f2f6278b41d75028118/yarl-1.8.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2b4fa2606adf392051d990c3b3877d768771adc3faf2e117b9de7eb977741229"},
+    {url = "https://files.pythonhosted.org/packages/de/c2/bdfaa94701e9f1dbd0dfd0454bcb56cf49669ba4591361161fbc5a5ef455/yarl-1.8.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:63243b21c6e28ec2375f932a10ce7eda65139b5b854c0f6b82ed945ba526bff3"},
+    {url = "https://files.pythonhosted.org/packages/df/8e/6163228567a53797d5468d39ec6d9133fa78aeb3490ff6a979730e056209/yarl-1.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de986979bbd87272fe557e0a8fcb66fd40ae2ddfe28a8b1ce4eae22681728fef"},
+    {url = "https://files.pythonhosted.org/packages/e6/d3/5f5b39db2c8c09f6923418c9329a04fe6f68825f27d2cb9776871d75ddc3/yarl-1.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77e913b846a6b9c5f767b14dc1e759e5aff05502fe73079f6f4176359d832581"},
+    {url = "https://files.pythonhosted.org/packages/ea/4c/7b7728f7db3dcf126a26fc07b4cbef20e6c1fdddc2ba03f0c0fc4b7b3db3/yarl-1.8.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:705227dccbe96ab02c7cb2c43e1228e2826e7ead880bb19ec94ef279e9555b5b"},
+    {url = "https://files.pythonhosted.org/packages/ec/e8/eaa1e4f8084f3533c4c8d1077b3aac1654975eaa497132cd14a369b7dbd0/yarl-1.8.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baf211dcad448a87a0d9047dc8282d7de59473ade7d7fdf22150b1d23859f946"},
+    {url = "https://files.pythonhosted.org/packages/ed/cd/14b70241fce4f1770bdd51d6c926d56f82aa9e6de89386e48610e81bafae/yarl-1.8.2-cp37-cp37m-win32.whl", hash = "sha256:0414fd91ce0b763d4eadb4456795b307a71524dbacd015c657bb2a39db2eab89"},
+    {url = "https://files.pythonhosted.org/packages/f1/e1/e76a76353444f895a1f0b52e71c28d27a25c4657e51ed30666ef7bb7ff74/yarl-1.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:009a028127e0a1755c38b03244c0bea9d5565630db9c4cf9572496e947137a87"},
+    {url = "https://files.pythonhosted.org/packages/f9/fa/9c746d29462714663d04cf9e34cc44a86efa17705a811c77556643b80f1b/yarl-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:326dd1d3caf910cd26a26ccbfb84c03b608ba32499b5d6eeb09252c920bcbe4f"},
 ]
 "zipp 3.10.0" = [
     {url = "https://files.pythonhosted.org/packages/40/8a/d63273ed0fa4a3d06f77e7b043f6577d8894e95515b0c187c52e2c0efabb/zipp-3.10.0-py3-none-any.whl", hash = "sha256:4fcb6f278987a6605757302a6e40e896257570d11c51628968ccb2a47e80c6c1"},
diff --git a/pyproject.toml b/pyproject.toml
index b5c7b4fc..57f91e56 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -47,13 +47,16 @@ target-version = ['py39']
 profile = "black"
 
 [tool.mina.packages.core]
-includes = ["avilla/core", "avilla/core/py.typed"]
+includes = ["avilla/core", "avilla/core/py.typed", "avilla/spec/core"]
 
 [tool.mina.packages.core.project]
 name = "avilla-core"
-version = "1.0.0rc4"
+version = "1.0.0-alpha.5"
 authors = [
   {name = "GreyElaina", email = "GreyElaina@outlook.com"},
+  {name = "BlueGlassBlock", email = "blueglassblock@outlook.com"},
+  {name = "ProgramRipper", email = "programripper@foxmail.com"},
+  {name = "RF-Tar-Railt", email = "rf_tar_railt@qq.com"}
 ]
 dependencies = [
     "graia-broadcast",
@@ -79,11 +82,14 @@ raw-dependencies = [
 
 [tool.mina.packages.elizabeth.project]
 name = "avilla-elizabeth"
-version = "1.0.0rc4" # WIP for release.
+version = "1.0.0-alpha.5" # WIP for release.
 authors = [
   {name = "GreyElaina", email = "GreyElaina@outlook.com"},
 ]
-dependencies = []
+dependencies = [
+  "avilla-core >= 1.0.0-alpha.5",
+  "avilla-spec-qq >= 1.0.0-alpha.5"
+]
 description = ""
 license = {text = "MIT"}
 readme = "README.md"
@@ -92,3 +98,27 @@ requires-python = ">=3.9"
 [tool.mina.packages.elizabeth.project.urls]
 homepage = "https://github.com/GraiaProject/Avilla"
 repository = "https://github.com/GraiaProject/Avilla"
+
+[tool.mina.packages."spec/qq"]
+includes = ["avilla/spec/qq"]
+
+[tool.mina.packages."spec/qq".project]
+name = "avilla-spec-qq"
+version = "1.0.0-alpha.5"
+authors = [
+  {name = "GreyElaina", email = "GreyElaina@outlook.com"},
+  {name = "BlueGlassBlock", email = "blueglassblock@outlook.com"},
+  {name = "ProgramRipper", email = "programripper@foxmail.com"},
+  {name = "RF-Tar-Railt", email = "rf_tar_railt@qq.com"}
+]
+dependencies = [
+  "avilla-core >= 1.0.0-alpha.5"
+]
+description = ""
+license = {text = "MIT"}
+readme = "README.md"
+requires-python = ">=3.9"
+
+[tool.mina.packages."spec/qq".project.urls]
+homepage = "https://github.com/GraiaProject/Avilla"
+repository = "https://github.com/GraiaProject/Avilla"
\ No newline at end of file
diff --git a/pyrightconfig.json b/pyrightconfig.json
index 25d23b0f..8a1e023a 100644
--- a/pyrightconfig.json
+++ b/pyrightconfig.json
@@ -1,3 +1,4 @@
 {
-    "exclude": ["__pypackages__", ".venv"]
+    "exclude": ["__pypackages__", ".venv"],
+    "reportShadowedImports": false,
 }
diff --git a/avilla/core/trait/extension.py b/temp/extension.py
similarity index 78%
rename from avilla/core/trait/extension.py
rename to temp/extension.py
index 50bdd86f..7efd8dbb 100644
--- a/avilla/core/trait/extension.py
+++ b/temp/extension.py
@@ -7,7 +7,7 @@
 from avilla.core.trait.signature import ExtensionImpl
 
 if TYPE_CHECKING:
-    from avilla.core.relationship import Relationship
+    from avilla.core.context import Context
 
 
 class FnExtension:
@@ -20,23 +20,25 @@ def set_group(self, group: str):
 
 E = TypeVar("E", bound=FnExtension)
 
+
 class ExtensionHandler:
-    rs: Relationship
+    rs: Context
 
-    _artifacts: dict[ExtensionImpl, Callable[[Relationship, FnExtension], Awaitable[Any]]]
+    _artifacts: dict[ExtensionImpl, Callable[[Context, FnExtension], Awaitable[Any]]]
 
-    def __init__(self, rs: Relationship):
+    def __init__(self, rs: Context):
         self.rs = rs
 
-        self._artifacts = {k: v for k, v in rs._artifacts.items() if isinstance(k, ExtensionImpl)}
-    
-    def add_impl(self, signature: ExtensionImpl, impl: Callable[[Relationship, FnExtension], Awaitable[Any]]):
+        self._artifacts = {k: v for k, v in rs._impl_artifacts.items() if isinstance(k, ExtensionImpl)}
+
+    def add_impl(self, signature: ExtensionImpl, impl: Callable[[Context, FnExtension], Awaitable[Any]]):
         self._artifacts[signature] = impl
-    
+
     def impl(self, signature: ExtensionImpl[E]):
-        def wrapper(impl: Callable[[Relationship, E], Awaitable[Any]]):
+        def wrapper(impl: Callable[[Context, E], Awaitable[Any]]):
             self._artifacts[signature] = impl  # type: ignore
             return impl
+
         return wrapper
 
     async def handle_extensions(self):
@@ -60,7 +62,7 @@ async def handle_extensions(self):
             raise NotImplementedError(
                 f"groups {repr(failed_group)} cannot be displayed due to all attempt for apply failed"
             )
-        
+
         for impl, impl_ext in impl_map.items():
             for ext in impl_ext:
                 await impl(self.rs, ext)


Test patch:
diff --git a/test.py b/test.py
index 6bbdc82b..1efb01e7 100644
--- a/test.py
+++ b/test.py
@@ -1,66 +1,27 @@
-import asyncio
-import sys
-from datetime import timedelta
+from inspect import cleandoc
 
+from avilla.core.resource import LocalFileResource
+from avilla.core.elements import Picture
 from creart import create
+from launart import Launart
 from graia.amnesia.builtins.aiohttp import AiohttpClientService
 from graia.broadcast import Broadcast
 
-from avilla.core.account import AbstractAccount
-
-# from avilla.core.action import MessageSend
-from avilla.core.application import Avilla
-from avilla.core.cell.cells import Privilege, Summary
-from avilla.core.elements import Picture
-from avilla.core.event.message import MessageReceived
-from avilla.core.message import Message
-from avilla.core.relationship import Relationship
-from avilla.core.resource import LocalFileResource
-from avilla.core.skeleton.message import MessageSend
-from avilla.core.skeleton.privilege import MuteTrait
-from avilla.core.utilles.selector import DynamicSelector, Selector
+from avilla.core import Avilla, Context, MessageReceived
 from avilla.elizabeth.connection.config import WebsocketClientConfig
 from avilla.elizabeth.protocol import ElizabethProtocol
 
-protocol = ElizabethProtocol(WebsocketClientConfig("1779309090", "testafafv4fv34v34g3y45"))
 broadcast = create(Broadcast)
-avilla = Avilla(broadcast, [protocol], [AiohttpClientService()])
+launart = Launart()
+launart.add_service(AiohttpClientService())
+avilla = Avilla(broadcast, launart, [ElizabethProtocol(WebsocketClientConfig("1779309090", "testafafv4fv34v34g3y45"))])
 
 
 @broadcast.receiver(MessageReceived)
-async def on_message_received(event: MessageReceived, rs: Relationship, account: AbstractAccount):
-    print(event, rs, rs.ctx.pattern, DynamicSelector(mode="exist").member(lambda x: x == "1846913566").match(rs.ctx))
-    print(await rs.pull(Privilege >> Summary, rs.ctx))
-    if DynamicSelector.fragment().group("*").member("1846913566").match(rs.ctx):
-        # await rs.exec(MessageSend([
-        #    "Hello, Avilla!", Image(LocalFileResource("development/photo_2022-07-10_22-12-22.jpg"))
-        # ]))
-        # t = rs.complete(Selector().friend("1846913566"))
-        # print(t)
-        # rs2 = await account.get_relationship(t)
-        a = event.message.content.get(Picture)
-        print(a, event.message.content)
-        if a:
-            b = await rs.fetch(a[0].resource)
-            print("pulled!", len(list(b)))
-        # r = await rs.send_message(
-        #    [
-        #        "Hello, Avilla!",
-        #        Picture(LocalFileResource("development/photo_2022-07-10_22-12-22.jpg")),
-        #        "\n本消息将于 10s 后撤回",
-        #    ]
-        # )
-        print(await rs.cast(MuteTrait).mute(rs.mainline.copy().member("3542335634"), timedelta(minutes=10)))
-        await asyncio.sleep(2)
-        print(await rs.cast(MuteTrait).unmute(rs.mainline.copy().member("3542335634")))
-        # c = await rs.cast(MessageTrait).revoke(r)
-        # print("1")
-        # async for i in rs.query(DynamicSelector().group("*").member("*")):
-        #    print(i)
-        # print("2")
-        # print(rs.complete(DynamicSelector().group("*")))
-        # async for i in rs.query(DynamicSelector().land(rs.land).group("*").member("*")):
-        #    print(i)
+async def on_message_received(ctx: Context, event: MessageReceived):
+    print(event, ctx.client, ctx.client.follows("group.member(208924405)"))
+    if ctx.client.follows("group.member(208924405)"):
+        await ctx.scene.send_message([Picture(LocalFileResource("./development/photo_2022-07-10_22-12-22.jpg"))])
 
 
 avilla.launch_manager.launch_blocking(loop=broadcast.loop)