diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..885b9f95bca6d42af83f6b7747bddc63c2c847cc
Binary files /dev/null and b/.DS_Store differ
diff --git a/src/.DS_Store b/src/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..ee844f4024b1481186cd0bbd0c5483e0eabae090
Binary files /dev/null and b/src/.DS_Store differ
diff --git a/src/HelloWorld.java b/src/HelloWorld.java
deleted file mode 100644
index 5b97145fb66add90f85840d9ebca95338a64147d..0000000000000000000000000000000000000000
--- a/src/HelloWorld.java
+++ /dev/null
@@ -1,7 +0,0 @@
-public class HelloWorld {
-
-    public static void main(String[] args) {
-
-        System.out.println("Hello World");
-    }
-}
\ No newline at end of file
diff --git a/src/conf/conf.go b/src/conf/conf.go
new file mode 100644
index 0000000000000000000000000000000000000000..734b1dab84d05bd7a37a22b1d5158387411a0b74
--- /dev/null
+++ b/src/conf/conf.go
@@ -0,0 +1,96 @@
+package conf
+
+var (
+	WorkerEndpoint1  string = "localhost:9001"
+	WorkerEndpoint2  string = "localhost:9002"
+	WorkerEndpoint3  string = ""
+	WorkerEndpoint4  string = ""
+	WorkerEndpoint5  string = ""
+	WorkerEndpoint6  string = ""
+	WorkerEndpoint7  string = ""
+	WorkerEndpoint8  string = ""
+	WorkerEndpoint9  string = ""
+	WorkerEndpoint10 string = ""
+
+	LogFileName1  string = "machine.1.log"
+	LogFileName2  string = "machine.2.log"
+	LogFileName3  string = "machine.3.log"
+	LogFileName4  string = "machine.4.log"
+	LogFileName5  string = "machine.5.log"
+	LogFileName6  string = "machine.6.log"
+	LogFileName7  string = "machine.7.log"
+	LogFileName8  string = "machine.8.log"
+	LogFileName9  string = "machine.9.log"
+	LogFileName10 string = "machine.10.log"
+)
+
+type WorkerConfig struct {
+	Endpoint    string
+	LogFileName string
+}
+
+func GetWorkerConfigs() []WorkerConfig {
+	return []WorkerConfig{
+		{
+			Endpoint:    WorkerEndpoint1,
+			LogFileName: LogFileName1,
+		},
+		{
+			Endpoint:    WorkerEndpoint2,
+			LogFileName: LogFileName1,
+		},
+	}
+}
+
+/*func GetWorkerConfigs() []WorkerConfig {
+	return []WorkerConfig{
+		{
+			Endpoint:    WorkerEndpoint1,
+			LogFileName: LogFileName1,
+		},
+		{
+			Endpoint:    WorkerEndpoint2,
+			LogFileName: LogFileName2,
+		},
+		{
+			Endpoint:    WorkerEndpoint3,
+			LogFileName: LogFileName3,
+		},
+		{
+			Endpoint:    WorkerEndpoint4,
+			LogFileName: LogFileName4,
+		},
+		{
+			Endpoint:    WorkerEndpoint5,
+			LogFileName: LogFileName5,
+		},
+		{
+			Endpoint:    WorkerEndpoint6,
+			LogFileName: LogFileName6,
+		},
+		{
+			Endpoint:    WorkerEndpoint7,
+			LogFileName: LogFileName7,
+		},
+		{
+			Endpoint:    WorkerEndpoint8,
+			LogFileName: LogFileName8,
+		},
+		{
+			Endpoint:    WorkerEndpoint9,
+			LogFileName: LogFileName9,
+		},
+		{
+			Endpoint:    WorkerEndpoint10,
+			LogFileName: LogFileName10,
+		},
+	}
+}*/
+
+/*func GetLogFileNames() []string {
+	return []string{LogFileName1, LogFileName2, LogFileName3, LogFileName4, LogFileName5, LogFileName6, LogFileName7, LogFileName8, LogFileName9, LogFileName10}
+}*/
+
+/*func GetWorkerConfigs() []string {
+	return []string{WorkerEndpoint1, WorkerEndpoint2, WorkerEndpoint3, WorkerEndpoint4, WorkerEndpoint5, WorkerEndpoint6, WorkerEndpoint7, WorkerEndpoint8, WorkerEndpoint9, WorkerEndpoint10}
+}*/
diff --git a/src/coordinator/coordinator.go b/src/coordinator/coordinator.go
new file mode 100644
index 0000000000000000000000000000000000000000..70a3c1f51b0da83dec79a637e34586fe92434504
--- /dev/null
+++ b/src/coordinator/coordinator.go
@@ -0,0 +1,93 @@
+package coordinator
+
+import (
+	"CS425/cs-425-mp1/src/conf"
+	"CS425/cs-425-mp1/src/worker"
+	context "context"
+	sync "sync"
+
+	grpc "google.golang.org/grpc"
+)
+
+type Coordinator struct {
+	UnimplementedCoordinatorServiceServer
+}
+
+func (c *Coordinator) FetchCoordinatorOutput(ctx context.Context, coordinatorInput *CoordinatorInput) (*CoordinatorOutput, error) {
+
+	workerOutputs, err := FetchWorkerOutputs(ctx, &worker.WorkerInput{Data: coordinatorInput.Data, Flag: coordinatorInput.Flag})
+	if err != nil {
+		return nil, err
+	}
+	coordinatorOutput := CoordinatorOutput{}
+	fileNameList := []string{}
+	matchesList := []string{}
+
+	for i := 0; i < len(workerOutputs); i++ {
+		fileNameList = append(fileNameList, workerOutputs[i].GetFileName())
+		matchesList = append(matchesList, workerOutputs[i].GetMatches())
+	}
+	coordinatorOutput.FileName = fileNameList
+	coordinatorOutput.Matches = matchesList
+	return &coordinatorOutput, nil
+}
+
+func FetchWorkerOutputs(ctx context.Context, workerInput *worker.WorkerInput) ([]worker.WorkerOutput, error) {
+	var workerOutputs []worker.WorkerOutput
+	workerConfigs := conf.GetWorkerConfigs()
+	workerOutputChan := make(chan worker.WorkerOutput, 10)
+	var wg sync.WaitGroup
+	// Tell the 'wg' WaitGroup how many threads/goroutines
+	//	that are about to run concurrently.
+	wg.Add(len(workerConfigs))
+	for i := 0; i < len(workerConfigs); i++ {
+		// Spawn a thread for each iteration in the loop.
+		go func(ctx context.Context, workerInput *worker.WorkerInput, workerConfig conf.WorkerConfig, workerOutputChan chan worker.WorkerOutput) {
+			// At the end of the goroutine, tell the WaitGroup
+			//   that another thread has completed.
+			defer wg.Done()
+			var conn *grpc.ClientConn
+			conn, err := grpc.Dial(workerConfig.Endpoint, grpc.WithInsecure())
+			if err != nil {
+
+			}
+			defer conn.Close()
+			w := worker.NewWorkerServiceClient(conn)
+			workerInput.LogFileName = workerConfig.LogFileName
+			// take input from user to a list of args
+			workerOutput, err := w.FetchWorkerOutput(ctx, workerInput)
+			if err != nil {
+
+			}
+			workerOutputChan <- *workerOutput
+		}(ctx, workerInput, workerConfigs[i], workerOutputChan)
+		workerOutputs = append(workerOutputs, <-workerOutputChan)
+	}
+	// Wait for `wg.Done()` to be exectued the number of times
+	//   specified in the `wg.Add()` call.
+	// `wg.Done()` should be called the exact number of times
+	//   that was specified in `wg.Add()`.
+	wg.Wait()
+	close(workerOutputChan)
+
+	return workerOutputs, nil
+}
+
+func FetchWorkerOutputUtil(ctx context.Context, workerInput *worker.WorkerInput, workerConfig conf.WorkerConfig, workerOutputChan chan worker.WorkerOutput) {
+	var conn *grpc.ClientConn
+	conn, err := grpc.Dial(workerConfig.Endpoint, grpc.WithInsecure())
+	if err != nil {
+		return
+	}
+	defer conn.Close()
+
+	w := worker.NewWorkerServiceClient(conn)
+	workerInput.LogFileName = workerConfig.LogFileName
+	// take input from user to a list of args
+	workerOutput, err := w.FetchWorkerOutput(ctx, workerInput)
+	if err != nil {
+		return
+	}
+	workerOutputChan <- *workerOutput
+	return
+}
diff --git a/src/coordinator/coordinator.pb.go b/src/coordinator/coordinator.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..d5f5640124566e09b0997e06273a64cad6791931
--- /dev/null
+++ b/src/coordinator/coordinator.pb.go
@@ -0,0 +1,234 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.1
+// 	protoc        v3.21.5
+// source: coordinator.proto
+
+package coordinator
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type CoordinatorInput struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+	Flag string `protobuf:"bytes,2,opt,name=flag,proto3" json:"flag,omitempty"`
+}
+
+func (x *CoordinatorInput) Reset() {
+	*x = CoordinatorInput{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_coordinator_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CoordinatorInput) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CoordinatorInput) ProtoMessage() {}
+
+func (x *CoordinatorInput) ProtoReflect() protoreflect.Message {
+	mi := &file_coordinator_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CoordinatorInput.ProtoReflect.Descriptor instead.
+func (*CoordinatorInput) Descriptor() ([]byte, []int) {
+	return file_coordinator_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *CoordinatorInput) GetData() string {
+	if x != nil {
+		return x.Data
+	}
+	return ""
+}
+
+func (x *CoordinatorInput) GetFlag() string {
+	if x != nil {
+		return x.Flag
+	}
+	return ""
+}
+
+type CoordinatorOutput struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	FileName []string `protobuf:"bytes,1,rep,name=fileName,proto3" json:"fileName,omitempty"`
+	Matches  []string `protobuf:"bytes,2,rep,name=matches,proto3" json:"matches,omitempty"`
+}
+
+func (x *CoordinatorOutput) Reset() {
+	*x = CoordinatorOutput{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_coordinator_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CoordinatorOutput) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CoordinatorOutput) ProtoMessage() {}
+
+func (x *CoordinatorOutput) ProtoReflect() protoreflect.Message {
+	mi := &file_coordinator_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CoordinatorOutput.ProtoReflect.Descriptor instead.
+func (*CoordinatorOutput) Descriptor() ([]byte, []int) {
+	return file_coordinator_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *CoordinatorOutput) GetFileName() []string {
+	if x != nil {
+		return x.FileName
+	}
+	return nil
+}
+
+func (x *CoordinatorOutput) GetMatches() []string {
+	if x != nil {
+		return x.Matches
+	}
+	return nil
+}
+
+var File_coordinator_proto protoreflect.FileDescriptor
+
+var file_coordinator_proto_rawDesc = []byte{
+	0x0a, 0x11, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72,
+	0x22, 0x3a, 0x0a, 0x10, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x49,
+	0x6e, 0x70, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x61, 0x67,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x22, 0x49, 0x0a, 0x11,
+	0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75,
+	0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a,
+	0x07, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07,
+	0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x32, 0x6f, 0x0a, 0x12, 0x43, 0x6f, 0x6f, 0x72, 0x64,
+	0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x59, 0x0a,
+	0x16, 0x46, 0x65, 0x74, 0x63, 0x68, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f,
+	0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1d, 0x2e, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69,
+	0x6e, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f,
+	0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e,
+	0x61, 0x74, 0x6f, 0x72, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72,
+	0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x00, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x63, 0x6f,
+	0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x33,
+}
+
+var (
+	file_coordinator_proto_rawDescOnce sync.Once
+	file_coordinator_proto_rawDescData = file_coordinator_proto_rawDesc
+)
+
+func file_coordinator_proto_rawDescGZIP() []byte {
+	file_coordinator_proto_rawDescOnce.Do(func() {
+		file_coordinator_proto_rawDescData = protoimpl.X.CompressGZIP(file_coordinator_proto_rawDescData)
+	})
+	return file_coordinator_proto_rawDescData
+}
+
+var file_coordinator_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_coordinator_proto_goTypes = []interface{}{
+	(*CoordinatorInput)(nil),  // 0: coordinator.CoordinatorInput
+	(*CoordinatorOutput)(nil), // 1: coordinator.CoordinatorOutput
+}
+var file_coordinator_proto_depIdxs = []int32{
+	0, // 0: coordinator.CoordinatorService.FetchCoordinatorOutput:input_type -> coordinator.CoordinatorInput
+	1, // 1: coordinator.CoordinatorService.FetchCoordinatorOutput:output_type -> coordinator.CoordinatorOutput
+	1, // [1:2] is the sub-list for method output_type
+	0, // [0:1] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_coordinator_proto_init() }
+func file_coordinator_proto_init() {
+	if File_coordinator_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_coordinator_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CoordinatorInput); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_coordinator_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CoordinatorOutput); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_coordinator_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_coordinator_proto_goTypes,
+		DependencyIndexes: file_coordinator_proto_depIdxs,
+		MessageInfos:      file_coordinator_proto_msgTypes,
+	}.Build()
+	File_coordinator_proto = out.File
+	file_coordinator_proto_rawDesc = nil
+	file_coordinator_proto_goTypes = nil
+	file_coordinator_proto_depIdxs = nil
+}
diff --git a/src/coordinator/coordinator.proto b/src/coordinator/coordinator.proto
new file mode 100644
index 0000000000000000000000000000000000000000..9081b6c67e45bd12362f23031cc064df3a3be70e
--- /dev/null
+++ b/src/coordinator/coordinator.proto
@@ -0,0 +1,18 @@
+syntax = "proto3";
+package coordinator;
+
+option go_package = "./coordinator";
+
+message CoordinatorInput {
+    string data = 1;
+    string flag = 2;
+}
+
+message CoordinatorOutput {
+    repeated string fileName = 1;
+    repeated string  matches = 2;
+}
+
+service CoordinatorService {
+  rpc FetchCoordinatorOutput(CoordinatorInput) returns (CoordinatorOutput) {}
+}
\ No newline at end of file
diff --git a/src/coordinator/coordinator_grpc.pb.go b/src/coordinator/coordinator_grpc.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..5c91083dbb5d29322bff852f2c0595d9ed46fdd9
--- /dev/null
+++ b/src/coordinator/coordinator_grpc.pb.go
@@ -0,0 +1,105 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.2.0
+// - protoc             v3.21.5
+// source: coordinator.proto
+
+package coordinator
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// CoordinatorServiceClient is the client API for CoordinatorService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type CoordinatorServiceClient interface {
+	FetchCoordinatorOutput(ctx context.Context, in *CoordinatorInput, opts ...grpc.CallOption) (*CoordinatorOutput, error)
+}
+
+type coordinatorServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewCoordinatorServiceClient(cc grpc.ClientConnInterface) CoordinatorServiceClient {
+	return &coordinatorServiceClient{cc}
+}
+
+func (c *coordinatorServiceClient) FetchCoordinatorOutput(ctx context.Context, in *CoordinatorInput, opts ...grpc.CallOption) (*CoordinatorOutput, error) {
+	out := new(CoordinatorOutput)
+	err := c.cc.Invoke(ctx, "/coordinator.CoordinatorService/FetchCoordinatorOutput", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// CoordinatorServiceServer is the server API for CoordinatorService service.
+// All implementations must embed UnimplementedCoordinatorServiceServer
+// for forward compatibility
+type CoordinatorServiceServer interface {
+	FetchCoordinatorOutput(context.Context, *CoordinatorInput) (*CoordinatorOutput, error)
+	mustEmbedUnimplementedCoordinatorServiceServer()
+}
+
+// UnimplementedCoordinatorServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedCoordinatorServiceServer struct {
+}
+
+func (UnimplementedCoordinatorServiceServer) FetchCoordinatorOutput(context.Context, *CoordinatorInput) (*CoordinatorOutput, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method FetchCoordinatorOutput not implemented")
+}
+func (UnimplementedCoordinatorServiceServer) mustEmbedUnimplementedCoordinatorServiceServer() {}
+
+// UnsafeCoordinatorServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to CoordinatorServiceServer will
+// result in compilation errors.
+type UnsafeCoordinatorServiceServer interface {
+	mustEmbedUnimplementedCoordinatorServiceServer()
+}
+
+func RegisterCoordinatorServiceServer(s grpc.ServiceRegistrar, srv CoordinatorServiceServer) {
+	s.RegisterService(&CoordinatorService_ServiceDesc, srv)
+}
+
+func _CoordinatorService_FetchCoordinatorOutput_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(CoordinatorInput)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(CoordinatorServiceServer).FetchCoordinatorOutput(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/coordinator.CoordinatorService/FetchCoordinatorOutput",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(CoordinatorServiceServer).FetchCoordinatorOutput(ctx, req.(*CoordinatorInput))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// CoordinatorService_ServiceDesc is the grpc.ServiceDesc for CoordinatorService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var CoordinatorService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "coordinator.CoordinatorService",
+	HandlerType: (*CoordinatorServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "FetchCoordinatorOutput",
+			Handler:    _CoordinatorService_FetchCoordinatorOutput_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "coordinator.proto",
+}
diff --git a/src/go.mod b/src/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..10d80ed11e0d74238c1520ddb038f32f0dcc44f6
--- /dev/null
+++ b/src/go.mod
@@ -0,0 +1,16 @@
+module CS425/cs-425-mp1/src
+
+go 1.19
+
+require (
+	google.golang.org/grpc v1.49.0
+	google.golang.org/protobuf v1.28.1
+)
+
+require (
+	github.com/golang/protobuf v1.5.2 // indirect
+	golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect
+	golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect
+	golang.org/x/text v0.3.3 // indirect
+	google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
+)
diff --git a/src/go.sum b/src/go.sum
new file mode 100644
index 0000000000000000000000000000000000000000..9f0cd57e130ca270a8ba9805373551e8a946a704
--- /dev/null
+++ b/src/go.sum
@@ -0,0 +1,83 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
+google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/src/worker/worker.go b/src/worker/worker.go
new file mode 100644
index 0000000000000000000000000000000000000000..5ff3b7c01a99c19b9d77ebfd81be77bb447131e8
--- /dev/null
+++ b/src/worker/worker.go
@@ -0,0 +1,27 @@
+package worker
+
+import (
+	"context"
+	"os/exec"
+	"strings"
+)
+
+type Worker struct {
+	UnimplementedWorkerServiceServer
+}
+
+func (w *Worker) FetchWorkerOutput(ctx context.Context, workerInput *WorkerInput) (*WorkerOutput, error) {
+	app := "grep"
+	arg0 := workerInput.Flag
+	arg1 := workerInput.Data
+	arg2 := workerInput.LogFileName
+
+	cmd := exec.Command(app, arg0, arg1, arg2)
+
+	stdout, _ := cmd.Output()
+	matches := strings.TrimSuffix(string(stdout), "\n")
+	workerOutput := WorkerOutput{}
+	workerOutput.Matches = matches
+	workerOutput.FileName = workerInput.LogFileName
+	return &workerOutput, nil
+}
diff --git a/src/worker/worker.pb.go b/src/worker/worker.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..bef06a24f540791f487507c59e0bdb76d22780ac
--- /dev/null
+++ b/src/worker/worker.pb.go
@@ -0,0 +1,240 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.1
+// 	protoc        v3.21.5
+// source: worker.proto
+
+package worker
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type WorkerInput struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Data        string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+	Flag        string `protobuf:"bytes,2,opt,name=flag,proto3" json:"flag,omitempty"`
+	LogFileName string `protobuf:"bytes,3,opt,name=logFileName,proto3" json:"logFileName,omitempty"`
+}
+
+func (x *WorkerInput) Reset() {
+	*x = WorkerInput{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_worker_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *WorkerInput) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WorkerInput) ProtoMessage() {}
+
+func (x *WorkerInput) ProtoReflect() protoreflect.Message {
+	mi := &file_worker_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use WorkerInput.ProtoReflect.Descriptor instead.
+func (*WorkerInput) Descriptor() ([]byte, []int) {
+	return file_worker_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *WorkerInput) GetData() string {
+	if x != nil {
+		return x.Data
+	}
+	return ""
+}
+
+func (x *WorkerInput) GetFlag() string {
+	if x != nil {
+		return x.Flag
+	}
+	return ""
+}
+
+func (x *WorkerInput) GetLogFileName() string {
+	if x != nil {
+		return x.LogFileName
+	}
+	return ""
+}
+
+type WorkerOutput struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	FileName string `protobuf:"bytes,1,opt,name=fileName,proto3" json:"fileName,omitempty"`
+	Matches  string `protobuf:"bytes,2,opt,name=matches,proto3" json:"matches,omitempty"`
+}
+
+func (x *WorkerOutput) Reset() {
+	*x = WorkerOutput{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_worker_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *WorkerOutput) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WorkerOutput) ProtoMessage() {}
+
+func (x *WorkerOutput) ProtoReflect() protoreflect.Message {
+	mi := &file_worker_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use WorkerOutput.ProtoReflect.Descriptor instead.
+func (*WorkerOutput) Descriptor() ([]byte, []int) {
+	return file_worker_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *WorkerOutput) GetFileName() string {
+	if x != nil {
+		return x.FileName
+	}
+	return ""
+}
+
+func (x *WorkerOutput) GetMatches() string {
+	if x != nil {
+		return x.Matches
+	}
+	return ""
+}
+
+var File_worker_proto protoreflect.FileDescriptor
+
+var file_worker_proto_rawDesc = []byte{
+	0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06,
+	0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x22, 0x57, 0x0a, 0x0b, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72,
+	0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x61,
+	0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x12, 0x20, 0x0a,
+	0x0b, 0x6c, 0x6f, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x0b, 0x6c, 0x6f, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22,
+	0x44, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12,
+	0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d,
+	0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x61,
+	0x74, 0x63, 0x68, 0x65, 0x73, 0x32, 0x51, 0x0a, 0x0d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x53,
+	0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x40, 0x0a, 0x11, 0x46, 0x65, 0x74, 0x63, 0x68, 0x57,
+	0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x13, 0x2e, 0x77, 0x6f,
+	0x72, 0x6b, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74,
+	0x1a, 0x14, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72,
+	0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x77, 0x6f,
+	0x72, 0x6b, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_worker_proto_rawDescOnce sync.Once
+	file_worker_proto_rawDescData = file_worker_proto_rawDesc
+)
+
+func file_worker_proto_rawDescGZIP() []byte {
+	file_worker_proto_rawDescOnce.Do(func() {
+		file_worker_proto_rawDescData = protoimpl.X.CompressGZIP(file_worker_proto_rawDescData)
+	})
+	return file_worker_proto_rawDescData
+}
+
+var file_worker_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_worker_proto_goTypes = []interface{}{
+	(*WorkerInput)(nil),  // 0: worker.WorkerInput
+	(*WorkerOutput)(nil), // 1: worker.WorkerOutput
+}
+var file_worker_proto_depIdxs = []int32{
+	0, // 0: worker.WorkerService.FetchWorkerOutput:input_type -> worker.WorkerInput
+	1, // 1: worker.WorkerService.FetchWorkerOutput:output_type -> worker.WorkerOutput
+	1, // [1:2] is the sub-list for method output_type
+	0, // [0:1] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_worker_proto_init() }
+func file_worker_proto_init() {
+	if File_worker_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_worker_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*WorkerInput); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_worker_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*WorkerOutput); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_worker_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_worker_proto_goTypes,
+		DependencyIndexes: file_worker_proto_depIdxs,
+		MessageInfos:      file_worker_proto_msgTypes,
+	}.Build()
+	File_worker_proto = out.File
+	file_worker_proto_rawDesc = nil
+	file_worker_proto_goTypes = nil
+	file_worker_proto_depIdxs = nil
+}
diff --git a/src/worker/worker.proto b/src/worker/worker.proto
new file mode 100644
index 0000000000000000000000000000000000000000..1ce9760db2a39e55b1e23d6f0d2097fd7cb79242
--- /dev/null
+++ b/src/worker/worker.proto
@@ -0,0 +1,19 @@
+syntax = "proto3";
+package worker;
+
+option go_package = "./worker";
+
+message WorkerInput {
+    string data = 1;
+    string flag = 2;
+    string logFileName = 3;
+}
+
+message WorkerOutput {
+    string fileName = 1;
+    string  matches = 2;
+}
+
+service WorkerService {
+  rpc FetchWorkerOutput(WorkerInput) returns (WorkerOutput) {}
+}
\ No newline at end of file
diff --git a/src/worker/worker_grpc.pb.go b/src/worker/worker_grpc.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..85827b10890da30d8527dec8e93f2d9cee8859ab
--- /dev/null
+++ b/src/worker/worker_grpc.pb.go
@@ -0,0 +1,105 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.2.0
+// - protoc             v3.21.5
+// source: worker.proto
+
+package worker
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// WorkerServiceClient is the client API for WorkerService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type WorkerServiceClient interface {
+	FetchWorkerOutput(ctx context.Context, in *WorkerInput, opts ...grpc.CallOption) (*WorkerOutput, error)
+}
+
+type workerServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewWorkerServiceClient(cc grpc.ClientConnInterface) WorkerServiceClient {
+	return &workerServiceClient{cc}
+}
+
+func (c *workerServiceClient) FetchWorkerOutput(ctx context.Context, in *WorkerInput, opts ...grpc.CallOption) (*WorkerOutput, error) {
+	out := new(WorkerOutput)
+	err := c.cc.Invoke(ctx, "/worker.WorkerService/FetchWorkerOutput", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// WorkerServiceServer is the server API for WorkerService service.
+// All implementations must embed UnimplementedWorkerServiceServer
+// for forward compatibility
+type WorkerServiceServer interface {
+	FetchWorkerOutput(context.Context, *WorkerInput) (*WorkerOutput, error)
+	mustEmbedUnimplementedWorkerServiceServer()
+}
+
+// UnimplementedWorkerServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedWorkerServiceServer struct {
+}
+
+func (UnimplementedWorkerServiceServer) FetchWorkerOutput(context.Context, *WorkerInput) (*WorkerOutput, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method FetchWorkerOutput not implemented")
+}
+func (UnimplementedWorkerServiceServer) mustEmbedUnimplementedWorkerServiceServer() {}
+
+// UnsafeWorkerServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to WorkerServiceServer will
+// result in compilation errors.
+type UnsafeWorkerServiceServer interface {
+	mustEmbedUnimplementedWorkerServiceServer()
+}
+
+func RegisterWorkerServiceServer(s grpc.ServiceRegistrar, srv WorkerServiceServer) {
+	s.RegisterService(&WorkerService_ServiceDesc, srv)
+}
+
+func _WorkerService_FetchWorkerOutput_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(WorkerInput)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(WorkerServiceServer).FetchWorkerOutput(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/worker.WorkerService/FetchWorkerOutput",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(WorkerServiceServer).FetchWorkerOutput(ctx, req.(*WorkerInput))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// WorkerService_ServiceDesc is the grpc.ServiceDesc for WorkerService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var WorkerService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "worker.WorkerService",
+	HandlerType: (*WorkerServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "FetchWorkerOutput",
+			Handler:    _WorkerService_FetchWorkerOutput_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "worker.proto",
+}