Files
boshu2__agentops/cli/cmd/ao/codex.go
T
2026-04-03 10:47:44 -04:00

1161 lines
41 KiB
Go

package main
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"time"
"github.com/spf13/cobra"
"github.com/boshu2/agentops/cli/internal/pool"
"github.com/boshu2/agentops/cli/internal/ratchet"
"github.com/boshu2/agentops/cli/internal/storage"
"github.com/boshu2/agentops/cli/internal/types"
)
var (
codexStartLimit int
codexStartQuery string
codexStartNoMaintenance bool
codexStopSessionID string
codexStopTranscriptPath string
codexStopAutoExtract bool
codexStopNoHistoryFallback bool
codexStopNoCloseLoop bool
codexStatusDays int
)
type codexArtifactRef struct {
Title string `json:"title"`
Path string `json:"path"`
ModifiedAt string `json:"modified_at"`
}
type codexLifecycleEvent struct {
SessionID string `json:"session_id,omitempty"`
ThreadName string `json:"thread_name,omitempty"`
Query string `json:"query,omitempty"`
Timestamp string `json:"timestamp"`
TranscriptPath string `json:"transcript_path,omitempty"`
TranscriptSource string `json:"transcript_source,omitempty"`
SyntheticTranscript bool `json:"synthetic_transcript,omitempty"`
StartupContextPath string `json:"startup_context_path,omitempty"`
MemoryPath string `json:"memory_path,omitempty"`
Status string `json:"status,omitempty"`
Summary string `json:"summary,omitempty"`
HandoffPath string `json:"handoff_path,omitempty"`
}
type codexLifecycleState struct {
SchemaVersion int `json:"schema_version"`
Runtime lifecycleRuntimeProfile `json:"runtime"`
LastStart *codexLifecycleEvent `json:"last_start,omitempty"`
LastStop *codexLifecycleEvent `json:"last_stop,omitempty"`
UpdatedAt string `json:"updated_at"`
}
type codexStartResult struct {
Runtime lifecycleRuntimeProfile `json:"runtime"`
ContextQuery string `json:"context_query,omitempty"`
StartupContextPath string `json:"startup_context_path"`
MemoryPath string `json:"memory_path,omitempty"`
CloseLoop *flywheelCloseLoopResult `json:"close_loop,omitempty"`
Flywheel *flywheelBrief `json:"flywheel,omitempty"`
Briefings []codexArtifactRef `json:"briefings,omitempty"`
Learnings []learning `json:"learnings,omitempty"`
Patterns []pattern `json:"patterns,omitempty"`
Findings []knowledgeFinding `json:"findings,omitempty"`
RecentSessions []session `json:"recent_sessions,omitempty"`
NextWork []nextWorkItem `json:"next_work,omitempty"`
Research []codexArtifactRef `json:"research,omitempty"`
StatePath string `json:"state_path"`
}
type codexEnsureStartResult struct {
Runtime lifecycleRuntimeProfile `json:"runtime"`
Performed bool `json:"performed"`
Reason string `json:"reason,omitempty"`
SessionID string `json:"session_id,omitempty"`
ContextQuery string `json:"context_query,omitempty"`
StartupContextPath string `json:"startup_context_path,omitempty"`
MemoryPath string `json:"memory_path,omitempty"`
StatePath string `json:"state_path,omitempty"`
}
type codexStopResult struct {
Runtime lifecycleRuntimeProfile `json:"runtime"`
TranscriptPath string `json:"transcript_path"`
TranscriptSource string `json:"transcript_source"`
SyntheticTranscript bool `json:"synthetic_transcript,omitempty"`
Session SessionCloseResult `json:"session"`
CloseLoop *flywheelCloseLoopResult `json:"close_loop,omitempty"`
MemoryPath string `json:"memory_path,omitempty"`
StatePath string `json:"state_path"`
}
type codexEnsureStopResult struct {
Runtime lifecycleRuntimeProfile `json:"runtime"`
Performed bool `json:"performed"`
Reason string `json:"reason,omitempty"`
SessionID string `json:"session_id,omitempty"`
TranscriptPath string `json:"transcript_path,omitempty"`
TranscriptSource string `json:"transcript_source,omitempty"`
SyntheticTranscript bool `json:"synthetic_transcript,omitempty"`
HandoffPath string `json:"handoff_path,omitempty"`
MemoryPath string `json:"memory_path,omitempty"`
StatePath string `json:"state_path,omitempty"`
}
type codexCaptureHealth struct {
SessionsIndexed int `json:"sessions_indexed"`
LastForgeTime string `json:"last_forge_time,omitempty"`
LastForgeAge string `json:"last_forge_age,omitempty"`
PendingKnowledge int `json:"pending_knowledge"`
PendingQuarantine int `json:"pending_quarantine"`
}
type codexRetrievalHealth struct {
Learnings int `json:"learnings"`
Patterns int `json:"patterns"`
Findings int `json:"findings"`
NextWork int `json:"next_work"`
Briefings int `json:"briefings"`
Research int `json:"research"`
}
type codexPromotionHealth struct {
PendingPool int `json:"pending_pool"`
StagedPool int `json:"staged_pool"`
RejectedPool int `json:"rejected_pool"`
}
type codexCitationHealth struct {
WindowDays int `json:"window_days"`
Total int `json:"total"`
Deduped int `json:"deduped"`
UniqueArtifacts int `json:"unique_artifacts"`
UniqueSessions int `json:"unique_sessions"`
UniqueWorkspaces int `json:"unique_workspaces"`
Retrieved int `json:"retrieved"`
Reference int `json:"reference"`
Applied int `json:"applied"`
}
type codexStatusResult struct {
Runtime lifecycleRuntimeProfile `json:"runtime"`
State *codexLifecycleState `json:"state,omitempty"`
Flywheel *flywheelBrief `json:"flywheel,omitempty"`
Capture codexCaptureHealth `json:"capture"`
Retrieval codexRetrievalHealth `json:"retrieval"`
Promotion codexPromotionHealth `json:"promotion"`
Citations codexCitationHealth `json:"citations"`
}
var codexCmd = &cobra.Command{
Use: "codex",
Short: "Codex-native lifecycle commands for hookless sessions",
Long: `Codex-native lifecycle commands for runtimes without Claude/OpenCode lifecycle hooks.
Use these commands to make the knowledge flywheel explicit in Codex:
ao codex start Surface prior context and run safe maintenance
ao codex stop Forge the current session, queue learnings, and close the loop
ao codex status Show hookless lifecycle health and flywheel status`,
}
var codexStartCmd = &cobra.Command{
Use: "start",
Short: "Start a Codex session with explicit flywheel maintenance",
Args: cobra.NoArgs,
RunE: runCodexStart,
}
var codexEnsureStartCmd = &cobra.Command{
Use: "ensure-start",
Short: "Ensure Codex startup context exists once per thread",
Args: cobra.NoArgs,
RunE: runCodexEnsureStart,
}
var codexStopCmd = &cobra.Command{
Use: "stop",
Short: "Close a Codex session without relying on runtime hooks",
Args: cobra.NoArgs,
RunE: runCodexStop,
}
var codexEnsureStopCmd = &cobra.Command{
Use: "ensure-stop",
Short: "Ensure Codex closeout runs once per thread",
Args: cobra.NoArgs,
RunE: runCodexEnsureStop,
}
var codexStatusCmd = &cobra.Command{
Use: "status",
Short: "Show Codex hookless lifecycle health",
Args: cobra.NoArgs,
RunE: runCodexStatus,
}
func init() {
codexCmd.GroupID = "workflow"
rootCmd.AddCommand(codexCmd)
codexCmd.AddCommand(codexStartCmd, codexEnsureStartCmd, codexStopCmd, codexEnsureStopCmd, codexStatusCmd)
codexStartCmd.Flags().IntVar(&codexStartLimit, "limit", 3, "Maximum artifacts to surface per category")
codexStartCmd.Flags().StringVar(&codexStartQuery, "query", "", "Optional startup query (defaults to the current Codex thread name)")
codexStartCmd.Flags().BoolVar(&codexStartNoMaintenance, "no-maintenance", false, "Skip safe close-loop maintenance on start")
codexEnsureStartCmd.Flags().IntVar(&codexStartLimit, "limit", 3, "Maximum artifacts to surface per category")
codexEnsureStartCmd.Flags().StringVar(&codexStartQuery, "query", "", "Optional startup query (defaults to the current Codex thread name)")
codexEnsureStartCmd.Flags().BoolVar(&codexStartNoMaintenance, "no-maintenance", false, "Skip safe close-loop maintenance on start")
codexStopCmd.Flags().StringVar(&codexStopSessionID, "session", "", "Codex session ID to close (defaults to the active thread)")
codexStopCmd.Flags().StringVar(&codexStopTranscriptPath, "transcript", "", "Explicit transcript path to forge instead of runtime discovery")
codexStopCmd.Flags().BoolVar(&codexStopAutoExtract, "auto-extract", true, "Write lightweight learnings and handoff artifacts during closeout")
codexStopCmd.Flags().BoolVar(&codexStopNoHistoryFallback, "no-history-fallback", false, "Disable history.jsonl fallback when no archived Codex transcript exists")
codexStopCmd.Flags().BoolVar(&codexStopNoCloseLoop, "no-close-loop", false, "Skip flywheel close-loop maintenance after forging")
codexEnsureStopCmd.Flags().StringVar(&codexStopSessionID, "session", "", "Codex session ID to close (defaults to the active thread)")
codexEnsureStopCmd.Flags().StringVar(&codexStopTranscriptPath, "transcript", "", "Explicit transcript path to forge instead of runtime discovery")
codexEnsureStopCmd.Flags().BoolVar(&codexStopAutoExtract, "auto-extract", true, "Write lightweight learnings and handoff artifacts during closeout")
codexEnsureStopCmd.Flags().BoolVar(&codexStopNoHistoryFallback, "no-history-fallback", false, "Disable history.jsonl fallback when no archived Codex transcript exists")
codexEnsureStopCmd.Flags().BoolVar(&codexStopNoCloseLoop, "no-close-loop", false, "Skip flywheel close-loop maintenance after forging")
codexStatusCmd.Flags().IntVar(&codexStatusDays, "days", 7, "Citation window in days for Codex lifecycle health")
}
func runCodexStart(cmd *cobra.Command, args []string) error {
cwd, err := resolveProjectDir()
if err != nil {
return err
}
result, err := performCodexStart(cwd)
if err != nil {
return err
}
return outputCodexStartResult(result)
}
func runCodexEnsureStart(cmd *cobra.Command, args []string) error {
cwd, err := resolveProjectDir()
if err != nil {
return err
}
if err := ensureCodexLifecycleDirs(cwd); err != nil {
return err
}
profile := detectCodexLifecycleProfile()
sessionID := profile.SessionID
if strings.TrimSpace(sessionID) == "" {
sessionID = resolveSessionID("")
}
state, statePath, err := loadOrInitCodexLifecycleState(cwd)
if err != nil {
return err
}
if codexStartAlreadyStarted(state, sessionID) {
existingSessionID := sessionID
if state.LastStart != nil {
existingSessionID = firstNonEmptyTrimmed(existingSessionID, state.LastStart.SessionID)
}
return outputCodexEnsureStartResult(codexEnsureStartResult{
Runtime: profile,
Performed: false,
Reason: "startup already recorded for this Codex thread",
SessionID: existingSessionID,
ContextQuery: firstNonEmptyTrimmed(codexStartQuery, profile.ThreadName, "codex startup"),
StartupContextPath: firstNonEmptyLifecycleField(state, func(event *codexLifecycleEvent) string { return event.StartupContextPath }),
MemoryPath: firstNonEmptyLifecycleField(state, func(event *codexLifecycleEvent) string { return event.MemoryPath }),
StatePath: statePath,
})
}
result, err := performCodexStart(cwd)
if err != nil {
return err
}
return outputCodexEnsureStartResult(codexEnsureStartResult{
Runtime: result.Runtime,
Performed: true,
Reason: "startup recorded for current Codex thread",
SessionID: firstNonEmptyTrimmed(sessionID, result.Runtime.SessionID),
ContextQuery: result.ContextQuery,
StartupContextPath: result.StartupContextPath,
MemoryPath: result.MemoryPath,
StatePath: result.StatePath,
})
}
func codexStartAlreadyStarted(state *codexLifecycleState, sessionID string) bool {
if state == nil || state.LastStart == nil {
return false
}
if strings.TrimSpace(sessionID) == "" || strings.TrimSpace(state.LastStart.SessionID) != strings.TrimSpace(sessionID) {
return false
}
startupContextPath := strings.TrimSpace(state.LastStart.StartupContextPath)
if startupContextPath == "" {
return false
}
return fileExists(startupContextPath)
}
func performCodexStart(cwd string) (codexStartResult, error) {
if err := ensureCodexLifecycleDirs(cwd); err != nil {
return codexStartResult{}, err
}
profile := detectCodexLifecycleProfile()
sessionID := profile.SessionID
if strings.TrimSpace(sessionID) == "" {
sessionID = resolveSessionID("")
}
query := strings.TrimSpace(codexStartQuery)
if query == "" {
query = strings.TrimSpace(profile.ThreadName)
}
if query == "" {
query = "codex startup"
}
var closeLoop *flywheelCloseLoopResult
if !codexStartNoMaintenance {
threshold, err := time.ParseDuration(defaultAutoPromoteThreshold)
if err != nil {
return codexStartResult{}, fmt.Errorf("parse default close-loop threshold: %w", err)
}
result, err := performFlywheelCloseLoop(cwd, filepath.Join(".agents", "knowledge", "pending"), threshold, true)
if err != nil {
return codexStartResult{}, fmt.Errorf("run codex startup maintenance: %w", err)
}
closeLoop = &result
}
briefings, learnings, patterns, findings, recentSessions, nextWork, research := collectCodexStartupArtifacts(cwd, query, codexStartLimit)
recordLookupCitations(cwd, learnings, patterns, findings, sessionID, query, "retrieved")
memoryPath, err := syncCodexMemory(cwd)
if err != nil {
VerbosePrintf("Warning: codex memory sync: %v\n", err)
}
startupContextPath, err := writeCodexStartupContext(cwd, profile, query, briefings, learnings, patterns, findings, recentSessions, nextWork, research)
if err != nil {
return codexStartResult{}, fmt.Errorf("write codex startup context: %w", err)
}
state, statePath, err := loadOrInitCodexLifecycleState(cwd)
if err != nil {
return codexStartResult{}, err
}
state.Runtime = profile
state.LastStart = &codexLifecycleEvent{
SessionID: sessionID,
ThreadName: profile.ThreadName,
Query: query,
Timestamp: time.Now().UTC().Format(time.RFC3339),
StartupContextPath: startupContextPath,
MemoryPath: memoryPath,
Status: lifecycleModeCodexHookless,
Summary: fmt.Sprintf("surfaced %d learnings, %d patterns, %d findings", len(learnings), len(patterns), len(findings)),
}
state.UpdatedAt = time.Now().UTC().Format(time.RFC3339)
if err := saveCodexLifecycleState(statePath, state); err != nil {
return codexStartResult{}, err
}
return codexStartResult{
Runtime: profile,
ContextQuery: query,
StartupContextPath: startupContextPath,
MemoryPath: memoryPath,
CloseLoop: closeLoop,
Flywheel: loadFlywheelBrief(cwd),
Briefings: briefings,
Learnings: learnings,
Patterns: patterns,
Findings: findings,
RecentSessions: recentSessions,
NextWork: nextWork,
Research: research,
StatePath: statePath,
}, nil
}
func runCodexStop(cmd *cobra.Command, args []string) error {
cwd, err := resolveProjectDir()
if err != nil {
return err
}
result, err := performCodexStop(cwd)
if err != nil {
return err
}
return outputCodexStopResult(result)
}
func runCodexEnsureStop(cmd *cobra.Command, args []string) error {
cwd, err := resolveProjectDir()
if err != nil {
return err
}
result, err := performCodexStop(cwd)
if err != nil {
return err
}
performed := result.Session.Status != "already_closed"
return outputCodexEnsureStopResult(codexEnsureStopResult{
Runtime: result.Runtime,
Performed: performed,
Reason: ensureStopReason(result),
SessionID: result.Session.SessionID,
TranscriptPath: result.TranscriptPath,
TranscriptSource: result.TranscriptSource,
SyntheticTranscript: result.SyntheticTranscript,
HandoffPath: result.Session.HandoffWritten,
MemoryPath: result.MemoryPath,
StatePath: result.StatePath,
})
}
func performCodexStop(cwd string) (codexStopResult, error) {
if err := ensureCodexLifecycleDirs(cwd); err != nil {
return codexStopResult{}, err
}
profile := detectCodexLifecycleProfile()
state, statePath, err := loadOrInitCodexLifecycleState(cwd)
if err != nil {
return codexStopResult{}, err
}
sessionID := strings.TrimSpace(codexStopSessionID)
if sessionID == "" {
sessionID = strings.TrimSpace(profile.SessionID)
}
transcriptPath := strings.TrimSpace(codexStopTranscriptPath)
transcriptSource := "explicit"
syntheticTranscript := false
if transcriptPath == "" {
transcriptPath, transcriptSource, syntheticTranscript, sessionID, err = resolveCodexStopTranscript(cwd, sessionID, codexStopNoHistoryFallback)
if err != nil {
return codexStopResult{}, err
}
}
if codexStopAlreadyClosed(state, sessionID, transcriptPath) {
return buildCodexStopAlreadyClosedResult(profile, state, statePath, sessionID, transcriptPath, transcriptSource, syntheticTranscript), nil
}
closeResult, err := forgeExtractReportWithOptions(transcriptPath, cwd, codexStopAutoExtract, false)
if err != nil {
return codexStopResult{}, err
}
var closeLoop *flywheelCloseLoopResult
if !codexStopNoCloseLoop {
threshold, err := time.ParseDuration(defaultAutoPromoteThreshold)
if err != nil {
return codexStopResult{}, fmt.Errorf("parse default close-loop threshold: %w", err)
}
result, err := performFlywheelCloseLoop(cwd, filepath.Join(".agents", "knowledge", "pending"), threshold, true)
if err != nil {
return codexStopResult{}, fmt.Errorf("run codex close-loop maintenance: %w", err)
}
closeLoop = &result
}
if err := performHooklessSessionEndMaintenance(cwd); err != nil {
VerbosePrintf("Warning: codex session-end maintenance: %v\n", err)
}
memoryPath, err := syncCodexMemory(cwd)
if err != nil {
VerbosePrintf("Warning: codex memory sync: %v\n", err)
}
state.Runtime = profile
state.LastStop = &codexLifecycleEvent{
SessionID: closeResult.SessionID,
ThreadName: profile.ThreadName,
Timestamp: time.Now().UTC().Format(time.RFC3339),
TranscriptPath: transcriptPath,
TranscriptSource: transcriptSource,
SyntheticTranscript: syntheticTranscript,
MemoryPath: memoryPath,
Status: closeResult.Status,
Summary: closeResult.Message,
HandoffPath: closeResult.HandoffWritten,
}
state.UpdatedAt = time.Now().UTC().Format(time.RFC3339)
if err := saveCodexLifecycleState(statePath, state); err != nil {
return codexStopResult{}, err
}
return codexStopResult{
Runtime: profile,
TranscriptPath: transcriptPath,
TranscriptSource: transcriptSource,
SyntheticTranscript: syntheticTranscript,
Session: closeResult,
CloseLoop: closeLoop,
MemoryPath: memoryPath,
StatePath: statePath,
}, nil
}
func codexStopAlreadyClosed(state *codexLifecycleState, sessionID, transcriptPath string) bool {
if state == nil || state.LastStop == nil {
return false
}
lastSessionID := strings.TrimSpace(state.LastStop.SessionID)
lastTranscript := normalizeCodexLifecyclePath(state.LastStop.TranscriptPath)
currentTranscript := normalizeCodexLifecyclePath(transcriptPath)
if currentTranscript != "" && lastTranscript != "" {
if currentTranscript != lastTranscript {
return false
}
if sessionID != "" && lastSessionID != "" && strings.TrimSpace(sessionID) != lastSessionID {
return false
}
return true
}
if sessionID == "" || lastSessionID == "" {
return false
}
return strings.TrimSpace(sessionID) == lastSessionID
}
func buildCodexStopAlreadyClosedResult(profile lifecycleRuntimeProfile, state *codexLifecycleState, statePath, sessionID, transcriptPath, transcriptSource string, syntheticTranscript bool) codexStopResult {
lastStop := &codexLifecycleEvent{}
if state != nil && state.LastStop != nil {
lastStop = state.LastStop
}
resolvedSessionID := firstNonEmptyTrimmed(sessionID, lastStop.SessionID)
resolvedTranscriptPath := firstNonEmptyTrimmed(transcriptPath, lastStop.TranscriptPath)
resolvedTranscriptSource := firstNonEmptyTrimmed(transcriptSource, lastStop.TranscriptSource)
if resolvedTranscriptSource == "" {
resolvedTranscriptSource = "explicit"
}
return codexStopResult{
Runtime: profile,
TranscriptPath: resolvedTranscriptPath,
TranscriptSource: resolvedTranscriptSource,
SyntheticTranscript: syntheticTranscript || lastStop.SyntheticTranscript,
Session: SessionCloseResult{
SessionID: resolvedSessionID,
Transcript: resolvedTranscriptPath,
Status: "already_closed",
Message: "Codex closeout already recorded for this session",
HandoffWritten: lastStop.HandoffPath,
},
MemoryPath: firstNonEmptyTrimmed(lastStop.MemoryPath),
StatePath: statePath,
}
}
func ensureStopReason(result codexStopResult) string {
if result.Session.Status == "already_closed" {
return "closeout already recorded for this Codex thread"
}
return "closeout recorded for current Codex thread"
}
func runCodexStatus(cmd *cobra.Command, args []string) error {
cwd, err := resolveProjectDir()
if err != nil {
return err
}
profile := detectCodexLifecycleProfile()
state, _, err := loadOrInitCodexLifecycleState(cwd)
if err != nil {
return err
}
result := codexStatusResult{
Runtime: profile,
State: state,
Flywheel: loadFlywheelBrief(cwd),
Capture: collectCodexCaptureHealth(cwd),
Retrieval: collectCodexRetrievalHealth(cwd),
Promotion: collectCodexPromotionHealth(cwd),
Citations: collectCodexCitationHealth(cwd, codexStatusDays),
}
return outputCodexStatusResult(result)
}
func collectCodexStartupArtifacts(cwd, query string, limit int) ([]codexArtifactRef, []learning, []pattern, []knowledgeFinding, []session, []nextWorkItem, []codexArtifactRef) {
if limit <= 0 {
limit = 3
}
briefings := collectRecentCodexArtifacts(filepath.Join(cwd, ".agents", "briefings"), query, limit)
learnings, _ := collectLearnings(cwd, query, limit, "", 0)
patterns, _ := collectPatterns(cwd, query, limit, "", 0)
findings, _ := collectFindings(cwd, query, limit, "", 0)
recentSessions, _ := collectRecentSessions(cwd, query, minInt(limit, MaxSessionsToInject))
repoFilter := filepath.Base(cwd)
if root := findGitRoot(cwd); root != "" {
repoFilter = filepath.Base(root)
}
nextWork, _ := readUnconsumedItems(filepath.Join(cwd, ".agents", "rpi", "next-work.jsonl"), repoFilter)
if len(nextWork) > limit {
nextWork = nextWork[:limit]
}
research := collectRecentResearchArtifacts(cwd, query, limit)
return briefings, learnings, patterns, findings, recentSessions, nextWork, research
}
func collectRecentResearchArtifacts(cwd, query string, limit int) []codexArtifactRef {
return collectRecentCodexArtifacts(filepath.Join(cwd, ".agents", SectionResearch), query, limit)
}
func collectRecentCodexArtifacts(dir, query string, limit int) []codexArtifactRef {
entries, err := os.ReadDir(dir)
if err != nil {
return nil
}
type researchFile struct {
path string
modTime time.Time
}
var files []researchFile
for _, entry := range entries {
if entry.IsDir() || filepath.Ext(entry.Name()) != ".md" {
continue
}
info, err := entry.Info()
if err != nil {
continue
}
files = append(files, researchFile{
path: filepath.Join(dir, entry.Name()),
modTime: info.ModTime(),
})
}
slices.SortFunc(files, func(a, b researchFile) int {
return b.modTime.Compare(a.modTime)
})
queryLower := strings.ToLower(strings.TrimSpace(query))
var artifacts []codexArtifactRef
for _, file := range files {
if queryLower != "" {
baseLower := strings.ToLower(filepath.Base(file.path))
if !strings.Contains(baseLower, queryLower) {
data, err := os.ReadFile(file.path)
if err != nil || !strings.Contains(strings.ToLower(string(data)), queryLower) {
continue
}
}
}
artifacts = append(artifacts, codexArtifactRef{
Title: strings.TrimSuffix(filepath.Base(file.path), filepath.Ext(file.path)),
Path: file.path,
ModifiedAt: file.modTime.UTC().Format(time.RFC3339),
})
if len(artifacts) >= limit {
break
}
}
return artifacts
}
func resolveCodexStopTranscript(cwd, sessionID string, noHistoryFallback bool) (string, string, bool, string, error) {
if sessionID != "" {
if path, err := findTranscriptBySessionID(sessionID); err == nil {
return path, "archived", false, sessionID, nil
}
if !noHistoryFallback {
path, err := synthesizeCodexHistoryTranscript(cwd, sessionID)
if err == nil {
return path, "history-fallback", true, sessionID, nil
}
}
}
if path, err := findLastCodexArchivedTranscript(); err == nil {
return path, "archived", false, extractSessionIDFromCodexArchivedPath(path), nil
}
if noHistoryFallback {
return "", "", false, sessionID, fmt.Errorf("no Codex transcript found and history fallback is disabled")
}
fallbackSessionID := sessionID
if fallbackSessionID == "" {
fallbackSessionID = resolveCodexSessionIDFromHome()
}
if fallbackSessionID == "" {
return "", "", false, "", fmt.Errorf("no Codex transcript or active history session found")
}
path, err := synthesizeCodexHistoryTranscript(cwd, fallbackSessionID)
if err != nil {
return "", "", false, fallbackSessionID, err
}
return path, "history-fallback", true, fallbackSessionID, nil
}
func resolveCodexSessionIDFromHome() string {
homeDir, err := os.UserHomeDir()
if err != nil {
return ""
}
return resolveCodexSessionID(homeDir)
}
func extractSessionIDFromCodexArchivedPath(path string) string {
match := codexArchivedSessionPattern.FindStringSubmatch(filepath.Base(path))
if len(match) == 2 {
return match[1]
}
return ""
}
func syncCodexMemory(cwd string) (string, error) {
root := findGitRoot(cwd)
if root == "" {
root = cwd
}
path := filepath.Join(root, "MEMORY.md")
if err := syncMemory(cwd, path, 10, true); err != nil {
return path, err
}
return path, nil
}
func codexLifecycleStatePath(cwd string) string {
return filepath.Join(cwd, ".agents", "ao", "codex", "state.json")
}
func normalizeCodexLifecyclePath(path string) string {
trimmed := strings.TrimSpace(path)
if trimmed == "" {
return ""
}
if abs, err := filepath.Abs(trimmed); err == nil {
return filepath.Clean(abs)
}
return filepath.Clean(trimmed)
}
func firstNonEmptyTrimmed(values ...string) string {
for _, value := range values {
if trimmed := strings.TrimSpace(value); trimmed != "" {
return trimmed
}
}
return ""
}
func firstNonEmptyLifecycleField(state *codexLifecycleState, getter func(*codexLifecycleEvent) string) string {
if state == nil || getter == nil || state.LastStart == nil {
return ""
}
return firstNonEmptyTrimmed(getter(state.LastStart))
}
func ensureCodexLifecycleDirs(cwd string) error {
for _, dir := range []string{
filepath.Join(cwd, ".agents", "ao", "codex"),
filepath.Join(cwd, ".agents", "ao", "codex", "transcripts"),
} {
if err := os.MkdirAll(dir, 0o750); err != nil {
return fmt.Errorf("create codex lifecycle dir %s: %w", dir, err)
}
}
return nil
}
func loadOrInitCodexLifecycleState(cwd string) (*codexLifecycleState, string, error) {
if err := ensureCodexLifecycleDirs(cwd); err != nil {
return nil, "", err
}
path := codexLifecycleStatePath(cwd)
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return &codexLifecycleState{SchemaVersion: 1}, path, nil
}
return nil, "", fmt.Errorf("read codex lifecycle state: %w", err)
}
var state codexLifecycleState
if err := json.Unmarshal(data, &state); err != nil {
return nil, "", fmt.Errorf("parse codex lifecycle state: %w", err)
}
if state.SchemaVersion == 0 {
state.SchemaVersion = 1
}
if err := validateCodexLifecycleState(&state); err != nil {
return nil, "", fmt.Errorf("validating codex lifecycle state: %w", err)
}
return &state, path, nil
}
// expectedCodexSchemaVersion is the schema version this code can handle.
const expectedCodexSchemaVersion = 1
// validateCodexLifecycleState checks invariants on a deserialized lifecycle state:
// schema version, timestamp format (RFC3339), and temporal ordering.
func validateCodexLifecycleState(state *codexLifecycleState) error {
if state.SchemaVersion != expectedCodexSchemaVersion {
return fmt.Errorf("unsupported schema_version %d (expected %d)", state.SchemaVersion, expectedCodexSchemaVersion)
}
if state.UpdatedAt != "" {
if _, err := time.Parse(time.RFC3339, state.UpdatedAt); err != nil {
return fmt.Errorf("invalid updated_at timestamp %q: %w", state.UpdatedAt, err)
}
}
if state.LastStart != nil && state.LastStart.Timestamp != "" {
if _, err := time.Parse(time.RFC3339, state.LastStart.Timestamp); err != nil {
return fmt.Errorf("invalid last_start timestamp %q: %w", state.LastStart.Timestamp, err)
}
}
if state.LastStop != nil && state.LastStop.Timestamp != "" {
if _, err := time.Parse(time.RFC3339, state.LastStop.Timestamp); err != nil {
return fmt.Errorf("invalid last_stop timestamp %q: %w", state.LastStop.Timestamp, err)
}
}
// If both start and stop exist with timestamps, stop must not precede start.
if state.LastStart != nil && state.LastStop != nil &&
state.LastStart.Timestamp != "" && state.LastStop.Timestamp != "" {
startT, err1 := time.Parse(time.RFC3339, state.LastStart.Timestamp)
stopT, err2 := time.Parse(time.RFC3339, state.LastStop.Timestamp)
if err1 == nil && err2 == nil && stopT.Before(startT) {
return fmt.Errorf("last_stop (%s) is before last_start (%s)", state.LastStop.Timestamp, state.LastStart.Timestamp)
}
}
return nil
}
func saveCodexLifecycleState(path string, state *codexLifecycleState) error {
data, err := json.MarshalIndent(state, "", " ")
if err != nil {
return fmt.Errorf("marshal codex lifecycle state: %w", err)
}
if err := atomicWriteFile(path, append(data, '\n'), 0o600); err != nil {
return fmt.Errorf("write codex lifecycle state: %w", err)
}
return nil
}
func writeCodexStartupContext(cwd string, profile lifecycleRuntimeProfile, query string, briefings []codexArtifactRef, learnings []learning, patterns []pattern, findings []knowledgeFinding, recentSessions []session, nextWork []nextWorkItem, research []codexArtifactRef) (string, error) {
bundle := buildRankedContextBundle(cwd, query, codexStartLimit, learnings, patterns, findings, recentSessions, nextWork, research)
var sb strings.Builder
sb.WriteString("# Codex Startup Context\n\n")
sb.WriteString(fmt.Sprintf("- Runtime: %s\n", profile.Runtime))
sb.WriteString(fmt.Sprintf("- Lifecycle mode: %s\n", profile.Mode))
if profile.ThreadName != "" {
sb.WriteString(fmt.Sprintf("- Thread: %s\n", profile.ThreadName))
}
if query != "" {
sb.WriteString(fmt.Sprintf("- Query: %s\n", query))
}
sb.WriteString("\n## Briefings\n")
if len(briefings) == 0 {
sb.WriteString(fmt.Sprintf("- No recent knowledge briefing surfaced. Build one with `ao knowledge brief --goal %q` when workspace builders are available.\n", query))
} else {
sb.WriteString("- Treat matched knowledge briefings as the primary dynamic surface for this thread; use the ranked context below as supporting operator state.\n")
for _, item := range briefings {
sb.WriteString(fmt.Sprintf("- %s\n", item.Title))
}
}
sb.WriteString("\n## Selected Context\n")
sb.WriteString("The sections below favor stable operator surfaces and canonical runtime artifacts before recency-heavy history.\n\n")
sb.WriteString(renderRankedIntelSectionFromBundle(bundle, "startup", 4000))
sb.WriteString("\n## Excluded By Default\n")
for _, bullet := range codexStartupExclusionBullets() {
sb.WriteString(fmt.Sprintf("- %s\n", bullet))
}
path := filepath.Join(cwd, ".agents", "ao", "codex", "startup-context.md")
if err := atomicWriteFile(path, []byte(sb.String()), 0o600); err != nil {
return "", err
}
return path, nil
}
func countGlobMatches(pattern string) int {
matches, err := filepath.Glob(pattern)
if err != nil {
return 0
}
return len(matches)
}
func collectCodexCaptureHealth(cwd string) codexCaptureHealth {
result := codexCaptureHealth{
SessionsIndexed: countGlobMatches(filepath.Join(cwd, storage.DefaultBaseDir, storage.SessionsDir, "*.jsonl")),
PendingKnowledge: countGlobMatches(filepath.Join(cwd, ".agents", "knowledge", "pending", "*.md")),
PendingQuarantine: countGlobMatches(filepath.Join(cwd, ".agents", "knowledge", "pending", ".quarantine", "*.md")),
}
if lastForge := findLastForgeTime(cwd); !lastForge.IsZero() {
result.LastForgeTime = lastForge.UTC().Format(time.RFC3339)
result.LastForgeAge = formatDurationBrief(time.Since(lastForge))
}
return result
}
func collectCodexRetrievalHealth(cwd string) codexRetrievalHealth {
repoFilter := filepath.Base(cwd)
if root := findGitRoot(cwd); root != "" {
repoFilter = filepath.Base(root)
}
nextWork, _ := readUnconsumedItems(filepath.Join(cwd, ".agents", "rpi", "next-work.jsonl"), repoFilter)
return codexRetrievalHealth{
Learnings: countGlobMatches(filepath.Join(cwd, ".agents", "learnings", "*.md")),
Patterns: countGlobMatches(filepath.Join(cwd, ".agents", "patterns", "*.md")),
Findings: countGlobMatches(filepath.Join(cwd, ".agents", SectionFindings, "*.md")),
NextWork: len(nextWork),
Briefings: countGlobMatches(filepath.Join(cwd, ".agents", "briefings", "*.md")),
Research: countGlobMatches(filepath.Join(cwd, ".agents", SectionResearch, "*.md")),
}
}
func collectCodexPromotionHealth(cwd string) codexPromotionHealth {
p := pool.NewPool(cwd)
pending, _ := p.List(pool.ListOptions{Status: types.PoolStatusPending})
staged, _ := p.List(pool.ListOptions{Status: types.PoolStatusStaged})
rejected, _ := p.List(pool.ListOptions{Status: types.PoolStatusRejected})
return codexPromotionHealth{
PendingPool: len(pending),
StagedPool: len(staged),
RejectedPool: len(rejected),
}
}
func collectCodexCitationHealth(cwd string, days int) codexCitationHealth {
result := codexCitationHealth{WindowDays: days}
citations, err := ratchet.LoadCitations(cwd)
if err != nil {
return result
}
end := time.Now()
start := end.AddDate(0, 0, -days)
var filtered []types.CitationEvent
for _, citation := range citations {
citation = normalizeCitationEventForRuntime(cwd, citation)
if citation.CitedAt.Before(start) || citation.CitedAt.After(end) {
continue
}
if !isRetrievableArtifactPath(cwd, citation.ArtifactPath) {
continue
}
filtered = append(filtered, citation)
result.Total++
switch canonicalCitationType(citation.CitationType) {
case "applied":
result.Applied++
case "reference":
result.Reference++
default:
result.Retrieved++
}
}
aggregate := buildCitationAggregate(cwd, filtered)
result.Deduped = aggregate.DedupedEvents
result.UniqueArtifacts = aggregate.UniqueArtifacts
result.UniqueSessions = aggregate.UniqueSessions
result.UniqueWorkspaces = aggregate.UniqueWorkspaces
return result
}
func outputCodexStartResult(result codexStartResult) error {
if GetOutput() == "json" {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(result)
}
fmt.Println("Codex Start")
fmt.Println("===========")
fmt.Printf("Mode: %s (%s)\n", result.Runtime.Mode, result.Runtime.Runtime)
if result.Runtime.ThreadName != "" {
fmt.Printf("Thread: %s\n", result.Runtime.ThreadName)
}
fmt.Printf("Startup context: %s\n", result.StartupContextPath)
if result.MemoryPath != "" {
fmt.Printf("Memory: %s\n", result.MemoryPath)
}
if result.CloseLoop != nil {
fmt.Printf("Maintenance: ingest=%d promote=%d reward=%d\n",
result.CloseLoop.Ingest.Added, result.CloseLoop.AutoPromote.Promoted, result.CloseLoop.CitationFeedback.Rewarded)
}
fmt.Println()
printNamedItems("Briefings", result.Briefings, func(item codexArtifactRef) string { return firstLine(item.Title) })
printNamedItems("Learnings", result.Learnings, func(item learning) string { return firstLine(item.Title) })
printNamedItems("Patterns", result.Patterns, func(item pattern) string { return firstLine(item.Name) })
printNamedItems("Findings", result.Findings, func(item knowledgeFinding) string { return firstLine(item.Title) })
printNamedItems("Next Work", result.NextWork, func(item nextWorkItem) string { return firstLine(item.Title) })
printNamedItems("Research", result.Research, func(item codexArtifactRef) string { return firstLine(item.Title) })
return nil
}
func outputCodexEnsureStartResult(result codexEnsureStartResult) error {
if GetOutput() == "json" {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(result)
}
fmt.Println("Codex Ensure Start")
fmt.Println("==================")
fmt.Printf("Mode: %s (%s)\n", result.Runtime.Mode, result.Runtime.Runtime)
if result.Runtime.ThreadName != "" {
fmt.Printf("Thread: %s\n", result.Runtime.ThreadName)
}
if result.SessionID != "" {
fmt.Printf("Session: %s\n", result.SessionID)
}
fmt.Printf("Performed: %t\n", result.Performed)
if result.Reason != "" {
fmt.Printf("Reason: %s\n", result.Reason)
}
if result.StartupContextPath != "" {
fmt.Printf("Startup context: %s\n", shortenPath(result.StartupContextPath))
}
if result.MemoryPath != "" {
fmt.Printf("Memory: %s\n", shortenPath(result.MemoryPath))
}
return nil
}
func outputCodexStopResult(result codexStopResult) error {
if GetOutput() == "json" {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(result)
}
fmt.Println("Codex Stop")
fmt.Println("==========")
fmt.Printf("Mode: %s (%s)\n", result.Runtime.Mode, result.Runtime.Runtime)
fmt.Printf("Transcript: %s\n", shortenPath(result.TranscriptPath))
fmt.Printf("Source: %s\n", result.TranscriptSource)
if result.SyntheticTranscript {
fmt.Println("Transcript mode: synthesized from Codex history.jsonl")
}
fmt.Printf("Session: %s\n", result.Session.SessionID)
fmt.Printf("Learnings: %d extracted, %d rejected\n", result.Session.LearningsExtracted, result.Session.LearningsRejected)
if result.Session.HandoffWritten != "" {
fmt.Printf("Handoff: %s\n", shortenPath(result.Session.HandoffWritten))
}
if result.CloseLoop != nil {
fmt.Printf("Close-loop: ingest=%d promote=%d reward=%d\n",
result.CloseLoop.Ingest.Added, result.CloseLoop.AutoPromote.Promoted, result.CloseLoop.CitationFeedback.Rewarded)
}
return nil
}
func outputCodexEnsureStopResult(result codexEnsureStopResult) error {
if GetOutput() == "json" {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(result)
}
fmt.Println("Codex Ensure Stop")
fmt.Println("=================")
fmt.Printf("Mode: %s (%s)\n", result.Runtime.Mode, result.Runtime.Runtime)
if result.Runtime.ThreadName != "" {
fmt.Printf("Thread: %s\n", result.Runtime.ThreadName)
}
if result.SessionID != "" {
fmt.Printf("Session: %s\n", result.SessionID)
}
fmt.Printf("Performed: %t\n", result.Performed)
if result.Reason != "" {
fmt.Printf("Reason: %s\n", result.Reason)
}
if result.TranscriptPath != "" {
fmt.Printf("Transcript: %s\n", shortenPath(result.TranscriptPath))
}
if result.TranscriptSource != "" {
fmt.Printf("Source: %s\n", result.TranscriptSource)
}
if result.SyntheticTranscript {
fmt.Println("Transcript mode: synthesized from Codex history.jsonl")
}
if result.HandoffPath != "" {
fmt.Printf("Handoff: %s\n", shortenPath(result.HandoffPath))
}
if result.MemoryPath != "" {
fmt.Printf("Memory: %s\n", shortenPath(result.MemoryPath))
}
return nil
}
func outputCodexStatusResult(result codexStatusResult) error {
if GetOutput() == "json" {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(result)
}
fmt.Println("Codex Lifecycle Status")
fmt.Println("======================")
fmt.Printf("Mode: %s (%s)\n", result.Runtime.Mode, result.Runtime.Runtime)
if result.Runtime.ThreadName != "" {
fmt.Printf("Thread: %s\n", result.Runtime.ThreadName)
}
fmt.Println()
fmt.Printf("Capture: sessions=%d pending=%d quarantine=%d\n",
result.Capture.SessionsIndexed, result.Capture.PendingKnowledge, result.Capture.PendingQuarantine)
if result.Capture.LastForgeAge != "" {
fmt.Printf("Last forge: %s ago\n", result.Capture.LastForgeAge)
}
fmt.Printf("Retrieval: learnings=%d patterns=%d findings=%d next-work=%d briefings=%d research=%d\n",
result.Retrieval.Learnings, result.Retrieval.Patterns, result.Retrieval.Findings, result.Retrieval.NextWork, result.Retrieval.Briefings, result.Retrieval.Research)
fmt.Printf("Promotion: pending=%d staged=%d rejected=%d\n",
result.Promotion.PendingPool, result.Promotion.StagedPool, result.Promotion.RejectedPool)
fmt.Printf("Citations (%dd): total=%d unique=%d retrieved=%d reference=%d applied=%d\n",
result.Citations.WindowDays, result.Citations.Total, result.Citations.UniqueArtifacts,
result.Citations.Retrieved, result.Citations.Reference, result.Citations.Applied)
if result.Flywheel != nil {
sign := "+"
if result.Flywheel.Velocity < 0 {
sign = ""
}
fmt.Printf("Flywheel: %s (%s%.3f/week)\n", result.Flywheel.Status, sign, result.Flywheel.Velocity)
}
if result.State != nil {
if result.State.LastStart != nil {
fmt.Printf("Last start: %s\n", result.State.LastStart.Timestamp)
}
if result.State.LastStop != nil {
fmt.Printf("Last stop: %s\n", result.State.LastStop.Timestamp)
}
}
return nil
}
func printNamedItems[T any](heading string, items []T, label func(T) string) {
fmt.Printf("%s:\n", heading)
if len(items) == 0 {
fmt.Println(" - none")
return
}
for _, item := range items {
fmt.Printf(" - %s\n", label(item))
}
}