Repository: Tochemey/goakt
Pull request #28 (2023-02-16 08:22:15)

refactor: code base

codecov[bot]: # [Codecov](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) Report
Base: **58.25**% // Head: **57.50**% // Decreases project coverage by **`-0.76%`** :warning:
> Coverage data is based on head [(`d7a0414`)](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) compared to base [(`f260293`)](https://codecov.io/gh/Tochemey/goakt/commit/f260293e61accb53ddde02b394f6ead8b5d6f94c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene).
> Patch coverage: 55.24% of modified lines in pull request are covered.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main      #28      +/-   ##
==========================================
- Coverage   58.25%   57.50%   -0.76%     
==========================================
  Files          40       40              
  Lines        3517     3589      +72     
==========================================
+ Hits         2049     2064      +15     
- Misses       1332     1383      +51     
- Partials      136      142       +6     
```


| [Impacted Files](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) | Coverage Δ | |
|---|---|---|
| [actors/config.go](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL2NvbmZpZy5nbw==) | `81.31% <0.00%> (-2.78%)` | :arrow_down: |
| [actors/errors.go](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL2Vycm9ycy5nbw==) | `0.00% <ø> (ø)` | |
| [actors/pid\_option.go](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL3BpZF9vcHRpb24uZ28=) | `100.00% <ø> (ø)` | |
| [actors/actor\_system.go](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL2FjdG9yX3N5c3RlbS5nbw==) | `39.88% <42.50%> (-0.23%)` | :arrow_down: |
| [actors/address.go](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL2FkZHJlc3MuZ28=) | `50.66% <50.66%> (-49.34%)` | :arrow_down: |
| [actors/pid.go](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL3BpZC5nbw==) | `59.03% <64.70%> (-0.65%)` | :arrow_down: |
| [actors/path.go](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL3BhdGguZ28=) | `71.42% <71.42%> (ø)` | |
| [actors/passivation.go](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL3Bhc3NpdmF0aW9uLmdv) | `95.45% <100.00%> (ø)` | |
| [actors/types.go](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL3R5cGVzLmdv) | `92.85% <100.00%> (ø)` | |
| [modules/projection/projection.go](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-bW9kdWxlcy9wcm9qZWN0aW9uL3Byb2plY3Rpb24uZ28=) | `74.29% <0.00%> (-2.81%)` | :arrow_down: |
| ... and [2 more](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/Tochemey/goakt/pull/28?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene).


Patch:
diff --git a/actors/actor.go b/actors/actor.go
index da335aa..e107240 100644
--- a/actors/actor.go
+++ b/actors/actor.go
@@ -19,20 +19,3 @@ type Actor interface {
 	// The execution happens when every messages that have not been processed yet will be processed before the actor shutdowns
 	PostStop(ctx context.Context) error
 }
-
-// LocalID represents an actor identifier. It is a combination of the type and the actual
-// identification number. Example: user-1234 is represented as: Kind=User and Value=1234
-type LocalID struct {
-	kind string // Kind specifies the type of actor. example: User
-	id   string // Value specifies the identifier of the actor: example: 1234
-}
-
-// Kind specifies the type of actor. example: User
-func (i LocalID) Kind() string {
-	return i.kind
-}
-
-// ID return the relative id of the actor
-func (i LocalID) ID() string {
-	return i.id
-}
diff --git a/actors/actor_system.go b/actors/actor_system.go
index 9090e42..7c78c30 100644
--- a/actors/actor_system.go
+++ b/actors/actor_system.go
@@ -39,11 +39,11 @@ type ActorSystem interface {
 	// Stop stops the actor system
 	Stop(ctx context.Context) error
 	// StartActor creates an actor in the system and starts it
-	StartActor(ctx context.Context, kind, id string, actor Actor) PID
+	StartActor(ctx context.Context, name string, actor Actor) PID
 	// StopActor stops a given actor in the system
-	StopActor(ctx context.Context, kind, id string) error
+	StopActor(ctx context.Context, name string) error
 	// RestartActor restarts a given actor in the system
-	RestartActor(ctx context.Context, kind, id string) (PID, error)
+	RestartActor(ctx context.Context, name string) (PID, error)
 	// EventBus returns the actor system event bus
 	EventBus() eventbus.EventBus
 	// NumActors returns the total number of active actors in the system
@@ -130,7 +130,7 @@ func (a *actorSystem) NumActors() uint64 {
 }
 
 // StartActor creates or returns the instance of a given actor in the system
-func (a *actorSystem) StartActor(ctx context.Context, kind, id string, actor Actor) PID {
+func (a *actorSystem) StartActor(ctx context.Context, name string, actor Actor) PID {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "StartActor")
 	defer span.End()
@@ -138,10 +138,10 @@ func (a *actorSystem) StartActor(ctx context.Context, kind, id string, actor Act
 	if !a.hasStarted.Load() {
 		return nil
 	}
-	// create the address of the given actor
-	addr := GetAddress(a, kind, id)
+	// get the path of the given actor
+	actorPath := NewPath(name, NewAddress(protocol, a.name, a.host, a.port))
 	// check whether the given actor already exist in the system or not
-	pid, exist := a.actors.Get(string(addr))
+	pid, exist := a.actors.Get(actorPath.String())
 	// actor already exist no need recreate it.
 	if exist {
 		// check whether the given actor heart beat
@@ -152,26 +152,26 @@ func (a *actorSystem) StartActor(ctx context.Context, kind, id string, actor Act
 	}
 
 	// create an instance of the actor ref
-	pid = newPID(ctx, actor,
+	pid = newPID(ctx,
+		actorPath,
+		actor,
 		withInitMaxRetries(a.config.ActorInitMaxRetries()),
 		withPassivationAfter(a.config.ExpireActorAfter()),
 		withSendReplyTimeout(a.config.ReplyTimeout()),
 		withCustomLogger(a.config.logger),
 		withActorSystem(a),
-		withLocalID(kind, id),
 		withSupervisorStrategy(a.config.supervisorStrategy),
-		withTelemetry(a.config.telemetry),
-		withAddress(addr))
+		withTelemetry(a.config.telemetry))
 
 	// add the given actor to the actor map
-	a.actors.Set(string(addr), pid)
+	a.actors.Set(actorPath.String(), pid)
 
 	// return the actor ref
 	return pid
 }
 
 // StopActor stops a given actor in the system
-func (a *actorSystem) StopActor(ctx context.Context, kind, id string) error {
+func (a *actorSystem) StopActor(ctx context.Context, name string) error {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "StopActor")
 	defer span.End()
@@ -179,20 +179,20 @@ func (a *actorSystem) StopActor(ctx context.Context, kind, id string) error {
 	if !a.hasStarted.Load() {
 		return errors.New("actor system has not started yet")
 	}
-	// create the address of the given actor
-	addr := GetAddress(a, kind, id)
+	// get the path of the given actor
+	actorPath := NewPath(name, NewAddress(protocol, a.name, a.host, a.port))
 	// check whether the given actor already exist in the system or not
-	pid, exist := a.actors.Get(string(addr))
+	pid, exist := a.actors.Get(actorPath.String())
 	// actor is found.
 	if exist {
 		// stop the given actor
 		return pid.Shutdown(ctx)
 	}
-	return fmt.Errorf("actor=%s not found in the system", addr)
+	return fmt.Errorf("actor=%s not found in the system", actorPath.String())
 }
 
 // RestartActor restarts a given actor in the system
-func (a *actorSystem) RestartActor(ctx context.Context, kind, id string) (PID, error) {
+func (a *actorSystem) RestartActor(ctx context.Context, name string) (PID, error) {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "RestartActor")
 	defer span.End()
@@ -200,20 +200,20 @@ func (a *actorSystem) RestartActor(ctx context.Context, kind, id string) (PID, e
 	if !a.hasStarted.Load() {
 		return nil, errors.New("actor system has not started yet")
 	}
-	// create the address of the given actor
-	addr := GetAddress(a, kind, id)
+	// get the path of the given actor
+	actorPath := NewPath(name, NewAddress(protocol, a.name, a.host, a.port))
 	// check whether the given actor already exist in the system or not
-	pid, exist := a.actors.Get(string(addr))
+	pid, exist := a.actors.Get(actorPath.String())
 	// actor is found.
 	if exist {
 		// restart the given actor
 		if err := pid.Restart(ctx); err != nil {
 			// return the error in case the restart failed
-			return nil, errors.Wrapf(err, "failed to restart actor=%s", addr)
+			return nil, errors.Wrapf(err, "failed to restart actor=%s", actorPath.String())
 		}
 		return pid, nil
 	}
-	return nil, fmt.Errorf("actor=%s not found in the system", addr)
+	return nil, fmt.Errorf("actor=%s not found in the system", actorPath.String())
 }
 
 // Name returns the actor system name
@@ -268,7 +268,7 @@ func (a *actorSystem) Start(ctx context.Context) error {
 	if err := a.registerMetrics(); err != nil {
 		a.logger.Error(errors.Wrapf(err, "failed to register actorSystem=%s metrics", a.name))
 	}
-	a.logger.Infof("%s System started on Node=%s...", a.name, a.nodeAddr)
+	a.logger.Infof("%s ActorSystem started on Node=%s...", a.name, a.nodeAddr)
 	return nil
 }
 
@@ -277,7 +277,7 @@ func (a *actorSystem) Stop(ctx context.Context) error {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "Stop")
 	defer span.End()
-	a.logger.Infof("%s System is shutting down on Node=%s...", a.name, a.nodeAddr)
+	a.logger.Infof("%s ActorSystem is shutting down on Node=%s...", a.name, a.nodeAddr)
 
 	// stop remoting service when set
 	if a.remotingService != nil {
@@ -295,7 +295,7 @@ func (a *actorSystem) Stop(ctx context.Context) error {
 		if err := actor.Shutdown(ctx); err != nil {
 			return err
 		}
-		a.actors.Remove(string(actor.Address()))
+		a.actors.Remove(actor.ActorPath().String())
 	}
 
 	// reset the actor system
@@ -341,17 +341,16 @@ func (a *actorSystem) RemoteLookup(ctx context.Context, request *pb.RemoteLookup
 	}
 
 	// construct the actor address
-	kind := reqCopy.GetAddress().GetKind()
-	id := reqCopy.GetAddress().GetId()
-	addr := GetAddress(a, kind, id)
+	name := reqCopy.GetAddress().GetName()
+	actorPath := NewPath(name, NewAddress(protocol, a.name, a.host, a.port))
 	// start or get the PID of the actor
 	// check whether the given actor already exist in the system or not
-	_, exist := a.actors.Get(string(addr))
+	_, exist := a.actors.Get(actorPath.String())
 	// return an error when the remote address is not found
 	if !exist {
 		// log the error
-		logger.Error(ErrRemoteActorNotFound(string(addr)))
-		return nil, ErrRemoteActorNotFound(string(addr))
+		logger.Error(ErrRemoteActorNotFound(actorPath.String()))
+		return nil, ErrRemoteActorNotFound(actorPath.String())
 	}
 
 	return &pb.RemoteLookupResponse{}, nil
@@ -388,17 +387,16 @@ func (a *actorSystem) RemoteSendSync(ctx context.Context, request *pb.RemoteSend
 	}
 
 	// construct the actor address
-	kind := reqCopy.GetReceiver().GetKind()
-	id := reqCopy.GetReceiver().GetId()
-	addr := GetAddress(a, kind, id)
+	name := reqCopy.GetReceiver().GetName()
+	actorPath := NewPath(name, NewAddress(protocol, a.name, a.host, a.port))
 	// start or get the PID of the actor
 	// check whether the given actor already exist in the system or not
-	pid, exist := a.actors.Get(string(addr))
+	pid, exist := a.actors.Get(string(actorPath.String()))
 	// return an error when the remote address is not found
 	if !exist {
 		// log the error
-		logger.Error(ErrRemoteActorNotFound(string(addr)))
-		return nil, ErrRemoteActorNotFound(string(addr))
+		logger.Error(ErrRemoteActorNotFound(actorPath.String()))
+		return nil, ErrRemoteActorNotFound(actorPath.String())
 	}
 	// restart the actor when it is not live
 	if !pid.IsOnline() {
@@ -450,17 +448,21 @@ func (a *actorSystem) RemoteSendAsync(ctx context.Context, request *pb.RemoteSen
 	}
 
 	// construct the actor address
-	kind := reqCopy.GetAddress().GetKind()
-	id := reqCopy.GetAddress().GetId()
-	addr := GetAddress(a, kind, id)
+	actorPath := NewPath(
+		reqCopy.GetAddress().GetName(),
+		NewAddress(
+			protocol,
+			reqCopy.GetAddress().GetActorSystem(),
+			reqCopy.GetAddress().GetHost(),
+			int(reqCopy.GetAddress().GetPort())))
 	// start or get the PID of the actor
 	// check whether the given actor already exist in the system or not
-	pid, exist := a.actors.Get(string(addr))
+	pid, exist := a.actors.Get(actorPath.String())
 	// return an error when the remote address is not found
 	if !exist {
 		// log the error
-		logger.Error(ErrRemoteActorNotFound(string(addr)))
-		return nil, ErrRemoteActorNotFound(string(addr))
+		logger.Error(ErrRemoteActorNotFound(actorPath.String()))
+		return nil, ErrRemoteActorNotFound(actorPath.String())
 	}
 	// restart the actor when it is not live
 	if !pid.IsOnline() {
diff --git a/actors/address.go b/actors/address.go
index 08d39c9..062c3ae 100644
--- a/actors/address.go
+++ b/actors/address.go
@@ -1,23 +1,165 @@
 package actors
 
 import (
-	"fmt"
-	"strings"
-)
+	"bytes"
+	"net/url"
+	"strconv"
 
-// Address is the actor address in the actor system
-type Address string
+	"github.com/pkg/errors"
+)
 
 const (
 	protocol = "goakt"
 )
 
-// GetAddress returns a unique address for a given actor in a given actor system.
-// kind represents the type of actor and id represents an entity of that type of actor
-// example: kind=User, id=john therefore the address is goakt://sys@hostA:9000/user/john
-func GetAddress(system ActorSystem, kind, id string) Address {
-	// construct the given address string value
-	addr := fmt.Sprintf("%s://%s@%s/%s/%s", protocol, system.Name(), system.NodeAddr(), strings.ToLower(kind), id)
-	// return the newly created address
-	return Address(addr)
+// Address represents the physical location under which an Actor can be
+// reached. Examples are local addresses, identified by the ActorSystem’s name,
+// and remote addresses, identified by protocol, host and port.
+type Address struct {
+	// host is the host address
+	host string
+	// port is the port number
+	port int
+	// system is the actor system name
+	system string
+	// protocol is the protocol
+	protocol string
+}
+
+// NewAddress creates an instance of Address
+func NewAddress(protocol string, system string, host string, port int) *Address {
+	return &Address{
+		host:     host,
+		port:     port,
+		system:   system,
+		protocol: protocol,
+	}
+}
+
+// WithHost sets the hosts of a given Address and returns a new instance of the address
+func (a *Address) WithHost(host string) *Address {
+	return NewAddress(a.Protocol(), a.System(), host, a.Port())
+}
+
+// WithPort sets the port of a given Address and returns a new instance of the address
+func (a *Address) WithPort(port int) *Address {
+	return NewAddress(a.Protocol(), a.System(), a.System(), port)
+}
+
+// WithSystem sets the actor system of a given Address and returns a new instance of the address
+func (a *Address) WithSystem(system string) *Address {
+	return NewAddress(a.Protocol(), system, a.Host(), a.Port())
+}
+
+// WithProtocol sets the protocol of a given Address and returns a new instance of the address
+func (a *Address) WithProtocol(protocol string) *Address {
+	return NewAddress(protocol, a.System(), a.Host(), a.Port())
+}
+
+// Host returns the host
+func (a *Address) Host() string {
+	return a.host
+}
+
+// Port returns the port number
+func (a *Address) Port() int {
+	return a.port
+}
+
+// System returns the actor system name
+func (a *Address) System() string {
+	return a.system
+}
+
+// Protocol returns the protocol
+func (a *Address) Protocol() string {
+	return a.protocol
+}
+
+// IsRemote true if this Address is usable globally.
+// Unlike locally defined addresses of global scope are safe to sent to other hosts, as they globally and uniquely identify an addressable entity.
+func (a *Address) IsRemote() bool {
+	return len(a.host) > 0
+}
+
+// IsLocal returns true if this Address is only defined locally.
+// It is not safe to send locally scoped addresses to remote
+func (a *Address) IsLocal() bool {
+	return len(a.host) == 0
+}
+
+// HostPort returns the host and port in the following string format
+// @host:port
+func (a *Address) HostPort() string {
+	// create a bytes buffer instance
+	buf := bytes.NewBuffer(nil)
+	// write the host value when it is set
+	if len(a.host) > 0 {
+		buf.WriteByte('@')
+		buf.WriteString(a.host)
+	}
+
+	// write the port when the port is set
+	if a.port > 0 {
+		buf.WriteByte(':')
+		buf.WriteString(strconv.Itoa(a.port))
+	}
+
+	// return the constructed string
+	return buf.String()
+}
+
+// String returns the canonical String representation of this Address formatted as:
+// `protocol://system@host:port`
+func (a *Address) String() string {
+	// if the protocol is not goakt
+	// then panic
+	if a.protocol != protocol {
+		panic("invalid protocol")
+	}
+	// create a bytes buffer instance
+	buf := bytes.NewBuffer(nil)
+	// write the protocol field to bytes buffer
+	buf.WriteString(a.protocol)
+	buf.WriteString("://")
+	buf.WriteString(a.system)
+
+	// write the host to the bytes buffer when it is defined
+	if len(a.host) > 0 {
+		buf.WriteByte('@')
+		buf.WriteString(a.host)
+	}
+
+	// write the port to the bytes buffer when it is set
+	if a.port > 0 {
+		buf.WriteByte(':')
+		buf.WriteString(strconv.Itoa(a.port))
+	}
+
+	// returns the constructed string value
+	return buf.String()
+}
+
+// Parse parses a new Address from a given string
+func (a *Address) Parse(address string) *Address {
+	// let us parse the address and panic in case of error
+	uri, err := url.Parse(address)
+	// panic when there is an error
+	if err != nil {
+		panic(errors.Wrapf(err, "failed to parse the address [%s]", address))
+	}
+
+	// check whether the user info is empty or not
+	// parse the port
+	port, err := strconv.Atoi(uri.Port())
+	// handle the error
+	if err != nil {
+		panic(errors.Wrapf(err, "failed to parse the address [%s]", address))
+	}
+
+	if uri.User == nil {
+		return NewAddress(uri.Scheme, uri.Hostname(), "", port)
+	}
+
+	return NewAddress(uri.Scheme, uri.User.String(), uri.Hostname(), port)
 }
diff --git a/actors/config.go b/actors/config.go
index e51cd19..24723b2 100644
--- a/actors/config.go
+++ b/actors/config.go
@@ -3,6 +3,7 @@ package actors
 import (
 	"errors"
 	"net"
+	"regexp"
 	"strconv"
 	"time"
 
@@ -50,6 +51,10 @@ func NewConfig(name, nodeHostAndPort string, options ...Option) (*Config, error)
 	if name == "" {
 		return nil, ErrNameRequired
 	}
+	if match, _ := regexp.MatchString("^[a-zA-Z0-9][a-zA-Z0-9-_]*$", name); !match {
+		return nil, ErrInvalidActorSystemName
+	}
+
 	// check whether the node host and port is set and valid
 	if err := validateHostAndPort(nodeHostAndPort); err != nil {
 		return nil, err
diff --git a/actors/errors.go b/actors/errors.go
index 4a4894a..e3c8315 100644
--- a/actors/errors.go
+++ b/actors/errors.go
@@ -8,6 +8,7 @@ import (
 )
 
 var (
+	ErrInvalidActorSystemName       = errors.New("invalid ActorSystem name, must contain only word characters (i.e. [a-zA-Z0-9] plus non-leading '-' or '_')")
 	ErrNotReady                     = errors.New("actor is not ready")
 	ErrUnhandled                    = errors.New("unhandled message")
 	ErrMissingConfig                = errors.New("config is missing")
diff --git a/actors/passivation.go b/actors/passivation.go
index 4cc1b4b..97e8f21 100644
--- a/actors/passivation.go
+++ b/actors/passivation.go
@@ -41,12 +41,12 @@ func (p *pid) passivationListener() {
 	// only passivate when actor is alive
 	if !p.IsOnline() {
 		// add some logging info
-		p.logger.Infof("Actor=%s is offline. No need to passivate", p.addr)
+		p.logger.Infof("Actor=%s is offline. No need to passivate", p.ActorPath().String())
 		return
 	}
 
 	// add some logging info
-	p.logger.Infof("Passivation mode has been triggered for actor=%s...", p.addr)
+	p.logger.Infof("Passivation mode has been triggered for actor=%s...", p.ActorPath().String())
 	// passivate the actor
 	p.passivate()
 }
diff --git a/actors/path.go b/actors/path.go
new file mode 100644
index 0000000..47636cd
--- /dev/null
+++ b/actors/path.go
@@ -0,0 +1,62 @@
+package actors
+
+import (
+	"fmt"
+
+	"github.com/google/uuid"
+)
+
+// Path is a unique path to an actor
+type Path struct {
+	// specifies the Address under which this path can be reached
+	address *Address
+	// specifies the name of the actor that this path refers to.
+	name string
+	// specifies the internal unique id of the actor that this path refer to.
+	id uuid.UUID
+	// specifies the path for the parent actor.
+	parent *Path
+}
+
+// NewPath creates an immutable Path
+func NewPath(name string, address *Address) *Path {
+	// create the instance and return it
+	return &Path{
+		address: address,
+		name:    name,
+		id:      uuid.New(),
+	}
+}
+
+// Parent returns the parent path
+func (a *Path) Parent() *Path {
+	return a.parent
+}
+
+// WithParent sets the parent actor path and returns a new path
+// This function is immutable
+func (a *Path) WithParent(parent *Path) *Path {
+	newPath := NewPath(a.name, a.address)
+	newPath.parent = parent
+	return newPath
+}
+
+// Address return the actor path address
+func (a *Path) Address() *Address {
+	return a.address
+}
+
+// Name returns the name of the actor that this path refers to.
+func (a *Path) Name() string {
+	return a.name
+}
+
+// ID returns the internal unique id of the actor that this path refer to.
+func (a *Path) ID() uuid.UUID {
+	return a.id
+}
+
+// String returns the string representation of an actorPath
+func (a *Path) String() string {
+	return fmt.Sprintf("%s/%s", a.address.String(), a.name)
+}
diff --git a/actors/pid.go b/actors/pid.go
index 20f7701..8dc4b72 100644
--- a/actors/pid.go
+++ b/actors/pid.go
@@ -42,7 +42,7 @@ type PID interface {
 	// at a given point in time while the actor heart is still beating
 	ErrorsCount(ctx context.Context) uint64
 	// SpawnChild creates a child actor
-	SpawnChild(ctx context.Context, kind, id string, actor Actor) (PID, error)
+	SpawnChild(ctx context.Context, name string, actor Actor) (PID, error)
 	// Restart restarts the actor
 	Restart(ctx context.Context) error
 	// Watch an actor
@@ -51,10 +51,8 @@ type PID interface {
 	UnWatch(pid PID)
 	// ActorSystem returns the underlying actor system
 	ActorSystem() ActorSystem
-	// Address returns the address of the actor
-	Address() Address
-	// LocalID returns the actor unique identifier
-	LocalID() *LocalID
+	// ActorPath returns the path of the actor
+	ActorPath() *Path
 	// SendAsync sends an asynchronous message to another PID
 	SendAsync(ctx context.Context, to PID, message proto.Message) error
 	// SendSync sends a synchronous message to another actor and expect a response.
@@ -91,11 +89,8 @@ type PID interface {
 type pid struct {
 	Actor
 
-	// addr represents the actor unique address
-	addr Address
-
-	// actor unique identifier
-	id *LocalID
+	// specifies the actor path
+	actorPath *Path
 
 	// helps determine whether the actor should handle messages or not.
 	isOnline bool
@@ -162,7 +157,7 @@ type pid struct {
 var _ PID = (*pid)(nil)
 
 // newPID creates a new pid
-func newPID(ctx context.Context, actor Actor, opts ...pidOption) *pid {
+func newPID(ctx context.Context, actorPath *Path, actor Actor, opts ...pidOption) *pid {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "NewPID")
 	defer span.End()
@@ -170,7 +165,6 @@ func newPID(ctx context.Context, actor Actor, opts ...pidOption) *pid {
 	// create the actor PID
 	pid := &pid{
 		Actor:                  actor,
-		addr:                   "",
 		isOnline:               false,
 		lastProcessingTime:     atomic.Time{},
 		passivateAfter:         2 * time.Minute,
@@ -191,18 +185,14 @@ func newPID(ctx context.Context, actor Actor, opts ...pidOption) *pid {
 		supervisorStrategy:     pb.StrategyDirective_STOP_DIRECTIVE,
 		watchMen:               tools.NewConcurrentSlice[*watchMan](),
 		telemetry:              telemetry.New(),
+		actorPath:              actorPath,
 	}
+
 	// set the custom options to override the default values
 	for _, opt := range opts {
 		opt(pid)
 	}
 
-	// let us set the addr when the actor system and kind are set
-	if pid.system != nil && pid.LocalID().Kind() != "" {
-		// create the address of the given actor and set it
-		pid.addr = GetAddress(pid.system, pid.LocalID().Kind(), pid.LocalID().ID())
-	}
-
 	// initialize the actor and init processing messages
 	pid.init(ctx)
 	// init processing messages
@@ -221,7 +211,7 @@ func newPID(ctx context.Context, actor Actor, opts ...pidOption) *pid {
 	// we just log it for now
 	// TODO decide what to do when we fail to register the metrics or export the metrics registration as public
 	if err := pid.registerMetrics(); err != nil {
-		pid.logger.Error(errors.Wrapf(err, "failed to register actor=%s metrics", pid.Address()))
+		pid.logger.Error(errors.Wrapf(err, "failed to register actor=%s metrics", pid.ActorPath().String()))
 	}
 
 	// return the actor reference
@@ -239,16 +229,6 @@ func (p *pid) Children(ctx context.Context) []PID {
 	return kiddos
 }
 
-// LocalID returns the unique actor identifier
-func (p *pid) LocalID() *LocalID {
-	p.mu.Lock()
-	defer p.mu.Unlock()
-	if p.id == nil {
-		return &LocalID{}
-	}
-	return p.id
-}
-
 // IsOnline returns true when the actor is alive ready to process messages and false
 // when the actor is stopped or not started at all
 func (p *pid) IsOnline() bool {
@@ -266,12 +246,12 @@ func (p *pid) ActorSystem() ActorSystem {
 	return sys
 }
 
-// Address return the address of the actor
-func (p *pid) Address() Address {
+// Path return the path of the actor
+func (p *pid) ActorPath() *Path {
 	p.mu.Lock()
-	address := p.addr
+	path := p.actorPath
 	p.mu.Unlock()
-	return address
+	return path
 }
 
 // Restart restarts the actor. This call can panic which is the expected behaviour.
@@ -281,7 +261,7 @@ func (p *pid) Restart(ctx context.Context) error {
 	ctx, span := telemetry.SpanContext(ctx, "Restart")
 	defer span.End()
 	// first check whether we have an empty PID
-	if p == nil || p.addr == "" {
+	if p == nil || p.actorPath == nil {
 		return ErrUndefinedActor
 	}
 	// check whether the actor is ready and stop it
@@ -324,7 +304,7 @@ func (p *pid) Restart(ctx context.Context) error {
 }
 
 // SpawnChild creates a child actor and start watching it for error
-func (p *pid) SpawnChild(ctx context.Context, kind, id string, actor Actor) (PID, error) {
+func (p *pid) SpawnChild(ctx context.Context, name string, actor Actor) (PID, error) {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "SpawnChild")
 	defer span.End()
@@ -333,10 +313,11 @@ func (p *pid) SpawnChild(ctx context.Context, kind, id string, actor Actor) (PID
 		return nil, ErrNotReady
 	}
 
-	// create the address of the given actor
-	addr := GetAddress(p.ActorSystem(), kind, id)
+	// create the child actor path
+	childActorPath := NewPath(name, p.ActorPath().Address()).WithParent(p.ActorPath())
+
 	// check whether the child actor already exist and just return the PID
-	if cid, ok := p.children.Get(addr); ok {
+	if cid, ok := p.children.Get(name); ok {
 		// check whether the actor is stopped
 		if !cid.IsOnline() {
 			// then reboot it
@@ -348,16 +329,16 @@ func (p *pid) SpawnChild(ctx context.Context, kind, id string, actor Actor) (PID
 	}
 
 	// create the child pid
-	cid := newPID(ctx, actor,
+	cid := newPID(ctx,
+		childActorPath,
+		actor,
 		withInitMaxRetries(p.initMaxRetries),
 		withPassivationAfter(p.passivateAfter),
 		withSendReplyTimeout(p.sendReplyTimeout),
 		withCustomLogger(p.logger),
 		withActorSystem(p.system),
-		withLocalID(kind, id),
 		withSupervisorStrategy(p.supervisorStrategy),
-		withShutdownTimeout(p.shutdownTimeout),
-		withAddress(addr))
+		withShutdownTimeout(p.shutdownTimeout))
 
 	// add the pid to the map
 	p.children.Set(cid)
@@ -535,11 +516,11 @@ func (p *pid) RemoteSendSync(ctx context.Context, to *pb.Address, message proto.
 
 	// construct the from address
 	from := &pb.Address{
-		ActorSystem: p.ActorSystem().Name(),
-		Host:        p.ActorSystem().Host(),
-		Port:        int32(p.ActorSystem().Port()),
-		Kind:        p.LocalID().Kind(),
-		Id:          p.LocalID().ID(),
+		ActorSystem: p.ActorPath().Address().System(),
+		Host:        p.ActorPath().Address().Host(),
+		Port:        int32(p.ActorPath().Address().Port()),
+		Name:        p.ActorPath().Name(),
+		Id:          p.ActorPath().ID().String(),
 	}
 
 	// create an instance of remote client service
@@ -575,7 +556,7 @@ func (p *pid) Shutdown(ctx context.Context) error {
 
 	// check whether the actor is still alive. Maybe it has been passivated already
 	if !p.IsOnline() {
-		p.logger.Infof("Actor=%s is offline. Maybe it has been passivated or stopped already", p.Address())
+		p.logger.Infof("Actor=%s is offline. Maybe it has been passivated or stopped already", p.ActorPath().String())
 		return nil
 	}
 
@@ -583,23 +564,18 @@ func (p *pid) Shutdown(ctx context.Context) error {
 	p.stop(ctx)
 
 	// add some logging
-	p.logger.Info("Shutdown process is on going for actor=%s...", p.Address())
+	p.logger.Info("Shutdown process is on going for actor=%s...", p.ActorPath().String())
 	// signal we are shutting down to stop processing messages
 	p.shutdownSignal <- Unit{}
 	// perform some cleanup with the actor
 	if err := p.Actor.PostStop(ctx); err != nil {
-		p.logger.Error(fmt.Errorf("failed to stop the underlying receiver for actor=%s. Cause:%v", p.addr, err))
+		p.logger.Error(fmt.Errorf("failed to stop the underlying receiver for actor=%s. Cause:%v", p.ActorPath().String(), err))
 		return err
 	}
-	p.logger.Infof("Actor=%s successfully shutdown", p.Address())
+	p.logger.Infof("Actor=%s successfully shutdown", p.ActorPath().String())
 	return nil
 }
 
-// Watchers return the list of watchMen
-func (p *pid) watchers() *tools.ConcurrentSlice[*watchMan] {
-	return p.watchMen
-}
-
 // Watch a pid for errors, and send on the returned channel if an error occurred
 func (p *pid) Watch(pid PID) {
 	// create a watcher
@@ -621,7 +597,7 @@ func (p *pid) UnWatch(pid PID) {
 		// grab the item value
 		w := item.Value
 		// locate the given watcher
-		if w.Parent.Address() == p.Address() {
+		if w.Parent.ActorPath() == p.ActorPath() {
 			// stop the watching go routine
 			w.Done <- Unit{}
 			// remove the watcher from the list
@@ -631,6 +607,11 @@ func (p *pid) UnWatch(pid PID) {
 	}
 }
 
+// Watchers return the list of watchMen
+func (p *pid) watchers() *tools.ConcurrentSlice[*watchMan] {
+	return p.watchMen
+}
+
 // doReceive pushes a given message to the actor mailbox
 func (p *pid) doReceive(ctx ReceiveContext) {
 	// acquire the lock and release it once done
@@ -704,7 +685,7 @@ func (p *pid) reset() {
 	// we just log it for now
 	// TODO decide what to do when we fail to register the metrics or export the metrics registration as public
 	if err := p.registerMetrics(); err != nil {
-		p.logger.Error(errors.Wrapf(err, "failed to register actor=%s metrics", p.Address()))
+		p.logger.Error(errors.Wrapf(err, "failed to register actor=%s metrics", p.ActorPath().String()))
 	}
 }
 
@@ -727,7 +708,7 @@ func (p *pid) freeChildren(ctx context.Context) {
 		}
 		// unwatch the child
 		p.UnWatch(child)
-		p.children.Delete(child.Address())
+		p.children.Delete(child.ActorPath())
 	}
 }
 
@@ -771,7 +752,7 @@ func (p *pid) stop(ctx context.Context) {
 	// signal we are shutting down to stop processing messages
 	p.shutdownSignal <- Unit{}
 	// add some logging
-	p.logger.Infof("Remaining messages in the mailbox have been processed for actor=%s", p.Address())
+	p.logger.Infof("Remaining messages in the mailbox have been processed for actor=%s", p.ActorPath().String())
 	// stop the ticker
 	ticker.Stop()
 }
@@ -879,7 +860,7 @@ func (p *pid) supervise(cid PID, watcher *watchMan) {
 		case <-watcher.Done:
 			return
 		case err := <-watcher.ErrChan:
-			p.logger.Errorf("child actor=%s is panicking: Err=%v", cid.Address(), err)
+			p.logger.Errorf("child actor=%s is panicking: Err=%v", cid.ActorPath().String(), err)
 			switch p.supervisorStrategy {
 			case pb.StrategyDirective_STOP_DIRECTIVE:
 				// shutdown the actor and panic in case of error
@@ -889,7 +870,7 @@ func (p *pid) supervise(cid PID, watcher *watchMan) {
 				// unwatch the given actor
 				p.UnWatch(cid)
 				// remove the actor from the children map
-				p.children.Delete(cid.Address())
+				p.children.Delete(cid.ActorPath())
 			case pb.StrategyDirective_RESTART_DIRECTIVE:
 				// restart the actor
 				if err := cid.Restart(context.Background()); err != nil {
@@ -903,7 +884,7 @@ func (p *pid) supervise(cid PID, watcher *watchMan) {
 				// unwatch the given actor
 				p.UnWatch(cid)
 				// remove the actor from the children map
-				p.children.Delete(cid.Address())
+				p.children.Delete(cid.ActorPath())
 			}
 		}
 	}
diff --git a/actors/pid_option.go b/actors/pid_option.go
index 9fa0db8..1fc78fe 100644
--- a/actors/pid_option.go
+++ b/actors/pid_option.go
@@ -40,13 +40,6 @@ func withCustomLogger(logger log.Logger) pidOption {
 	}
 }
 
-// withAddress sets the address of the pid
-func withAddress(addr Address) pidOption {
-	return func(pid *pid) {
-		pid.addr = addr
-	}
-}
-
 // withActorSystem set the actor system of the pid
 func withActorSystem(sys ActorSystem) pidOption {
 	return func(pid *pid) {
@@ -54,16 +47,6 @@ func withActorSystem(sys ActorSystem) pidOption {
 	}
 }
 
-// withLocalID set the kind of actor represented by the pid
-func withLocalID(kind, id string) pidOption {
-	return func(pid *pid) {
-		pid.id = &LocalID{
-			kind: kind,
-			id:   id,
-		}
-	}
-}
-
 // withSupervisorStrategy sets the supervisor strategy to used when dealing
 // with child actors
 func withSupervisorStrategy(strategy pb.StrategyDirective) pidOption {
diff --git a/actors/types.go b/actors/types.go
index 9eb9a46..284ce24 100644
--- a/actors/types.go
+++ b/actors/types.go
@@ -6,13 +6,13 @@ type Unit struct{}
 
 type pidMap struct {
 	mu   sync.Mutex
-	pids map[Address]PID
+	pids map[string]PID
 }
 
 func newPIDMap(cap int) *pidMap {
 	return &pidMap{
 		mu:   sync.Mutex{},
-		pids: make(map[Address]PID, cap),
+		pids: make(map[string]PID, cap),
 	}
 }
 
@@ -22,25 +22,25 @@ func (m *pidMap) Len() int {
 }
 
 // Get retrieves a pid by its address
-func (m *pidMap) Get(addr Address) (pid PID, ok bool) {
+func (m *pidMap) Get(path string) (pid PID, ok bool) {
 	m.mu.Lock()
 	defer m.mu.Unlock()
-	pid, ok = m.pids[addr]
+	pid, ok = m.pids[path]
 	return
 }
 
 // Set sets a pid in the map
 func (m *pidMap) Set(child PID) {
 	m.mu.Lock()
-	m.pids[child.Address()] = child
+	m.pids[child.ActorPath().String()] = child
 	m.mu.Unlock()
 }
 
 // Delete removes a pid from the map
-func (m *pidMap) Delete(addr Address) {
+func (m *pidMap) Delete(addr *Path) {
 	m.mu.Lock()
 	defer m.mu.Unlock()
-	delete(m.pids, addr)
+	delete(m.pids, addr.String())
 }
 
 // List returns all actors as a slice
diff --git a/examples/actor-event-sourced/main.go b/examples/actor-event-sourced/main.go
index 021cc61..2178e6d 100644
--- a/examples/actor-event-sourced/main.go
+++ b/examples/actor-event-sourced/main.go
@@ -48,7 +48,7 @@ func main() {
 	// create the persistence actor using the behavior previously created
 	persistentActor := eventsourcing.NewEventSourcedActor[*samplepb.Account](behavior, eventStore)
 	// spawn the actor
-	pid := actorSystem.StartActor(ctx, behavior.Kind(), behavior.ID(), persistentActor)
+	pid := actorSystem.StartActor(ctx, behavior.Kind(), persistentActor)
 
 	// send some commands to the pid
 	var command proto.Message
diff --git a/examples/actor-receive/main.go b/examples/actor-receive/main.go
index e5650c0..59c364a 100644
--- a/examples/actor-receive/main.go
+++ b/examples/actor-receive/main.go
@@ -32,7 +32,7 @@ func main() {
 	_ = actorSystem.Start(ctx)
 
 	// create an actor
-	actor := actorSystem.StartActor(ctx, "Pinger", "123", NewPinger())
+	actor := actorSystem.StartActor(ctx, "Ping", NewPinger())
 
 	startTime := time.Now()
 
@@ -48,7 +48,7 @@ func main() {
 	<-interruptSignal
 
 	// log some stats
-	logger.Infof("Actor=%s has processed %d messages in %s", actor.Address(), actor.ReceivedCount(ctx), time.Since(startTime))
+	logger.Infof("Actor=%s has processed %d messages in %s", actor.ActorPath().String(), actor.ReceivedCount(ctx), time.Since(startTime))
 
 	// stop the actor system
 	_ = actorSystem.Stop(ctx)
diff --git a/examples/actor-to-actor/main.go b/examples/actor-to-actor/main.go
index 705e05b..c190040 100644
--- a/examples/actor-to-actor/main.go
+++ b/examples/actor-to-actor/main.go
@@ -34,16 +34,16 @@ func main() {
 	_ = actorSystem.Start(ctx)
 
 	// create an actor
-	pingActor := actorSystem.StartActor(ctx, "Pinger", "pinger-1", NewPingActor())
-	pongActor := actorSystem.StartActor(ctx, "Ponger", "ponger-1", NewPongActor())
+	pingActor := actorSystem.StartActor(ctx, "Ping", NewPingActor())
+	pongActor := actorSystem.StartActor(ctx, "Pong", NewPongActor())
 
 	// start the conversation
 	_ = pingActor.SendAsync(ctx, pongActor, new(samplepb.Ping))
 
 	// shutdown both actors after 3 seconds of conversation
 	timer := time.AfterFunc(3*time.Second, func() {
-		log.DefaultLogger.Infof("PingActor=%s has processed %d messages", pingActor.Address(), pingActor.ReceivedCount(ctx))
-		log.DefaultLogger.Infof("PongActor=%s has processed %d messages", pongActor.Address(), pongActor.ReceivedCount(ctx))
+		log.DefaultLogger.Infof("PingActor=%s has processed %d messages", pingActor.ActorPath().String(), pingActor.ReceivedCount(ctx))
+		log.DefaultLogger.Infof("PongActor=%s has processed %d messages", pongActor.ActorPath().String(), pongActor.ReceivedCount(ctx))
 		_ = pingActor.Shutdown(ctx)
 		_ = pongActor.Shutdown(ctx)
 	})
@@ -86,7 +86,7 @@ func (p *PingActor) PreStart(ctx context.Context) error {
 func (p *PingActor) Receive(ctx goakt.ReceiveContext) {
 	switch ctx.Message().(type) {
 	case *samplepb.Pong:
-		p.logger.Infof(fmt.Sprintf("received Pong from %s", ctx.Sender().Address()))
+		p.logger.Infof(fmt.Sprintf("received Pong from %s", ctx.Sender().ActorPath().String()))
 		// reply the sender in case there is a sender
 		if ctx.Sender() != goakt.NoSender {
 			// let us reply to the sender
@@ -131,7 +131,7 @@ func (p *PongActor) PreStart(ctx context.Context) error {
 func (p *PongActor) Receive(ctx goakt.ReceiveContext) {
 	switch ctx.Message().(type) {
 	case *samplepb.Ping:
-		p.logger.Infof(fmt.Sprintf("received Ping from %s", ctx.Sender().Address()))
+		p.logger.Infof(fmt.Sprintf("received Ping from %s", ctx.Sender().ActorPath().String()))
 		// reply the sender in case there is a sender
 		if ctx.Sender() != nil && ctx.Sender() != goakt.NoSender {
 			_ = ctx.Self().SendAsync(ctx.Context(), ctx.Sender(), new(samplepb.Pong))
diff --git a/pb/goakt/v1/remoting.pb.go b/pb/goakt/v1/remoting.pb.go
index aa9e6d2..44c5b4a 100644
--- a/pb/goakt/v1/remoting.pb.go
+++ b/pb/goakt/v1/remoting.pb.go
@@ -248,8 +248,8 @@ type Address struct {
 	Host string `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"`
 	// Specifies the remote port
 	Port int32 `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"`
-	// Specifies the actor kind(a.k.a actor type)
-	Kind string `protobuf:"bytes,4,opt,name=kind,proto3" json:"kind,omitempty"`
+	// Specifies the actor name
+	Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"`
 	// Specifies the actor unique id on the remote host
 	Id string `protobuf:"bytes,5,opt,name=id,proto3" json:"id,omitempty"`
 }
@@ -307,9 +307,9 @@ func (x *Address) GetPort() int32 {
 	return 0
 }
 
-func (x *Address) GetKind() string {
+func (x *Address) GetName() string {
 	if x != nil {
-		return x.Kind
+		return x.Name
 	}
 	return ""
 }
@@ -444,8 +444,8 @@ var file_goakt_v1_remoting_proto_rawDesc = []byte{
 	0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04,
 	0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74,
 	0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04,
-	0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05,
+	0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05,
 	0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x42, 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f,
 	0x74, 0x65, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
 	0x2b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
diff --git a/protos/internal/goakt/v1/remoting.proto b/protos/internal/goakt/v1/remoting.proto
index c6ae17e..5075ff5 100644
--- a/protos/internal/goakt/v1/remoting.proto
+++ b/protos/internal/goakt/v1/remoting.proto
@@ -50,8 +50,8 @@ message Address {
   string host = 2;
   // Specifies the remote port
   int32 port = 3;
-  // Specifies the actor kind(a.k.a actor type)
-  string kind = 4;
+  // Specifies the actor name
+  string name = 4;
   // Specifies the actor unique id on the remote host
   string id = 5;
 }
diff --git a/readme.md b/readme.md
index faf727d..e05ed8c 100644
--- a/readme.md
+++ b/readme.md
@@ -47,100 +47,100 @@ go get github.com/Tochemey/goakt
 package main
 
 import (
-	"context"
-	"os"
-	"os/signal"
-	"sync"
-	"syscall"
-	"time"
-
-	samplepb "github.com/tochemey/goakt/_examples/protos/pb/v1"
-	goakt "github.com/tochemey/goakt/actors"
-	"github.com/tochemey/goakt/log"
-	"go.uber.org/atomic"
+  "context"
+  "os"
+  "os/signal"
+  "sync"
+  "syscall"
+  "time"
+
+  goakt "github.com/tochemey/goakt/actors"
+  samplepb "github.com/tochemey/goakt/examples/protos/pb/v1"
+  "github.com/tochemey/goakt/log"
+  "go.uber.org/atomic"
 )
 
 func main() {
-	ctx := context.Background()
+  ctx := context.Background()
 
-	// use the goakt default logger. real-life implement the logger interface`
-	logger := log.DefaultLogger
+  // use the goakt default logger. real-life implement the logger interface`
+  logger := log.DefaultLogger
+  // create the actor system configuration. kindly in real-life application handle the error
+  config, _ := goakt.NewConfig("SampleActorSystem", "127.0.0.1:0",
+    goakt.WithExpireActorAfter(10*time.Second),
+    goakt.WithLogger(logger),
+    goakt.WithActorInitMaxRetries(3))
 
-	// create the actor system configuration. kindly in real-life application handle the error
-	config, _ := goakt.NewConfig("SampleActorSystem", "127.0.0.1:0",
-		goakt.WithExpireActorAfter(10*time.Second),
-		goakt.WithLogger(logger),
-		goakt.WithActorInitMaxRetries(3))
+  // create the actor system. kindly in real-life application handle the error
+  actorSystem, _ := goakt.NewActorSystem(config)
 
-	// create the actor system. kindly in real-life application handle the error
-	actorSystem, _ := goakt.NewActorSystem(config)
+  // start the actor system
+  _ = actorSystem.Start(ctx)
 
-	// start the actor system
-	_ = actorSystem.Start(ctx)
+  // create an actor
+  actor := actorSystem.StartActor(ctx, "Ping", NewPinger())
 
-	// create an actor
-	actor := actorSystem.StartActor(ctx, "Pinger", "123", NewPinger())
+  startTime := time.Now()
 
-	startTime := time.Now()
+  // send some messages to the actor
+  count := 100
+  for i := 0; i < count; i++ {
+    _ = goakt.SendAsync(ctx, actor, new(samplepb.Ping))
+  }
 
-	// send some messages to the actor
-	count := 1_000_000
-	for i := 0; i < count; i++ {
-		_ = goakt.SendAsync(ctx, actor, new(samplepb.Ping))
-	}
+  // capture ctrl+c
+  interruptSignal := make(chan os.Signal, 1)
+  signal.Notify(interruptSignal, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
+  <-interruptSignal
 
-	// capture ctrl+c
-	interruptSignal := make(chan os.Signal, 1)
-	signal.Notify(interruptSignal, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
-	<-interruptSignal
+  // log some stats
+  logger.Infof("Actor=%s has processed %d messages in %s", actor.ActorPath().String(), actor.ReceivedCount(ctx), time.Since(startTime))
 
-	// log some stats
-	log.DefaultLogger.Infof("Actor=%s has processed %d messages in %s", actor.Address(), actor.TotalProcessed(ctx), time.Since(startTime))
-
-	// stop the actor system
-	_ = actorSystem.Stop(ctx)
-	os.Exit(0)
+  // stop the actor system
+  _ = actorSystem.Stop(ctx)
+  os.Exit(0)
 }
 
 type Pinger struct {
-	mu     sync.Mutex
-	count  *atomic.Int32
-	logger log.Logger
+  mu     sync.Mutex
+  count  *atomic.Int32
+  logger log.Logger
 }
 
 var _ goakt.Actor = (*Pinger)(nil)
 
 func NewPinger() *Pinger {
-	return &Pinger{
-		mu: sync.Mutex{},
-	}
+  return &Pinger{
+    mu: sync.Mutex{},
+  }
 }
 
 func (p *Pinger) PreStart(ctx context.Context) error {
-	// set the logger
-	p.mu.Lock()
-	defer p.mu.Unlock()
-	p.logger = log.DefaultLogger
-	p.count = atomic.NewInt32(0)
-	p.logger.Info("About to Start")
-	return nil
+  // set the logger
+  p.mu.Lock()
+  defer p.mu.Unlock()
+  p.logger = log.DefaultLogger
+  p.count = atomic.NewInt32(0)
+  p.logger.Info("About to Start")
+  return nil
 }
 
 func (p *Pinger) Receive(ctx goakt.ReceiveContext) {
-	switch ctx.Message().(type) {
-	case *samplepb.Ping:
-		p.logger.Info("received Ping")
-		p.count.Add(1)
-	default:
-		p.logger.Panic(goakt.ErrUnhandled)
-	}
+  switch ctx.Message().(type) {
+  case *samplepb.Ping:
+    p.logger.Info("received Ping")
+    p.count.Add(1)
+  default:
+    p.logger.Panic(goakt.ErrUnhandled)
+  }
 }
 
 func (p *Pinger) PostStop(ctx context.Context) error {
-	p.logger.Info("About to stop")
-	p.logger.Infof("Processed=%d messages", p.count.Load())
-	return nil
+  p.logger.Info("About to stop")
+  p.logger.Infof("Processed=%d messages", p.count.Load())
+  return nil
 }
+
 ```
 
 ## Contribution


Test patch:
diff --git a/actors/actor_system_test.go b/actors/actor_system_test.go
index 8d3a6de..bc1dca3 100644
--- a/actors/actor_system_test.go
+++ b/actors/actor_system_test.go
@@ -9,7 +9,7 @@ import (
 	"github.com/tochemey/goakt/log"
 )
 
-func TestNewActorSystem(t *testing.T) {
+func TestActorSystem(t *testing.T) {
 	t.Run("With Defaults", func(t *testing.T) {
 		cfg, err := NewConfig("testSys", "localhost:0", WithLogger(log.DiscardLogger))
 		require.NoError(t, err)
@@ -36,7 +36,7 @@ func TestNewActorSystem(t *testing.T) {
 		cfg, _ := NewConfig("testSys", "localhost:0", WithLogger(log.DiscardLogger))
 		sys, _ := NewActorSystem(cfg)
 		actor := NewTestActor()
-		actorRef := sys.StartActor(ctx, "Test", "test-1", actor)
+		actorRef := sys.StartActor(ctx, "Test", actor)
 		assert.Nil(t, actorRef)
 	})
 	t.Run("With StartActor an actor when started", func(t *testing.T) {
@@ -49,7 +49,7 @@ func TestNewActorSystem(t *testing.T) {
 		assert.NoError(t, err)
 
 		actor := NewTestActor()
-		actorRef := sys.StartActor(ctx, "Test", "test-1", actor)
+		actorRef := sys.StartActor(ctx, "Test", actor)
 		assert.NotNil(t, actorRef)
 
 		assert.NoError(t, sys.Stop(ctx))
@@ -64,10 +64,10 @@ func TestNewActorSystem(t *testing.T) {
 		assert.NoError(t, err)
 
 		actor := NewTestActor()
-		ref1 := sys.StartActor(ctx, "Test", "test-1", actor)
+		ref1 := sys.StartActor(ctx, "Test", actor)
 		assert.NotNil(t, ref1)
 
-		ref2 := sys.StartActor(ctx, "Test", "test-1", actor)
+		ref2 := sys.StartActor(ctx, "Test", actor)
 		assert.NotNil(t, ref2)
 
 		// point to the same memory address
diff --git a/actors/address_test.go b/actors/address_test.go
index d84c990..4dea261 100644
--- a/actors/address_test.go
+++ b/actors/address_test.go
@@ -6,15 +6,52 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func TestGetAddress(t *testing.T) {
-	actorSys := &actorSystem{
-		nodeAddr: "hostA:9000",
-		name:     "TestSystem",
-	}
-	kind := "User"
-	id := "john"
-
-	addr := GetAddress(actorSys, kind, id)
-	expected := "goakt://TestSystem@hostA:9000/user/john"
-	assert.Equal(t, expected, string(addr))
+func TestActorAddress(t *testing.T) {
+	t.Run("testCase1", func(t *testing.T) {
+		address := "goakt://sys@host:1234/abc/def/"
+		expected := "goakt://sys@host:1234"
+		addr := new(Address)
+		actual := addr.Parse(address)
+		assert.Equal(t, expected, actual.String())
+	})
+
+	t.Run("testCase2", func(t *testing.T) {
+		address := "goakt://sys/abc/def"
+		addr := new(Address)
+		assert.Panics(t, func() {
+			addr.Parse(address)
+		})
+	})
+
+	t.Run("testCase3", func(t *testing.T) {
+		address := "goakt://host:1234/abc/def/"
+		expected := "goakt://host:1234"
+		addr := new(Address)
+		actual := addr.Parse(address)
+		assert.Equal(t, expected, actual.String())
+	})
+
+	t.Run("testCase4", func(t *testing.T) {
+		address := "goakt://sys@host:1234"
+		expected := "goakt://sys@host:1234"
+		addr := new(Address)
+		actual := addr.Parse(address)
+		assert.Equal(t, expected, actual.String())
+	})
+
+	t.Run("testCase5", func(t *testing.T) {
+		address := "goakt://sys@host:1234/"
+		expected := "goakt://sys@host:1234"
+		addr := new(Address)
+		actual := addr.Parse(address)
+		assert.Equal(t, expected, actual.String())
+	})
+
+	t.Run("testCase6", func(t *testing.T) {
+		address := "goakt://sys@host/abc/def/"
+		addr := new(Address)
+		assert.Panics(t, func() {
+			addr.Parse(address)
+		})
+	})
 }
diff --git a/actors/pid_option_test.go b/actors/pid_option_test.go
index defc040..22297d9 100644
--- a/actors/pid_option_test.go
+++ b/actors/pid_option_test.go
@@ -35,19 +35,6 @@ func TestPIDOptions(t *testing.T) {
 			option:         withCustomLogger(log.DefaultLogger),
 			expectedConfig: &pid{logger: log.DefaultLogger},
 		},
-		{
-			name:           "WithAddress",
-			option:         withAddress(Address("some-address")),
-			expectedConfig: &pid{addr: Address("some-address")},
-		},
-		{
-			name:   "WithLocalID",
-			option: withLocalID("some-kind", "some-id"),
-			expectedConfig: &pid{id: &LocalID{
-				kind: "some-kind",
-				id:   "some-id",
-			}},
-		},
 		{
 			name:           "WithSupervisorStrategy",
 			option:         withSupervisorStrategy(pb.StrategyDirective_RESTART_DIRECTIVE),
diff --git a/actors/pid_test.go b/actors/pid_test.go
index 5144f97..4d1b6f4 100644
--- a/actors/pid_test.go
+++ b/actors/pid_test.go
@@ -26,14 +26,18 @@ func TestActorReceive(t *testing.T) {
 	defer goleak.VerifyNone(t)
 	ctx := context.TODO()
 
+	// create the actor path
+	actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
+
 	// create the actor ref
 	pid := newPID(
 		ctx,
+		actorPath,
 		NewTestActor(),
 		withInitMaxRetries(1),
 		withCustomLogger(log.DefaultLogger),
-		withSendReplyTimeout(recvTimeout),
-		withLocalID("Test", "test-1"))
+		withSendReplyTimeout(recvTimeout))
+
 	assert.NotNil(t, pid)
 	// let us send 10 messages to the actor
 	count := 10
@@ -63,10 +67,11 @@ func TestActorWithPassivation(t *testing.T) {
 		withInitMaxRetries(1),
 		withPassivationAfter(passivateAfter),
 		withSendReplyTimeout(recvTimeout),
-		withLocalID("Test", "test-1"),
 	}
 
-	pid := newPID(ctx, NewTestActor(), opts...)
+	// create the actor path
+	actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
+	pid := newPID(ctx, actorPath, NewTestActor(), opts...)
 	assert.NotNil(t, pid)
 
 	// let us sleep for some time to make the actor idle
@@ -92,10 +97,11 @@ func TestActorWithReply(t *testing.T) {
 		opts := []pidOption{
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
-			withLocalID("Test", "test-1"),
 		}
 
-		pid := newPID(ctx, NewTestActor(), opts...)
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
+		pid := newPID(ctx, actorPath, NewTestActor(), opts...)
 		assert.NotNil(t, pid)
 
 		actual, err := SendSync(ctx, pid, new(testpb.TestReply), recvTimeout)
@@ -114,10 +120,11 @@ func TestActorWithReply(t *testing.T) {
 		opts := []pidOption{
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
-			withLocalID("Test", "test-1"),
 		}
 
-		pid := newPID(ctx, NewTestActor(), opts...)
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
+		pid := newPID(ctx, actorPath, NewTestActor(), opts...)
 		assert.NotNil(t, pid)
 
 		actual, err := SendSync(ctx, pid, new(testpb.TestSend), recvTimeout)
@@ -138,20 +145,17 @@ func TestActorRestart(t *testing.T) {
 		require.NoError(t, err)
 		assert.NotNil(t, cfg)
 
-		actorSys, err := NewActorSystem(cfg)
-		require.NoError(t, err)
-
 		// create a Ping actor
 		actor := NewTestActor()
 		assert.NotNil(t, actor)
 
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		// create the actor ref
-		pid := newPID(ctx, actor,
+		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withPassivationAfter(10*time.Second),
 			withCustomLogger(log.DiscardLogger),
-			withActorSystem(actorSys),
-			withLocalID("Test", "test-1"),
 			withSendReplyTimeout(recvTimeout))
 		assert.NotNil(t, pid)
 
@@ -181,60 +185,57 @@ func TestActorRestart(t *testing.T) {
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
 	})
-	t.Run("restart with error: case where shutdown is not fully completed", func(t *testing.T) {
-		defer goleak.VerifyNone(t)
-		ctx := context.TODO()
-		// create a Ping actor
-		pid := newPID(
-			ctx,
-			NewTestActor(),
-			withInitMaxRetries(1),
-			withSendReplyTimeout(recvTimeout),
-			withCustomLogger(log.DiscardLogger),
-			withLocalID("Test", "test-1"))
-		assert.NotNil(t, pid)
-
-		// stop the actor
-		err := pid.Shutdown(ctx)
-		assert.NoError(t, err)
-
-		// restarting this actor
-		err = pid.Restart(ctx)
-		assert.EqualError(t, err, ErrUndefinedActor.Error())
-	})
+	//t.Run("restart with error: case where shutdown is not fully completed", func(t *testing.T) {
+	//	defer goleak.VerifyNone(t)
+	//	ctx := context.TODO()
+	//	// create the actor path
+	//	actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
+	//
+	//	// create a Ping actor
+	//	pid := newPID(
+	//		ctx,
+	//		actorPath,
+	//		NewTestActor(),
+	//		withInitMaxRetries(1),
+	//		withSendReplyTimeout(recvTimeout),
+	//		withCustomLogger(log.DiscardLogger))
+	//	assert.NotNil(t, pid)
+	//
+	//	// stop the actor
+	//	err := pid.Shutdown(ctx)
+	//	assert.NoError(t, err)
+	//
+	//	// restarting this actor
+	//	err = pid.Restart(ctx)
+	//	assert.EqualError(t, err, ErrUndefinedActor.Error())
+	//})
 	t.Run("restart an actor", func(t *testing.T) {
 		defer goleak.VerifyNone(t)
 		ctx := context.TODO()
-		cfg, err := NewConfig("testSys", "localhost:0")
-		require.NoError(t, err)
-		assert.NotNil(t, cfg)
-
-		actorSys, err := NewActorSystem(cfg)
-		require.NoError(t, err)
 
 		// create a Ping actor
 		actor := NewTestActor()
 		assert.NotNil(t, actor)
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 
 		// create the actor ref
-		pid := newPID(ctx, actor,
+		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withPassivationAfter(passivateAfter),
 			withCustomLogger(log.DiscardLogger),
-			withActorSystem(actorSys),
-			withLocalID("Test", "test-1"),
 			withSendReplyTimeout(recvTimeout))
 		assert.NotNil(t, pid)
 		// let us send 10 messages to the actor
 		count := 10
 		for i := 0; i < count; i++ {
-			err = SendAsync(ctx, pid, new(testpb.TestSend))
+			err := SendAsync(ctx, pid, new(testpb.TestSend))
 			assert.NoError(t, err)
 		}
 		assert.EqualValues(t, count, pid.ReceivedCount(ctx))
 
 		// restart the actor
-		err = pid.Restart(ctx)
+		err := pid.Restart(ctx)
 		assert.NoError(t, err)
 		assert.True(t, pid.IsOnline())
 		// let us send 10 messages to the actor
@@ -255,26 +256,19 @@ func TestChildActor(t *testing.T) {
 
 		// create a test context
 		ctx := context.TODO()
-		// create a basic actor system
-		cfg, err := NewConfig("testSys", "localhost:0")
-		require.NoError(t, err)
-		assert.NotNil(t, cfg)
-
-		actorSys, err := NewActorSystem(cfg)
-		require.NoError(t, err)
+		// create the actor path
+		actorPath := NewPath("Parent", NewAddress(protocol, "sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx,
+		parent := newPID(ctx, actorPath,
 			NewParentActor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
-			withActorSystem(actorSys),
-			withLocalID("Parent", "papa"),
 			withSendReplyTimeout(recvTimeout))
 		assert.NotNil(t, parent)
 
 		// create the child actor
-		child, err := parent.SpawnChild(ctx, "Child", "johnny", NewChildActor())
+		child, err := parent.SpawnChild(ctx, "Child", NewChildActor())
 		assert.NoError(t, err)
 		assert.NotNil(t, child)
 
@@ -296,27 +290,21 @@ func TestChildActor(t *testing.T) {
 
 		// create a test context
 		ctx := context.TODO()
-		// create a basic actor system
-		cfg, err := NewConfig("testSys", "localhost:0")
-		require.NoError(t, err)
-		assert.NotNil(t, cfg)
-
-		actorSys, err := NewActorSystem(cfg)
-		require.NoError(t, err)
+		// create the actor path
+		actorPath := NewPath("Parent", NewAddress(protocol, "sys", "host", 1))
 
 		// create the parent actor
 		parent := newPID(ctx,
+			actorPath,
 			NewParentActor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withPassivationDisabled(),
-			withActorSystem(actorSys),
-			withLocalID("Parent", "papa"),
 			withSendReplyTimeout(recvTimeout))
 		assert.NotNil(t, parent)
 
 		// create the child actor
-		child, err := parent.SpawnChild(ctx, "Child", "johnny", NewChildActor())
+		child, err := parent.SpawnChild(ctx, "Child", NewChildActor())
 		assert.NoError(t, err)
 		assert.NotNil(t, child)
 
@@ -340,29 +328,23 @@ func TestChildActor(t *testing.T) {
 
 		// create a test context
 		ctx := context.TODO()
-		// create a basic actor system
-		cfg, err := NewConfig("testSys", "localhost:0")
-		require.NoError(t, err)
-		assert.NotNil(t, cfg)
-
-		actorSys, err := NewActorSystem(cfg)
-		require.NoError(t, err)
 
 		logger := log.DiscardLogger
+		// create the actor path
+		actorPath := NewPath("Parent", NewAddress(protocol, "sys", "host", 1))
 		// create the parent actor
 		parent := newPID(ctx,
+			actorPath,
 			NewParentActor(),
 			withInitMaxRetries(1),
 			withCustomLogger(logger),
 			withPassivationDisabled(),
-			withActorSystem(actorSys),
-			withLocalID("Parent", "papa"),
 			withSupervisorStrategy(pb.StrategyDirective_RESTART_DIRECTIVE),
 			withSendReplyTimeout(recvTimeout))
 		assert.NotNil(t, parent)
 
 		// create the child actor
-		child, err := parent.SpawnChild(ctx, "Child", "johnny", NewChildActor())
+		child, err := parent.SpawnChild(ctx, "Child", NewChildActor())
 		assert.NoError(t, err)
 		assert.NotNil(t, child)
 
@@ -389,7 +371,9 @@ func BenchmarkActor(b *testing.B) {
 		actor := &BenchActor{}
 
 		// create the actor ref
-		pid := newPID(ctx, actor,
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
+		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(recvTimeout))
@@ -409,7 +393,9 @@ func BenchmarkActor(b *testing.B) {
 		actor := &BenchActor{}
 
 		// create the actor ref
-		pid := newPID(ctx, actor,
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
+		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(recvTimeout))
@@ -426,7 +412,9 @@ func BenchmarkActor(b *testing.B) {
 		actor := &BenchActor{}
 
 		// create the actor ref
-		pid := newPID(ctx, actor,
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
+		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(recvTimeout))
@@ -451,7 +439,9 @@ func BenchmarkActor(b *testing.B) {
 		actor := &BenchActor{}
 
 		// create the actor ref
-		pid := newPID(ctx, actor,
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
+		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(recvTimeout))
@@ -478,7 +468,9 @@ func BenchmarkActor(b *testing.B) {
 		actor := &BenchActor{}
 
 		// create the actor ref
-		pid := newPID(ctx, actor,
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
+		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withPassivationAfter(5*time.Second),
@@ -498,8 +490,10 @@ func BenchmarkActor(b *testing.B) {
 		ctx := context.TODO()
 		actor := &BenchActor{}
 
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		// create the actor ref
-		pid := newPID(ctx, actor,
+		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withPassivationAfter(5*time.Second),
@@ -515,9 +509,10 @@ func BenchmarkActor(b *testing.B) {
 	b.Run("receive-reply:multiple senders", func(b *testing.B) {
 		ctx := context.TODO()
 		actor := &BenchActor{}
-
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		// create the actor ref
-		pid := newPID(ctx, actor,
+		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withPassivationAfter(5*time.Second),
@@ -541,9 +536,10 @@ func BenchmarkActor(b *testing.B) {
 	b.Run("receive-reply:multiple senders times hundred", func(b *testing.B) {
 		ctx := context.TODO()
 		actor := &BenchActor{}
-
+		// create the actor path
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		// create the actor ref
-		pid := newPID(ctx, actor,
+		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withPassivationAfter(5*time.Second),
diff --git a/modules/eventsourcing/actor_test.go b/modules/eventsourcing/actor_test.go
index c427747..5c9a944 100644
--- a/modules/eventsourcing/actor_test.go
+++ b/modules/eventsourcing/actor_test.go
@@ -53,7 +53,7 @@ func TestEventSourcedActor(t *testing.T) {
 		// create the persistence actor using the behavior previously created
 		persistentActor := NewEventSourcedActor[*testpb.Account](behavior, eventStore)
 		// spawn the actor
-		pid := actorSystem.StartActor(ctx, behavior.Kind(), behavior.ID(), persistentActor)
+		pid := actorSystem.StartActor(ctx, behavior.Kind(), persistentActor)
 		require.NotNil(t, pid)
 
 		var command proto.Message
@@ -144,7 +144,7 @@ func TestEventSourcedActor(t *testing.T) {
 		// create the persistence actor using the behavior previously created
 		persistentActor := NewEventSourcedActor[*testpb.Account](behavior, eventStore)
 		// spawn the actor
-		pid := actorSystem.StartActor(ctx, behavior.Kind(), behavior.ID(), persistentActor)
+		pid := actorSystem.StartActor(ctx, behavior.Kind(), persistentActor)
 		require.NotNil(t, pid)
 
 		var command proto.Message
@@ -224,7 +224,7 @@ func TestEventSourcedActor(t *testing.T) {
 		// create the persistence actor using the behavior previously created
 		persistentActor := NewEventSourcedActor[*testpb.Account](behavior, eventStore)
 		// spawn the actor
-		pid := actorSystem.StartActor(ctx, behavior.Kind(), behavior.ID(), persistentActor)
+		pid := actorSystem.StartActor(ctx, behavior.Kind(), persistentActor)
 		require.NotNil(t, pid)
 
 		command := &testpb.TestSend{}
@@ -296,7 +296,7 @@ func TestEventSourcedActor(t *testing.T) {
 		// create the persistence actor using the behavior previously created
 		persistentActor := NewEventSourcedActor[*testpb.Account](behavior, eventStore)
 		// spawn the actor
-		pid := actorSystem.StartActor(ctx, behavior.Kind(), behavior.ID(), persistentActor)
+		pid := actorSystem.StartActor(ctx, behavior.Kind(), persistentActor)
 		require.NotNil(t, pid)
 
 		var command proto.Message
@@ -353,12 +353,12 @@ func TestEventSourcedActor(t *testing.T) {
 		assert.True(t, proto.Equal(expected, resultingState))
 
 		// shutdown the persistent actor
-		assert.NoError(t, actorSystem.StopActor(ctx, behavior.Kind(), behavior.ID()))
+		assert.NoError(t, actorSystem.StopActor(ctx, behavior.Kind()))
 		// wait a while
 		time.Sleep(time.Second)
 
 		// restart the actor
-		pid, err = actorSystem.RestartActor(ctx, behavior.Kind(), behavior.ID())
+		pid, err = actorSystem.RestartActor(ctx, behavior.Kind())
 		assert.NoError(t, err)
 
 		// fetch the current state