diff --git a/Makefile b/Makefile
index 3a3c42cd9723366e5c62544979ed22dcff209df5..8de202fa56f0de52a80f6f8a63e68ab6fe18ef33 100644
--- a/Makefile
+++ b/Makefile
@@ -9,6 +9,7 @@ lint_diff: PYTHON_FILES=$(shell git diff --name-only --diff-filter=d main | grep
 lint lint_diff:
 	poetry run black $(PYTHON_FILES) --check
 	poetry run ruff .
+	poetry run mypy $(PYTHON_FILES)
 
 test:
 	poetry run pytest -vv -n 20 --cov=semantic_router --cov-report=term-missing --cov-report=xml --cov-fail-under=100
diff --git a/README.md b/README.md
index 9dac42225f967e558b3cac590e3dd4a0bf7a782b..b4b3c0e3260bea834a352de9ddaedfddfe798f68 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@
 <img alt="" src="https://img.shields.io/github/repo-size/aurelio-labs/semantic-router" />
 <img alt="GitHub Issues" src="https://img.shields.io/github/issues/aurelio-labs/semantic-router" />
 <img alt="GitHub Pull Requests" src="https://img.shields.io/github/issues-pr/aurelio-labs/semantic-router" />
+<img src="https://codecov.io/gh/aurelio-labs/semantic-router/graph/badge.svg?token=H8OOMV2TUF" />
 <img alt="Github License" src="https://img.shields.io/badge/License-MIT-yellow.svg" />
 </p>
 
diff --git a/coverage.xml b/coverage.xml
index 3c9c2e7c7acc2890d77de9dd322f29415a4d39aa..8e6ca91d8e505ae98209a2c0ff3add414c2095e8 100644
--- a/coverage.xml
+++ b/coverage.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" ?>
-<coverage version="7.3.2" timestamp="1702458856280" lines-valid="311" lines-covered="311" line-rate="1" branches-covered="0" branches-valid="0" branch-rate="0" complexity="0">
+<coverage version="7.3.2" timestamp="1702463592393" lines-valid="334" lines-covered="334" line-rate="1" branches-covered="0" branches-valid="0" branch-rate="0" complexity="0">
 	<!-- Generated by coverage.py: https://coverage.readthedocs.io/en/7.3.2 -->
 	<!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->
 	<sources>
@@ -12,10 +12,11 @@
 					<methods/>
 					<lines>
 						<line number="1" hits="1"/>
-						<line number="3" hits="1"/>
+						<line number="2" hits="1"/>
+						<line number="4" hits="1"/>
 					</lines>
 				</class>
-				<class name="layer.py" filename="layer.py" complexity="0" line-rate="1" branch-rate="0">
+				<class name="hybrid_layer.py" filename="hybrid_layer.py" complexity="0" line-rate="1" branch-rate="0">
 					<methods/>
 					<lines>
 						<line number="1" hits="1"/>
@@ -28,144 +29,162 @@
 						<line number="16" hits="1"/>
 						<line number="17" hits="1"/>
 						<line number="18" hits="1"/>
-						<line number="20" hits="1"/>
+						<line number="19" hits="1"/>
 						<line number="21" hits="1"/>
-						<line number="23" hits="1"/>
 						<line number="24" hits="1"/>
 						<line number="25" hits="1"/>
 						<line number="26" hits="1"/>
 						<line number="28" hits="1"/>
+						<line number="29" hits="1"/>
 						<line number="30" hits="1"/>
-						<line number="32" hits="1"/>
-						<line number="34" hits="1"/>
+						<line number="31" hits="1"/>
+						<line number="33" hits="1"/>
 						<line number="35" hits="1"/>
-						<line number="36" hits="1"/>
 						<line number="37" hits="1"/>
 						<line number="38" hits="1"/>
-						<line number="39" hits="1"/>
+						<line number="40" hits="1"/>
 						<line number="41" hits="1"/>
-						<line number="46" hits="1"/>
-						<line number="48" hits="1"/>
-						<line number="51" hits="1"/>
+						<line number="42" hits="1"/>
+						<line number="43" hits="1"/>
+						<line number="44" hits="1"/>
+						<line number="45" hits="1"/>
+						<line number="47" hits="1"/>
+						<line number="49" hits="1"/>
+						<line number="50" hits="1"/>
 						<line number="52" hits="1"/>
 						<line number="54" hits="1"/>
 						<line number="55" hits="1"/>
-						<line number="57" hits="1"/>
-						<line number="58" hits="1"/>
 						<line number="60" hits="1"/>
 						<line number="61" hits="1"/>
-						<line number="63" hits="1"/>
+						<line number="62" hits="1"/>
+						<line number="64" hits="1"/>
 						<line number="65" hits="1"/>
-						<line number="68" hits="1"/>
+						<line number="66" hits="1"/>
+						<line number="70" hits="1"/>
 						<line number="71" hits="1"/>
-						<line number="74" hits="1"/>
+						<line number="73" hits="1"/>
 						<line number="75" hits="1"/>
-						<line number="82" hits="1"/>
-						<line number="83" hits="1"/>
+						<line number="76" hits="1"/>
+						<line number="78" hits="1"/>
+						<line number="80" hits="1"/>
+						<line number="85" hits="1"/>
+						<line number="86" hits="1"/>
+						<line number="88" hits="1"/>
 						<line number="89" hits="1"/>
-						<line number="94" hits="1"/>
+						<line number="91" hits="1"/>
+						<line number="93" hits="1"/>
 						<line number="95" hits="1"/>
+						<line number="96" hits="1"/>
 						<line number="97" hits="1"/>
 						<line number="99" hits="1"/>
 						<line number="100" hits="1"/>
+						<line number="101" hits="1"/>
 						<line number="102" hits="1"/>
-						<line number="103" hits="1"/>
-						<line number="107" hits="1"/>
+						<line number="104" hits="1"/>
+						<line number="105" hits="1"/>
+						<line number="106" hits="1"/>
+						<line number="108" hits="1"/>
 						<line number="109" hits="1"/>
-						<line number="110" hits="1"/>
 						<line number="111" hits="1"/>
 						<line number="112" hits="1"/>
-						<line number="113" hits="1"/>
 						<line number="114" hits="1"/>
-						<line number="115" hits="1"/>
+						<line number="116" hits="1"/>
 						<line number="117" hits="1"/>
+						<line number="118" hits="1"/>
 						<line number="120" hits="1"/>
+						<line number="121" hits="1"/>
+						<line number="122" hits="1"/>
 						<line number="123" hits="1"/>
+						<line number="124" hits="1"/>
+						<line number="125" hits="1"/>
 						<line number="126" hits="1"/>
 						<line number="128" hits="1"/>
-						<line number="129" hits="1"/>
-						<line number="130" hits="1"/>
+						<line number="131" hits="1"/>
 						<line number="132" hits="1"/>
 						<line number="135" hits="1"/>
 						<line number="136" hits="1"/>
-						<line number="137" hits="1"/>
 						<line number="138" hits="1"/>
 						<line number="139" hits="1"/>
 						<line number="141" hits="1"/>
-						<line number="144" hits="1"/>
+						<line number="142" hits="1"/>
+						<line number="143" hits="1"/>
 						<line number="145" hits="1"/>
-						<line number="146" hits="1"/>
-						<line number="148" hits="1"/>
-						<line number="149" hits="1"/>
-						<line number="150" hits="1"/>
-						<line number="151" hits="1"/>
-						<line number="153" hits="1"/>
-						<line number="155" hits="1"/>
-						<line number="157" hits="1"/>
-						<line number="158" hits="1"/>
-						<line number="160" hits="1"/>
-						<line number="161" hits="1"/>
-						<line number="162" hits="1"/>
-						<line number="163" hits="1"/>
-						<line number="164" hits="1"/>
-						<line number="165" hits="1"/>
-						<line number="167" hits="1"/>
-						<line number="169" hits="1"/>
-						<line number="170" hits="1"/>
-						<line number="172" hits="1"/>
-						<line number="174" hits="1"/>
-						<line number="175" hits="1"/>
-						<line number="180" hits="1"/>
-						<line number="181" hits="1"/>
-						<line number="182" hits="1"/>
-						<line number="184" hits="1"/>
-						<line number="185" hits="1"/>
-						<line number="186" hits="1"/>
-						<line number="190" hits="1"/>
-						<line number="191" hits="1"/>
-						<line number="193" hits="1"/>
-						<line number="195" hits="1"/>
-						<line number="196" hits="1"/>
-						<line number="198" hits="1"/>
-						<line number="200" hits="1"/>
-						<line number="205" hits="1"/>
-						<line number="206" hits="1"/>
-						<line number="208" hits="1"/>
-						<line number="209" hits="1"/>
-						<line number="211" hits="1"/>
-						<line number="213" hits="1"/>
-						<line number="215" hits="1"/>
-						<line number="216" hits="1"/>
-						<line number="217" hits="1"/>
-						<line number="219" hits="1"/>
-						<line number="220" hits="1"/>
-						<line number="221" hits="1"/>
-						<line number="222" hits="1"/>
-						<line number="224" hits="1"/>
-						<line number="225" hits="1"/>
-						<line number="226" hits="1"/>
-						<line number="228" hits="1"/>
-						<line number="229" hits="1"/>
-						<line number="233" hits="1"/>
-						<line number="235" hits="1"/>
-						<line number="237" hits="1"/>
-						<line number="238" hits="1"/>
-						<line number="239" hits="1"/>
-						<line number="241" hits="1"/>
-						<line number="242" hits="1"/>
-						<line number="243" hits="1"/>
-						<line number="244" hits="1"/>
-						<line number="245" hits="1"/>
-						<line number="246" hits="1"/>
-						<line number="247" hits="1"/>
-						<line number="249" hits="1"/>
-						<line number="252" hits="1"/>
-						<line number="255" hits="1"/>
-						<line number="258" hits="1"/>
-						<line number="260" hits="1"/>
-						<line number="261" hits="1"/>
-						<line number="262" hits="1"/>
-						<line number="264" hits="1"/>
+					</lines>
+				</class>
+				<class name="layer.py" filename="layer.py" complexity="0" line-rate="1" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="1" hits="1"/>
+						<line number="3" hits="1"/>
+						<line number="8" hits="1"/>
+						<line number="9" hits="1"/>
+						<line number="10" hits="1"/>
+						<line number="13" hits="1"/>
+						<line number="14" hits="1"/>
+						<line number="15" hits="1"/>
+						<line number="16" hits="1"/>
+						<line number="18" hits="1"/>
+						<line number="19" hits="1"/>
+						<line number="21" hits="1"/>
+						<line number="22" hits="1"/>
+						<line number="23" hits="1"/>
+						<line number="24" hits="1"/>
+						<line number="26" hits="1"/>
+						<line number="28" hits="1"/>
+						<line number="30" hits="1"/>
+						<line number="32" hits="1"/>
+						<line number="33" hits="1"/>
+						<line number="34" hits="1"/>
+						<line number="35" hits="1"/>
+						<line number="36" hits="1"/>
+						<line number="37" hits="1"/>
+						<line number="39" hits="1"/>
+						<line number="41" hits="1"/>
+						<line number="43" hits="1"/>
+						<line number="46" hits="1"/>
+						<line number="47" hits="1"/>
+						<line number="49" hits="1"/>
+						<line number="50" hits="1"/>
+						<line number="52" hits="1"/>
+						<line number="53" hits="1"/>
+						<line number="55" hits="1"/>
+						<line number="56" hits="1"/>
+						<line number="58" hits="1"/>
+						<line number="60" hits="1"/>
+						<line number="63" hits="1"/>
+						<line number="66" hits="1"/>
+						<line number="67" hits="1"/>
+						<line number="68" hits="1"/>
+						<line number="75" hits="1"/>
+						<line number="76" hits="1"/>
+						<line number="82" hits="1"/>
+						<line number="87" hits="1"/>
+						<line number="88" hits="1"/>
+						<line number="90" hits="1"/>
+						<line number="92" hits="1"/>
+						<line number="93" hits="1"/>
+						<line number="95" hits="1"/>
+						<line number="96" hits="1"/>
+						<line number="98" hits="1"/>
+						<line number="99" hits="1"/>
+						<line number="101" hits="1"/>
+						<line number="102" hits="1"/>
+						<line number="103" hits="1"/>
+						<line number="104" hits="1"/>
+						<line number="105" hits="1"/>
+						<line number="106" hits="1"/>
+						<line number="107" hits="1"/>
+						<line number="109" hits="1"/>
+						<line number="112" hits="1"/>
+						<line number="113" hits="1"/>
+						<line number="116" hits="1"/>
+						<line number="117" hits="1"/>
+						<line number="119" hits="1"/>
+						<line number="120" hits="1"/>
+						<line number="122" hits="1"/>
+						<line number="123" hits="1"/>
+						<line number="124" hits="1"/>
+						<line number="126" hits="1"/>
 					</lines>
 				</class>
 				<class name="linear.py" filename="linear.py" complexity="0" line-rate="1" branch-rate="0">
@@ -260,31 +279,40 @@
 					<lines>
 						<line number="1" hits="1"/>
 						<line number="3" hits="1"/>
-						<line number="6" hits="1"/>
-						<line number="7" hits="1"/>
+						<line number="5" hits="1"/>
 						<line number="8" hits="1"/>
+						<line number="9" hits="1"/>
 						<line number="10" hits="1"/>
-						<line number="11" hits="1"/>
+						<line number="12" hits="1"/>
 						<line number="13" hits="1"/>
 						<line number="14" hits="1"/>
+						<line number="16" hits="1"/>
+						<line number="17" hits="1"/>
+						<line number="18" hits="1"/>
 						<line number="19" hits="1"/>
 						<line number="20" hits="1"/>
-						<line number="21" hits="1"/>
 						<line number="22" hits="1"/>
-						<line number="23" hits="1"/>
+						<line number="24" hits="1"/>
 						<line number="25" hits="1"/>
+						<line number="26" hits="1"/>
 						<line number="27" hits="1"/>
 						<line number="28" hits="1"/>
 						<line number="29" hits="1"/>
 						<line number="30" hits="1"/>
-						<line number="31" hits="1"/>
 						<line number="32" hits="1"/>
-						<line number="33" hits="1"/>
 						<line number="34" hits="1"/>
+						<line number="35" hits="1"/>
 						<line number="36" hits="1"/>
 						<line number="37" hits="1"/>
+						<line number="38" hits="1"/>
 						<line number="39" hits="1"/>
 						<line number="40" hits="1"/>
+						<line number="41" hits="1"/>
+						<line number="42" hits="1"/>
+						<line number="44" hits="1"/>
+						<line number="45" hits="1"/>
+						<line number="46" hits="1"/>
+						<line number="47" hits="1"/>
 					</lines>
 				</class>
 				<class name="cohere.py" filename="encoders/cohere.py" complexity="0" line-rate="1" branch-rate="0">
@@ -352,6 +380,10 @@
 		</package>
 		<package name="utils" line-rate="1" branch-rate="0" complexity="0">
 			<classes>
+				<class name="__init__.py" filename="utils/__init__.py" complexity="0" line-rate="1" branch-rate="0">
+					<methods/>
+					<lines/>
+				</class>
 				<class name="logger.py" filename="utils/logger.py" complexity="0" line-rate="1" branch-rate="0">
 					<methods/>
 					<lines>
diff --git a/docs/examples/hybrid-layer.ipynb b/docs/examples/hybrid-layer.ipynb
index 98fccf6972026d62e6d53a3c96492ca90287207e..8b1da5ae75f0a8a9572996b8e416a282d2c48f1b 100644
--- a/docs/examples/hybrid-layer.ipynb
+++ b/docs/examples/hybrid-layer.ipynb
@@ -11,7 +11,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "The Hybrid Layer in the Semantic Router library can improve decision making performance particularly for niche use-cases that contain specific terminology, such as finance or medical. It helps us provide more importance to decision making based on the keywords contained in our utterances and user queries."
+    "The Hybrid Layer in the Semantic Router library can improve  making performance particularly for niche use-cases that contain specific terminology, such as finance or medical. It helps us provide more importance to  making based on the keywords contained in our utterances and user queries."
    ]
   },
   {
@@ -34,36 +34,37 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "!pip install -qU semantic-router==0.0.5"
+    "!pip install -qU semantic-router==0.0.6"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "We start by defining a dictionary mapping decisions to example phrases that should trigger those decisions."
+    "We start by defining a dictionary mapping s to example phrases that should trigger those s."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import os\n",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "ImportError",
+     "evalue": "cannot import name 'Route' from 'semantic_router.schema' (/Users/jakit/customers/aurelio/semantic-router/.venv/lib/python3.11/site-packages/semantic_router/schema.py)",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mImportError\u001b[0m                               Traceback (most recent call last)",
+      "\u001b[1;32m/Users/jakit/customers/aurelio/semantic-router/docs/examples/hybrid-layer.ipynb Cell 7\u001b[0m line \u001b[0;36m1\n\u001b[0;32m----> <a href='vscode-notebook-cell:/Users/jakit/customers/aurelio/semantic-router/docs/examples/hybrid-layer.ipynb#X10sZmlsZQ%3D%3D?line=0'>1</a>\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39msemantic_router\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mschema\u001b[39;00m \u001b[39mimport\u001b[39;00m Route\n\u001b[1;32m      <a href='vscode-notebook-cell:/Users/jakit/customers/aurelio/semantic-router/docs/examples/hybrid-layer.ipynb#X10sZmlsZQ%3D%3D?line=2'>3</a>\u001b[0m politics \u001b[39m=\u001b[39m Route(\n\u001b[1;32m      <a href='vscode-notebook-cell:/Users/jakit/customers/aurelio/semantic-router/docs/examples/hybrid-layer.ipynb#X10sZmlsZQ%3D%3D?line=3'>4</a>\u001b[0m     name\u001b[39m=\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mpolitics\u001b[39m\u001b[39m\"\u001b[39m,\n\u001b[1;32m      <a href='vscode-notebook-cell:/Users/jakit/customers/aurelio/semantic-router/docs/examples/hybrid-layer.ipynb#X10sZmlsZQ%3D%3D?line=4'>5</a>\u001b[0m     utterances\u001b[39m=\u001b[39m[\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m     <a href='vscode-notebook-cell:/Users/jakit/customers/aurelio/semantic-router/docs/examples/hybrid-layer.ipynb#X10sZmlsZQ%3D%3D?line=11'>12</a>\u001b[0m     ],\n\u001b[1;32m     <a href='vscode-notebook-cell:/Users/jakit/customers/aurelio/semantic-router/docs/examples/hybrid-layer.ipynb#X10sZmlsZQ%3D%3D?line=12'>13</a>\u001b[0m )\n",
+      "\u001b[0;31mImportError\u001b[0m: cannot import name 'Route' from 'semantic_router.schema' (/Users/jakit/customers/aurelio/semantic-router/.venv/lib/python3.11/site-packages/semantic_router/schema.py)"
+     ]
+    }
+   ],
+   "source": [
+    "from semantic_router.schema import Route\n",
     "\n",
-    "os.environ[\"COHERE_API_KEY\"] = \"BQBiUqqjDRsYl1QKKux4JsqKdDkjyInS5T3Z3eJP\""
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from semantic_router.schema import Decision\n",
-    "\n",
-    "politics = Decision(\n",
+    "politics = Route(\n",
     "    name=\"politics\",\n",
     "    utterances=[\n",
     "        \"isn't politics the best thing ever\",\n",
@@ -89,7 +90,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "chitchat = Decision(\n",
+    "chitchat = Route(\n",
     "    name=\"chitchat\",\n",
     "    utterances=[\n",
     "        \"how's the weather today?\",\n",
@@ -100,7 +101,7 @@
     "    ],\n",
     ")\n",
     "\n",
-    "chitchat = Decision(\n",
+    "chitchat = Route(\n",
     "    name=\"chitchat\",\n",
     "    utterances=[\n",
     "        \"how's the weather today?\",\n",
@@ -111,7 +112,7 @@
     "    ],\n",
     ")\n",
     "\n",
-    "decisions = [politics, chitchat]"
+    "routes = [politics, chitchat]"
    ]
   },
   {
@@ -127,6 +128,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
+    "import os\n",
     "from semantic_router.encoders import CohereEncoder\n",
     "from getpass import getpass\n",
     "\n",
@@ -141,7 +143,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Now we define the `DecisionLayer`. When called, the decision layer will consume text (a query) and output the category (`Decision`) it belongs to — to initialize a `DecisionLayer` we need our `encoder` model and a list of `decisions`."
+    "Now we define the `RouteLayer`. When called, the route layer will consume text (a query) and output the category (`Route`) it belongs to — to initialize a `RouteLayer` we need our `encoder` model and a list of `routes`."
    ]
   },
   {
@@ -150,9 +152,9 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "from semantic_router.layer import HybridDecisionLayer\n",
+    "from semantic_router.hybrid_layer import HybridRouteLayer\n",
     "\n",
-    "dl = HybridDecisionLayer(encoder=encoder, decisions=decisions)"
+    "dl = HybridRouteLayer(encoder=encoder, routes=routes)"
    ]
   },
   {
@@ -197,7 +199,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.11.5"
+   "version": "3.11.3"
   }
  },
  "nbformat": 4,
diff --git a/poetry.lock b/poetry.lock
index 3bedc8de3502b726b4fdbc6d765f0c7b1ffacea9..b459e6bab91d1777c8b70090352de26bc1ab70e3 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1065,6 +1065,53 @@ files = [
     {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"},
 ]
 
+[[package]]
+name = "mypy"
+version = "1.7.1"
+description = "Optional static typing for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"},
+    {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"},
+    {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"},
+    {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"},
+    {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"},
+    {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"},
+    {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"},
+    {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"},
+    {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"},
+    {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"},
+    {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"},
+    {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"},
+    {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"},
+    {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"},
+    {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"},
+    {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"},
+    {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"},
+    {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"},
+    {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"},
+    {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"},
+    {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"},
+    {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"},
+    {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"},
+    {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"},
+    {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"},
+    {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"},
+    {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"},
+]
+
+[package.dependencies]
+mypy-extensions = ">=1.0.0"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+typing-extensions = ">=4.1.0"
+
+[package.extras]
+dmypy = ["psutil (>=4.0)"]
+install-types = ["pip"]
+mypyc = ["setuptools (>=50)"]
+reports = ["lxml"]
+
 [[package]]
 name = "mypy-extensions"
 version = "1.0.0"
@@ -2055,4 +2102,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.10"
-content-hash = "b17b9fd9486d6c744c41a31ab54f7871daba1e2d4166fda228033c5858f6f9d8"
+content-hash = "58bf19052f05863cb4623e85a73de5758d581ff539cfb69f0920e57f6cb035d0"
diff --git a/pyproject.toml b/pyproject.toml
index b21cd485683a42c26724bba6c32724b197ec518e..5a8e18e06303a4406535d6640045d9cfc3e50768 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "semantic-router"
-version = "0.0.6"
+version = "0.0.7"
 description = "Super fast semantic router for AI decision making"
 authors = [
     "James Briggs <james@aurelio.ai>",
@@ -29,6 +29,7 @@ pytest = "^7.4.3"
 pytest-mock = "^3.12.0"
 pytest-cov = "^4.1.0"
 pytest-xdist = "^3.5.0"
+mypy = "^1.7.1"
 
 [build-system]
 requires = ["poetry-core"]
@@ -36,3 +37,6 @@ build-backend = "poetry.core.masonry.api"
 
 [tool.ruff.per-file-ignores]
 "*.ipynb" = ["E402"]
+
+[tool.mypy]
+ignore_missing_imports = true
diff --git a/semantic_router/__init__.py b/semantic_router/__init__.py
index 734906f8554e11898fbefe8c95ef92a555dc5c8d..0c445bea3ff4efd8f3aa8950e2c772277d93b20c 100644
--- a/semantic_router/__init__.py
+++ b/semantic_router/__init__.py
@@ -1,3 +1,4 @@
-from .layer import DecisionLayer, HybridDecisionLayer
+from .hybrid_layer import HybridRouteLayer
+from .layer import RouteLayer
 
-__all__ = ["DecisionLayer", "HybridDecisionLayer"]
+__all__ = ["RouteLayer", "HybridRouteLayer"]
diff --git a/semantic_router/encoders/base.py b/semantic_router/encoders/base.py
index b6de1f89b80f42ea42d3abe76bbf61441936aa6e..632ebc7924a5a74088068bfb329a4e04c68cb6df 100644
--- a/semantic_router/encoders/base.py
+++ b/semantic_router/encoders/base.py
@@ -7,5 +7,5 @@ class BaseEncoder(BaseModel):
     class Config:
         arbitrary_types_allowed = True
 
-    def __call__(self, docs: list[str]) -> list[float]:
+    def __call__(self, docs: list[str]) -> list[list[float]]:
         raise NotImplementedError("Subclasses must implement this method")
diff --git a/semantic_router/encoders/bm25.py b/semantic_router/encoders/bm25.py
index 0d498197b5e548ad3fd7cc0eade0b457f47d795f..c9da628e1493e53760f6c060dcd64e4dfccdc3d4 100644
--- a/semantic_router/encoders/bm25.py
+++ b/semantic_router/encoders/bm25.py
@@ -1,29 +1,36 @@
+from typing import Any
+
 from pinecone_text.sparse import BM25Encoder as encoder
 
 from semantic_router.encoders import BaseEncoder
 
 
 class BM25Encoder(BaseEncoder):
-    model: encoder | None = None
+    model: Any | None = None
     idx_mapping: dict[int, int] | None = None
 
     def __init__(self, name: str = "bm25"):
         super().__init__(name=name)
-        # initialize BM25 encoder with default params (trained on MSMarco)
         self.model = encoder.default()
-        self.idx_mapping = {
-            idx: i
-            for i, idx in enumerate(self.model.get_params()["doc_freq"]["indices"])
-        }
+
+        params = self.model.get_params()
+        doc_freq = params["doc_freq"]
+        if isinstance(doc_freq, dict):
+            indices = doc_freq["indices"]
+            self.idx_mapping = {int(idx): i for i, idx in enumerate(indices)}
+        else:
+            raise TypeError("Expected a dictionary for 'doc_freq'")
 
     def __call__(self, docs: list[str]) -> list[list[float]]:
+        if self.model is None or self.idx_mapping is None:
+            raise ValueError("Model or index mapping is not initialized.")
         if len(docs) == 1:
             sparse_dicts = self.model.encode_queries(docs)
         elif len(docs) > 1:
             sparse_dicts = self.model.encode_documents(docs)
         else:
             raise ValueError("No documents to encode.")
-        # convert sparse dict to sparse vector
+
         embeds = [[0.0] * len(self.idx_mapping)] * len(docs)
         for i, output in enumerate(sparse_dicts):
             indices = output["indices"]
@@ -32,9 +39,9 @@ class BM25Encoder(BaseEncoder):
                 if idx in self.idx_mapping:
                     position = self.idx_mapping[idx]
                     embeds[i][position] = val
-                else:
-                    print(idx, "not in encoder.idx_mapping")
         return embeds
 
     def fit(self, docs: list[str]):
+        if self.model is None:
+            raise ValueError("Model is not initialized.")
         self.model.fit(docs)
diff --git a/semantic_router/hybrid_layer.py b/semantic_router/hybrid_layer.py
new file mode 100644
index 0000000000000000000000000000000000000000..dec6336e917d1a21ead95720d50f5f2e582aaa81
--- /dev/null
+++ b/semantic_router/hybrid_layer.py
@@ -0,0 +1,145 @@
+import numpy as np
+from numpy.linalg import norm
+from tqdm.auto import tqdm
+
+from semantic_router.encoders import (
+    BaseEncoder,
+    BM25Encoder,
+    CohereEncoder,
+    OpenAIEncoder,
+)
+from semantic_router.schema import Route
+from semantic_router.utils.logger import logger
+
+
+class HybridRouteLayer:
+    index = None
+    sparse_index = None
+    categories = None
+    score_threshold = 0.82
+
+    def __init__(
+        self, encoder: BaseEncoder, routes: list[Route] = [], alpha: float = 0.3
+    ):
+        self.encoder = encoder
+        self.sparse_encoder = BM25Encoder()
+        self.alpha = alpha
+        # decide on default threshold based on encoder
+        if isinstance(encoder, OpenAIEncoder):
+            self.score_threshold = 0.82
+        elif isinstance(encoder, CohereEncoder):
+            self.score_threshold = 0.3
+        else:
+            self.score_threshold = 0.82
+        # if routes list has been passed, we initialize index now
+        if routes:
+            # initialize index now
+            for route in tqdm(routes):
+                self._add_route(route=route)
+
+    def __call__(self, text: str) -> str | None:
+        results = self._query(text)
+        top_class, top_class_scores = self._semantic_classify(results)
+        passed = self._pass_threshold(top_class_scores, self.score_threshold)
+        if passed:
+            return top_class
+        else:
+            return None
+
+    def add(self, route: Route):
+        self._add_route(route=route)
+
+    def _add_route(self, route: Route):
+        # create embeddings
+        dense_embeds = np.array(self.encoder(route.utterances))  # * self.alpha
+        sparse_embeds = np.array(
+            self.sparse_encoder(route.utterances)
+        )  # * (1 - self.alpha)
+
+        # create route array
+        if self.categories is None:
+            self.categories = np.array([route.name] * len(route.utterances))
+            self.utterances = np.array(route.utterances)
+        else:
+            str_arr = np.array([route.name] * len(route.utterances))
+            self.categories = np.concatenate([self.categories, str_arr])
+            self.utterances = np.concatenate(
+                [self.utterances, np.array(route.utterances)]
+            )
+        # create utterance array (the dense index)
+        if self.index is None:
+            self.index = dense_embeds
+        else:
+            self.index = np.concatenate([self.index, dense_embeds])
+        # create sparse utterance array
+        if self.sparse_index is None:
+            self.sparse_index = sparse_embeds
+        else:
+            self.sparse_index = np.concatenate([self.sparse_index, sparse_embeds])
+
+    def _query(self, text: str, top_k: int = 5):
+        """Given some text, encodes and searches the index vector space to
+        retrieve the top_k most similar records.
+        """
+        # create dense query vector
+        xq_d = np.array(self.encoder([text]))
+        xq_d = np.squeeze(xq_d)  # Reduce to 1d array.
+        # create sparse query vector
+        xq_s = np.array(self.sparse_encoder([text]))
+        xq_s = np.squeeze(xq_s)
+        # convex scaling
+        xq_d, xq_s = self._convex_scaling(xq_d, xq_s)
+
+        if self.index is not None and self.sparse_index is not None:
+            # calculate dense vec similarity
+            index_norm = norm(self.index, axis=1)
+            xq_d_norm = norm(xq_d.T)
+            sim_d = np.dot(self.index, xq_d.T) / (index_norm * xq_d_norm)
+            # calculate sparse vec similarity
+            sparse_norm = norm(self.sparse_index, axis=1)
+            xq_s_norm = norm(xq_s.T)
+            sim_s = np.dot(self.sparse_index, xq_s.T) / (sparse_norm * xq_s_norm)
+            total_sim = sim_d + sim_s
+            # get indices of top_k records
+            top_k = min(top_k, total_sim.shape[0])
+            idx = np.argpartition(total_sim, -top_k)[-top_k:]
+            scores = total_sim[idx]
+            # get the utterance categories (route names)
+            routes = self.categories[idx] if self.categories is not None else []
+            return [{"route": d, "score": s.item()} for d, s in zip(routes, scores)]
+        else:
+            logger.warning("No index found. Please add routes to the layer.")
+            return []
+
+    def _convex_scaling(self, dense: np.ndarray, sparse: np.ndarray):
+        # scale sparse and dense vecs
+        dense = np.array(dense) * self.alpha
+        sparse = np.array(sparse) * (1 - self.alpha)
+        return dense, sparse
+
+    def _semantic_classify(self, query_results: list[dict]) -> tuple[str, list[float]]:
+        scores_by_class: dict[str, list[float]] = {}
+        for result in query_results:
+            score = result["score"]
+            route = result["route"]
+            if route in scores_by_class:
+                scores_by_class[route].append(score)
+            else:
+                scores_by_class[route] = [score]
+
+        # Calculate total score for each class
+        total_scores = {route: sum(scores) for route, scores in scores_by_class.items()}
+        top_class = max(total_scores, key=lambda x: total_scores[x], default=None)
+
+        # Return the top class and its associated scores
+        if top_class is not None:
+            return str(top_class), scores_by_class.get(top_class, [])
+        else:
+            logger.warning("No classification found for semantic classifier.")
+            return "", []
+
+    def _pass_threshold(self, scores: list[float], threshold: float) -> bool:
+        if scores:
+            return max(scores) > threshold
+        else:
+            return False
diff --git a/semantic_router/layer.py b/semantic_router/layer.py
index 1bb900fb78884becca16a37988751786d356a408..cb408c5c5f452b78e9750976d7c669a01028450a 100644
--- a/semantic_router/layer.py
+++ b/semantic_router/layer.py
@@ -1,23 +1,21 @@
 import numpy as np
-from numpy.linalg import norm
-from tqdm.auto import tqdm
 
 from semantic_router.encoders import (
     BaseEncoder,
-    BM25Encoder,
     CohereEncoder,
     OpenAIEncoder,
 )
 from semantic_router.linear import similarity_matrix, top_scores
-from semantic_router.schema import Decision
+from semantic_router.schema import Route
+from semantic_router.utils.logger import logger
 
 
-class DecisionLayer:
+class RouteLayer:
     index = None
     categories = None
     score_threshold = 0.82
 
-    def __init__(self, encoder: BaseEncoder, decisions: list[Decision] = []):
+    def __init__(self, encoder: BaseEncoder, routes: list[Route] = []):
         self.encoder = encoder
         # decide on default threshold based on encoder
         if isinstance(encoder, OpenAIEncoder):
@@ -26,10 +24,10 @@ class DecisionLayer:
             self.score_threshold = 0.3
         else:
             self.score_threshold = 0.82
-        # if decisions list has been passed, we initialize index now
-        if decisions:
+        # if routes list has been passed, we initialize index now
+        if routes:
             # initialize index now
-            self.add_decisions(decisions=decisions)
+            self.add_routes(routes=routes)
 
     def __call__(self, text: str) -> str | None:
         results = self._query(text)
@@ -40,18 +38,15 @@ class DecisionLayer:
         else:
             return None
 
-    # def add(self, decision: Decision):
-    #     self.add_decision(decision=decision)
-
-    def add_decision(self, decision: Decision):
+    def add_route(self, route: Route):
         # create embeddings
-        embeds = self.encoder(decision.utterances)
+        embeds = self.encoder(route.utterances)
 
-        # create decision array
+        # create route array
         if self.categories is None:
-            self.categories = np.array([decision.name] * len(embeds))
+            self.categories = np.array([route.name] * len(embeds))
         else:
-            str_arr = np.array([decision.name] * len(embeds))
+            str_arr = np.array([route.name] * len(embeds))
             self.categories = np.concatenate([self.categories, str_arr])
         # create utterance array (the index)
         if self.index is None:
@@ -60,22 +55,20 @@ class DecisionLayer:
             embed_arr = np.array(embeds)
             self.index = np.concatenate([self.index, embed_arr])
 
-    def add_decisions(self, decisions: list[Decision]):
-        # create embeddings for all decisions
+    def add_routes(self, routes: list[Route]):
+        # create embeddings for all routes
         all_utterances = [
-            utterance for decision in decisions for utterance in decision.utterances
+            utterance for route in routes for utterance in route.utterances
         ]
         embedded_utterance = self.encoder(all_utterances)
 
-        # create decision array
-        decision_names = [
-            decision.name for decision in decisions for _ in decision.utterances
-        ]
-        decision_array = np.array(decision_names)
+        # create route array
+        route_names = [route.name for route in routes for _ in route.utterances]
+        route_array = np.array(route_names)
         self.categories = (
-            np.concatenate([self.categories, decision_array])
+            np.concatenate([self.categories, route_array])
             if self.categories is not None
-            else decision_array
+            else route_array
         )
 
         # create utterance array (the index)
@@ -98,164 +91,33 @@ class DecisionLayer:
             # calculate similarity matrix
             sim = similarity_matrix(xq, self.index)
             scores, idx = top_scores(sim, top_k)
-            # get the utterance categories (decision names)
-            decisions = self.categories[idx] if self.categories is not None else []
-            return [
-                {"decision": d, "score": s.item()} for d, s in zip(decisions, scores)
-            ]
+            # get the utterance categories (route names)
+            routes = self.categories[idx] if self.categories is not None else []
+            return [{"route": d, "score": s.item()} for d, s in zip(routes, scores)]
         else:
+            logger.warning("No index found for route layer.")
             return []
 
     def _semantic_classify(self, query_results: list[dict]) -> tuple[str, list[float]]:
-        scores_by_class = {}
+        scores_by_class: dict[str, list[float]] = {}
         for result in query_results:
             score = result["score"]
-            decision = result["decision"]
-            if decision in scores_by_class:
-                scores_by_class[decision].append(score)
+            route = result["route"]
+            if route in scores_by_class:
+                scores_by_class[route].append(score)
             else:
-                scores_by_class[decision] = [score]
+                scores_by_class[route] = [score]
 
         # Calculate total score for each class
-        total_scores = {
-            decision: sum(scores) for decision, scores in scores_by_class.items()
-        }
+        total_scores = {route: sum(scores) for route, scores in scores_by_class.items()}
         top_class = max(total_scores, key=lambda x: total_scores[x], default=None)
 
         # Return the top class and its associated scores
-        return str(top_class), scores_by_class.get(top_class, [])
-
-    def _pass_threshold(self, scores: list[float], threshold: float) -> bool:
-        if scores:
-            return max(scores) > threshold
+        if top_class is not None:
+            return str(top_class), scores_by_class.get(top_class, [])
         else:
-            return False
-
-
-class HybridDecisionLayer:
-    index = None
-    sparse_index = None
-    categories = None
-    score_threshold = 0.82
-
-    def __init__(
-        self, encoder: BaseEncoder, decisions: list[Decision] = [], alpha: float = 0.3
-    ):
-        self.encoder = encoder
-        self.sparse_encoder = BM25Encoder()
-        self.alpha = alpha
-        # decide on default threshold based on encoder
-        if isinstance(encoder, OpenAIEncoder):
-            self.score_threshold = 0.82
-        elif isinstance(encoder, CohereEncoder):
-            self.score_threshold = 0.3
-        else:
-            self.score_threshold = 0.82
-        # if decisions list has been passed, we initialize index now
-        if decisions:
-            # initialize index now
-            for decision in tqdm(decisions):
-                self._add_decision(decision=decision)
-
-    def __call__(self, text: str) -> str | None:
-        results = self._query(text)
-        top_class, top_class_scores = self._semantic_classify(results)
-        passed = self._pass_threshold(top_class_scores, self.score_threshold)
-        if passed:
-            return top_class
-        else:
-            return None
-
-    def add(self, decision: Decision):
-        self._add_decision(decision=decision)
-
-    def _add_decision(self, decision: Decision):
-        # create embeddings
-        dense_embeds = np.array(self.encoder(decision.utterances))  # * self.alpha
-        sparse_embeds = np.array(
-            self.sparse_encoder(decision.utterances)
-        )  # * (1 - self.alpha)
-
-        # create decision array
-        if self.categories is None:
-            self.categories = np.array([decision.name] * len(decision.utterances))
-            self.utterances = np.array(decision.utterances)
-        else:
-            str_arr = np.array([decision.name] * len(decision.utterances))
-            self.categories = np.concatenate([self.categories, str_arr])
-            self.utterances = np.concatenate(
-                [self.utterances, np.array(decision.utterances)]
-            )
-        # create utterance array (the dense index)
-        if self.index is None:
-            self.index = dense_embeds
-        else:
-            self.index = np.concatenate([self.index, dense_embeds])
-        # create sparse utterance array
-        if self.sparse_index is None:
-            self.sparse_index = sparse_embeds
-        else:
-            self.sparse_index = np.concatenate([self.sparse_index, sparse_embeds])
-
-    def _query(self, text: str, top_k: int = 5):
-        """Given some text, encodes and searches the index vector space to
-        retrieve the top_k most similar records.
-        """
-        # create dense query vector
-        xq_d = np.array(self.encoder([text]))
-        xq_d = np.squeeze(xq_d)  # Reduce to 1d array.
-        # create sparse query vector
-        xq_s = np.array(self.sparse_encoder([text]))
-        xq_s = np.squeeze(xq_s)
-        # convex scaling
-        xq_d, xq_s = self._convex_scaling(xq_d, xq_s)
-
-        if self.index is not None:
-            # calculate dense vec similarity
-            index_norm = norm(self.index, axis=1)
-            xq_d_norm = norm(xq_d.T)
-            sim_d = np.dot(self.index, xq_d.T) / (index_norm * xq_d_norm)
-            # calculate sparse vec similarity
-            sparse_norm = norm(self.sparse_index, axis=1)
-            xq_s_norm = norm(xq_s.T)
-            sim_s = np.dot(self.sparse_index, xq_s.T) / (sparse_norm * xq_s_norm)
-            total_sim = sim_d + sim_s
-            # get indices of top_k records
-            top_k = min(top_k, total_sim.shape[0])
-            idx = np.argpartition(total_sim, -top_k)[-top_k:]
-            scores = total_sim[idx]
-            # get the utterance categories (decision names)
-            decisions = self.categories[idx] if self.categories is not None else []
-            return [
-                {"decision": d, "score": s.item()} for d, s in zip(decisions, scores)
-            ]
-        else:
-            return []
-
-    def _convex_scaling(self, dense: list[float], sparse: list[float]):
-        # scale sparse and dense vecs
-        dense = np.array(dense) * self.alpha
-        sparse = np.array(sparse) * (1 - self.alpha)
-        return dense, sparse
-
-    def _semantic_classify(self, query_results: list[dict]) -> tuple[str, list[float]]:
-        scores_by_class = {}
-        for result in query_results:
-            score = result["score"]
-            decision = result["decision"]
-            if decision in scores_by_class:
-                scores_by_class[decision].append(score)
-            else:
-                scores_by_class[decision] = [score]
-
-        # Calculate total score for each class
-        total_scores = {
-            decision: sum(scores) for decision, scores in scores_by_class.items()
-        }
-        top_class = max(total_scores, key=lambda x: total_scores[x], default=None)
-
-        # Return the top class and its associated scores
-        return str(top_class), scores_by_class.get(top_class, [])
+            logger.warning("No classification found for semantic classifier.")
+            return "", []
 
     def _pass_threshold(self, scores: list[float], threshold: float) -> bool:
         if scores:
diff --git a/semantic_router/schema.py b/semantic_router/schema.py
index 37a43dd41007634706caedc1b5c5dadd6d734bba..007cddcbeb2c9e464e02a6c7f6cd12d2e9769cbc 100644
--- a/semantic_router/schema.py
+++ b/semantic_router/schema.py
@@ -10,7 +10,7 @@ from semantic_router.encoders import (
 )
 
 
-class Decision(BaseModel):
+class Route(BaseModel):
     name: str
     utterances: list[str]
     description: str | None = None
@@ -38,19 +38,19 @@ class Encoder:
         elif self.type == EncoderType.COHERE:
             self.model = CohereEncoder(name)
 
-    def __call__(self, texts: list[str]) -> list[float]:
+    def __call__(self, texts: list[str]) -> list[list[float]]:
         return self.model(texts)
 
 
 @dataclass
 class SemanticSpace:
     id: str
-    decisions: list[Decision]
+    routes: list[Route]
     encoder: str = ""
 
-    def __init__(self, decisions: list[Decision] = []):
+    def __init__(self, routes: list[Route] = []):
         self.id = ""
-        self.decisions = decisions
+        self.routes = routes
 
-    def add(self, decision: Decision):
-        self.decisions.append(decision)
+    def add(self, route: Route):
+        self.routes.append(route)
diff --git a/semantic_router/utils/__init__.py b/semantic_router/utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/unit/encoders/test_bm25.py b/tests/unit/encoders/test_bm25.py
index c198715133829ff4869167b80117c40dba72d4fb..e654d7bbc98070b6db16249c3164d515852e28e5 100644
--- a/tests/unit/encoders/test_bm25.py
+++ b/tests/unit/encoders/test_bm25.py
@@ -33,3 +33,22 @@ class TestBM25Encoder:
         assert all(
             isinstance(sublist, list) for sublist in result
         ), "Each item in result should be a list"
+
+    def test_init_with_non_dict_doc_freq(self, mocker):
+        mock_encoder = mocker.MagicMock()
+        mock_encoder.get_params.return_value = {"doc_freq": "not a dict"}
+        mocker.patch(
+            "pinecone_text.sparse.BM25Encoder.default", return_value=mock_encoder
+        )
+        with pytest.raises(TypeError):
+            BM25Encoder()
+
+    def test_call_method_with_uninitialized_model_or_mapping(self, bm25_encoder):
+        bm25_encoder.model = None
+        with pytest.raises(ValueError):
+            bm25_encoder(["test"])
+
+    def test_fit_with_uninitialized_model(self, bm25_encoder):
+        bm25_encoder.model = None
+        with pytest.raises(ValueError):
+            bm25_encoder.fit(["test"])
diff --git a/tests/unit/test_hybrid_layer.py b/tests/unit/test_hybrid_layer.py
new file mode 100644
index 0000000000000000000000000000000000000000..94720cd8d9567b19e78a016a03c2cc90b8f62d40
--- /dev/null
+++ b/tests/unit/test_hybrid_layer.py
@@ -0,0 +1,118 @@
+import pytest
+
+from semantic_router.encoders import BaseEncoder, CohereEncoder, OpenAIEncoder
+from semantic_router.hybrid_layer import HybridRouteLayer
+from semantic_router.schema import Route
+
+
+def mock_encoder_call(utterances):
+    # Define a mapping of utterances to return values
+    mock_responses = {
+        "Hello": [0.1, 0.2, 0.3],
+        "Hi": [0.4, 0.5, 0.6],
+        "Goodbye": [0.7, 0.8, 0.9],
+        "Bye": [1.0, 1.1, 1.2],
+        "Au revoir": [1.3, 1.4, 1.5],
+    }
+    return [mock_responses.get(u, [0, 0, 0]) for u in utterances]
+
+
+@pytest.fixture
+def base_encoder():
+    return BaseEncoder(name="test-encoder")
+
+
+@pytest.fixture
+def cohere_encoder(mocker):
+    mocker.patch.object(CohereEncoder, "__call__", side_effect=mock_encoder_call)
+    return CohereEncoder(name="test-cohere-encoder", cohere_api_key="test_api_key")
+
+
+@pytest.fixture
+def openai_encoder(mocker):
+    mocker.patch.object(OpenAIEncoder, "__call__", side_effect=mock_encoder_call)
+    return OpenAIEncoder(name="test-openai-encoder", openai_api_key="test_api_key")
+
+
+@pytest.fixture
+def routes():
+    return [
+        Route(name="Route 1", utterances=["Hello", "Hi"]),
+        Route(name="Route 2", utterances=["Goodbye", "Bye", "Au revoir"]),
+    ]
+
+
+class TestHybridRouteLayer:
+    def test_initialization(self, openai_encoder, routes):
+        route_layer = HybridRouteLayer(encoder=openai_encoder, routes=routes)
+        assert route_layer.index is not None and route_layer.categories is not None
+        assert route_layer.score_threshold == 0.82
+        assert len(route_layer.index) == 5
+        assert len(set(route_layer.categories)) == 2
+
+    def test_initialization_different_encoders(self, cohere_encoder, openai_encoder):
+        route_layer_cohere = HybridRouteLayer(encoder=cohere_encoder)
+        assert route_layer_cohere.score_threshold == 0.3
+
+        route_layer_openai = HybridRouteLayer(encoder=openai_encoder)
+        assert route_layer_openai.score_threshold == 0.82
+
+    def test_add_route(self, openai_encoder):
+        route_layer = HybridRouteLayer(encoder=openai_encoder)
+        route = Route(name="Route 3", utterances=["Yes", "No"])
+        route_layer.add(route)
+        assert route_layer.index is not None and route_layer.categories is not None
+        assert len(route_layer.index) == 2
+        assert len(set(route_layer.categories)) == 1
+
+    def test_add_multiple_routes(self, openai_encoder, routes):
+        route_layer = HybridRouteLayer(encoder=openai_encoder)
+        for route in routes:
+            route_layer.add(route)
+        assert route_layer.index is not None and route_layer.categories is not None
+        assert len(route_layer.index) == 5
+        assert len(set(route_layer.categories)) == 2
+
+    def test_query_and_classification(self, openai_encoder, routes):
+        route_layer = HybridRouteLayer(encoder=openai_encoder, routes=routes)
+        query_result = route_layer("Hello")
+        assert query_result in ["Route 1", "Route 2"]
+
+    def test_query_with_no_index(self, openai_encoder):
+        route_layer = HybridRouteLayer(encoder=openai_encoder)
+        assert route_layer("Anything") is None
+
+    def test_semantic_classify(self, openai_encoder, routes):
+        route_layer = HybridRouteLayer(encoder=openai_encoder, routes=routes)
+        classification, score = route_layer._semantic_classify(
+            [
+                {"route": "Route 1", "score": 0.9},
+                {"route": "Route 2", "score": 0.1},
+            ]
+        )
+        assert classification == "Route 1"
+        assert score == [0.9]
+
+    def test_semantic_classify_multiple_routes(self, openai_encoder, routes):
+        route_layer = HybridRouteLayer(encoder=openai_encoder, routes=routes)
+        classification, score = route_layer._semantic_classify(
+            [
+                {"route": "Route 1", "score": 0.9},
+                {"route": "Route 2", "score": 0.1},
+                {"route": "Route 1", "score": 0.8},
+            ]
+        )
+        assert classification == "Route 1"
+        assert score == [0.9, 0.8]
+
+    def test_pass_threshold(self, openai_encoder):
+        route_layer = HybridRouteLayer(encoder=openai_encoder)
+        assert not route_layer._pass_threshold([], 0.5)
+        assert route_layer._pass_threshold([0.6, 0.7], 0.5)
+
+    def test_failover_score_threshold(self, base_encoder):
+        route_layer = HybridRouteLayer(encoder=base_encoder)
+        assert route_layer.score_threshold == 0.82
+
+
+# Add more tests for edge cases and error handling as needed.
diff --git a/tests/unit/test_layer.py b/tests/unit/test_layer.py
index 4d919f912ae635269e9f7dca93ac85030f9dd7cd..66e0d53bb9350c77578682f9ea0742b1d3dfe0b2 100644
--- a/tests/unit/test_layer.py
+++ b/tests/unit/test_layer.py
@@ -1,12 +1,8 @@
 import pytest
 
 from semantic_router.encoders import BaseEncoder, CohereEncoder, OpenAIEncoder
-from semantic_router.layer import (
-    DecisionLayer,
-    HybridDecisionLayer,
-)
-
-from semantic_router.schema import Decision
+from semantic_router.layer import RouteLayer
+from semantic_router.schema import Route
 
 
 def mock_encoder_call(utterances):
@@ -39,185 +35,94 @@ def openai_encoder(mocker):
 
 
 @pytest.fixture
-def decisions():
+def routes():
     return [
-        Decision(name="Decision 1", utterances=["Hello", "Hi"]),
-        Decision(name="Decision 2", utterances=["Goodbye", "Bye", "Au revoir"]),
+        Route(name="Route 1", utterances=["Hello", "Hi"]),
+        Route(name="Route 2", utterances=["Goodbye", "Bye", "Au revoir"]),
     ]
 
 
-class TestDecisionLayer:
-    def test_initialization(self, openai_encoder, decisions):
-        decision_layer = DecisionLayer(encoder=openai_encoder, decisions=decisions)
-        assert decision_layer.score_threshold == 0.82
-        assert len(decision_layer.index) if decision_layer.index is not None else 0 == 5
+class TestRouteLayer:
+    def test_initialization(self, openai_encoder, routes):
+        route_layer = RouteLayer(encoder=openai_encoder, routes=routes)
+        assert route_layer.score_threshold == 0.82
+        assert len(route_layer.index) if route_layer.index is not None else 0 == 5
         assert (
-            len(set(decision_layer.categories))
-            if decision_layer.categories is not None
+            len(set(route_layer.categories))
+            if route_layer.categories is not None
             else 0 == 2
         )
 
     def test_initialization_different_encoders(self, cohere_encoder, openai_encoder):
-        decision_layer_cohere = DecisionLayer(encoder=cohere_encoder)
-        assert decision_layer_cohere.score_threshold == 0.3
-
-        decision_layer_openai = DecisionLayer(encoder=openai_encoder)
-        assert decision_layer_openai.score_threshold == 0.82
-
-    def test_add_decision(self, openai_encoder):
-        decision_layer = DecisionLayer(encoder=openai_encoder)
-        decision1 = Decision(name="Decision 1", utterances=["Yes", "No"])
-        decision2 = Decision(name="Decision 2", utterances=["Maybe", "Sure"])
-
-        decision_layer.add_decision(decision=decision1)
-        assert (
-            decision_layer.index is not None and decision_layer.categories is not None
-        )
-        assert len(decision_layer.index) == 2
-        assert len(set(decision_layer.categories)) == 1
-        assert set(decision_layer.categories) == {"Decision 1"}
-
-        decision_layer.add_decision(decision=decision2)
-        assert len(decision_layer.index) == 4
-        assert len(set(decision_layer.categories)) == 2
-        assert set(decision_layer.categories) == {"Decision 1", "Decision 2"}
-
-    def test_add_multiple_decisions(self, openai_encoder, decisions):
-        decision_layer = DecisionLayer(encoder=openai_encoder)
-        decision_layer.add_decisions(decisions=decisions)
-        assert (
-            decision_layer.index is not None and decision_layer.categories is not None
-        )
-        assert len(decision_layer.index) == 5
-        assert len(set(decision_layer.categories)) == 2
-
-    def test_query_and_classification(self, openai_encoder, decisions):
-        decision_layer = DecisionLayer(encoder=openai_encoder, decisions=decisions)
-        query_result = decision_layer("Hello")
-        assert query_result in ["Decision 1", "Decision 2"]
+        route_layer_cohere = RouteLayer(encoder=cohere_encoder)
+        assert route_layer_cohere.score_threshold == 0.3
+
+        route_layer_openai = RouteLayer(encoder=openai_encoder)
+        assert route_layer_openai.score_threshold == 0.82
+
+    def test_add_route(self, openai_encoder):
+        route_layer = RouteLayer(encoder=openai_encoder)
+        route1 = Route(name="Route 1", utterances=["Yes", "No"])
+        route2 = Route(name="Route 2", utterances=["Maybe", "Sure"])
+
+        route_layer.add_route(route=route1)
+        assert route_layer.index is not None and route_layer.categories is not None
+        assert len(route_layer.index) == 2
+        assert len(set(route_layer.categories)) == 1
+        assert set(route_layer.categories) == {"Route 1"}
+
+        route_layer.add_route(route=route2)
+        assert len(route_layer.index) == 4
+        assert len(set(route_layer.categories)) == 2
+        assert set(route_layer.categories) == {"Route 1", "Route 2"}
+
+    def test_add_multiple_routes(self, openai_encoder, routes):
+        route_layer = RouteLayer(encoder=openai_encoder)
+        route_layer.add_routes(routes=routes)
+        assert route_layer.index is not None and route_layer.categories is not None
+        assert len(route_layer.index) == 5
+        assert len(set(route_layer.categories)) == 2
+
+    def test_query_and_classification(self, openai_encoder, routes):
+        route_layer = RouteLayer(encoder=openai_encoder, routes=routes)
+        query_result = route_layer("Hello")
+        assert query_result in ["Route 1", "Route 2"]
 
     def test_query_with_no_index(self, openai_encoder):
-        decision_layer = DecisionLayer(encoder=openai_encoder)
-        assert decision_layer("Anything") is None
+        route_layer = RouteLayer(encoder=openai_encoder)
+        assert route_layer("Anything") is None
 
-    def test_semantic_classify(self, openai_encoder, decisions):
-        decision_layer = DecisionLayer(encoder=openai_encoder, decisions=decisions)
-        classification, score = decision_layer._semantic_classify(
+    def test_semantic_classify(self, openai_encoder, routes):
+        route_layer = RouteLayer(encoder=openai_encoder, routes=routes)
+        classification, score = route_layer._semantic_classify(
             [
-                {"decision": "Decision 1", "score": 0.9},
-                {"decision": "Decision 2", "score": 0.1},
+                {"route": "Route 1", "score": 0.9},
+                {"route": "Route 2", "score": 0.1},
             ]
         )
-        assert classification == "Decision 1"
+        assert classification == "Route 1"
         assert score == [0.9]
 
-    def test_semantic_classify_multiple_decisions(self, openai_encoder, decisions):
-        decision_layer = DecisionLayer(encoder=openai_encoder, decisions=decisions)
-        classification, score = decision_layer._semantic_classify(
-            [
-                {"decision": "Decision 1", "score": 0.9},
-                {"decision": "Decision 2", "score": 0.1},
-                {"decision": "Decision 1", "score": 0.8},
-            ]
-        )
-        assert classification == "Decision 1"
-        assert score == [0.9, 0.8]
-
-    def test_pass_threshold(self, openai_encoder):
-        decision_layer = DecisionLayer(encoder=openai_encoder)
-        assert not decision_layer._pass_threshold([], 0.5)
-        assert decision_layer._pass_threshold([0.6, 0.7], 0.5)
-
-    def test_failover_score_threshold(self, base_encoder):
-        decision_layer = DecisionLayer(encoder=base_encoder)
-        assert decision_layer.score_threshold == 0.82
-
-
-class TestHybridDecisionLayer:
-    def test_initialization(self, openai_encoder, decisions):
-        decision_layer = HybridDecisionLayer(
-            encoder=openai_encoder, decisions=decisions
-        )
-        assert decision_layer.score_threshold == 0.82
-        assert (
-            decision_layer.index is not None and decision_layer.categories is not None
-        )
-        assert len(decision_layer.index) == 5
-        assert len(set(decision_layer.categories)) == 2
-
-    def test_initialization_different_encoders(self, cohere_encoder, openai_encoder):
-        decision_layer_cohere = HybridDecisionLayer(encoder=cohere_encoder)
-        assert decision_layer_cohere.score_threshold == 0.3
-
-        decision_layer_openai = HybridDecisionLayer(encoder=openai_encoder)
-        assert decision_layer_openai.score_threshold == 0.82
-
-    def test_add_decision(self, openai_encoder):
-        decision_layer = HybridDecisionLayer(encoder=openai_encoder)
-        decision = Decision(name="Decision 3", utterances=["Yes", "No"])
-        decision_layer.add(decision)
-        assert (
-            decision_layer.index is not None and decision_layer.categories is not None
-        )
-        assert len(decision_layer.index) == 2
-        assert len(set(decision_layer.categories)) == 1
-
-    def test_add_multiple_decisions(self, openai_encoder, decisions):
-        decision_layer = HybridDecisionLayer(encoder=openai_encoder)
-        for decision in decisions:
-            decision_layer.add(decision)
-        assert (
-            decision_layer.index is not None and decision_layer.categories is not None
-        )
-        assert len(decision_layer.index) == 5
-        assert len(set(decision_layer.categories)) == 2
-
-    def test_query_and_classification(self, openai_encoder, decisions):
-        decision_layer = HybridDecisionLayer(
-            encoder=openai_encoder, decisions=decisions
-        )
-        query_result = decision_layer("Hello")
-        assert query_result in ["Decision 1", "Decision 2"]
-
-    def test_query_with_no_index(self, openai_encoder):
-        decision_layer = HybridDecisionLayer(encoder=openai_encoder)
-        assert decision_layer("Anything") is None
-
-    def test_semantic_classify(self, openai_encoder, decisions):
-        decision_layer = HybridDecisionLayer(
-            encoder=openai_encoder, decisions=decisions
-        )
-        classification, score = decision_layer._semantic_classify(
-            [
-                {"decision": "Decision 1", "score": 0.9},
-                {"decision": "Decision 2", "score": 0.1},
-            ]
-        )
-        assert classification == "Decision 1"
-        assert score == [0.9]
-
-    def test_semantic_classify_multiple_decisions(self, openai_encoder, decisions):
-        decision_layer = HybridDecisionLayer(
-            encoder=openai_encoder, decisions=decisions
-        )
-        classification, score = decision_layer._semantic_classify(
+    def test_semantic_classify_multiple_routes(self, openai_encoder, routes):
+        route_layer = RouteLayer(encoder=openai_encoder, routes=routes)
+        classification, score = route_layer._semantic_classify(
             [
-                {"decision": "Decision 1", "score": 0.9},
-                {"decision": "Decision 2", "score": 0.1},
-                {"decision": "Decision 1", "score": 0.8},
+                {"route": "Route 1", "score": 0.9},
+                {"route": "Route 2", "score": 0.1},
+                {"route": "Route 1", "score": 0.8},
             ]
         )
-        assert classification == "Decision 1"
+        assert classification == "Route 1"
         assert score == [0.9, 0.8]
 
     def test_pass_threshold(self, openai_encoder):
-        decision_layer = HybridDecisionLayer(encoder=openai_encoder)
-        assert not decision_layer._pass_threshold([], 0.5)
-        assert decision_layer._pass_threshold([0.6, 0.7], 0.5)
+        route_layer = RouteLayer(encoder=openai_encoder)
+        assert not route_layer._pass_threshold([], 0.5)
+        assert route_layer._pass_threshold([0.6, 0.7], 0.5)
 
     def test_failover_score_threshold(self, base_encoder):
-        decision_layer = HybridDecisionLayer(encoder=base_encoder)
-        assert decision_layer.score_threshold == 0.82
+        route_layer = RouteLayer(encoder=base_encoder)
+        assert route_layer.score_threshold == 0.82
 
 
 # Add more tests for edge cases and error handling as needed.
diff --git a/tests/unit/test_schema.py b/tests/unit/test_schema.py
index 2563bf0bc21b7769f96d1119fdc29b6afab66d1a..f471755c35796d33ac9329a2ddb3a20816230cda 100644
--- a/tests/unit/test_schema.py
+++ b/tests/unit/test_schema.py
@@ -2,10 +2,10 @@ import pytest
 
 from semantic_router.schema import (
     CohereEncoder,
-    Decision,
     Encoder,
     EncoderType,
     OpenAIEncoder,
+    Route,
     SemanticSpace,
 )
 
@@ -46,16 +46,14 @@ class TestSemanticSpaceDataclass:
     def test_semanticspace_initialization(self):
         semantic_space = SemanticSpace()
         assert semantic_space.id == ""
-        assert semantic_space.decisions == []
+        assert semantic_space.routes == []
 
-    def test_semanticspace_add_decision(self):
-        decision = Decision(
-            name="test", utterances=["hello", "hi"], description="greeting"
-        )
+    def test_semanticspace_add_route(self):
+        route = Route(name="test", utterances=["hello", "hi"], description="greeting")
         semantic_space = SemanticSpace()
-        semantic_space.add(decision)
+        semantic_space.add(route)
 
-        assert len(semantic_space.decisions) == 1
-        assert semantic_space.decisions[0].name == "test"
-        assert semantic_space.decisions[0].utterances == ["hello", "hi"]
-        assert semantic_space.decisions[0].description == "greeting"
+        assert len(semantic_space.routes) == 1
+        assert semantic_space.routes[0].name == "test"
+        assert semantic_space.routes[0].utterances == ["hello", "hi"]
+        assert semantic_space.routes[0].description == "greeting"
diff --git a/walkthrough.ipynb b/walkthrough.ipynb
index 2e9570b881948caab8ac1ef25be4795147f858ca..d31a88dc0da38dec04e019100bfc28815adf7906 100644
--- a/walkthrough.ipynb
+++ b/walkthrough.ipynb
@@ -11,7 +11,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "The Semantic Router library can be used as a super fast decision making layer on top of LLMs. That means rather than waiting on a slow agent to decide what to do, we can use the magic of semantic vector space to make decisions. Cutting decision making time down from seconds to milliseconds."
+    "The Semantic Router library can be used as a super fast route making layer on top of LLMs. That means rather than waiting on a slow agent to decide what to do, we can use the magic of semantic vector space to make routes. Cutting route making time down from seconds to milliseconds."
    ]
   },
   {
@@ -41,7 +41,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "We start by defining a dictionary mapping decisions to example phrases that should trigger those decisions."
+    "We start by defining a dictionary mapping routes to example phrases that should trigger those routes."
    ]
   },
   {
@@ -50,9 +50,9 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "from semantic_router.schema import Decision\n",
+    "from semantic_router.schema import Route\n",
     "\n",
-    "politics = Decision(\n",
+    "politics = Route(\n",
     "    name=\"politics\",\n",
     "    utterances=[\n",
     "        \"isn't politics the best thing ever\",\n",
@@ -77,7 +77,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "chitchat = Decision(\n",
+    "chitchat = Route(\n",
     "    name=\"chitchat\",\n",
     "    utterances=[\n",
     "        \"how's the weather today?\",\n",
@@ -88,7 +88,7 @@
     "    ],\n",
     ")\n",
     "\n",
-    "decisions = [politics, chitchat]"
+    "routes = [politics, chitchat]"
    ]
   },
   {
@@ -119,7 +119,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Now we define the `DecisionLayer`. When called, the decision layer will consume text (a query) and output the category (`Decision`) it belongs to — to initialize a `DecisionLayer` we need our `encoder` model and a list of `decisions`."
+    "Now we define the `RouteLayer`. When called, the route layer will consume text (a query) and output the category (`Route`) it belongs to — to initialize a `RouteLayer` we need our `encoder` model and a list of `routes`."
    ]
   },
   {
@@ -128,9 +128,9 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "from semantic_router.layer import DecisionLayer\n",
+    "from semantic_router.router import RouteLayer\n",
     "\n",
-    "dl = DecisionLayer(encoder=encoder, decisions=decisions)"
+    "dl = RouteLayer(encoder=encoder, routes=routes)"
    ]
   },
   {
@@ -162,7 +162,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Both are classified accurately, what if we send a query that is unrelated to our existing `Decision` objects?"
+    "Both are classified accurately, what if we send a query that is unrelated to our existing `Route` objects?"
    ]
   },
   {