@@ -1,11 +1,14 @@
 package cmd
 
 import (
+	"bufio"
 	"encoding/json"
 	"fmt"
+	"io"
 	"os"
 	"path/filepath"
 	"slices"
+	"strings"
 	"time"
 
 	"github.com/charmbracelet/crush/internal/config"
@@ -14,20 +17,30 @@ import (
 	"github.com/spf13/cobra"
 )
 
-func init() {
-	rootCmd.AddCommand(logsCmd)
-}
-
 var logsCmd = &cobra.Command{
 	Use:   "logs",
 	Short: "View crush logs",
-	Long:  `View the logs generated by Crush. This command allows you to see the log output for debugging and monitoring purposes.`,
+	Long:  `View the logs generated by Crush. This command allows you to see the log output for debugging and monitoring.`,
 	RunE: func(cmd *cobra.Command, args []string) error {
 		cwd, err := cmd.Flags().GetString("cwd")
 		if err != nil {
 			return fmt.Errorf("failed to get current working directory: %v", err)
 		}
+
+		follow, err := cmd.Flags().GetBool("follow")
+		if err != nil {
+			return fmt.Errorf("failed to get follow flag: %v", err)
+		}
+
+		tailLines, err := cmd.Flags().GetInt("tail")
+		if err != nil {
+			return fmt.Errorf("failed to get tail flag: %v", err)
+		}
+
 		log.SetLevel(log.DebugLevel)
+		// Configure log to output to stdout instead of stderr
+		log.SetOutput(os.Stdout)
+
 		cfg, err := config.Load(cwd, false)
 		if err != nil {
 			return fmt.Errorf("failed to load configuration: %v", err)
@@ -38,62 +51,155 @@ var logsCmd = &cobra.Command{
 			log.Warn("Looks like you are not in a crush project. No logs found.")
 			return nil
 		}
-		t, err := tail.TailFile(logsFile, tail.Config{Follow: true, ReOpen: true, Logger: tail.DiscardingLogger})
-		if err != nil {
-			return fmt.Errorf("failed to tail log file: %v", err)
-		}
 
-		// Print the text of each received line
-		for line := range t.Lines {
-			var data map[string]any
-			if err := json.Unmarshal([]byte(line.Text), &data); err != nil {
-				continue
+		if follow {
+			// Follow mode - tail the file continuously
+			t, err := tail.TailFile(logsFile, tail.Config{Follow: true, ReOpen: true, Logger: tail.DiscardingLogger})
+			if err != nil {
+				return fmt.Errorf("failed to tail log file: %v", err)
 			}
-			msg := data["msg"]
-			level := data["level"]
-			otherData := []any{}
-			keys := []string{}
-			for k := range data {
-				keys = append(keys, k)
-			}
-			slices.Sort(keys)
-			for _, k := range keys {
-				switch k {
-				case "msg", "level", "time":
-					continue
-				case "source":
-					source, ok := data[k].(map[string]any)
-					if !ok {
-						continue
-					}
-					sourceFile := fmt.Sprintf("%s:%d", source["file"], int(source["line"].(float64)))
-					otherData = append(otherData, "source", sourceFile)
 
-				default:
-					otherData = append(otherData, k, data[k])
-				}
+			// Print the text of each received line
+			for line := range t.Lines {
+				printLogLine(line.Text)
 			}
-			log.SetTimeFunction(func(_ time.Time) time.Time {
-				// parse the timestamp from the log line if available
-				t, err := time.Parse(time.RFC3339, data["time"].(string))
+		} else if tailLines > 0 {
+			// Tail mode - show last N lines
+			lines, err := readLastNLines(logsFile, tailLines)
+			if err != nil {
+				return fmt.Errorf("failed to read last %d lines: %v", tailLines, err)
+			}
+			for _, line := range lines {
+				printLogLine(line)
+			}
+		} else {
+			// Oneshot mode - read the entire file once
+			file, err := os.Open(logsFile)
+			if err != nil {
+				return fmt.Errorf("failed to open log file: %v", err)
+			}
+			defer file.Close()
+
+			reader := bufio.NewReader(file)
+			for {
+				line, err := reader.ReadString('\n')
 				if err != nil {
-					return time.Now() // fallback to current time if parsing fails
+					if err == io.EOF && line != "" {
+						// Handle last line without newline
+						printLogLine(line)
+					}
+					break
 				}
-				return t
-			})
-			switch level {
-			case "INFO":
-				log.Info(msg, otherData...)
-			case "DEBUG":
-				log.Debug(msg, otherData...)
-			case "ERROR":
-				log.Error(msg, otherData...)
-			case "WARN":
-				log.Warn(msg, otherData...)
-			default:
-				log.Info(msg, otherData...)
+				// Remove trailing newline
+				line = strings.TrimSuffix(line, "\n")
+				printLogLine(line)
 			}
 		}
+
 		return nil
 	},
 }
+
+func init() {
+	logsCmd.Flags().BoolP("follow", "f", false, "Follow log output")
+	logsCmd.Flags().IntP("tail", "t", 0, "Show only the last N lines")
+	rootCmd.AddCommand(logsCmd)
+}
+
+// readLastNLines reads the last N lines from a file using a simple circular buffer approach
+func readLastNLines(filename string, n int) ([]string, error) {
+	file, err := os.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+
+	// Use a circular buffer to keep only the last N lines
+	lines := make([]string, n)
+	count := 0
+	index := 0
+
+	reader := bufio.NewReader(file)
+	for {
+		line, err := reader.ReadString('\n')
+		if err != nil {
+			if err == io.EOF && line != "" {
+				// Handle last line without newline
+				line = strings.TrimSuffix(line, "\n")
+				lines[index] = line
+				count++
+				index = (index + 1) % n
+			}
+			break
+		}
+		// Remove trailing newline
+		line = strings.TrimSuffix(line, "\n")
+		lines[index] = line
+		count++
+		index = (index + 1) % n
+	}
+
+	// Extract the last N lines in correct order
+	if count <= n {
+		// We have fewer lines than requested, return them all
+		return lines[:count], nil
+	}
+
+	// We have more lines than requested, extract from circular buffer
+	result := make([]string, n)
+	for i := range n {
+		result[i] = lines[(index+i)%n]
+	}
+	return result, nil
+}
+
+func printLogLine(lineText string) {
+	var data map[string]any
+	if err := json.Unmarshal([]byte(lineText), &data); err != nil {
+		return
+	}
+	msg := data["msg"]
+	level := data["level"]
+	otherData := []any{}
+	keys := []string{}
+	for k := range data {
+		keys = append(keys, k)
+	}
+	slices.Sort(keys)
+	for _, k := range keys {
+		switch k {
+		case "msg", "level", "time":
+			continue
+		case "source":
+			source, ok := data[k].(map[string]any)
+			if !ok {
+				continue
+			}
+			sourceFile := fmt.Sprintf("%s:%d", source["file"], int(source["line"].(float64)))
+			otherData = append(otherData, "source", sourceFile)
+
+		default:
+			otherData = append(otherData, k, data[k])
+		}
+	}
+	log.SetTimeFunction(func(_ time.Time) time.Time {
+		// parse the timestamp from the log line if available
+		t, err := time.Parse(time.RFC3339, data["time"].(string))
+		if err != nil {
+			return time.Now() // fallback to current time if parsing fails
+		}
+		return t
+	})
+	switch level {
+	case "INFO":
+		log.Info(msg, otherData...)
+	case "DEBUG":
+		log.Debug(msg, otherData...)
+	case "ERROR":
+		log.Error(msg, otherData...)
+	case "WARN":
+		log.Warn(msg, otherData...)
+	default:
+		log.Info(msg, otherData...)
+	}
+}