# internal/adapters/cli/finalize

Package finalize composes the scafld finalize CLI boundary.

## Handler

```go
func Handler(stdin io.Reader) func(context.Context, []string, io.Writer, io.Writer) int
```

Handler returns a CLI-compatible handler for the host-facing finalize command.

## Run

```go
func Run(ctx context.Context, args []string, stdin io.Reader, stdout io.Writer) error
```

Run handles the public `scafld finalize <task_id>` command and the `scafld finalize --json --stdin` child process invoked by the finalize MCP transport. It composes deterministic snapshot, acceptance, and signing adapters around the accepted review evidence already sealed in the session ledger, then persists the signed receipt and archives the matching spec.

## Request

```go
type Request struct {
	TaskID        string   `json:"task_id"`
	Root          string   `json:"root,omitempty"`
	BaseRef       string   `json:"base_ref,omitempty"`
	ScopeHint     []string `json:"scope_hint,omitempty"`
	HookEventName string   `json:"hook_event_name,omitempty"`
}
```

Request is the finalize stdin payload sent by the MCP transport.

HookEventName is never sent by the MCP transport. It is populated only when a host hook (a Claude Code Stop hook) pipes its own event payload into `finalize --stdin`, which is how a taskless hook invocation is told apart from an agent that called the finalize tool and simply forgot the task\_id.

- `TaskID: string` (json:"task_id"): 
- `Root: string` (json:"root,omitempty"): 
- `BaseRef: string` (json:"base_ref,omitempty"): 
- `ScopeHint: []string` (json:"scope_hint,omitempty"): 
- `HookEventName: string` (json:"hook_event_name,omitempty"):
