# Add Pi review-runner adapter; drop `entire review attach`

`1d8ceda`→[main](/content/gh/entireio/cli/commits/main/index.html)·

dipree·1mo ago·11 files·+443 added/-164 removed

Pi can now be driven by `entire review` like claude-code/codex/gemini: it runs headless via `pi --mode json <prompt>`, inherits the ENTIRE_REVIEW_* env vars, and self-tags its session through the existing hook adoption path. No marker file or manual attach is needed.

- Add cmd/entire/cli/agent/pi/reviewer.go: NewReviewer() (ReviewerTemplate)  
+ a parser mapping pi's JSON event stream to review Events, with tests.  
- Wire pi into launchableReviewerFor.  
- Remove the `entire review attach` subcommand and its plumbing (Deps.AttachCmd, newReviewAttachCmd). Its only unique behavior — consuming a pending-review marker — is folded into `entire attach --review`, which already covers manual tagging. Tests migrated to the `attach --review` surface; stale doc comments updated.

## Sessions

86a03348156eView transcript

[?\List me all the potential command combinations for review.Pi·Opus 4.8·3 steps](/content/gh/entireio/cli/session/019e9fb5-004d-7145-8f48-db6a240d0ab3#timeline-86a03348156e/index.html)

## Changes

11

- cmd/entire/cli
  
  - agent/pi
  
    - Areviewer.go+180
  
    - Areviewer_test.go+206

- Mattach.go+31/-4

- Mattach_test.go+7/-7

- integration_test

- Mreview_test.go+1/-1

- review

- Dattach_test.go-47

- Mcmd.go+2/-11

- Mmarker_fallback.go+5/-7

- Mreview_bridge.go+4/-6

- Mreview_helpers.go+6/-80

- Mroot.go+1/-1

```go
package pi

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"os/exec"

"github.com/entireio/cli/cmd/entire/cli/review"
	reviewtypes "github.com/entireio/cli/cmd/entire/cli/review/types"
)

// piReviewMaxScannerBuf is the bufio.Scanner cap for the Pi review parser.
// 64MB matches the claude-code and codex parsers so all three tolerate the
// same worst-case line length (a tool result packed into one JSON envelope).
const piReviewMaxScannerBuf = 64 * 1024 * 1024

// NewReviewer returns the AgentReviewer for the Pi coding agent.
//
// Argv shape: pi --mode json <prompt> [--model <pattern>]. The prompt is a
// positional argument; stdin is unused. Stdout is newline-delimited JSON
// event envelopes (one event per line, see Pi's docs/json.md), which the
// parser decodes into the review Event stream.
//
// Pi spawned this way is a child process of `entire review`, so it inherits
// the ENTIRE_REVIEW_* env vars set by AppendReviewEnv. Pi's lifecycle hook
// then self-tags the session as a review via the shared adoptReviewEnv path —
// no marker file and no `entire attach` are needed.
func NewReviewer() *reviewtypes.ReviewerTemplate {
	return &reviewtypes.ReviewerTemplate{
		AgentName: "pi",
		BuildCmd:  buildReviewCmd,
		Parser:    parsePiOutput,
	}
}

// buildReviewCmd builds the exec.Cmd for a Pi review run.
// Exposed at package level for test inspection of argv and env.
func buildReviewCmd(ctx context.Context, cfg reviewtypes.RunConfig) *exec.Cmd {
	prompt := review.ComposeReviewPrompt(cfg)
	args := []string{"--mode", "json", prompt}
	if cfg.Model != "" {
		args = append(args, "--model", cfg.Model)
	}
	cmd := exec.CommandContext(ctx, "pi", args...)
	cmd.Env = review.AppendReviewEnv(os.Environ(), "pi", cfg, prompt)
	return cmd
}

// piStreamEnvelope is one line of `pi --mode json` stdout. Only the fields the
// review parser consumes are declared; unknown fields and event types are
// ignored so new Pi event types don't break parsing.
type piStreamEnvelope struct {
	Type     string           `json:"type"`
	ToolName string           `json:"toolName"`
	Args     json.RawMessage  `json:"args"`
	Message  *piStreamMessage `json:"message"`
}

// additional code...
```
