package cli import ( "fmt" "github.com/spf13/cobra" ) // newMemoryCmd turns note storage on for a project, or off. // // A command rather than a configuration key for the same reason threads are: // keeping what an agent decided to remember is a decision about data, not about // deployment, and it should look like an act rather than a default nobody read. func newMemoryCmd(open opener) *cobra.Command { var ( project string hours int off bool ) cmd := &cobra.Command{ Use: "memory", Short: "Keep notes an agent writes for itself, across conversations", Long: "With this on, an agent can save and search notes through /v1/memory or the\n" + "MCP tools at /mcp (remember, recall, forget), and find them again in later\n" + "conversations.\n\n" + "Off for every project until this is run. The retention is required: notes\n" + "expire that many hours after they were last written, so a store nobody\n" + "chose a number for does not keep everything forever.", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { if !off && hours <= 0 { return fmt.Errorf("--retain-hours is required: say how long notes are kept, or pass --off") } s, err := open(cmd.Context()) if err != nil { return err } defer s.Close() keep := hours if off { keep = 0 } if err := s.SetMemoryRetention(cmd.Context(), project, keep); err != nil { return err } if keep == 0 { fmt.Fprintf(cmd.OutOrStdout(), "%s keeps no notes. Existing ones are removed at the next prune.\n", project) return nil } fmt.Fprintf(cmd.OutOrStdout(), "%s keeps notes for %d hours after they were last written.\n", project, keep) return nil }, } cmd.Flags().StringVar(&project, "project", "default", "project id") cmd.Flags().IntVar(&hours, "retain-hours", 0, "how long a note is kept after it was last written") cmd.Flags().BoolVar(&off, "off", false, "stop keeping notes for this project") return cmd }