diff --git a/.gitignore b/.gitignore
index 1c908f4e7aa524e7e6db11e200e66785904bad7e..37bec31ad4e16a0912958f4fede2c304b5005649 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,3 +46,16 @@ docs/_build
 /workflow-all/workflow-jobs/src/main/resources/edu/nrao/archive/workflow/scripts/open-permissions.sh
 /archiveIface/archiveIface/webpack/stats.json
 /git-info.txt
+develop-eggs
+build/metadata
+#**/build/**
+apps/**/build/**
+services/**/build/**
+shared/**/build/**
+projects_checklist.txt
+.installed.cfg
+.ipynb_checkpoints
+deps.png
+build/pkgs
+eggs
+parts
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..79d404658d21dd65b7f8ba54abcc1c23d91e20be
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,17 @@
+all: ${HOME}/miniconda3 ${HOME}/miniconda3/envs/data metadata build
+
+${HOME}/miniconda3:
+	@echo Please install miniconda to ${HOME}/miniconda3
+	@exit 1
+
+${HOME}/miniconda3/envs/data: environment.yml
+	conda env update
+	touch $@
+
+.PHONY: metadata
+metadata:
+	buildout parts=gen_metadata
+
+.PHONY: build
+build:
+	buildout parts=build_pkgs name=all
diff --git a/apps/cli/executables/alma_product_fetch/__init__.py b/apps/cli/executables/alma_product_fetch/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/alma_product_fetch/build/lib/alma_product_fetch/__init__.py b/apps/cli/executables/alma_product_fetch/build/lib/alma_product_fetch/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/alma_product_fetch/src/alma_product_fetch/__init__.py b/apps/cli/executables/alma_product_fetch/src/alma_product_fetch/__init__.py
index 2cc3af47341604e9d3345553baa30478c04f6b12..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/apps/cli/executables/alma_product_fetch/src/alma_product_fetch/__init__.py
+++ b/apps/cli/executables/alma_product_fetch/src/alma_product_fetch/__init__.py
@@ -1,11 +0,0 @@
-r"""
-    An import of the Joint Alma Observatories listfiles.py into the AAT/PPI system.
-
-    Given an MOUS Status UID (the most common identifier for a processing unit),
-    perform a database query to obtain the list of files required for a restore
-    and proceed to obtain them from the NAASC NGAS machines.
-
-    Initially written to use wget, this is rewritten to use requests and to
-    attempt to validate the data retrieved.
-
-"""
diff --git a/apps/cli/executables/alma_product_fetch/src/alma_product_fetch/commands.py b/apps/cli/executables/alma_product_fetch/src/alma_product_fetch/commands.py
index d33bf4fcd98d8acd25b05fc23ab34d0dbe13a619..1470cda6f651d355baa82984cfb482ffbe533b0e 100644
--- a/apps/cli/executables/alma_product_fetch/src/alma_product_fetch/commands.py
+++ b/apps/cli/executables/alma_product_fetch/src/alma_product_fetch/commands.py
@@ -10,7 +10,7 @@ import cx_Oracle as almadb
 import requests
 import sys
 from ._version import ___version___ as version
-from pymygdala import LogHandler
+from pymygdala.models import LogHandler
 from pycapo import CapoConfig
 
 """
diff --git a/apps/cli/executables/alma_reingester/__init__.py b/apps/cli/executables/alma_reingester/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/alma_reingester/build/lib/alma_reingester/__init__.py b/apps/cli/executables/alma_reingester/build/lib/alma_reingester/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/alma_reingester/setup.py b/apps/cli/executables/alma_reingester/setup.py
index 1793c98dc75dd7ff5871075aae26d4354542e553..5bb5b7593ee937a9145c708962abb67b6cfd1050 100644
--- a/apps/cli/executables/alma_reingester/setup.py
+++ b/apps/cli/executables/alma_reingester/setup.py
@@ -16,7 +16,7 @@ setup(
     author_email='dms-ssa@nrao.edu',
     url='TBD',
     license="GPL",
-    install_requires=['cx-Oracle', 'pycapo', 'psycopg2', 'events', 'schema'],
+    install_requires=['cx_Oracle', 'pycapo', 'psycopg2', 'events', 'schema'],
     keywords=[],
     packages=['alma_reingester'],
     package_dir={'':'src'},
diff --git a/apps/cli/executables/datafetcher/__init__.py b/apps/cli/executables/datafetcher/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/datafetcher/build/lib/datafetcher/__init__.py b/apps/cli/executables/datafetcher/build/lib/datafetcher/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/datafetcher/conda/meta.yaml b/apps/cli/executables/datafetcher/conda/meta.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f4c722b7b212e60a6d05b1525ac4817b05535bff
--- /dev/null
+++ b/apps/cli/executables/datafetcher/conda/meta.yaml
@@ -0,0 +1,48 @@
+{% set name = "datafetcher" %}
+{% set version = "4.0.0a1.dev1" %}
+
+package:
+  name: "{{ name|lower }}"
+  version: "{{ version }}"
+
+build:
+  entry_points:
+    - datafetcher = work.datafetcher.commands:main
+  script: {{ PYTHON }} setup.py develop
+
+source:
+  path: ../../apps/cli/executables/datafetcher
+#  - path: ../../apps/cli/executables/datafetcher/src/datafetcher
+
+requirements:
+  build:
+    - python==3.8
+    - pika>=1.1,<2
+    - pycapo>=0.3.0,<1.0
+    - beautifulsoup4>=4.9.1,<5.0
+    - lxml>=4.3.2,<5.0
+    - psycopg2>=2.8.5,<3.0
+    - pyopenssl>=19.1.0,<20.0
+    - requests>=2.23,<3.0
+  run:
+    - python==3.8
+#    - pika>=1.1,<2
+#    - pycapo>=0.3.0,<1.0
+#    - beautifulsoup4>=4.9.1,<5.0
+#    - lxml>=4.3.2,<5.0
+#    - psycopg2>=2.8.5,<3.0
+#    - pyopenssl>=19.1.0,<20.0
+#    - requests>=2.23,<3.0
+
+#test:
+#  source_files:
+#    - test/
+#  requires:
+#    - pytest>=5.4,<6.0
+#  commands:
+#    - pytest -vv --log-level=DEBUG --showlocals test/datafetcher_test.py
+
+about:
+  license: "GPL"
+  license_family: "GPL"
+  summary: "NRAO Archive Data Fetcher Script"
\ No newline at end of file
diff --git a/apps/cli/executables/datafetcher/docs/source/__init__.py b/apps/cli/executables/datafetcher/docs/source/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/datafetcher/setup.py b/apps/cli/executables/datafetcher/setup.py
index fd16588d5f295c997903b517f77ad4427e75cfdc..84415da77099fcd47dcf8120dd31be7b8a1f0b1c 100644
--- a/apps/cli/executables/datafetcher/setup.py
+++ b/apps/cli/executables/datafetcher/setup.py
@@ -9,29 +9,17 @@ VERSION = open('_version.py').readlines()[-1].split()[-1].strip("\"'")
 README = Path('README.md').read_text()
 
 requires = [
-    'pika==1.1.0',
-    'pycapo==0.2.1post1',
-    'bs4==0.0.1',
-    'beautifulsoup4==4.9.1',
-    'lxml==4.3.2',
-    'psycopg2==2.8.5',
-    'pyinstaller==3.2',
-    'pyopenssl=19.1.0',
-    'tox==3.1.3',
-    'tox-pyenv==1.1.0'
+    'pika>=1.1,<2',
+    'pycapo>=0.3.0,<1.0',
+    'beautifulsoup4>=4.9.1,<5.0',
+    'lxml>=4.3.2,<5.0',
+    'psycopg2>=2.8.5,<3.0',
+    'pyopenssl>=19.1.0,<20.0',
+    'requests>=2.23,<3.0'
 ]
 
 tests_require = [
-    'bs4==0.0.1',
-    'beautifulsoup4==4.9.1',
-    'psycopg2==2.8.5',
-    'pyopenssl=19.1.0',
-    'pyinstaller==3.2',
-    'pytest==5.4',
-    'pytest-runner==4.2',
-    'tox==3.1.3',
-    'tox-pyenv==1.1.0',
-
+    'pytest>=5.4,<6.0'
 ]
 setup(
     name=Path().absolute().name,
@@ -42,7 +30,8 @@ setup(
     author_email='dms-ssa@nrao.edu',
     url='TBD',
     license="GPL",
-    install_requires=['requests', 'pycapo'],
+    install_requires=requires,
+    tests_require=tests_require,
     keywords=[],
     packages=['datafetcher'],
     package_dir={'':'src'},
diff --git a/apps/cli/executables/datafetcher/test/testing_utils.py b/apps/cli/executables/datafetcher/test/testing_utils.py
index c4a03556e6cb1602dfb308d5272640a75ca4a49b..91be50e9e317d3bc92b0580ba4d58e461f0a082d 100644
--- a/apps/cli/executables/datafetcher/test/testing_utils.py
+++ b/apps/cli/executables/datafetcher/test/testing_utils.py
@@ -9,11 +9,11 @@ from pathlib import Path
 
 from pycapo import CapoConfig
 
-from src.datafetcher.errors import \
+from datafetcher.errors import \
     MissingSettingsException, NoProfileException
-from src.datafetcher.locations_report import \
+from datafetcher.locations_report import \
     LocationsReport
-from src.datafetcher.utilities import \
+from datafetcher.utilities import \
     REQUIRED_SETTINGS, get_arg_parser, \
     ExecutionSite
 
diff --git a/apps/cli/executables/epilogue/__init__.py b/apps/cli/executables/epilogue/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/epilogue/setup.py b/apps/cli/executables/epilogue/setup.py
index 0acc5ade106d493e3ce4c4ad13cae1bd5cf3618b..02c96229be89ae431d8b75a8f882eb4c22339807 100644
--- a/apps/cli/executables/epilogue/setup.py
+++ b/apps/cli/executables/epilogue/setup.py
@@ -4,7 +4,7 @@
 from pathlib import Path
 from setuptools import setup, find_packages
 
-VERSION = open('src/_version.py').readlines()[-1].split()[-1].strip("\"'")
+VERSION = open('src/epilogue/_version.py').readlines()[-1].split()[-1].strip("\"'")
 README = Path('README.md').read_text()
 
 setup(
diff --git a/apps/cli/executables/ingestion/__init__.py b/apps/cli/executables/ingestion/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/ingestion/build/lib/ingestion/__init__.py b/apps/cli/executables/ingestion/build/lib/ingestion/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/ingestion/src/ingestion/__init__.py b/apps/cli/executables/ingestion/src/ingestion/__init__.py
index a6179fe25dc37f26ff86ad760223a46a23d9c094..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/apps/cli/executables/ingestion/src/ingestion/__init__.py
+++ b/apps/cli/executables/ingestion/src/ingestion/__init__.py
@@ -1,15 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from .metadata import *
-from .files import *
-
-import numpy
-from psycopg2.extensions import register_adapter, AsIs
-def addapt_numpy_float32(numpy_float32):
-    return AsIs(numpy_float32)
-register_adapter(numpy.float32, addapt_numpy_float32)
-
-__all__ = ['SDM', 'SDMTable', 'SDMBinaryTable', 'buildtable',
-           'ngasstatus', 'archivefile', 'retrievefile',
-           'ingest', 'ingestBDF', 'ingestSDM', 'ingestmetadata']
diff --git a/apps/cli/executables/ingestion/src/ingestion/archive.py b/apps/cli/executables/ingestion/src/ingestion/archive.py
index 2a853878a0b577bb79caa5751e02186aa900378b..78bd082599c8453611d6e8b902822200ab5f1d35 100644
--- a/apps/cli/executables/ingestion/src/ingestion/archive.py
+++ b/apps/cli/executables/ingestion/src/ingestion/archive.py
@@ -6,7 +6,7 @@ import sys
 from pycapo import CapoConfig
 import logging
 from pathlib import Path
-from _version import ___version___ as _version
+from ._version import ___version___ as _version
 
 from pymygdala import LogHandler, SendNRAOEvent
 from . import evlasciencedatamodel as sc
diff --git a/apps/cli/executables/ingestion/src/ingestion/files/__init__.py b/apps/cli/executables/ingestion/src/ingestion/files/__init__.py
index de1913b47c78ab91bc23473ea77b637c8895b8df..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/apps/cli/executables/ingestion/src/ingestion/files/__init__.py
+++ b/apps/cli/executables/ingestion/src/ingestion/files/__init__.py
@@ -1,7 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from ..files.ngasclient import ngasstatus, archivefile, retrievefile
-from ..files.ingestobs import ingest, ingestBDF, ingestSDM, ingestmetadata
-
-__all__ = ['ngasstatus', 'archivefile', 'retrievefile',
-           'ingest', 'ingestBDF', 'ingestSDM', 'ingestmetadata']
\ No newline at end of file
diff --git a/apps/cli/executables/ingestion/src/ingestion/metadata/__init__.py b/apps/cli/executables/ingestion/src/ingestion/metadata/__init__.py
index 9bcc1f9160dd04d2509e37e2385ddaef5a7dabb7..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/apps/cli/executables/ingestion/src/ingestion/metadata/__init__.py
+++ b/apps/cli/executables/ingestion/src/ingestion/metadata/__init__.py
@@ -1,5 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from ..metadata.sciencemodel import SDM, SDMTable, SDMBinaryTable, buildtable
-
-__all__ = ['SDM', 'SDMTable', 'SDMBinaryTable', 'buildtable', ]
diff --git a/apps/cli/executables/vlba_grabber/__init__.py b/apps/cli/executables/vlba_grabber/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/vlba_grabber/build/lib/vlba_grabber/__init__.py b/apps/cli/executables/vlba_grabber/build/lib/vlba_grabber/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/vlba_grabber/src/vlba_grabber/ngas_retriever.py b/apps/cli/executables/vlba_grabber/src/vlba_grabber/ngas_retriever.py
index db9040c44342729d03dafb626c24b1375f52a37c..ce19c874b96cc6f0f128d542907070ad00050060 100644
--- a/apps/cli/executables/vlba_grabber/src/vlba_grabber/ngas_retriever.py
+++ b/apps/cli/executables/vlba_grabber/src/vlba_grabber/ngas_retriever.py
@@ -12,7 +12,7 @@ import argparse as ap
 import logging
 import logging.handlers
 
-from _version import ___version___ as version
+from ._version import ___version___ as version
 from pymygdala import LogHandler
 from pycapo import CapoConfig
 from bs4 import BeautifulSoup
diff --git a/apps/cli/executables/weblog_thumbs/__init__.py b/apps/cli/executables/weblog_thumbs/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/executables/weblog_thumbs/build/lib/weblog_thumbs/__init__.py b/apps/cli/executables/weblog_thumbs/build/lib/weblog_thumbs/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/launchers/pymygdala/__init__.py b/apps/cli/launchers/pymygdala/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/launchers/pymygdala/build/lib/pymygdala/__init__.py b/apps/cli/launchers/pymygdala/build/lib/pymygdala/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/launchers/pymygdala/src/pymygdala/__init__.py b/apps/cli/launchers/pymygdala/src/pymygdala/__init__.py
index 2bd3604219860f21112fe39cf3c6f176e746f0bc..00924d7ae1576ee1f8b8352041ef0510f6f3ae37 100644
--- a/apps/cli/launchers/pymygdala/src/pymygdala/__init__.py
+++ b/apps/cli/launchers/pymygdala/src/pymygdala/__init__.py
@@ -6,4 +6,4 @@ Using this library you can log messages to RabbitMQ with a standard-isg logging
 Many (most?) of the defaults for things like routing keys, exchange names and CAPO properties are heavily NRAO-centric but you can order-ride them if you want.
 """
 
-from .models import (LogHandler, LogDumper, SendEvent, SendNRAOEvent, RPCEvent)
+from .models import (LogHandler, LogDumper, SendEvent, SendNRAOEvent, RPCEvent)
\ No newline at end of file
diff --git a/apps/cli/launchers/wf/__init__.py b/apps/cli/launchers/wf/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/launchers/wf/build/lib/wf/__init__.py b/apps/cli/launchers/wf/build/lib/wf/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/launchers/wf/setup.py b/apps/cli/launchers/wf/setup.py
index c496a495bde16d914d7bab603be7873b6da4f3d3..5e4539f7772b35ec947533333a8ebaba06d4484e 100644
--- a/apps/cli/launchers/wf/setup.py
+++ b/apps/cli/launchers/wf/setup.py
@@ -16,7 +16,7 @@ setup(
     author_email='dms-ssa@nrao.edu',
     url='TBD',
     license="GPL",
-    install_requires=['pika', 'psycopg2', 'cx-Oracle', 'pymygdala', 'pycapo', 'schema'],
+    install_requires=['pika', 'psycopg2', 'cx_Oracle', 'pymygdala', 'pycapo', 'schema'],
     keywords=[],
     packages=['wf'],
     package_dir={'':'src'},
diff --git a/apps/cli/launchers/wf/src/wf/__init__.py b/apps/cli/launchers/wf/src/wf/__init__.py
index d8682ebfd92bc138ac73a95631b62769d1076966..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/apps/cli/launchers/wf/src/wf/__init__.py
+++ b/apps/cli/launchers/wf/src/wf/__init__.py
@@ -1,3 +0,0 @@
-r""" wf: utility for running workflows
-"""
-from .commands import wf, WorkflowTracker
\ No newline at end of file
diff --git a/apps/cli/launchers/wf/src/wf/ingest_wf_interfaces.py b/apps/cli/launchers/wf/src/wf/ingest_wf_interfaces.py
index 917c70646ff565c05b8d099ec6cc24e56acbb33f..8fea4a90910b6db4408fd57e3b55de0f650de06f 100644
--- a/apps/cli/launchers/wf/src/wf/ingest_wf_interfaces.py
+++ b/apps/cli/launchers/wf/src/wf/ingest_wf_interfaces.py
@@ -11,7 +11,7 @@ import logging
 
 from . import wf, WorkflowTracker
 from pathlib import Path
-from _version import ___version___ as version
+from ._version import ___version___ as version
 from pycapo import CapoConfig
 from .ous_wf_interfaces import lookup_single_locator, lookup_project_code, lookup_eb_uid
 
diff --git a/apps/cli/launchers/wf/src/wf/ous_wf_interfaces.py b/apps/cli/launchers/wf/src/wf/ous_wf_interfaces.py
index c0aeb9d64b1b980ef72594f1f49ab3c9f45d9ed7..356a399b5f58599f7fcc54d64202fa344df6cbc6 100644
--- a/apps/cli/launchers/wf/src/wf/ous_wf_interfaces.py
+++ b/apps/cli/launchers/wf/src/wf/ous_wf_interfaces.py
@@ -8,7 +8,7 @@ import schema
 import argparse as ap
 import cx_Oracle as almadb
 
-from _version import ___version___ as version
+from ._version import ___version___ as version
 from datetime import datetime
 from pycapo import CapoConfig
 from pathlib import Path
diff --git a/apps/cli/launchers/wf/src/wf/utility_wf_interfaces.py b/apps/cli/launchers/wf/src/wf/utility_wf_interfaces.py
index 39fb57c9212d640f2929fd5aa3e3d6a2c65b6570..d8456c1594e8ae1807d934c7540007bfe3d0fbb9 100644
--- a/apps/cli/launchers/wf/src/wf/utility_wf_interfaces.py
+++ b/apps/cli/launchers/wf/src/wf/utility_wf_interfaces.py
@@ -4,7 +4,7 @@ import sys
 
 
 from . import wf
-from _version import ___version___ as version
+from ._version import ___version___ as version
 
 
 _RUN_QACLEAN_DESCRIPTION = """"""
diff --git a/apps/cli/utilities/datafinder/__init__.py b/apps/cli/utilities/datafinder/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/datafinder/build/lib/datafinder/__init__.py b/apps/cli/utilities/datafinder/build/lib/datafinder/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/datafinder/src/datafinder/datafinder.py b/apps/cli/utilities/datafinder/src/datafinder/datafinder.py
index 261ac31f279b29e40eb91d4ce8b22cbc2f27f9cc..c15d4c350786bc8784598cb247371234e5fbe631 100644
--- a/apps/cli/utilities/datafinder/src/datafinder/datafinder.py
+++ b/apps/cli/utilities/datafinder/src/datafinder/datafinder.py
@@ -26,7 +26,7 @@ from tqdm import tqdm
 
 import schema
 from .util import groups_of
-from schema import ScienceProduct, AncillaryProduct, Project
+from schema.model import ScienceProduct, AncillaryProduct, Project
 from schema.ngasmodel import NGASFile
 
 
diff --git a/apps/cli/utilities/datafinder/src/datafinder/missingbdfs.py b/apps/cli/utilities/datafinder/src/datafinder/missingbdfs.py
index 523ab9a2dee3b4351bb323b72b1a591896e71f57..899a1a8a01cab4b55a7b5512ccdc01d810ba6df9 100644
--- a/apps/cli/utilities/datafinder/src/datafinder/missingbdfs.py
+++ b/apps/cli/utilities/datafinder/src/datafinder/missingbdfs.py
@@ -11,7 +11,7 @@ from pandas import DataFrame
 
 import schema
 from .util import groups_of
-from schema import File
+from schema.model import File
 from schema.legacy_model import t_ngas_file_sets
 from schema.ngasmodel import NGASFile
 from sqlalchemy.sql import *
diff --git a/apps/cli/utilities/datafinder/src/datafinder/reconciler.py b/apps/cli/utilities/datafinder/src/datafinder/reconciler.py
index 9e5a8aac9958157923d58e065c8e478bbf77aa80..728eda1781b69506f6637e9c5a3c19c1c37f28dc 100644
--- a/apps/cli/utilities/datafinder/src/datafinder/reconciler.py
+++ b/apps/cli/utilities/datafinder/src/datafinder/reconciler.py
@@ -10,9 +10,9 @@ from schema.ngasmodel import NGASFile
 
 
 def main():
-    session = pyat.schema.create_session('SDM', profile='local')
-    ngas = pyat.schema.create_session('NGAS', profile='local')
-    legacy = pyat.schema.create_session('LEGACY', profile='local')
+    session = schema.create_session('SDM', profile='local')
+    ngas = schema.create_session('NGAS', profile='local')
+    legacy = schema.create_session('LEGACY', profile='local')
 
     print('loading SDMs from NGAS')
     sdm_query = select([NGASFile.file_id.label('ngas_id')])\
diff --git a/apps/cli/utilities/dumplogs/__init__.py b/apps/cli/utilities/dumplogs/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/dumplogs/build/lib/dumplogs/__init__.py b/apps/cli/utilities/dumplogs/build/lib/dumplogs/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/dumplogs/src/dumplogs/commands.py b/apps/cli/utilities/dumplogs/src/dumplogs/commands.py
index 72476086073f52b3e2b401702787bd7ecce35928..90ee4a525b2ee26de477ed81fa5d84809c7a9cb0 100644
--- a/apps/cli/utilities/dumplogs/src/dumplogs/commands.py
+++ b/apps/cli/utilities/dumplogs/src/dumplogs/commands.py
@@ -11,7 +11,7 @@ from blessings import Terminal
 from pycapo import CapoConfig
 from pytz import timezone
 
-from _version import ___version___ as version
+from ._version import ___version___ as version
 
 # Description of this widget.
 _DESCRIPTION = """Command line tool for dumping out AMQP logs for the AAT/PPI, version {}."""
diff --git a/apps/cli/utilities/faultchecker/__init__.py b/apps/cli/utilities/faultchecker/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/faultchecker/build/lib/faultchecker/__init__.py b/apps/cli/utilities/faultchecker/build/lib/faultchecker/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/faultchecker/src/faultchecker/__init__.py b/apps/cli/utilities/faultchecker/src/faultchecker/__init__.py
index ed09ba1c57251751702901465f47f4cdd4869021..127cd03ad62fb2a459cd494cb892fa1839a10c30 100644
--- a/apps/cli/utilities/faultchecker/src/faultchecker/__init__.py
+++ b/apps/cli/utilities/faultchecker/src/faultchecker/__init__.py
@@ -1 +1 @@
-from _version import ___version___ as version
\ No newline at end of file
+from ._version import ___version___ as version
\ No newline at end of file
diff --git a/apps/cli/utilities/mr_books/__init__.py b/apps/cli/utilities/mr_books/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/mr_books/build/lib/mr_books/__init__.py b/apps/cli/utilities/mr_books/build/lib/mr_books/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/mr_books/src/mr_books/__init__.py b/apps/cli/utilities/mr_books/src/mr_books/__init__.py
index 9bc18fa59bebc781b7d467412e7c6e0a328a53c4..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/apps/cli/utilities/mr_books/src/mr_books/__init__.py
+++ b/apps/cli/utilities/mr_books/src/mr_books/__init__.py
@@ -1 +0,0 @@
-from _version import ___version___ as version
diff --git a/apps/cli/utilities/mr_books/src/mr_books/commands.py b/apps/cli/utilities/mr_books/src/mr_books/commands.py
index aabe9484684526135bdbd778719b62161914181c..418bc5613f434fc6eedcbf34bd789e76da05da59 100644
--- a/apps/cli/utilities/mr_books/src/mr_books/commands.py
+++ b/apps/cli/utilities/mr_books/src/mr_books/commands.py
@@ -18,7 +18,7 @@ from sqlalchemy import create_engine, or_
 from sqlalchemy.orm import sessionmaker
 
 from pymygdala import SendNRAOEvent, LogHandler
-from _version import ___version___ as version
+from ._version import ___version___ as version
 from schema.model import ExecutionBlock
 from schema.ngasmodel import NGASFile, NGASDisk, NGASHost
 
diff --git a/apps/cli/utilities/mr_clean/__init__.py b/apps/cli/utilities/mr_clean/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/mr_clean/build/lib/mr_clean/__init__.py b/apps/cli/utilities/mr_clean/build/lib/mr_clean/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/mr_clean/src/mr_clean/__init__.py b/apps/cli/utilities/mr_clean/src/mr_clean/__init__.py
index 3688fc465f5538f20d7077732f69fdaa1949b5df..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/apps/cli/utilities/mr_clean/src/mr_clean/__init__.py
+++ b/apps/cli/utilities/mr_clean/src/mr_clean/__init__.py
@@ -1,18 +0,0 @@
-r""" mr_clean: AAT/PPI utility for periodically cleaning things up
-
-mr_clean cleans up:
-* the download directory
-* the spool directory
-* the temp directory
-
-This is configured through CAPO settings:
-* edu.nrao.archive.configuration.JanitorSettings.spoolDirectory, string
-* edu.nrao.archive.configuration.JanitorSettings.spoolDaysToKeep, int
-* edu.nrao.archive.configuration.JanitorSettings.tempDirectory, string
-* edu.nrao.archive.configuration.JanitorSettings.tempDaysToKeep, int
-* edu.nrao.archive.configuration.JanitorSettings.downloadDirectory, string
-* edu.nrao.archive.configuration.JanitorSettings.downloadDaysToKeep, int
-* edu.nrao.archive.configuration.JanitorSettings.enabled, (true, false)
-
-'enabled' is a boolean that controls whether mr_clean actually does anything or not, if it is set to false then the best mr_clean will do for you is parse the command line arguments, look at CAPO settings and tell you what settings it would have used.
-"""
\ No newline at end of file
diff --git a/apps/cli/utilities/mr_clean/src/mr_clean/commands.py b/apps/cli/utilities/mr_clean/src/mr_clean/commands.py
index 6c387e3db3314037cee2896810f61211e5e922b3..d35df9dc7d8c77cba50822e8eb9c2f80c5a8d858 100644
--- a/apps/cli/utilities/mr_clean/src/mr_clean/commands.py
+++ b/apps/cli/utilities/mr_clean/src/mr_clean/commands.py
@@ -12,7 +12,7 @@ import pendulum
 import time
 from pycapo import CapoConfig
 
-from _version import ___version___ as version
+from ._version import ___version___ as version
 from pymygdala import LogHandler, SendNRAOEvent
 
 _DESCRIPTION = """AAT/PPI request file/directory cleaner, version {}. Cleans up the spool directory and downloads area."""
diff --git a/apps/cli/utilities/proprietary_setter/__init__.py b/apps/cli/utilities/proprietary_setter/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/proprietary_setter/build/lib/proprietary_setter/__init__.py b/apps/cli/utilities/proprietary_setter/build/lib/proprietary_setter/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/proprietary_setter/src/proprietary_setter/commands.py b/apps/cli/utilities/proprietary_setter/src/proprietary_setter/commands.py
index afd893a0cb60b02b9077f8e4943a7503aaaf275d..ac62780b1725ca9e5e56c2171ae2d2a192a20ee6 100644
--- a/apps/cli/utilities/proprietary_setter/src/proprietary_setter/commands.py
+++ b/apps/cli/utilities/proprietary_setter/src/proprietary_setter/commands.py
@@ -14,7 +14,7 @@ import logging
 from astropy.time import Time
 from sqlalchemy import exc as sa_exc
 
-from _version import ___version___ as version
+from ._version import ___version___ as version
 from support.logging import get_console_logger, LOG_MESSAGE_FORMATTER
 from support.capo import get_my_capo_config
 from schema import create_session
diff --git a/apps/cli/utilities/qa_results/__init__.py b/apps/cli/utilities/qa_results/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/qa_results/build/lib/qa_results/__init__.py b/apps/cli/utilities/qa_results/build/lib/qa_results/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/qa_results/src/qa_results/__init__.py b/apps/cli/utilities/qa_results/src/qa_results/__init__.py
index a594901dfb5933483cf41031ff501aa654a1a249..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/apps/cli/utilities/qa_results/src/qa_results/__init__.py
+++ b/apps/cli/utilities/qa_results/src/qa_results/__init__.py
@@ -1,18 +0,0 @@
-r"""
-    A nice, clean command-line interface for the Data Analysts to
-    notify the newArchive of the PASS/FAIL status of CIPL run
-    results.
-
-    On a PASS: send an ArchiveEvent signifying that we
-        should run the calibration ingestion workflow
-
-    On a FAIL: send an ArchiveEvent signifying that the
-        data is no good, and should be marked as
-        DoNotCalibrate
-
-
-    In either case, the script needs to identify a fileSetId from the
-    subdirectory name in the QA2 directory (this is used by Amygdala to
-    uniquely identify the observation).
-
-"""
\ No newline at end of file
diff --git a/apps/cli/utilities/s_code_project_updater/__init__.py b/apps/cli/utilities/s_code_project_updater/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/cli/utilities/s_code_project_updater/build/lib/s_code_project_updater/__init__.py b/apps/cli/utilities/s_code_project_updater/build/lib/s_code_project_updater/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/build/recipes/build_pkgs/build_pkgs.py b/build/recipes/build_pkgs/build_pkgs.py
new file mode 100644
index 0000000000000000000000000000000000000000..ad50462f74a3f8ed847c85e21b000e999551bdde
--- /dev/null
+++ b/build/recipes/build_pkgs/build_pkgs.py
@@ -0,0 +1,50 @@
+import subprocess
+
+def get_pkg_list():
+    """
+    Run a couple shell commands to parse the metadata directory for its packages.
+    :return: List of packages in metadata directory
+    """
+    find_proc = subprocess.run(["find", "build/metadata",
+                                  "-name", "meta.yaml"],
+                                 stdout=subprocess.PIPE)
+    paths = find_proc.stdout.decode('utf-8')
+    fmt_paths = paths.replace("build/metadata/", "").replace("/meta.yaml", "")
+    return fmt_paths.split('\n')
+
+class Recipe:
+    def __init__(self, buildout, name, options):
+        """
+        Initializes fields needed for recipe.
+        :param buildout: (Boilerplate) Dictionary of options from buildout section
+        of buildout.cfg
+        :param name: (Boilerplate) Name of section that uses this recipe.
+        :param options: (Boilerplate) Options of section that uses this recipe.
+        """
+        self.name = name
+        self.options = options
+        self.pkg_list = get_pkg_list()
+
+    def install(self):
+        """
+        Install method that runs when recipe has components it needs to install.
+        :return: Paths to files, as strings, created by the recipe.
+        """
+        if self.options['name'] == "all":
+            pkgs = self.pkg_list
+        else:
+            pkgs = self.options['name'].split(',')
+
+        for p in pkgs:
+            if p not in self.pkg_list or p == '':
+                print("Package {} not valid. Skipping.".format(p))
+                continue
+            subprocess.run(["conda", "build", "build/metadata/{}".format(p), "--output-folder", "build/pkgs/"],
+                           stdout=subprocess.PIPE)
+        self.options.created("build/pkgs/")
+
+        subprocess.run(["python3", "build/tools/transfer_to_builder.py"])
+
+        return self.options.created()
+
+    update = install
\ No newline at end of file
diff --git a/build/recipes/build_pkgs/setup.py b/build/recipes/build_pkgs/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..db69c236a8a32ec6f0a16d2be9ca896b83df5875
--- /dev/null
+++ b/build/recipes/build_pkgs/setup.py
@@ -0,0 +1,8 @@
+from setuptools import setup
+
+setup(
+    name='build_pkgs',
+    version='0.1',
+    py_modules = ['build_pkgs'],
+    entry_points = {"zc.buildout": ["default=build_pkgs:Recipe"]},
+)
\ No newline at end of file
diff --git a/build/recipes/setup_to_meta/setup.py b/build/recipes/setup_to_meta/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..24ade227647ff5b327d2f7a892a04a6a98ea004e
--- /dev/null
+++ b/build/recipes/setup_to_meta/setup.py
@@ -0,0 +1,8 @@
+from setuptools import setup
+
+setup(
+    name='setup_to_meta',
+    version='0.1',
+    py_modules = ['setup_to_meta'],
+    entry_points = {"zc.buildout": ["default=setup_to_meta:Recipe"]},
+)
\ No newline at end of file
diff --git a/build/recipes/setup_to_meta/setup_to_meta.py b/build/recipes/setup_to_meta/setup_to_meta.py
new file mode 100644
index 0000000000000000000000000000000000000000..e26e4777b24cf0c638dc4cdba01eeff83f3d9278
--- /dev/null
+++ b/build/recipes/setup_to_meta/setup_to_meta.py
@@ -0,0 +1,228 @@
+import json
+
+import setuptools, importlib, subprocess, os, re
+
+PYTHON_VERSION = '3.8'
+
+def write_metafile(metadata, filepath):
+    """
+    Writes given metadata to file with given path.
+    """
+    try:
+        os.makedirs(filepath[:-10])
+    except FileExistsError:
+        pass
+
+    with open(filepath, 'w') as f:
+        f.write(metadata)
+
+
+class MetadataGenerator:
+    """
+    Uses given info extracted from setup.py file to fill out metadata template.
+    """
+
+    def __init__(self, setup, path):
+        self.setup = setup
+        self.path = path
+    
+    def fmt_ep(self):
+        """
+        Format entry points section of metadata.
+        :return: Formatted string if entry points exists; else empty string.
+        """
+        ep_string = ''
+        if 'entry_points' in self.setup.keys() and 'console_scripts' in self.setup['entry_points']:
+            ep_string += 'entry_points:\n'
+            for ep in self.setup['entry_points']['console_scripts']:
+                ep_string += '    - {}\n'.format(ep)
+            ep_string += '  '
+        return ep_string
+
+    def fmt_reqs(self):
+        """
+        Format requirements section of metadata.
+        :return: Formatted string if requirements exists; else empty string.
+        """
+        reqs_string = ''
+        reqs_list = ''
+        if 'install_requires' in self.setup.keys():
+            reqs_string += 'requirements:\n'
+            build_reqs = '  build:\n'
+            run_reqs = '  run:\n'
+            host_reqs = '  host:\n'
+            reqs_list += '    - python={}\n'.format(PYTHON_VERSION)
+            for req in self.setup['install_requires']:
+                reqs_list += '    - {}\n'.format(req)
+            reqs_string += build_reqs + reqs_list + \
+                           run_reqs + reqs_list + \
+                           host_reqs + reqs_list + \
+                           '\n'
+        return reqs_string
+
+    def fmt_test(self):
+        """
+        Format test section of metadata.
+        NOTE: May need further tweaking to be smarter based on individual project
+        needs. For now, it's pretty dumb.
+        :return: Formatted string if tests_require exists; else empty string.
+        """
+        test_string = ''
+        if 'tests_require' in self.setup.keys():
+            test_string += (
+                'test:\n'
+                '  source_files:\n'
+                '    - test/\n'
+                '  requires:\n'
+            )
+
+            for req in self.setup['tests_require']:
+                test_string += '    - {}\n'.format(req)
+
+            test_string += (
+                '  commands:\n'
+                '    - pytest -vv --log-level=DEBUG --showlocals\n'
+                '\n'
+            )
+        return test_string
+
+    def generate(self):
+        # Filter numpy etc. out of the requirements
+        self.setup['install_requires'] = [req for req in self.setup['install_requires'] if req != 'numpy']
+    
+        name = self.setup['name']
+        version = self.setup['version']
+        entry_points = self.fmt_ep()
+        pth = self.path.replace("./", "")
+        requirements = self.fmt_reqs()
+        test = self.fmt_test()
+        lic = self.setup['license']
+        summary = self.setup['description']
+    
+        with open('build/tools/metafile_template.txt', 'r') as f:
+            metadata = f.read()
+    
+        return metadata.format(
+            name = name,
+            version = version,
+            entry_points = entry_points,
+            path = "../../../" + pth,
+            requirements = requirements,
+            test = test,
+            license = lic,
+            summary = summary
+        )
+
+
+def parse_setup(d):
+    """
+    Function for running parse_setup.py on each directory with a setup.py file.
+    NOTE: Contains a hack for getting parse_setup.py to run in each directory.
+    :param d: Directory with a setup.py file.
+    :return: Data collected from parse_setup.py.
+    """
+    subprocess.run(['cp', 'build/tools/parse_setup.py', d])
+    os.chdir(d)
+    proc = subprocess.run(['python3', 'parse_setup.py'], stdout=subprocess.PIPE)
+    os.chdir(root)
+    subprocess.run(['rm', '{}/parse_setup.py'.format(d)])
+
+    return json.loads(proc.stdout)
+
+def get_outputs(names):
+    """
+    Generate list of metadata files that will be created.
+    :param dirs: List of dirs of all subprojects with a setup.py file.
+    :return: List of paths to output files as strings.
+    """
+    outputs = []
+    for name in names:
+        outputs.append("build/metadata/{}/meta.yaml".format(name))
+
+    return outputs
+
+def get_dirs():
+    """
+    Finds all subdirectories containing setup.py files.
+    :return: List of directories as strings.
+    """
+    find = subprocess.run([
+        'find', '.', '-name', 'setup.py', '-not', '-path', './build/recipes/*'
+    ], stdout=subprocess.PIPE)
+    dirs = find.stdout.decode('utf-8').split('\n')
+    dirs_cpy = dirs
+
+    for i, d in enumerate(dirs_cpy):
+        dirs[i] = d.replace('/setup.py', '')
+
+    return dirs
+
+def get_names(dirs):
+    """
+    Generate list of subproject names based on the rule that the name of the
+    subproject directory will be the name of the subproject.
+    :return: List of names as strings.
+    """
+    names = []
+    for d in dirs:
+        if d != '':
+            name = d.split('/')[-1]
+
+            if name == "archive":
+                # Case with ./services/archive having special dir structure
+                name = "services"
+            names.append(name)
+
+    return names
+
+def del_substrings(s, substrings):
+    """
+    Function for deleting multiple substrings from a string.
+    :param s: String to be modified.
+    :param substrings: List of substrings to be targeted for deletion.
+    :return: Modified string.
+    """
+    for replace in substrings:
+        s = s.replace(replace, '')
+
+    return s
+
+root = os.getcwd()
+
+class Recipe:
+    """
+    Buildout Recipe class.
+    For more detailed information, see the link.
+    http://www.buildout.org/en/latest/topics/writing-recipes.html
+    """
+    def __init__(self, buildout, name, options):
+        """
+        Initializes fields needed for recipe.
+        :param buildout: (Boilerplate) Dictionary of options from buildout section
+        of buildout.cfg
+        :param name: (Boilerplate) Name of section that uses this recipe.
+        :param options: (Boilerplate) Options of section that uses this recipe.
+        """
+        self.dirs = get_dirs()
+        self.names = get_names(self.dirs)
+        self.outputs = get_outputs(self.names)
+        self.options = options
+
+    # TODO: Keep track of path in setup_dict
+    def install(self):
+        """
+        Install method that runs when recipe has components it needs to install.
+        :return: Paths to files, as strings, created by the recipe.
+        """
+        for i, d in enumerate(self.dirs):
+            if d != '':
+                setup_data = parse_setup(d)
+                metadata = MetadataGenerator(setup_data, d).generate()
+                write_metafile(metadata, self.outputs[i])
+                # Pass created file into options.created()
+                self.options.created(self.outputs[i])
+
+        return self.options.created()
+
+    # No special procedure for updating vs. installing
+    update = install
\ No newline at end of file
diff --git a/build/tools/metafile_template.txt b/build/tools/metafile_template.txt
new file mode 100644
index 0000000000000000000000000000000000000000..87fc1ad8239a464652270b883133d02aa4110016
--- /dev/null
+++ b/build/tools/metafile_template.txt
@@ -0,0 +1,18 @@
+{{% set name = "{name}" %}}
+{{% set version = "{version}" %}}
+
+package:
+  name: "{{{{ name|lower }}}}"
+  version: "{{{{ version }}}}"
+
+build:
+  noarch: python
+  {entry_points}script: "{{{{ PYTHON }}}} setup.py install --single-version-externally-managed --record=record.txt"
+
+source:
+  path: {path}
+
+{requirements}{test}about:
+  license: "{license}"
+  license_family: "{license}"
+  summary: "{summary}"
\ No newline at end of file
diff --git a/build/tools/parse_setup.py b/build/tools/parse_setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..8acd807b95980c86bcedb4f1a2b220ea5300da79
--- /dev/null
+++ b/build/tools/parse_setup.py
@@ -0,0 +1,40 @@
+import sys
+import setuptools
+import json
+
+data = {}
+def my_setup(*args, **kwargs):
+    """
+    A replacement for setuptools.setup().
+    """
+    fields = [
+        'name',
+        'version',
+        'description',
+        'license',
+        'install_requires',
+        'tests_require',
+        'entry_points'
+    ]
+
+    for field in fields:
+        data[field] = kwargs.get(field)
+
+def main():
+    # Author of these shenanigans: Daniel Lyons (but you already knew that)
+
+    global data
+    # Monkey-patch over the setuptools setup() function to do our function instead
+    setuptools.setup = my_setup
+
+    # Load the setup.py file
+    import setup
+
+    # Remove None-flavored values
+    data = {k: v for k, v in data.items() if v is not None}
+
+    # Instead of exiting, we now have populated our global variable, without doing any parsing
+    json.dump(data, sys.stdout)
+
+if __name__ == "__main__":
+    main()
\ No newline at end of file
diff --git a/build/tools/transfer_to_builder.py b/build/tools/transfer_to_builder.py
new file mode 100644
index 0000000000000000000000000000000000000000..6ae2edf2a24991e2aad023b7b65237f956d132eb
--- /dev/null
+++ b/build/tools/transfer_to_builder.py
@@ -0,0 +1,51 @@
+import subprocess, paramiko, fnmatch, os
+from scp import SCPClient
+
+def get_build_pkg_names():
+    """
+    Search through pkgs directory for built .tar.bz2 packages
+    :return: List of package archive file names
+    """
+    pkg_names = []
+    d = "build/pkgs/noarch/"
+    for file in os.listdir(d):
+        if fnmatch.fnmatch(file, "*.tar.bz2"):
+            pkg_names.append(d + file)
+
+    return pkg_names
+
+def create_ssh_client(server):
+    """
+    Use paramiko to load SSH keys if they exist and set up an SSH connection to a server.
+    :param server: The server to connect to
+    :return: Initialized SSH client object.
+    """
+    client = paramiko.SSHClient()
+    client.load_system_host_keys()
+    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+    client.connect(server)
+    return client
+
+def transfer_packages(pkg_names):
+    """
+    Use shell commands to transfer build archives to builder and update its conda package index.
+    :param pkg_names: Names of the .tar.bz2 files for the built packages.
+    """
+    if len(pkg_names):
+        builder_addr = "builder.aoc.nrao.edu"
+        builder_path = "/home/builder.aoc.nrao.edu/content/conda/noarch"
+        ssh = create_ssh_client(builder_addr)
+        with SCPClient(ssh.get_transport()) as scp:
+            [scp.put(pkg, builder_path) for pkg in pkg_names]
+        cmd_cd = "cd {}".format(builder_path)
+        cmd_index = "conda index .."
+        cmd_chmod = "chmod -f 664 *"
+        subprocess.run(["ssh", builder_addr,
+                        cmd_cd + " && " +
+                        cmd_index + " && " +
+                        cmd_chmod])
+    else:
+        print("No packages found in build/pkgs/noarch. Did conda build successfully build the package(s)?")
+
+if __name__ == "__main__":
+    transfer_packages(get_build_pkg_names())
\ No newline at end of file
diff --git a/buildout.cfg b/buildout.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..5ae4f1cc3931524a3c061e563efccd0d0a489b60
--- /dev/null
+++ b/buildout.cfg
@@ -0,0 +1,20 @@
+# Main section
+# Accessible from the command line using 'buildout key=value'
+# e.g. buildout parts=build_pkgs will specify build_pkgs
+# as a part that should be installed
+[buildout]
+develop = build/recipes/setup_to_meta build/recipes/build_pkgs
+
+# Section for building internal tools using conda
+# Depends on gen_metadata
+# Depends on `name` in [buildout] to specify which package to install
+# Specify name via command line using
+# `buildout parts=build_pkgs name={name}`
+[build_pkgs]
+=> gen_metadata
+recipe = build_pkgs
+name = ${buildout:name}
+
+# Section for generating meta.yaml files
+[gen_metadata]
+recipe = setup_to_meta
\ No newline at end of file
diff --git a/deployment/__init__.py b/deployment/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/deps.png b/deps.png
new file mode 100644
index 0000000000000000000000000000000000000000..1da8246559dbff971e7060ca6597f99f6cbe4a9c
Binary files /dev/null and b/deps.png differ
diff --git a/environment.yml b/environment.yml
index 7b9e8d6d4e094044c7068bb91a7c4c02424a8e2c..134998cb21caf6ac9702692f6aaa61286cebe041 100644
--- a/environment.yml
+++ b/environment.yml
@@ -1,7 +1,7 @@
 name: data
 channels:
-  - defaults
   - https://builder.aoc.nrao.edu/conda
+  - defaults
 dependencies:
   - alembic=1.4
   - astropy=4.0
@@ -17,15 +17,16 @@ dependencies:
   - pendulum=2.1
   - pid=2.2
   - psycopg2=2.8
-  - pycapo=0.2.1.post1
+  - pycapo=0.3.0
   - pyopenssl=19.1.0
   - pyramid=1.10
   - pyramid_debugtoolbar=4.5
   - pysftp=0.2.9
   - pytest=5.4
   - python=3.8
-  - requests=2.23
+  - requests>=2.23,<3.0
   - simplejson=3.17
   - sqlalchemy=1.3
   - tqdm=4.46
-  - waitress=1.4
\ No newline at end of file
+  - waitress=1.4
+  - zc.buildout=2.13.2
\ No newline at end of file
diff --git a/schema/__init__.py b/schema/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/services/archive/__init__.py b/services/archive/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/services/archive/build/lib/services/__init__.py b/services/archive/build/lib/services/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/services/archive/build/lib/services/auth/__init__.py b/services/archive/build/lib/services/auth/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/services/archive/build/lib/services/client_services/__init__.py b/services/archive/build/lib/services/client_services/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/services/archive/build/lib/services/ingestion_metadata/__init__.py b/services/archive/build/lib/services/ingestion_metadata/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/services/archive/build/lib/services/ingestion_metadata/tests/__init__.py b/services/archive/build/lib/services/ingestion_metadata/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/services/archive/build/lib/services/locator/__init__.py b/services/archive/build/lib/services/locator/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/services/archive/build/lib/services/mous_details/__init__.py b/services/archive/build/lib/services/mous_details/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/services/archive/build/lib/services/solr/__init__.py b/services/archive/build/lib/services/solr/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/services/archive/services/__init__.py b/services/archive/services/__init__.py
index a98528e2913fc31824733e23e680311ba266015c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/services/archive/services/__init__.py
+++ b/services/archive/services/__init__.py
@@ -1,78 +0,0 @@
-from services._version import ___version___ as version
-from pyat.schema import create_engine
-from pyramid.config import Configurator
-from pyramid_beaker import session_factory_from_settings
-from sqlalchemy.orm import scoped_session, sessionmaker
-from zope.sqlalchemy import ZopeTransactionExtension
-from pyramid.renderers import JSONP
-
-DB = {}
-
-
-def base_repr(s):
-    r""" Return the string representation of this class.
-
-        :return: The string representation of self.
-        """
-    repr_str_list = ['{c}(']
-    temp = ['{0}={{s.{0}}}'.format(key) for key in vars(s)]
-    self_list = ', '.join(temp)
-    repr_str_list.append(self_list)
-    repr_str_list.append(')')
-
-    return ''.join(repr_str_list).format(c=s.__class__.__name__, s=s)
-
-
-def main(global_config, **settings):
-    DB['SDM'] = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
-    DB['NGAS'] = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
-    DB['NGAS_NAASC'] = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
-    DB['VLASS'] = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
-
-    DB['SDM'].configure(bind=create_engine('SDM'))
-    DB['NGAS'].configure(bind=create_engine('NGAS'))
-    DB['NGAS_NAASC'].configure(bind=create_engine('NGAS_NAASC'))
-    DB['VLASS'].configure(bind=create_engine('VLASS'))
-
-    with Configurator(settings=settings) as config:
-        session_factory = session_factory_from_settings(settings)
-        config.set_session_factory(session_factory)
-
-        config.add_renderer('jsonp', JSONP(param_name='callback'))
-
-        config.include('pyramid_beaker')
-
-        config.add_route('product_location_service', '/location')
-        config.add_route('product_authorization_service', '/authorized')
-
-        config.add_route('get_solr_facets', '/restapi_get_execution_block_facets')
-        config.add_route('get_eb_project_view', '/restapi_get_eb_project_view')
-        config.add_route('get_paged_exec_blocks', '/restapi_get_paged_exec_blocks')
-        config.add_route('get_paged_images', '/restapi_get_paged_images')
-        config.add_route('get_full_exec_block_details', '/restapi_get_full_exec_block_details')
-        config.add_route('get_paged_alma_mouses', '/restapi_get_paged_alma_mouses')
-        config.add_route('echo_json_params', '/echo_json_params')
-        config.add_route('get_splash_message', '/get_splash_message')
-        config.add_route('acknowledge_splash_message', '/acknowledge_splash_message')
-        config.add_route('get_casa_version_list', '/restapi_get_casa_version_list')
-        config.add_route('get_release_notes_url', '/restapi_get_release_notes_url')
-        config.add_route('get_application_parameters', '/restapi_get_application_parameters')
-        config.add_route('get_pre_release_feature_flag', '/restapi_get_pre_release_feature_flag')
-        config.add_route('get_show_all_thumbnails_flag', '/restapi_get_show_all_thumbnails_flag')
-        config.add_route('get_rh_url', '/restapi_get_rh_url')
-        config.add_route('resolver_request', '/restapi_resolver_request')
-
-        config.add_route('mous_details_view', '/restapi_mous_details_view')
-        config.add_route('data_quality_notes_view', '/restapi_data_quality_notes')
-
-        config.add_route('image_metadata_service', '/image_metadata')
-        config.add_route('image_precursor_service', '/image_precursor')
-
-        config.scan('services.locator')
-        config.scan('services.auth')
-        config.scan('services.solr')
-        config.scan('services.client_services')
-        config.scan('services.mous_details')
-        config.scan('services.ingestion_metadata')
-        return config.make_wsgi_app()
-
diff --git a/services/archive/services/client_services/__init__.py b/services/archive/services/client_services/__init__.py
index 758ec00735c9d9816dd4d0c1f22c4059f1b2af1c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/services/archive/services/client_services/__init__.py
+++ b/services/archive/services/client_services/__init__.py
@@ -1,47 +0,0 @@
-
-
-# using sys to get the function name when throwing around exceptions.
-# https://stackoverflow.com/questions/251464/how-to-get-a-function-name-as-a-string-in-python
-# this_function_name = sys._getframe().f_code.co_name
-import sys
-
-
-def def_name():
-    """ Get the name of the calling function
-
-    This is a recipe from the python cookbook, attribution given in the sources I found to Alex Martelli.
-
-    :return: the name of the calling function
-    """
-    return sys._getframe(1).f_code.co_name
-
-
-class ResponseMsg(object):
-    SUCCESS = 0
-    SOFT_ERROR = 1
-    HARD_ERROR = 2
-
-    def __init__(self, flag, code, msg):
-        self.success = flag
-        self.code = code
-        self.message = msg
-
-    def __repr__(self):
-        r""" Return the string representation of this class.
-
-        :return: The string representation of self.
-        """
-        repr_str_list = ['{c}(']
-        temp = ['{0}={{s.{0}}}'.format(key) for key in vars(self)]
-        self_list = ', '.join(temp)
-        repr_str_list.append(self_list)
-        repr_str_list.append(')')
-
-        return ''.join(repr_str_list).format(c=ResponseMsg.__name__, s=self)
-
-    def as_dict(self):
-        return dict(
-            success=self.success,
-            code=self.code,
-            message=self.message
-        )
diff --git a/services/archive/services/client_services/data_quality_notes.py b/services/archive/services/client_services/data_quality_notes.py
index 68e9e5e19c4839aecc9ff1e96ad997ad48ad6096..045a513986d159fd3b064211fb608609f68c71fd 100644
--- a/services/archive/services/client_services/data_quality_notes.py
+++ b/services/archive/services/client_services/data_quality_notes.py
@@ -6,7 +6,7 @@ from pyramid.view import view_config
 
 from . import def_name
 
-from pyat.schema.model import ScienceProductComment, ProblemSeverityList, ProblemType
+from schema.model import ScienceProductComment, ProblemSeverityList, ProblemType
 from services import DB
 from sqlalchemy import exc as sa_exc, asc, desc
 
diff --git a/services/archive/services/ingestion_metadata/ingestion_metadata.py b/services/archive/services/ingestion_metadata/ingestion_metadata.py
index 0ef056238f9e77787ee4377fb4bea7218fdd1b1b..1895e9ac5fb8a42c764b75fbb20bb2aace976ca0 100644
--- a/services/archive/services/ingestion_metadata/ingestion_metadata.py
+++ b/services/archive/services/ingestion_metadata/ingestion_metadata.py
@@ -31,8 +31,8 @@
 #
 from pyramid.view import view_config
 from pyramid.httpexceptions import exception_response
-from pyat.schema import ExecutionBlock, ScienceProduct
-from pyat.schema.vlassmodel import ProductVersionArchiveid, ProductVersion, Product, Prerequisite
+from schema import ExecutionBlock, ScienceProduct
+from schema.vlassmodel import ProductVersionArchiveid, ProductVersion, Product, Prerequisite
 from sqlalchemy.orm import aliased
 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
 from services import DB
diff --git a/services/archive/services/locator/locator.py b/services/archive/services/locator/locator.py
index 5e2f132a00cde38bdfd299ea451f31e0155a672a..a66c2490ca764caae7cd2466df65df1216a08c98 100644
--- a/services/archive/services/locator/locator.py
+++ b/services/archive/services/locator/locator.py
@@ -7,8 +7,8 @@ The primary user of this information is the archive data fetcher.
 from functools import reduce
 from pathlib import Path
 
-from pyat.schema import ScienceProduct, AncillaryProduct
-from pyat.schema.ngasmodel import NGASFile, NGASDisk
+from schema import ScienceProduct, AncillaryProduct
+from schema.ngasmodel import NGASFile, NGASDisk
 from pyramid.httpexceptions import exception_response
 from pyramid.view import view_config
 from sqlalchemy import func
diff --git a/services/archive/services/mous_details/__init__.py b/services/archive/services/mous_details/__init__.py
index 9ac740bdb62b908f3fe187cf2005448d12b2bb05..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/services/archive/services/mous_details/__init__.py
+++ b/services/archive/services/mous_details/__init__.py
@@ -1,16 +0,0 @@
-
-
-# using sys to get the function name when throwing around exceptions.
-# https://stackoverflow.com/questions/251464/how-to-get-a-function-name-as-a-string-in-python
-# this_function_name = sys._getframe().f_code.co_name
-import sys
-
-
-def def_name():
-    """ Get the name of the calling function
-
-    This is a recipe from the python cookbook, attribution given in the sources I found to Alex Martelli.
-
-    :return: the name of the calling function
-    """
-    return sys._getframe(1).f_code.co_name
diff --git a/services/archive/services/mous_details/mous_details.py b/services/archive/services/mous_details/mous_details.py
index ea9a713ecb4e3e8adc6738cfbac04c48398bfaf9..13d3b2461280d1dc0e7ad9e933e38e1b9b8eb547 100644
--- a/services/archive/services/mous_details/mous_details.py
+++ b/services/archive/services/mous_details/mous_details.py
@@ -8,7 +8,7 @@ from . import def_name
 from services.solr.query_builder import ArchiveSolrParameters
 from services.client_services import ResponseMsg
 
-from pyat.schema import AlmaSourceDatum, AlmaSpwDatum, t_alma_spw_sources
+from schema import AlmaSourceDatum, AlmaSpwDatum, t_alma_spw_sources
 from services import DB
 
 log = logging.getLogger(__name__)
diff --git a/services/archive/services/solr/__init__.py b/services/archive/services/solr/__init__.py
index 9ac740bdb62b908f3fe187cf2005448d12b2bb05..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/services/archive/services/solr/__init__.py
+++ b/services/archive/services/solr/__init__.py
@@ -1,16 +0,0 @@
-
-
-# using sys to get the function name when throwing around exceptions.
-# https://stackoverflow.com/questions/251464/how-to-get-a-function-name-as-a-string-in-python
-# this_function_name = sys._getframe().f_code.co_name
-import sys
-
-
-def def_name():
-    """ Get the name of the calling function
-
-    This is a recipe from the python cookbook, attribution given in the sources I found to Alex Martelli.
-
-    :return: the name of the calling function
-    """
-    return sys._getframe(1).f_code.co_name
diff --git a/services/archive/setup.py b/services/archive/setup.py
index 36033313697ea066cfb5824ef868e44ddf0e7088..555b4fd0221b90ffe2b8f6a05d86e23fef1e296b 100644
--- a/services/archive/setup.py
+++ b/services/archive/setup.py
@@ -37,16 +37,16 @@ def find_version(*file_paths):
 
 
 requires = [
+    'pycapo',
     'pyramid',
-    'pyramid-beaker',
+    'pyramid_beaker',
+    'pyramid_debugtoolbar',
     'pyramid_tm',
+    'requests',
+    'schema',
     'sqlalchemy',
     'waitress',
-    'zope.sqlalchemy',
-    'pycapo',
-    'pyat',
-    'requests',
-    'pyramid_debugtoolbar',
+    'zope.sqlalchemy'
 ]
 
 setup(
diff --git a/shared/messaging/events/__init__.py b/shared/messaging/events/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/shared/messaging/events/build/lib/events/__init__.py b/shared/messaging/events/build/lib/events/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/shared/schema/__init__.py b/shared/schema/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/shared/schema/build/lib/schema/__init__.py b/shared/schema/build/lib/schema/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/shared/schema/setup.py b/shared/schema/setup.py
index 6ceb111c8d0cdc5477003fe44333d652ef73f690..e16ee2a511ea62e595a7e837b9c68a2fc0a2ac68 100644
--- a/shared/schema/setup.py
+++ b/shared/schema/setup.py
@@ -16,7 +16,7 @@ setup(
     author_email='dms-ssa@nrao.edu',
     url='TBD',
     license="GPL",
-    install_requires=['sqlalchemy', 'pycapo', 'psycopg2', 'mysqlclient', 'cx-Oracle'],
+    install_requires=['sqlalchemy', 'pycapo', 'psycopg2', 'mysqlclient', 'cx_Oracle'],
     keywords=[],
     packages=['schema'],
     package_dir={'':'src'},
diff --git a/shared/schema/src/schema/__init__.py b/shared/schema/src/schema/__init__.py
index 18dcffe8ebcbba4dc18e6aecde0e0d1f66a29873..9ef86007564c99b61f4b61268cfa35c9c87cce9e 100644
--- a/shared/schema/src/schema/__init__.py
+++ b/shared/schema/src/schema/__init__.py
@@ -81,4 +81,4 @@ class ArchiveDBSession:
         return self
 
     def __exit__(self, exc_type, exc_val, exc_tb):
-        self.session.close()
+        self.session.close()
\ No newline at end of file
diff --git a/shared/support/__init__.py b/shared/support/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/shared/support/build/lib/support/__init__.py b/shared/support/build/lib/support/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/support/conda/blessings/meta.yaml b/support/conda/blessings/meta.yaml
index e45bdc769f6b200510f4692fcaeae896df193646..4ec5d0ea732d11b207707c3630a5bd1cdc4caf81 100644
--- a/support/conda/blessings/meta.yaml
+++ b/support/conda/blessings/meta.yaml
@@ -10,6 +10,7 @@ source:
   sha256: "98e5854d805f50a5b58ac2333411b0482516a8210f23f43308baeb58d77c157d"
 
 build:
+  noarch: python
   number: 0
   script: "{{ PYTHON }} -m pip install . --no-deps --ignore-installed -vv "
 
diff --git a/support/conda/jxmlease/meta.yaml b/support/conda/jxmlease/meta.yaml
index c6f2a1f2cb13f3363b03acf13c2e4644a5ce9757..83c47a79450d726f5d3c5b15fe4280a9199657c8 100644
--- a/support/conda/jxmlease/meta.yaml
+++ b/support/conda/jxmlease/meta.yaml
@@ -10,6 +10,7 @@ source:
   sha256: fb04cfd54d8d7e4cc533108750047e9ccf43139c3c0220f8a082274b19564e98
 
 build:
+  noarch: python
   number: 0
   script: "{{ PYTHON }} -m pip install . --no-deps --ignore-installed -vv "
 
diff --git a/support/conda/pid/meta.yaml b/support/conda/pid/meta.yaml
index b6ede62f75be0147743a365d5b887d35b77512b8..684c879c8af1d834f0c4678958eeb65814f9fcef 100644
--- a/support/conda/pid/meta.yaml
+++ b/support/conda/pid/meta.yaml
@@ -10,6 +10,7 @@ source:
   sha256: "96eb7dba326b88f5164bc1afdc986c7793e0d32d7f62366256a3903c7b0614ef"
 
 build:
+  noarch: python
   number: 0
   script: "{{ PYTHON }} -m pip install . --no-deps --ignore-installed -vv "
 
diff --git a/support/conda/pika/meta.yaml b/support/conda/pika/meta.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..129e2c5e385ea5bbe14c3d326af74778eb656836
--- /dev/null
+++ b/support/conda/pika/meta.yaml
@@ -0,0 +1,41 @@
+{% set name = "pika" %}
+{% set version = "1.1.0" %}
+
+package:
+  name: "{{ name|lower }}"
+  version: "{{ version }}"
+
+source:
+  url: "https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/{{ name }}-{{ version }}.tar.gz"
+  sha256: 9fa76ba4b65034b878b2b8de90ff8660a59d925b087c5bb88f8fdbb4b64a1dbf
+
+build:
+  number: 0
+  noarch: python
+  script: "{{ PYTHON }} -m pip install . -vv"
+
+requirements:
+  host:
+    - pip
+    - python
+  run:
+    - python
+
+test:
+  imports:
+    - pika
+    - pika.adapters
+    - pika.adapters.utils
+
+about:
+  home: "https://pika.readthedocs.io"
+  license: BSD
+  license_family: BSD
+  license_file: 
+  summary: "Pika Python AMQP Client Library"
+  doc_url: 
+  dev_url: 
+
+extra:
+  recipe-maintainers:
+    - your-github-id-here
diff --git a/support/conda/pyat/meta.yaml b/support/conda/pyat/meta.yaml
index db7169e03b08384e9ea9bcdf2e87ccf6e5b5f60c..1f6b6342cd8bab63c107baa59538c3d0ee08ae48 100644
--- a/support/conda/pyat/meta.yaml
+++ b/support/conda/pyat/meta.yaml
@@ -57,6 +57,7 @@ requirements:
     - zope.sqlalchemy
 
 build:
+  noarch: python
   script: python setup.py install
 
 about:
diff --git a/support/conda/pycapo/meta.yaml b/support/conda/pycapo/meta.yaml
index caab0fdcebc5c2becd975238084effec7d8b9c31..1e4223dd6f8f7f4e3e0424a1db2e805265c6e9f7 100644
--- a/support/conda/pycapo/meta.yaml
+++ b/support/conda/pycapo/meta.yaml
@@ -1,5 +1,5 @@
 {% set name = "pycapo" %}
-{% set version = "0.2.1.post1" %}
+{% set version = "0.3.1" %}
 
 package:
   name: "{{ name|lower }}"
@@ -7,9 +7,10 @@ package:
 
 source:
   url: https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/{{ name }}-{{ version }}.tar.gz
-  sha256: 703002d913d4e38a4bcce7748674ef58d4fd63c9fd099316b4643a89955ff361
+  sha256: 987040fefc09d7ffc76ac9973b621ff304b653a18bf5d42ca4b2bdc948ef568b
 
 build:
+  noarch: python
   number: 0
   entry_points:
     - pycapo = pycapo.commands:pycapo
diff --git a/support/conda/pysftp/meta.yaml b/support/conda/pysftp/meta.yaml
index daa6c76ca687c67b501fdbfdf2ffe2af26d24ba7..053497efc2bbbeea7e56347eae845fc82ffe49d0 100644
--- a/support/conda/pysftp/meta.yaml
+++ b/support/conda/pysftp/meta.yaml
@@ -10,6 +10,7 @@ source:
   sha256: fbf55a802e74d663673400acd92d5373c1c7ee94d765b428d9f977567ac4854a
 
 build:
+  noarch: python
   number: 0
   script: "{{ PYTHON }} -m pip install . --no-deps --ignore-installed -vv "
 
diff --git a/support/conda/python_abi/LICENSE b/support/conda/python_abi/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..bc9189c759dd6b737cebb9cb2bd3cfcea6b427e5
--- /dev/null
+++ b/support/conda/python_abi/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2015-2018, conda-forge
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of staged-recipes nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/support/conda/python_abi/meta.yaml b/support/conda/python_abi/meta.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c88e13698ca67a7ed9f8017245e40b1a13e0ffe5
--- /dev/null
+++ b/support/conda/python_abi/meta.yaml
@@ -0,0 +1,31 @@
+# This file created by conda-build 3.18.12
+# meta.yaml template originally from:
+# /home/conda/recipe_root, last modified Wed Mar  4 17:58:59 2020
+# ------------------------------------------------
+
+package:
+    name: python_abi
+    version: '3.8'
+build:
+    number: '1'
+    noarch: python
+    string: 1_cp38
+requirements:
+    run:
+        - python 3.8.*
+    run_constrained:
+        - pypy <0a0
+test:
+    commands:
+        - python --version
+about:
+    home: https://github.com/conda-forge/python_abi-feedstock
+    license: BSD-3-Clause
+    license_family: BSD
+    license_file: LICENSE
+    summary: Metapackage to select python implementation
+extra:
+    copy_test_source_files: true
+    final: true
+    recipe-maintainers:
+        - isuruf
diff --git a/support/conda/zc.buildout/meta.yaml b/support/conda/zc.buildout/meta.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..06bb07949a2c2d0295ca291776c1007cf7bc69cf
--- /dev/null
+++ b/support/conda/zc.buildout/meta.yaml
@@ -0,0 +1,46 @@
+{% set name = "zc.buildout" %}
+{% set version = "2.13.2" %}
+
+package:
+  name: "{{ name|lower }}"
+  version: "{{ version }}"
+
+source:
+  url: "https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/{{ name }}-{{ version }}.tar.gz"
+  sha256: 5dd4de86dda684c46ef8ee9cc84e335ca7f6275d4363a684de82225270d1e328
+
+build:
+  noarch: python
+  number: 0
+  entry_points:
+    - buildout=zc.buildout.buildout:main
+  script: "{{ PYTHON }} -m pip install . -vv"
+
+requirements:
+  host:
+    - pip
+    - python
+    - setuptools >=8.0
+  run:
+    - python
+    - setuptools >=8.0
+
+test:
+  imports:
+    - zc
+    - zc.buildout
+  commands:
+    - buildout --help
+
+about:
+  home: "http://buildout.org"
+  license: Zope Public
+  license_family: OTHER
+  license_file: 
+  summary: "System for managing development buildouts"
+  doc_url: 
+  dev_url: 
+
+extra:
+  recipe-maintainers:
+    - your-github-id-here