Index: /trunk/ppSub/src/ppSubArguments.c
===================================================================
--- /trunk/ppSub/src/ppSubArguments.c	(revision 23234)
+++ /trunk/ppSub/src/ppSubArguments.c	(revision 23235)
@@ -30,5 +30,5 @@
     fprintf(stderr, "\nPan-STARRS PSF-matched image subtraction\n\n");
     fprintf(stderr, "Usage: %s INPUT.fits REFERENCE.fits OUTPUT_ROOT \n"
-            "\t[-psf REFERENCE.psf.fits] [-sources REFERENCE.cmf]\n\n"
+            "\t[-psf REFERENCE.psf.fits]\n\n"
             "This subtracts the convolved REFERENCE from the INPUT, by default.\n",
             program);
@@ -205,11 +205,11 @@
     }
 
-    pmConfigFileSetsMD(config->arguments, &argc, argv, "PPSUB.SOURCES", "-sources", NULL);
-
     psMetadata *arguments = config->arguments; // Command-line arguments
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-inmask", 0, "Input mask image", NULL);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-invariance", 0, "Input variance image", NULL);
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-insources", 0, "Input source list", NULL);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-refmask", 0, "Reference mask image", NULL);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-refvariance", 0, "Reference variance image", NULL);
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-refsources", 0, "Reference source list", NULL);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-stats", 0, "Statistics file", NULL);
     psMetadataAddF32(arguments, PS_LIST_TAIL, "-region", 0, "Size of iso-kernel region", NAN);
@@ -272,4 +272,8 @@
         fileList("INPUT.VARIANCE", inVariance, "Name of the input variance image", config);
     }
+    const char *inSources = psMetadataLookupStr(NULL, arguments, "-insources"); // Name of input source list
+    if (inSources && strlen(inSources) > 0) {
+        fileList("INPUT.SOURCES", inSources, "Name of the input source list", config);
+    }
 
     const char *refMask = psMetadataLookupStr(NULL, arguments, "-refmask"); // Name of reference mask
@@ -280,4 +284,8 @@
     if (refVariance && strlen(refVariance) > 0) {
         fileList("REF.VARIANCE", refVariance, "Name of the reference variance image", config);
+    }
+    const char *refSources = psMetadataLookupStr(NULL, arguments, "-refsources"); // Name of ref source list
+    if (refSources && strlen(refSources) > 0) {
+        fileList("REF.SOURCES", refSources, "Name of the reference source list", config);
     }
 
Index: /trunk/ppSub/src/ppSubCamera.c
===================================================================
--- /trunk/ppSub/src/ppSubCamera.c	(revision 23234)
+++ /trunk/ppSub/src/ppSubCamera.c	(revision 23235)
@@ -40,5 +40,5 @@
     pmFPAfile *inputMask = pmFPAfileBindFromArgs(&status, input, config, "PPSUB.INPUT.MASK", "INPUT.MASK");
     if (!status) {
-        psError (PS_ERR_UNKNOWN, false, "Failed to load file definition PPSUB.INPUT.MASK");
+        psError(PS_ERR_UNKNOWN, false, "Failed to load file definition PPSUB.INPUT.MASK");
         return NULL;
     }
@@ -51,9 +51,20 @@
     pmFPAfile *inputVariance = pmFPAfileBindFromArgs(&status, input, config, "PPSUB.INPUT.VARIANCE", "INPUT.VARIANCE");
     if (!status) {
-        psError (PS_ERR_UNKNOWN, false, "Failed to load file definition PPSUB.INPUT.VARIANCE");
+        psError(PS_ERR_UNKNOWN, false, "Failed to load file definition PPSUB.INPUT.VARIANCE");
         return NULL;
     }
     if (inputVariance && inputVariance->type != PM_FPA_FILE_VARIANCE) {
         psError(PS_ERR_IO, true, "PPSUB.INPUT.VARIANCE is not of type VARIANCE");
+        return false;
+    }
+
+    // Input source list
+    pmFPAfile *inputSources = pmFPAfileBindFromArgs(&status, input, config, "PPSUB.INPUT.SOURCES", "INPUT.SOURCES");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "Failed to load file definition PPSUB.INPUT.SOURCES");
+        return NULL;
+    }
+    if (inputSources && inputSources->type != PM_FPA_FILE_CMF) {
+        psError(PS_ERR_IO, true, "PPSUB.INPUT.SOURCES is not of type CMF");
         return false;
     }
@@ -74,5 +85,5 @@
     pmFPAfile *refMask = pmFPAfileBindFromArgs(&status, ref, config, "PPSUB.REF.MASK", "REF.MASK");
     if (!status) {
-        psError (PS_ERR_UNKNOWN, false, "Failed to load file definition PPSUB.REF.MASK");
+        psError(PS_ERR_UNKNOWN, false, "Failed to load file definition PPSUB.REF.MASK");
         return NULL;
     }
@@ -85,9 +96,20 @@
     pmFPAfile *refVariance = pmFPAfileBindFromArgs(&status, ref, config, "PPSUB.REF.VARIANCE", "REF.VARIANCE");
     if (!status) {
-        psError (PS_ERR_UNKNOWN, false, "Failed to load file definition PPSUB.REF.VARIANCE");
+        psError(PS_ERR_UNKNOWN, false, "Failed to load file definition PPSUB.REF.VARIANCE");
         return NULL;
     }
     if (refVariance && refVariance->type != PM_FPA_FILE_VARIANCE) {
         psError(PS_ERR_IO, true, "PPSUB.REF.VARIANCE is not of type VARIANCE");
+        return false;
+    }
+
+    // Reference source list
+    pmFPAfile *refSources = pmFPAfileBindFromArgs(&status, ref, config, "PPSUB.REF.SOURCES", "REF.SOURCES");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "Failed to load file definition PPSUB.REF.SOURCES");
+        return NULL;
+    }
+    if (refSources && refSources->type != PM_FPA_FILE_CMF) {
+        psError(PS_ERR_IO, true, "PPSUB.REF.SOURCES is not of type CMF");
         return false;
     }
@@ -241,20 +263,4 @@
     outKernels->save = true;
 
-#if 0
-    if (!pmFPAAddSourceFromFormat(output->fpa, "Subtraction", output->format)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to generate output FPA.");
-        return false;
-    }
-#endif
-
-    pmFPAfile *sources = pmFPAfileDefineFromArgs(&status, config, "PPSUB.SOURCES", "PPSUB.SOURCES");
-    if (!status) {
-        psError(PS_ERR_IO, false, "Failed to load file definition PPSUB.SOURCES");
-        return false;
-    }
-    if (sources && sources->type != PM_FPA_FILE_CMF) {
-        psError(PS_ERR_IO, true, "PPSUB.SOURCES is not of type CMF");
-        return false;
-    }
 
     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSim
Index: /trunk/ppSub/src/ppSubMakePSF.c
===================================================================
--- /trunk/ppSub/src/ppSubMakePSF.c	(revision 23234)
+++ /trunk/ppSub/src/ppSubMakePSF.c	(revision 23235)
@@ -81,6 +81,5 @@
     // Extract the loaded sources from the associated readout, and generate PSF
     // Here, we assume the image is background-subtracted
-    pmReadout *sourcesRO = pmFPAfileThisReadout(config->files, view, "PPSUB.SOURCES");
-    psArray *sources = psMetadataLookupPtr(&mdok, sourcesRO->analysis, "PSPHOT.SOURCES");
+    psArray *sources = psMetadataLookupPtr(&mdok, minuend->analysis, "PSPHOT.SOURCES");
     if (!psphotReadoutFindPSF(config, view, sources)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry on subtracted image.");
Index: /trunk/ppSub/src/ppSubMatchPSFs.c
===================================================================
--- /trunk/ppSub/src/ppSubMatchPSFs.c	(revision 23234)
+++ /trunk/ppSub/src/ppSubMatchPSFs.c	(revision 23235)
@@ -50,9 +50,30 @@
 
     // Sources in image, used for stamps: these must be loaded from previous analysis stages
-    pmReadout *sourcesRO = pmFPAfileThisReadout(config->files, view, "PPSUB.SOURCES"); // Readout with sources
-    psArray *sources = NULL;            // Sources in image; used for stamps
-    if (sourcesRO) {
-        sources = psMetadataLookupPtr(&mdok, sourcesRO->analysis, "PSPHOT.SOURCES");
+    psArray *inSources = psMetadataLookupPtr(&mdok, inRO->analysis, "PSPHOT.SOURCES"); // Input source list
+    psArray *refSources = psMetadataLookupPtr(&mdok, refRO->analysis, "PSPHOT.SOURCES"); // Ref source list
+
+    psArray *sources = NULL;            // Merged list of sources
+    if (inSources && refSources) {
+        float radius = psMetadataLookupF32(NULL, recipe, "SOURCE.RADIUS"); // Matching radius
+        psArray *lists = psArrayAlloc(2); // Source lists
+        lists->data[0] = psMemIncrRefCounter(inSources);
+        lists->data[1] = psMemIncrRefCounter(refSources);
+        sources = pmSourceMatchMerge(lists, radius);
+        psFree(lists);
+        if (!sources) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to merge source lists");
+            return false;
+        }
+    } else if (inSources) {
+        sources = psMemIncrRefCounter(inSources);
+    } else if (refSources) {
+        sources = psMemIncrRefCounter(refSources);
     }
+
+    psMetadataAddArray(inConv->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_META_REPLACE,
+                       "Merged source list", sources);
+    psMetadataAddArray(refConv->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_META_REPLACE,
+                       "Merged source list", sources);
+    psFree(sources);                    // Drop reference
 
     int footprint = psMetadataLookupS32(NULL, recipe, "STAMP.FOOTPRINT"); // Stamp half-size
