> ## Documentation Index
> Fetch the complete documentation index at: https://docs.goakt.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Behaviors

> Switch message handlers with Become and UnBecome.

Actors can change their message-handling logic at runtime using **behaviors**. A behavior is a function `func(ctx *ReceiveContext)` that processes messages. The default behavior is the actor's `Receive` method.

## Behavior type

```go theme={"theme":{"light":"github-light","dark":"dracula"}}
type Behavior func(ctx *ReceiveContext)
```

Behaviors are stored on a stack. The top of the stack handles each incoming message.

## API

| Method                        | Purpose                                                                                                                                                     |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ctx.Become(behavior)`        | Replace the current behavior. The current message finishes under the old behavior; subsequent messages use the new one. No stack—previous behavior is lost. |
| `ctx.BecomeStacked(behavior)` | Push a new behavior on top. Current message still uses the existing behavior; subsequent messages use the new one until `UnBecomeStacked`.                  |
| `ctx.UnBecomeStacked()`       | Pop the top behavior. Resume the previous one. No effect if the stack is empty.                                                                             |
| `ctx.UnBecome()`              | Reset to the default (initial) behavior. Clears the stack.                                                                                                  |

## Become vs BecomeStacked

* **Become** — Swap behavior. Use when transitioning to a new state and you do not need to return to the previous one.
* **BecomeStacked** — Push behavior. Use when you need to temporarily handle messages differently, then pop back (e.g., a modal dialog, a temporary protocol phase).

## Example

An account actor that switches behaviors based on authentication and transfer confirmation:

```go theme={"theme":{"light":"github-light","dark":"dracula"}}
package main

import (
    "context"
    "fmt"
    "time"

    "github.com/tochemey/goakt/v4/actor"
)

// Message types
type Login struct{ User string }
type Logout struct{}
type Transfer struct {
    To     string
    Amount int64
}

type Confirm struct{}
type Cancel struct{}

type AccountActor struct {
    balance         int64
    pendingTransfer *Transfer // stored when awaiting confirmation
}

func (a *AccountActor) PreStart(ctx *actor.Context) error { return nil }
func (a *AccountActor) PostStop(ctx *actor.Context) error  { return nil }

func (a *AccountActor) Receive(ctx *actor.ReceiveContext) {
    switch ctx.Message().(type) {
    case *Login:
        ctx.Become(a.Authenticated)
    default:
        ctx.Unhandled()
    }
}

func (a *AccountActor) Authenticated(ctx *actor.ReceiveContext) {
    switch msg := ctx.Message().(type) {
    case *Logout:
        ctx.UnBecome()
    case *Transfer:
        a.pendingTransfer = msg
        ctx.BecomeStacked(a.ConfirmTransfer)
    default:
        ctx.Unhandled()
    }
}

func (a *AccountActor) ConfirmTransfer(ctx *actor.ReceiveContext) {
    switch ctx.Message().(type) {
    case *Confirm:
        if a.pendingTransfer != nil {
            a.balance -= a.pendingTransfer.Amount
            a.pendingTransfer = nil
        }
        ctx.UnBecomeStacked()
    case *Cancel:
        a.pendingTransfer = nil
        ctx.UnBecomeStacked()
    default:
        ctx.Unhandled()
    }
}

func main() {
    ctx := context.Background()
    system, err := actor.NewActorSystem("behaviors-demo", 
        actor.WithLoggingDisabled(),
        actor.WithActorInitMaxRetries(3))
    if err != nil {
        panic(err)
    }
    if err := system.Start(ctx); err != nil {
        panic(err)
    }
    defer system.Stop(ctx)

    acc := &AccountActor{balance: 1000}
    pid, err := system.Spawn(ctx, "account", acc)
    if err != nil {
        panic(err)
    }

    // Login -> switches to Authenticated
    _ = actor.Tell(ctx, pid, &Login{User: "alice"})
    time.Sleep(10 * time.Millisecond)

    // Transfer -> pushes ConfirmTransfer on stack
    _ = actor.Tell(ctx, pid, &Transfer{To: "bob", Amount: 50})
    time.Sleep(10 * time.Millisecond)

    // Confirm -> pops ConfirmTransfer, executes transfer
    _ = actor.Tell(ctx, pid, &Confirm{})
    time.Sleep(10 * time.Millisecond)

    fmt.Println("Done. Balance:", acc.balance) // 950
}
```

## Stashing with behaviors

When switching behaviors, you may want to defer processing of the current message. Use `ctx.Stash()` to buffer it, then `ctx.Unstash()` or `ctx.UnstashAll()` after changing behavior. Requires `WithStashing()` at spawn. See [Stashing](/actor/stashing).
