diff --git a/README.md b/README.md
index 66cf0da621aee840c0c00f1f6ea08581acf1b2c0..6acd78b08b3a52c4b8e645499b3508f28db15eb5 100644
--- a/README.md
+++ b/README.md
@@ -40,5 +40,5 @@ python -m abb_egm_pyclient.run 6510 joint 30 0 0 20 10 0 0
 Or import the client from your own code:
 
 ```python
-from abb_egm_pyclient import EGMClient
+from abb_egm_pyclient.egm_client import EGMClient
 ```
diff --git a/abb_egm_pyclient/__init__.py b/abb_egm_pyclient/__init__.py
index 8776898633a8a701addb9fb0df417872d5f424c1..dd6ed28c84ccaf0dbec832d01b304b1d199508f1 100644
--- a/abb_egm_pyclient/__init__.py
+++ b/abb_egm_pyclient/__init__.py
@@ -1 +1,5 @@
-from .egm_client import EGMClient  # noqa: F401,F403
+import logging
+
+DEFAULT_UDP_PORT = 6510
+
+logging.getLogger()
diff --git a/abb_egm_pyclient/egm_client.py b/abb_egm_pyclient/egm_client.py
index ec3bd59db5f8dfecfb89c736fb1fadca6694fc20..9fa35055ae35ea19de76d877a9e5aafabac3ac83 100644
--- a/abb_egm_pyclient/egm_client.py
+++ b/abb_egm_pyclient/egm_client.py
@@ -1,13 +1,18 @@
 import socket
 import logging
-from typing import Any, Tuple
+from typing import Any, Optional, Tuple
 
+from abb_egm_pyclient import DEFAULT_UDP_PORT
 from abb_egm_pyclient.atomic_counter import AtomicCounter
 
-from abb_egm_pyclient.egm_pb2 import EgmRobot, EgmSensor, EgmHeader
+try:
+    from abb_egm_pyclient.egm_pb2 import EgmRobot, EgmSensor, EgmHeader  # type: ignore
+except ImportError:
+    raise ImportWarning(
+        "abb_egm_pyclient.egm_pb2 not found, have you extracted the protobufs?"
+    )
 
 import numpy as np
-import numpy.typing as npt
 
 log = logging.getLogger(__name__)
 
@@ -19,7 +24,7 @@ class EGMClientException(Exception):
 
 
 class EGMClientNotInitializedException(EGMClientException):
-    """When user tries to access attributes set in self.recieve_from_robot()"""
+    """When method is used before initialization"""
 
     pass
 
@@ -38,20 +43,20 @@ class EGMClient:
     socket
         UDP socket used for communication
     robot_controller_address
-        IP address to controller, comes from first packet recieved
+        IP address to controller, comes from first packet received
     send_counter
         An atomic counter used for sequence numbers for outbound packages
     """
 
-    def __init__(self, port=6510):
+    def __init__(self, port: int = DEFAULT_UDP_PORT):
         self.socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
         self.robot_controller_address = None
         self.send_counter = AtomicCounter()
 
         self.socket.bind(("", port))
 
-    def _get_last_packet(self) -> Tuple[bytes, Any]:
-        last_recieved = (None, None)
+    def _get_last_packet(self) -> Tuple[Optional[bytes], Any]:
+        last_received = (None, None)
 
         self.socket.setblocking(False)
 
@@ -59,11 +64,11 @@ class EGMClient:
             try:
                 data, addr = self.socket.recvfrom(2048)  # read from socket
                 if data:
-                    last_recieved = (data, addr)  # store last data and addr
+                    last_received = (data, addr)  # store last data and addr
             except socket.error as err:
                 # EWOULDBLOCK: recvfrom would block since socket buffer is empty
                 if err.args[0] == socket.EWOULDBLOCK:
-                    if last_recieved[0]:  # if last data got picked up
+                    if last_received[0]:  # if last data got picked up
                         break
                     else:
                         continue  # else wait for data
@@ -72,7 +77,7 @@ class EGMClient:
                     raise err  # if there is another error, raise exception
 
         self.socket.setblocking(True)
-        return last_recieved
+        return last_received
 
     def receive_msg(self) -> EgmRobot:
         """Get latest UDP packet from IRC5."""
@@ -121,7 +126,7 @@ class EGMClient:
         msg = self._create_sensor_msg()
 
         conf_as_list = np.asarray(configuration).tolist()
-        
+
         joints = conf_as_list[:6]
         external_joints = conf_as_list[6:]
 
@@ -130,8 +135,6 @@ class EGMClient:
         if len(external_joints) > 0:
             msg.planned.externalJoints.joints.extend(external_joints)
 
-
-
         self.send_msg(msg)
 
     def send_planned_frame(
diff --git a/abb_egm_pyclient/run/__main__.py b/abb_egm_pyclient/run/__main__.py
index e3889dee8447242adf607852070e3380d4741fd5..099054f845c5b42e4149b5b759c18f8ea562524a 100644
--- a/abb_egm_pyclient/run/__main__.py
+++ b/abb_egm_pyclient/run/__main__.py
@@ -1,11 +1,22 @@
 import argparse
-from abb_egm_pyclient.run.print_egm_feedback import print_egm_feedback
-from abb_egm_pyclient.run.send_configuration import send_configuration
-from abb_egm_pyclient.run.send_pose import send_pose
+
+try:
+    from abb_egm_pyclient.run.print_egm_feedback import print_egm_feedback
+    from abb_egm_pyclient.run.send_configuration import send_configuration
+    from abb_egm_pyclient.run.send_pose import send_pose
+    from abb_egm_pyclient import DEFAULT_UDP_PORT
+except ImportError:
+    raise ImportWarning("abb_egm_pyclient not found, have you installed the package?")
+
+import logging
+
+log = logging.getLogger(__name__)
 
 if __name__ == "__main__":
     parser = argparse.ArgumentParser(description="Run one of the example EGM scripts.")
-    parser.add_argument("port", type=int, help="UDP port")
+    parser.add_argument(
+        "--port", "-p", type=int, help="UDP port", default=DEFAULT_UDP_PORT
+    )
 
     subparsers = parser.add_subparsers(help="sub-command help", dest="subparser_name")
 
@@ -17,22 +28,22 @@ if __name__ == "__main__":
 
     parser_print = subparsers.add_parser(
         "print",
-        help="print messages recieved from the EGM interface on the controller",
+        help="print messages received from the EGM interface on the controller",
     )
 
     parser_joint = subparsers.add_parser(
         "joint",
-        help="print messages recieved from the EGM interface on the controller",
+        help="send joint configuration to the robot",
     )
     parser_joint.add_argument(
         "joint_values",
-        nargs="*",
+        nargs="+",
         type=float,
     )
 
     parser_pose = subparsers.add_parser(
         "pose",
-        help="print messages recieved from the EGM interface on the controller",
+        help="send pose to the robot",
     )
     parser_pose.add_argument(
         "pose_values", nargs=6, type=float, metavar=("x", "y", "z", "rx", "ry", "rz")
@@ -40,17 +51,17 @@ if __name__ == "__main__":
 
     args = parser.parse_args()
 
-    print(args.__dict__)
+    log.debug(f"args: {args}")
 
     if args.subparser_name == "print":
-        print_egm_feedback(args.port)
+        print_egm_feedback(port=args.port)
 
     if args.subparser_name == "joint":
         if len(args.joint_values) not in (6, 7):
             raise RuntimeError("Incorrect number of joint values.")
-        send_configuration(args.port, args.joint_values)
+        send_configuration(args.joint_values, port=args.port)
 
     if args.subparser_name == "pose":
-        send_configuration(args.port, *args.pose_values)
+        send_configuration(args.pose_values, port=args.port)
 
     func = func_sel_mapping[args.func_selection]
diff --git a/abb_egm_pyclient/run/print_egm_feedback.py b/abb_egm_pyclient/run/print_egm_feedback.py
index 5f88e96deb357c05f08f3c486cbf9436c001cb09..59542a660829929a105ec7d1feb065dfde5544d9 100644
--- a/abb_egm_pyclient/run/print_egm_feedback.py
+++ b/abb_egm_pyclient/run/print_egm_feedback.py
@@ -1,17 +1,12 @@
-#!/usr/bin/env python
 import logging
 
-try:
-    from abb_egm_pyclient import EGMClient
-except ImportError:
-    raise ImportWarning("abb_egm not found, have you installed the package?")
+from abb_egm_pyclient.egm_client import EGMClient
+from abb_egm_pyclient import DEFAULT_UDP_PORT
 
-DEFAULT_UDP_PORT = 6510
+log = logging.getLogger(__name__)
 
-log = logging.getLogger("egm_client")
 
-
-def print_egm_feedback(port: int) -> None:
+def print_egm_feedback(port: int = DEFAULT_UDP_PORT) -> None:
     """Print EGM feedback.
 
     Parameters
diff --git a/abb_egm_pyclient/run/send_configuration.py b/abb_egm_pyclient/run/send_configuration.py
index 411a975dcce3bbda6ab7051d1d77748f519c90fe..e7f2a3de0adb6e6565266716c1e2f4342ab8a56d 100644
--- a/abb_egm_pyclient/run/send_configuration.py
+++ b/abb_egm_pyclient/run/send_configuration.py
@@ -1,17 +1,16 @@
-#!/usr/bin/env python
 import sys
-from typing import Sequence
+from typing import List, Sequence
 import time
 
 import numpy as np
-import numpy.typing as npt
 
-from abb_egm_pyclient import EGMClient
+from abb_egm_pyclient.egm_client import EGMClient
+from abb_egm_pyclient import DEFAULT_UDP_PORT
 
-DEFAULT_UDP_PORT = 6510
 
-
-def send_configuration(port: int, target_conf: Sequence[float], joint_vel=1.0) -> None:
+def send_configuration(
+    target_conf: Sequence[float], port: int = DEFAULT_UDP_PORT, joint_vel=1.0
+) -> None:
     """Move robot to target configuration
 
     Parameters
@@ -27,7 +26,7 @@ def send_configuration(port: int, target_conf: Sequence[float], joint_vel=1.0) -
     egm_client = EGMClient(port=port)
 
     pb_robot_msg = egm_client.receive_msg()
-    start_conf: Sequence[float] = pb_robot_msg.feedBack.joints.joints
+    start_conf: List[float] = pb_robot_msg.feedBack.joints.joints
 
     if len(start_conf) == len(target_conf) - 1:
         start_conf.append(pb_robot_msg.feedBack.externalJoints.joints[0])
@@ -47,8 +46,6 @@ def send_configuration(port: int, target_conf: Sequence[float], joint_vel=1.0) -
 
         print(f"Current configuration {cur_configuration}")
 
-        new_conf = start_conf_arr
-
         conf = []
         for start_pos, delta in zip(start_conf, deltas):
             abs_change = n * delta / num_msgs
diff --git a/abb_egm_pyclient/run/send_pose.py b/abb_egm_pyclient/run/send_pose.py
index e709586f0ab3807e1d303637698617b1225b1f50..27a65db047ad7f54c6b1de9f68e257f8740a054a 100644
--- a/abb_egm_pyclient/run/send_pose.py
+++ b/abb_egm_pyclient/run/send_pose.py
@@ -1,6 +1,11 @@
-#!/usr/bin/env python
 """Send pose example."""
 
+from typing import List
+from abb_egm_pyclient import DEFAULT_UDP_PORT
 
-def send_pose(port, x, y, z, rx, ry, rz):
+
+def send_pose(
+    target_pose: List[float],
+    port: int = DEFAULT_UDP_PORT,
+):
     raise NotImplementedError("Planned example")
diff --git a/environment.yml b/environment.yml
index 0d84b9528317e7016bbeeb2d99420dca02fe2800..e3d6901d766ec8ebfb5e9b26055a8d1cb05ac637 100644
--- a/environment.yml
+++ b/environment.yml
@@ -1,7 +1,8 @@
-name: abb-egm-examples
+name: abb_egm_pyclient
 channels:
   - conda-forge
 dependencies:
-  - python >=3.7, <3.10
-  - protobuf
   - numpy
+  - python >=3.7, <3.13
+  - protobuf
+  - ruff
diff --git a/pyproject.toml b/pyproject.toml
index 4d7a504912c911d160496b53129b5fb75bda679f..665a089782169a86fb4c4a8cfb7fd322265c5e24 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,9 +1,17 @@
+[project]
+name = "abb_egm_pyclient"
+version = "0.1.0"
+description = "Python client to send EGM messages to ABB robots"
+authors = [
+    { name = "Anton Tetov", email = "anton@tetov.se" },
+]
+readme = "README.md"
+requires-python = ">= 3.7"
+license = {file = "LICENSE"}
+urls = { "Repository" = "https://gitlab.control.lth.se/robotlab/abb_egm_pyclient/"}
+dependencies = ["numpy", "protobuf"]
+optional-dependencies = { "dev" = ["ruff"] }
+
 [build-system]
-requires = ["setuptools >= 40.9.0", "wheel"]
+requires = ["setuptools>=61.0"]
 build-backend = "setuptools.build_meta"
-
-[tool.isort]
-profile = "black"
-
-[tool.mypy]
-plugins = "numpy.typing.mypy_plugin"
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 5ebadbe661fd47f5dfd13f997dc4f473545cba65..0000000000000000000000000000000000000000
--- a/setup.cfg
+++ /dev/null
@@ -1,20 +0,0 @@
-[metadata]
-name = abb_egm_pyclient
-version = 0.1.0
-
-[options]
-packages = abb_egm_pyclient
-python_requires = >= 3.7
-install_requires =
-    protobuf
-
-[options.extras_require]
-dev = 
-    black
-    flake8
-    isort >= 5.0.0
-    mypy
-
-[flake8]
-max-line-length = 88
-extend-ignore = E203
diff --git a/setup.py b/setup.py
deleted file mode 100644
index b908cbe55cb344569d32de1dfc10ca7323828dc5..0000000000000000000000000000000000000000
--- a/setup.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import setuptools
-
-setuptools.setup()