diff --git a/rosidl_adapter_proto/bin/rosidl_adapter_proto b/rosidl_adapter_proto/bin/rosidl_adapter_proto
index bf49b23..eb98bd7 100644
--- a/rosidl_adapter_proto/bin/rosidl_adapter_proto
+++ b/rosidl_adapter_proto/bin/rosidl_adapter_proto
@@ -23,9 +23,8 @@ import sys
 import pathlib
 import os
 
-from rosidl_cmake import read_generator_arguments
-from rosidl_adapter_proto import generate_proto
-from rosidl_adapter_proto import compile_proto
+from rosidl_adapter_proto import convert_to_proto
+
 
 def main(argv=sys.argv[1:]):
     parser = argparse.ArgumentParser(
@@ -41,47 +40,12 @@ def main(argv=sys.argv[1:]):
         help='Path to the protoc executable')
 
     args = parser.parse_args(argv)
-
-    generator_args = read_generator_arguments(args.generator_arguments_file)
-
-    # Generate .proto files
-    rc = generate_proto(args.generator_arguments_file) 
-    if rc:
-        return rc
-
-    # Compile .proto files using protoc
-    cpp_out_dir     = str(pathlib.Path(generator_args["output_dir"] + "/..").resolve())
-    proto_path_list = [str(pathlib.Path(generator_args["output_dir"] + "/..").resolve())]
-    proto_files     = []
-    package_name    = generator_args["package_name"]
-
-    if "additional_files" in generator_args:
-        proto_path_list += generator_args["additional_files"]
-
-    pathlib.Path(cpp_out_dir).mkdir(parents=True, exist_ok=True)
-
-    for idl_tuple in generator_args.get('idl_tuples', []):
-        idl_parts = idl_tuple.rsplit(':', 1)
-        assert len(idl_parts) == 2
-        idl_rel_path = pathlib.Path(idl_parts[1])
-        idl_stem = idl_rel_path.stem
-        generated_file = os.path.join(
-                    generator_args['output_dir'],
-                    str(idl_rel_path.parent),
-                    idl_stem + ".proto"
-        )
-        proto_files.append(str(pathlib.Path(generated_file).resolve()))
-
-    # compile proto files with protoc
-    rc = compile_proto(protoc_path     = args.protoc_path,
-                       proto_path_list = proto_path_list,
-                       cpp_out_dir     = cpp_out_dir,
-                       proto_files     = proto_files,
-                       package_name    = package_name
-    )
+    try: 
+        translate_to_proto(args.generator_arguments_file, args.protoc_path)
+    except RuntimeError:
+        return 1
     
-    return rc
-
+    return 0
 
 if __name__ == '__main__':
     sys.exit(main())
diff --git a/rosidl_adapter_proto/rosidl_adapter_proto/cli.py b/rosidl_adapter_proto/rosidl_adapter_proto/cli.py
new file mode 100644
index 0000000..7fd452d
--- /dev/null
+++ b/rosidl_adapter_proto/rosidl_adapter_proto/cli.py
@@ -0,0 +1,157 @@
+import argparse
+import os
+import pathlib
+import sys
+
+from ament_index_python import get_package_share_directory
+
+from catkin_pkg.package import package_exists_at
+from catkin_pkg.package import parse_package
+
+from rosidl_adapter.action import convert_action_to_idl
+from rosidl_adapter.msg import convert_msg_to_idl
+from rosidl_adapter.srv import convert_srv_to_idl
+
+from rosidl_cmake import read_generator_arguments
+
+from rosidl_cli.command.helpers import interface_path_as_tuple
+from rosidl_cli.command.helpers import legacy_generator_arguments_file
+from rosidl_cli.command.translate.extensions import TranslateCommandExtension
+from rosidl_cli.command.translate.api import translate
+
+from rosidl_adapter_proto import generate_proto
+from rosidl_adapter_proto import compile_proto
+
+def convert_to_proto(generator_arguments_file, protoc_path):
+    generator_args = read_generator_arguments(generator_arguments_file)
+
+    # Generate .proto files
+    rc = generate_proto(generator_arguments_file) 
+    if rc :
+        raise RuntimeError
+
+    # Compile .proto files using protoc
+    cpp_out_dir     = str(pathlib.Path(generator_args["output_dir"] + "/..").resolve())
+    proto_path_list = [str(pathlib.Path(generator_args["output_dir"] + "/..").resolve())]
+    proto_files     = []
+    package_name    = generator_args["package_name"]
+
+    if "additional_files" in generator_args:
+        proto_path_list += generator_args["additional_files"]
+
+    pathlib.Path(cpp_out_dir).mkdir(parents=True, exist_ok=True)
+
+    for idl_tuple in generator_args.get('idl_tuples', []):
+        idl_parts = idl_tuple.rsplit(':', 1)
+        assert len(idl_parts) == 2
+        idl_rel_path = pathlib.Path(idl_parts[1])
+        idl_stem = idl_rel_path.stem
+        generated_file = os.path.join(
+                    generator_args['output_dir'],
+                    str(idl_rel_path.parent),
+                    idl_stem + ".proto"
+        )
+        proto_files.append(str(pathlib.Path(generated_file).resolve()))
+
+    # compile proto files with protoc
+    rc = compile_proto(protoc_path     = protoc_path,
+                       proto_path_list = proto_path_list,
+                       cpp_out_dir     = cpp_out_dir,
+                       proto_files     = proto_files,
+                       package_name    = package_name
+    )
+    if rc :
+        raise RuntimeError
+
+    return proto_files
+
+
+def convert_files_to_idl(extension, conversion_function, argv=sys.argv[1:]):
+    parser = argparse.ArgumentParser(
+        description=f'Convert {extension} files to .idl')
+    parser.add_argument(
+        'interface_files', nargs='+',
+        help='The interface files to convert')
+    args = parser.parse_args(argv)
+
+    for interface_file in args.interface_files:
+        interface_file = pathlib.Path(interface_file)
+        package_dir = interface_file.parent.absolute()
+        while (
+            len(package_dir.parents) and
+            not package_exists_at(str(package_dir))
+        ):
+            package_dir = package_dir.parent
+        if not package_dir.parents:
+            print(
+                f"Could not find package for '{interface_file}'",
+                file=sys.stderr)
+            continue
+        warnings = []
+        pkg = parse_package(package_dir, warnings=warnings)
+
+        conversion_function(
+            package_dir, pkg.name,
+            interface_file.absolute().relative_to(package_dir),
+            interface_file.parent)
+
+
+class TranslateToProto(TranslateCommandExtension):
+
+    output_format = 'proto'
+
+    def translate(
+        self,
+        package_name,
+        interface_files,
+        include_paths,
+        output_path
+    ):
+
+        generated_files = []
+
+        package_share_path = pathlib.Path(
+            get_package_share_directory('rosidl_adapter_proto'))
+        templates_path = package_share_path / 'resource'
+
+
+        idl_interface_files = []
+        non_idl_interface_files = []
+        for path in interface_files:
+            if not path.endswith('.idl'):
+                non_idl_interface_files.append(path)
+            else:
+                idl_interface_files.append(path)
+        if non_idl_interface_files:
+            idl_interface_files.extend(translate(
+                package_name=package_name,
+                interface_files=non_idl_interface_files,
+                include_paths=include_paths,
+                output_format='idl',
+                output_path=output_path / 'tmp',
+            ))
+
+
+                # Generate code
+        with legacy_generator_arguments_file(
+            package_name=package_name,
+            interface_files=idl_interface_files,
+            include_paths=include_paths,
+            templates_path=templates_path,
+            output_path=output_path
+        ) as path_to_arguments_file:
+            generated_files.extend(convert_to_proto(path_to_arguments_file, '/usr/bin/protoc'))
+        return generated_files
+
+
+
+class TranslateMsgToProto(TranslateToProto):
+    input_format = 'msg'
+
+
+class TranslateSrvToProto(TranslateToProto):
+    input_format = 'srv'
+
+
+class TranslateActionToProto(TranslateToProto):
+    input_format = 'action'
diff --git a/rosidl_adapter_proto/setup.cfg b/rosidl_adapter_proto/setup.cfg
new file mode 100644
index 0000000..b0a21ca
--- /dev/null
+++ b/rosidl_adapter_proto/setup.cfg
@@ -0,0 +1,5 @@
+[options.entry_points]
+rosidl_cli.command.translate.extensions =
+  msg2proto = rosidl_adapter_proto.cli:TranslateMsgToProto
+  srv2proto = rosidl_adapter_proto.cli:TranslateSrvToProto
+  action2proto = rosidl_adapter_proto.cli:TranslateActionToProto