diff --git a/README.md b/README.md
index f4e98b0f986657d367d4e7b2837cfef4d92c661a..41e07b6edfb8e82ac6c9a86c8f4ba041d08f3e5d 100644
--- a/README.md
+++ b/README.md
@@ -16,10 +16,29 @@ Native Cuttlefish 'Hunks' are given access to a DOM/div element, making them nic
 
 'aye, but as the legends state: software doth make the hardware singeth'
 
+ok, I want to chart a path through this ... I need to
+ - load programs,
+ - load a program that speaks to nautilus
+  - (and then) load a nautilus program that speaks to ponyo
+  - then I'm on trax for ponyo dev, that's ok
+  - I think I can hit all of these steps today ... nt soon,
+  - it's probably worth some time at that point to organize the net-via-net-via-view issue? this problem as it goes ...
+
+once I'm back at ponyo, wakeup, I'll minmax some pnp time to make the headboards, and a stepper
+
+ -> view
+  - could save some headache, place contextmenu in top-level dom, not on plane? makes some sense
+  - on hunk reload ... sending a new def ... links not retained ? 
+
  -> typeset
   - do name -> names: ['float64', 'number'], for same byte-cast for colloquial type cast ... i.e. uint8 and byte, ? what else ? is it worth it, or just copy pasta ? should also be lists of things that can be hooked up !
 
- -> with programs, prototype a bootstrap that loads cuttlefish and waits ... then loads a program there ? 
+  what of these hunks that will autoload each time, the bootstraps?
+  ... np, fam, when we send a request to the manager to add them,
+  managers should just reply w/ an error - we have paths for that
+  this is a bug we can iron out later and ignore
+
+ -> with programs, prototype a bootstrap that loads cuttlefish and waits ... then loads a program there ?
 
 maybe this is something of a JAMTOC moment ... the view stores and manipulates represenations, we only need a minimum set of messages to load that representation remotely
 
diff --git a/gogetter.js b/gogetter.js
index 79c1bd6973e84e719d2657cd73e7448a4fd26510..0f5613ad81920291d4a49b6ed7abb0c0cb24ecb0 100644
--- a/gogetter.js
+++ b/gogetter.js
@@ -1,119 +1,123 @@
 // fs abstraction for sys
 
 function GoGetter() {
-    this.findHunks = (debug) => {
-        return new Promise((resolve, reject) => {
-            let htmlTreeDiver = (response) => {
-                // do we try to pick links out of this plaintext ? like a monkey ?
-                // I suppose we do
-                // header, for names
-                let hfront = response.indexOf('<h1>Index of /hunks') + 14
-                let hback = response.indexOf('</h1>')
-                let header = response.slice(hfront, hback)
-                if (debug) console.log('DIVE:', header);
-                let igot = unreturned.indexOf(header)
-                if (igot != -1) {
-                    //console.log('return success')
-                    unreturned.splice(igot, 1)
-                }
-
-                // git those paths (these aren't names, are they?)
-                let paths = response.split('<a href="/hunks/')
-                // rm first two, and last ()
-                paths = paths.slice(2) //
-
-                paths.forEach((path, index) => {
-                    let end = path.indexOf('"')
-                    //console.log('index', index, 'end', end)
-                    paths[index] = path.slice(0, end)
-                })
-
-                paths.forEach((path, index) => {
-                    if (path[path.length - 1] == '/') {
-                        //console.log('folder', path)
-                        let recurse = 'hunks/' + path
-                        //console.log('getting', recurse)
-                        unreturned.push(recurse)
-                        jQuery.get(recurse, htmlTreeDiver)
-                    } else if (path.includes('.js')) {
-                        //console.log('likely hunk', path)
-                        // secrets are rming .js
-                        path = path.slice(0, path.indexOf('.'))
-                        if (path === 'hunks' || path === 'manager' || path === 'template' || path.includes('hidden/')) {
-                            // don't add these special hunks
-                        } else {
-                            returned.push(path)
-                        }
-                    }
-                })
-
-                if (unreturned.length === 0) {
-                    // TODO cull hunks and hidden paths ...
-                    // now, writing menu options for each path
-                    // sort alphabetically
-                    returned.sort()
-                    //console.log('GG returns this', JSON.parse(JSON.stringify(returned)))
-                    resolve(returned)
-                }
-            }
-
-            let unreturned = new Array()
-            let returned = new Array()
-            unreturned.push('hunks/')
-            jQuery.get('hunks/', htmlTreeDiver)
+  // I'm keeping this here because GoGetter is localized to the environment, mgr is not
+  this.interpreterName = 'cuttlefish'
+  this.interpreterVersion = 'v0.1'
+
+  this.recursivePathSearch = (root, extension, debug) => {
+    return new Promise((resolve, reject) => {
+      let htmlTreeDiver = (response) => {
+        // do we try to pick links out of this plaintext ? like a monkey ?
+        // I suppose we do
+        // header, for names
+        let faceString = '<h1>Index of /' + root
+        if (debug) console.log('facestring', faceString)
+        let hfront = response.indexOf(faceString) + 14
+        let hback = response.indexOf('</h1>')
+        let header = response.slice(hfront, hback)
+        if (debug) console.log('DIVE:', header);
+        let igot = unreturned.indexOf(header)
+        if (igot != -1) {
+          //console.log('return success')
+          unreturned.splice(igot, 1)
+        }
+
+        // git those paths (these aren't names, are they?)
+        let paths = response.split('<a href="/' + root + '/')
+        // rm first two, and last ()
+        paths = paths.slice(2) //
+
+        paths.forEach((path, index) => {
+          let end = path.indexOf('"')
+          if (debug) console.log('index', index, 'end', end)
+          paths[index] = path.slice(0, end)
         })
-    }
-
-    // https://github.com/tc39/proposal-dynamic-import
-    this.importSource = (url) => {
-        // escape characters that are used to delimit the module URL.
-        // this way the following module works: 'data:text/javascript,console.log("hello")'
-        url = url.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
-
-        return new Promise((resolve, reject) => {
-            const script = document.createElement("script")
-            const tempGlobal = "__tempModuleLoadingVariable" + Math.random().toString(32).substring(2)
-
-            function cleanup() {
-                delete window[tempGlobal]
-                script.remove()
-            }
 
-            window[tempGlobal] = function(module) {
-                cleanup()
-                //console.log('ADDHUNK (2) import resolves', url)
-                resolve(module[Object.keys(module)[0]])
+        paths.forEach((path, index) => {
+          if (path[path.length - 1] == '/') {
+            //console.log('folder', path)
+            let recurse = root + '/' + path
+            //console.log('getting', recurse)
+            unreturned.push(recurse)
+            jQuery.get(recurse, htmlTreeDiver)
+          } else if (path.includes(extension)) {
+            //console.log('likely hunk', path)
+            // secrets are rming .js
+            path = path.slice(0, path.indexOf('.'))
+            if (path === 'hunks' || path === 'manager' || path === 'template' || path.includes('hidden/')) {
+              // don't add these special hunks
+            } else {
+              returned.push(path)
             }
-
-            script.type = "module"
-            script.textContent = `import * as m from "${url}"; window.${tempGlobal}(m);`
-
-            script.onerror = () => {
-                reject(new Error("Failed to load module script with URL " + url))
-                cleanup()
-            }
-
-            document.documentElement.appendChild(script)
-        })
-    }
-
-    this.getJson = (path) => {
-        return new Promise((resolve, reject) => {
-            $.ajax({
-            	url: path,
-            	type: 'GET',
-            	success: (data) => {
-            		resolve(data)
-            	},
-            	error: (err) => {
-            		reject(new Error("failure at GG ajax get for json object: program probably doesn't exist"))
-            	}
-            })
+          }
         })
-    }
 
-    // I'm keeping this here because GoGetter is localized to the environment, mgr is not
-    this.interpretername = 'cuttlefish 0.1'
+        if (unreturned.length === 0) {
+          // TODO cull hunks and hidden paths ...
+          // now, writing menu options for each path
+          // sort alphabetically
+          returned.sort()
+          //console.log('GG returns this', JSON.parse(JSON.stringify(returned)))
+          resolve(returned)
+        }
+      }
+
+      let unreturned = new Array()
+      let returned = new Array()
+      unreturned.push(root + '/')
+      jQuery.get(root + '/', htmlTreeDiver)
+    })
+  }
+
+  // https://github.com/tc39/proposal-dynamic-import
+  this.importSource = (url) => {
+    // escape characters that are used to delimit the module URL.
+    // this way the following module works: 'data:text/javascript,console.log("hello")'
+    url = url.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
+
+    return new Promise((resolve, reject) => {
+      const script = document.createElement("script")
+      const tempGlobal = "__tempModuleLoadingVariable" + Math.random().toString(32).substring(2)
+
+      function cleanup() {
+        delete window[tempGlobal]
+        script.remove()
+      }
+
+      window[tempGlobal] = function(module) {
+        cleanup()
+        //console.log('ADDHUNK (2) import resolves', url)
+        resolve(module[Object.keys(module)[0]])
+      }
+
+      script.type = "module"
+      script.textContent = `import * as m from "${url}"; window.${tempGlobal}(m);`
+
+      script.onerror = () => {
+        reject(new Error("Failed to load module script with URL " + url))
+        cleanup()
+      }
+
+      document.documentElement.appendChild(script)
+    })
+  }
+
+  this.getJson = (path) => {
+    return new Promise((resolve, reject) => {
+      $.ajax({
+        url: path,
+        type: 'GET',
+        success: (data) => {
+          resolve(data)
+        },
+        error: (err) => {
+          reject(new Error("failure at GG ajax get for json object: program probably doesn't exist"))
+        }
+      })
+    })
+  }
+
 }
 
 export default GoGetter
diff --git a/hunks/manager.js b/hunks/manager.js
index cb89f5f2cdebded5b95c9f1059c1c631f9b9f961..1eb02e4f4edd6db2efdac77afd605f44bf109641 100644
--- a/hunks/manager.js
+++ b/hunks/manager.js
@@ -1,4 +1,4 @@
-// heart of the fish ... 
+// heart of the fish ...
 
 import {
   Hunkify,
@@ -19,7 +19,7 @@ import GoGetter from '../gogetter.js'
 function Manager() {
   Hunkify(this, 'Manager')
   // need this tool
-  let GG = new GoGetter
+  let gg = new GoGetter
 
   let msgsin = new Input('byteArray', 'msgs')
   let msgsout = new Output('byteArray', 'msgs')
@@ -42,7 +42,7 @@ function Manager() {
   // for now, managers take callback paths to pipe data back through ?
   let getListOfAvailableComponents = () => {
     return new Promise((resolve, reject) => {
-      GG.findHunks().then((list) => {
+      gg.recursivePathSearch('hunks', '.js').then((list) => {
         resolve(list)
       }).catch((err) => {
         reject(err)
@@ -103,8 +103,8 @@ function Manager() {
     console.log('ok, from path', path)
 
     return new Promise((resolve, reject) => {
-      GG.importSource(path).then((src) => {
-        if (addHunkVerbose) console.log('GG importing source resolves', src)
+      gg.importSource(path).then((src) => {
+        if (addHunkVerbose) console.log('gg importing source resolves', src)
         try {
           let hunk = sourceToHunk(src, hunkName, id, state)
           hunks.push(hunk)
@@ -168,7 +168,7 @@ function Manager() {
     }
 
     // if the hunk has a dom, and we have a view, add it ...
-    if (hunk.dom !== null || hunk.dom !== undefined) {
+    if (hunk.dom !== null && hunk.dom !== undefined) {
       // this is only allowed in the tlview, and we manage that...
       let tlv = hunks.find((cnd) => {
         return cnd.id === 'TLView'
@@ -377,7 +377,8 @@ function Manager() {
         case MK.REQDESCRIBESELF:
           resp.push(MK.BRIEF)
           MSGS.writeTo(resp, this.id, 'string')
-          MSGS.writeTo(resp, GG.interpretername, 'string')
+          MSGS.writeTo(resp, gg.interpreterName, 'string')
+          MSGS.writeTo(resp, gg.interpreterVersion, 'string')
           MSGS.writeTo(resp, hunks.length, 'uint32')
           MSGS.writeTo(resp, writeLinkList().length, 'uint32')
           writeMessage(resp)
@@ -418,14 +419,21 @@ function Manager() {
         case MK.REQADDHUNK:
           // pull the rest out,
           // unknown-len types return with return.item and return.increment
-          let strname = MSGS.readFrom(msg, 1, 'string').item
+          let reqaddinc = 1
+          let strname = MSGS.readFrom(msg, reqaddinc, 'string')
+          reqaddinc += strname.increment
+          strname = strname.item
+          let strid = undefined
+          if(reqaddinc < msg.length) {
+            strid = MSGS.readFrom(msg, reqaddinc, 'string').item
+          }
           // then do,
           // a meta comment is that this add promise doesn't fail for
           // things like path-loading errors, that would be inside of gogetter.js
           // i.e. pulling a hunk loads it into that import script hack, that just
           // gets evaluated into the dom ...
           console.log('manager to add', strname)
-          this.addHunk(strname).then((hunk) => {
+          this.addHunk(strname, strid).then((hunk) => {
             console.log('successfully added hunk', hunk)
             // serialize
             resp.push(MK.HUNKALIVE)
diff --git a/hunks/view.js b/hunks/view.js
index 7789920e1b8477a5081e25cbb3b2376c1b329ec2..c64a1d878fcf63dcccc1ecc5cc254488f64d0313 100644
--- a/hunks/view.js
+++ b/hunks/view.js
@@ -235,12 +235,10 @@ function View() {
     })
 
     this.addContextOption('load a patch', (evt) => {
-      $(evt.target).append(' loading a list...')
-      patchset.findPatches()
+      patchset.findPatches(evt)
     })
 
     this.addContextOption('save this patch', (evt) => {
-      $(evt.target).append(' > input for the name > ')
       patchset.saveCurrent(evt, true)
     })
     // writeMessage([MK.REQLISTAVAIL])
@@ -617,10 +615,12 @@ function View() {
     let mt = {}
     let match = $(this.plane).find('#' + def.id).get(0)
     let menu = $(this.plane).children('.contextmenu').get(0)
-    if (match !== undefined) {
+    if (match) {
       // we have one already, we are likely updating it
+      // we need to be more careful about this
+      msgbox.write(`received new definition for the hunk with id "${def.id}", replacing that...`)
+      // need to carefully walk outputs to replace,
       mt = dt.readTransform(match)
-      $(match).remove()
     } else if (menu !== undefined) {
       mt = dt.readTransform(menu)
     } else if (def.id === "NROL39_0") { // TEMPORARY until better management with force layout
@@ -646,27 +646,45 @@ function View() {
     // write the def dom
     let de = dt.writeDefDom(def, true)
 
-    // if it's in the ref-to-add
-    let native = cuttlefishHunkRef.find((hnk) => {
-      return hnk.id === def.id
-    })
+    // later, we can walk for similar outputs, to maintain those links
+    if (match) {
+      // poll new outputs, replace with old outputs (these contain link information, should retain)
+      let newOtps = $(de).children('.outputs').children('.output')
+      for(let notp of newOtps){
+        let equiv = $(match).children('.outputs').children('#' + notp.id).get(0)
+        if(equiv){
+          msgbox.write(`maintaining output for ${equiv.id}`)
+          $(de).children('.outputs').children('#' + notp.id).replaceWith(equiv)
+        } else {
+          msgbox.write(`no equivalent output for ${equiv.id}, adding that`)
+        }
+      }
+      $(match).remove()
+    } else {
+      // shouldn't have to do this for refreshing descriptions...
+      // if it's in the ref-to-add
+      let native = cuttlefishHunkRef.find((hnk) => {
+        return hnk.id === def.id
+      })
 
-    if (native !== undefined) {
-      console.log("trying to add native hunk's dom")
-      try {
-        $(de).append($(native.dom).addClass('cuttlefishhunkdom'))
-        if ($(native.dom).is('.view')) {
-          de.style.height = '800px'
-          de.style.width = '1200px'
-          // leader on starting to reize these ...
-          $(de).append($('<div>').addClass('rsHandle').on('mousedown', (evt) => {
-            console.log('rshandle down')
-          }))
+      if (native !== undefined && native !== null) {
+        console.log("trying to add native hunk's dom: native:", native)
+        try {
+          $(de).append($(native.dom).addClass('cuttlefishhunkdom'))
+          if ($(native.dom).is('.view')) {
+            de.style.height = '800px'
+            de.style.width = '1200px'
+            // leader on starting to reize these ...
+            $(de).append($('<div>').addClass('rsHandle').on('mousedown', (evt) => {
+              console.log('rshandle down')
+            }))
+          }
+        } catch (err) {
+          msgbox.write(`native hunk attach fails ${err}`)
         }
-      } catch (err) {
-        msgbox.write(`native hunk attach fails ${err}`)
       }
     }
+
     //
     dt.writeTransform(de, mt)
     // rm menu if it's around
@@ -755,9 +773,10 @@ function View() {
     writeMessage([MK.HELLO])
   }
 
-  this.requestAddHunk = (name) => {
+  this.requestAddHunk = (name, id) => {
     let msg = [MK.REQADDHUNK]
     MSGS.writeTo(msg, name, 'string')
+    if (id) MSGS.writeTo(msg, id, 'string')
     writeMessage(msg)
   }
 
@@ -900,13 +919,18 @@ function View() {
           let intrprtrnm = MSGS.readFrom(msg, bi, 'string')
           bi += intrprtrnm.increment
           brief.interpreterName = intrprtrnm.item
+          let intrprtrv = MSGS.readFrom(msg, bi, 'string')
+          bi += intrprtrv.increment
+          brief.interpreterVersion = intrprtrv.item
           brief.numHunks = MSGS.readFrom(msg, bi, 'uint32')
           brief.numLinks = MSGS.readFrom(msg, bi + 5, 'uint32')
+          this.interpreterName = brief.interpreterName
+          this.interpreterVersion = brief.interpreterVersion
           msgbox.briefState.setFromBrief(brief)
           break
         case MK.LISTOFAVAIL:
           let stringlist = MSGS.readListFrom(msg, 1, 'string')
-          this.changeContextTitle('list of available:')
+          this.changeContextTitle('available hunks:')
           for (let item of stringlist) {
             this.addContextOption(item, (evt) => {
               let msg = [MK.REQADDHUNK]
@@ -920,6 +944,8 @@ function View() {
           console.log('hunk alive, going to deserialize')
           let def = defBySerial(msg, 1)
           putDef(def)
+          patchset.onHunkLoaded(def)
+          // bfstate should mixin to vptches
           msgbox.briefState.decrementHunks()
           break
         case MK.HUNKSTATECHANGE:
@@ -939,6 +965,7 @@ function View() {
         case MK.LINKALIVE:
           let alal = MSGS.readListFrom(msg, 1, 'string')
           putLink(alal[0], alal[1], alal[2], alal[3])
+          patchset.onLinkLoaded()
           msgbox.briefState.decrementLinks()
           break
         case MK.LINKREMOVED:
diff --git a/programs/linktest.json b/programs/linktest.json
deleted file mode 100644
index 383d995054dc2e39169f9ee3ee66d6570a290858..0000000000000000000000000000000000000000
--- a/programs/linktest.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
-    "programname": "linktest",
-    "hunks": [
-    {
-        "name": "input/string",
-        "id": "String_X"
-    },
-    {
-        "name": "interface/logger",
-        "id": "Logger_Uno"
-    },
-    {
-        "name": "interface/logger",
-        "id": "Logger_Duo"
-    },
-    {
-        "name": "link",
-        "id": "link_one"
-    },
-    {
-        "name": "comm/websocketclient",
-        "id": "wsclient"
-    }],
-    "links": [
-    {
-        "outhunk": "String_X",
-        "outname": "string",
-        "inhunk": "Logger_Uno",
-        "inname": "tolog"
-    },
-    {
-        "outhunk": "link_one",
-        "outname": "bytes",
-        "inhunk": "wsclient",
-        "inname": "bytes"
-    },
-    {
-        "outhunk": "wsclient",
-        "outname": "bytes",
-        "inhunk": "link_one",
-        "inname": "bytes"
-    },
-    {
-        "outhunk": "String_X",
-        "outname": "string",
-        "inhunk": "link_one",
-        "inname": "zero"
-    },
-    {
-        "outhunk": "link_one",
-        "outname": "one",
-        "inhunk": "Logger_Duo",
-        "inname": "tolog"
-    }]
-}
\ No newline at end of file
diff --git a/programs/ptest.json b/programs/ptest.json
new file mode 100644
index 0000000000000000000000000000000000000000..bd114b60d46c9b0ce922bee3e161857b163db932
--- /dev/null
+++ b/programs/ptest.json
@@ -0,0 +1 @@
+{"interpreterName":"cuttlefish","interpreterVersion":"v0.1","hunks":[{"id":"NROL39_0","name":"manager"},{"id":"TLView","name":"view"},{"id":"hnk_3","name":"view"},{"id":"hnk_2","name":"link","state":[{"name":"inputList","type":"string","value":"mgrMsgs (byteArray), num (number)"},{"name":"outputList","type":"string","value":"mgrMsgs (byteArray)"}]}],"links":[{"outhunk":"NROL39_0","outname":"msgs","inhunk":"TLView","inname":"msgs"},{"outhunk":"TLView","outname":"msgs","inhunk":"NROL39_0","inname":"msgs"},{"outhunk":"hnk_3","outname":"msgs","inhunk":"hnk_2","inname":"data"},{"outhunk":"hnk_2","outname":"data","inhunk":"hnk_3","inname":"msgs"}]}
\ No newline at end of file
diff --git a/programs/llink.json b/scratch/llink.json
similarity index 100%
rename from programs/llink.json
rename to scratch/llink.json
diff --git a/programs/mvnv.json b/scratch/mvnv.json
similarity index 100%
rename from programs/mvnv.json
rename to scratch/mvnv.json
diff --git a/programs/ntlink.json b/scratch/ntlink.json
similarity index 100%
rename from programs/ntlink.json
rename to scratch/ntlink.json
diff --git a/programs/wstest.json b/scratch/wstest.json
similarity index 100%
rename from programs/wstest.json
rename to scratch/wstest.json
diff --git a/view/vmsg.js b/view/vmsg.js
index 48accca2f11af6bf16bfed595eac67d56c12926b..418cfcec6df3d21885d10c8213d251d846941170 100644
--- a/view/vmsg.js
+++ b/view/vmsg.js
@@ -13,6 +13,7 @@ function MessageBox(View) {
     numLinksLeft: 0,
     setFromBrief: function(brief) {
       this.recipId = brief.interpreterId
+      this.recipVer = brief.interpreterVersion
       this.recipName = brief.interpreterName
       this.numHunksLeft = brief.numHunks
       this.numLinksLeft = brief.numLinks
@@ -37,9 +38,9 @@ function MessageBox(View) {
     postToDom: function() {
       let str
       if (this.numHunksLeft > 0 || this.numLinksLeft > 0) {
-        str = `manager id: ${this.recipId} <br>interpreter: ${this.recipName} <br> awaiting ${this.numHunksLeft} hunks and ${this.numLinksLeft} links`
+        str = `manager id: ${this.recipId} <br>interpreter: ${this.recipName} ${this.recipVer} <br> awaiting ${this.numHunksLeft} hunks and ${this.numLinksLeft} links`
       } else {
-        str = `manager id: ${this.recipId} <br>interpreter: ${this.recipName} <br> all loaded OK`
+        str = `manager id: ${this.recipId} <br>interpreter: ${this.recipName} ${this.recipVer} <br> all loaded OK`
       }
       $(themsgbox).find('#titleBox').html(str)
     }
diff --git a/view/vptch.js b/view/vptch.js
index a711a9a74a491fc39bda18363f7ef18f1c60da87..5c1b8a5e4df95fc3e080869640bc435dbe1c5310 100644
--- a/view/vptch.js
+++ b/view/vptch.js
@@ -1,31 +1,116 @@
 // patches are programs that are *incomplete without you*
 
-function PatchSet(View, MsgBox){
+import GoGetter from '../../gogetter.js'
+
+function PatchSet(View, MsgBox) {
   let view = View
   let msgbox = MsgBox
+  let gg = new GoGetter()
 
   this.init = () => {
     msgbox.write('hello from patchset')
   }
 
-  // the issue you're worrying about is:
-  /*
-  what of these hunks that will autoload each time, the bootstraps?
-  ... np, fam, when we send a request to the manager to add them,
-  managers should just reply w/ an error - we have paths for that
-  this is a bug we can iron out later and ignore
-  */
+  // load from server should be assumed, just rip that *baybie*
+  this.findPatches = (evt) => {
+    // and then,
+    $(evt.target).append(' > loading a list ...')
+    gg.recursivePathSearch('programs', '.json', true).then((list) => {
+      console.log('returns list', list)
+      // title, and options
+      view.changeContextTitle('available patches:')
+      // HERE NOW WRITE EM UUUUP VERY SIMPLE
+      for (let item of list) {
+        view.addContextOption(item, (evt) => {
+          try {
+            this.loadPatch(item)
+          } catch (err) {
+            msgbox.write('caught an error while starting program load')
+          }
+          $(view.plane).find('.contextmenu').remove()
+        })
+      }
+    })
+  }
+
+  let unloadedHunks = []
+  let unloadedStates = [] 
+  let unloadedLinks = []
+
+  let reqNextHunk = () => {
+    // from 0th position in array
+    view.requestAddHunk(unloadedHunks[0].name, unloadedHunks[0].id)
+  }
+
+  // callbacks,
+  this.onHunkLoaded = (def) => {
+    // not interested,
+    if(unloadedHunks.length < 1) return true
+    // find in list, rm
+    let place = unloadedHunks.findIndex((cand) => {
+      return (cand.id === def.id && cand.name === def.name)
+    })
+    if(place !== -1) {
+      if(place !== 0) console.error("watch out of order loading for programs... shouldn't be like that but it do")
+      unloadedHunks.shift()
+      msgbox.write(`patchset placed ${def.id}, ${unloadedHunks.length} hunks remaining`)
+      if(unloadedHunks.length < 1){
+        msgbox.write(`patchset loaded all hunks, now updating state`)
+      } else {
+        reqNextHunk()
+      }
+    } else {
+      console.error(`hunk not found in unloaded hunks, ${def.id}`)
+    }
+    // if place, else bad news ...
+    // HERE
+    // ...
+    // and when complete, load first link
+  }
+
+  // try for a one-at-a-time cycle,
+  this.loadHunkList = (list) => {
+
+  }
+
+  this.onLinkLoaded = (outId, outName, inId, inName) => {
+    // find in list, rm,
+  }
+
+  this.loadPatch = (name) => {
+    msgbox.write(`ok, loading a patch from: ${name}`)
+    gg.getJson('/programs/' + name + '.json').then((patch) => {
+      console.log('the patch', patch)
+      if (patch.interpreterName !== view.interpreterName) {
+        msgbox.write(`WARN: loading patch built in a different interpreter... some hunks may not exist: patch for: "${patch.interpreterName}", but view is connected to "${view.interpreterName}"`)
+      }
+      if (patch.interpreterVersion !== view.interpreterVersion) {
+        msgbox.write(`WARN: loading patch built in a different version of the interpreter... patch from "${patch.interpreterVersion}" and manager is running "${view.interpreterVersion}"`)
+      }
+      unloadedHunks = patch.hunks
+      unloadedLinks = patch.links
+      // kick it off by sending this message,
+      reqNextHunk()
+      // continue loading ... write a bootload of messages, in queu, waiting for each response?
+    }).catch((err) => {
+      console.error(err)
+      msgbox.write(`could not load program from: ${name}, caught an error from json load, see the console`)
+    })
+  }
+
   this.saveCurrent = (evt, debug) => {
-    if(debug) console.log('saving ...')
+    if (debug) console.log('saving ...')
     // riperoni ok
     let patch = {
+      interpreterName: gg.interpreterName,
+      interpreterVersion: gg.interpreterVersion,
       hunks: [],
       links: []
     }
     // js, u wyld
-    for(let hnk of $(view.plane).children('.block')){
+    for (let hnk of $(view.plane).children('.block')) {
       // dom is truth
-      if(debug) console.log('hnk', hnk)
+      if (debug) console.log('hnk', hnk)
       let name = $(hnk).children('.blockid').find('span').text()
       name = name.substring(1, name.length - 1)
       let phnk = {
@@ -33,20 +118,20 @@ function PatchSet(View, MsgBox){
         name: name
       }
       let state = []
-      for(let st of $(hnk).children('.state').children('.stateItem')){
+      for (let st of $(hnk).children('.state').children('.stateItem')) {
         // text is faithful,
         let text = $(st).find('p').text()
         let name = text.substring(0, text.indexOf(' '))
         let type = text.substring(text.indexOf('(') + 1, text.indexOf(')'))
-        if(debug) console.log('state: name', `"${name}"`, 'type', `"${type}"`)
+        if (debug) console.log('state: name', `"${name}"`, 'type', `"${type}"`)
         // the value... (typing on program saves? not if we JSON ...)
         let value
-        if(type === 'boolean'){
+        if (type === 'boolean') {
           let vstring = $(st).find('span').text()
           vstring = vstring.substring(vstring.indexOf('(') + 1, vstring.indexOf(')'))
-          if(vstring === 'true'){
+          if (vstring === 'true') {
             value = true
-          } else if (vstring === 'false'){
+          } else if (vstring === 'false') {
             value = false
           } else {
             console.error('error saving boolean value, setting to false')
@@ -57,23 +142,23 @@ function PatchSet(View, MsgBox){
         } else {
           // must be some kind of number,
           value = parseFloat($(st).find('input').val())
-        }// end if-on-types sequence
+        } // end if-on-types sequence
         state.push({
           name: name,
           type: type,
           value: value
         })
       } // end roll over states,
-      if(state.length > 0){
+      if (state.length > 0) {
         phnk.state = state
       }
       patch.hunks.push(phnk)
       // now roll over links in the hunk, to write outputs
-      for(let otp of $(hnk).children('.outputs').children('.output')){
-        if(debug) console.log('and output', otp)
+      for (let otp of $(hnk).children('.outputs').children('.output')) {
+        if (debug) console.log('and output', otp)
         let outId = otp.id.substring(0, otp.id.indexOf('_output_'))
         let outName = otp.id.substring(otp.id.indexOf('_output_') + 8)
-        for(let conn of otp.connectedTo){
+        for (let conn of otp.connectedTo) {
           let inId = conn.substring(1, conn.indexOf('_input_'))
           let inName = conn.substring(conn.indexOf('_input_') + 7)
           patch.links.push({
@@ -86,23 +171,25 @@ function PatchSet(View, MsgBox){
       } // end loop over outputs, for links ...
     } // end loop over hunks
     // we have this now,
-    if(debug) console.log('a patch', patch)
+    if (debug) console.log('a patch', patch)
     // prompt for name? ... via the (evt) on the callback ??
     $(evt.target).text('')
-    let tinput = $('<input>').attr('type', 'text').attr('size', 24).attr('value', 'patch').get(0)
+    let tinput = $('<input>').attr('type', 'text').attr('size', 24).attr('value', 'patchName').get(0)
     $(evt.target).append(tinput) // etc
     $(tinput).focus()
     $(tinput).select()
     $(tinput).on('keyup', (evt) => {
-      if(evt.keyCode == 13){
-        console.log('yar, ', tinput.value + '.json')
+      if (evt.keyCode == 13) {
+        if (debug) console.log('yar, ', tinput.value + '.json')
         let bleb = JSON.stringify(patch)
-        console.log('tryit...')
-        let url = URL.createObjectURL(new Blob([JSON.stringify(patch)], {type: "application/json"}))
+        if (debug) console.log('tryit...')
+        let url = URL.createObjectURL(new Blob([JSON.stringify(patch)], {
+          type: "application/json"
+        }))
         //window.location.href = url
-        console.log('url', url)
-        let anchor = $('<a>ok</a>').attr('href', url).attr('download', tinput.value+ '.json').get(0)
-        console.log(anchor)
+        if (debug) console.log('url', url)
+        let anchor = $('<a>ok</a>').attr('href', url).attr('download', tinput.value + '.json').get(0)
+        if (debug) console.log(anchor)
         $(evt.target).append(anchor)
         anchor.click()
         // finally, rip
@@ -113,15 +200,6 @@ function PatchSet(View, MsgBox){
     // should name it, and ID it for the interpeter ?
   }
 
-  // load from server should be assumed, just rip that *baybie*
-  this.findPatches = () => {
-    msgbox.write('would look for list')
-  }
-
-  this.loadPatch = (name) => {
-
-  }
-
 }
 
 export default PatchSet