diff --git a/bindep.txt b/bindep.txt
new file mode 100644
index 0000000..116e2ba
--- /dev/null
+++ b/bindep.txt
@@ -0,0 +1,16 @@
+# This is a cross-platform list tracking distribution packages needed by tests;
+# see http://docs.openstack.org/infra/bindep/ for additional information.
+
+libffi-devel [test platform:rpm]
+libffi-dev [test platform:dpkg]
+libssl-dev [platform:dpkg]
+openssl-devel [platform:rpm]
+python3-dev [compile test platform:dpkg platform:apk]
+python3-devel [compile test platform:rpm]
+libre2-dev [compile test platform:dpkg]
+libre2-4 [platform:ubuntu-bionic]
+libre2-3 [platform:debian-stretch]
+libre2-1v5 [platform:ubuntu-xenial]
+re2-devel [compile test platform:rpm]
+re2-dev [platform:apk]
+re2 [platform:rpm platform:apk]
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..e6727c0
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,20 @@
+[metadata]
+name = starlingx-zuul-jobs
+summary = A set of Ansible playbooks used by StarlingX for CI
+description-file =
+    README.rst
+author = StarlingX Team
+author-email = starlingx-discuss@lists.starlingx.io
+home-page = https://starlingx.io/
+classifier =
+    Intended Audience :: Information Technology
+    Intended Audience :: System Administrators
+    License :: OSI Approved :: Apache Software License
+    Operating System :: POSIX :: Linux
+    Programming Language :: Python
+
+[build_sphinx]
+source-dir = doc/source
+build-dir = doc/build
+all_files = 1
+warning-is-error = 1
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..6282ee4
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
+import setuptools
+
+# In python < 2.7.4, a lazy loading of package `pbr` will break
+# setuptools if some other modules registered functions in `atexit`.
+# solution from: http://bugs.python.org/issue15881#msg170215
+try:
+    import multiprocessing  # noqa
+except ImportError:
+    pass
+
+setuptools.setup(
+    setup_requires=['pbr>=2.0'],
+    pbr=True)
diff --git a/test-requirements.txt b/test-requirements.txt
new file mode 100644
index 0000000..1e6cac1
--- /dev/null
+++ b/test-requirements.txt
@@ -0,0 +1,11 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
+
+hacking>=1.1.0,<1.2 # Apache-2.0
+
+zuul
+ansible>=2.7.0,<2.8
+ansible-lint<4
+bashate>=0.2
+zuul-sphinx>=0.2.0
diff --git a/tests/inventory b/tests/inventory
new file mode 100644
index 0000000..68b2dac
--- /dev/null
+++ b/tests/inventory
@@ -0,0 +1,2 @@
+[all]
+localhost
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..0626851
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,89 @@
+[tox]
+minversion = 1.6
+skipsdist = True
+envlist = linters
+
+[testenv]
+basepython = python3
+install_command = pip install {opts} {packages}
+deps = -r{toxinidir}/test-requirements.txt
+
+[testenv:bindep]
+# Do not install any requirements. We want this to be fast and work even if
+# system dependencies are missing, since it's used to tell you what system
+# dependencies are missing! This also means that bindep must be installed
+# separately, outside of the requirements files.
+deps = bindep
+commands = bindep test
+
+[testenv:docs]
+whitelist_externals = bash
+commands =
+  bash -c 'if [ -d doc ]; then \
+    python setup.py build_sphinx; \
+  fi'
+
+[testenv:linters]
+whitelist_externals = bash
+passenv =
+  # NOTE(pabelanger): if you'd like to run tox -elinters locally, you'll need
+  # to export ANSIBLE_ROLES_PATH pointing to the currect repos.
+  # see openstack-zuul-jobs-linters job for more information.
+  ANSIBLE_ROLES_PATH
+setenv =
+  ANSIBLE_LIBRARY= {envsitepackagesdir}/zuul/ansible/base/library
+  ANSIBLE_ACTION_PLUGINS = {envsitepackagesdir}/zuul/ansible/base/actiongeneral
+commands =
+  flake8 {posargs}
+  # Ansible lint
+  # [ANSIBLE0012] Commands should not change things if nothing needs doing
+  bash -c 'if [ -d playbooks ]; then \
+    find playbooks -type f -regex ".*\.ya?ml" -print0 | xargs -t -n1 -0 \
+       ansible-lint -xANSIBLE0012; \
+    fi'
+  bash -c 'if [ -d roles ]; then \
+    find roles -maxdepth 1 -mindepth 1 -type d -printf "%p/\n" | xargs -t -n1 \
+        ansible-lint -xANSIBLE0012; \
+    fi'
+  # Ansible Syntax Check
+  bash -c 'if [ -d playbooks ]; then \
+    find playbooks -type f -regex ".*\.ya?ml" -print0 | xargs -t -n1 -0 \
+      ansible-playbook --syntax-check -i {toxinidir}/tests/inventory; \
+    fi'
+  # Check Shell Scripts Syntax
+  bash -c 'if [ -d scripts ]; then \
+    find {toxinidir}          \
+      -not \( -type d -name .?\* -prune \) \
+      -type f                              \
+      -not -name \*~                       \
+      -not -name \*.md                     \
+      \(                                   \
+        -name \*.sh                         \
+        -or -not -wholename \*/devstack/files/\* \
+        -wholename \*/devstack/\*           \
+      \)                                   \
+      -print0 | xargs -t -n1 -0 \
+        bashate -v -iE006; \
+    fi'
+
+[testenv:venv]
+commands = {posargs}
+
+[flake8]
+# These are ignored intentionally in openstack-infra projects;
+# please don't submit patches that solely correct them or enable them.
+ignore = E125,E129,H
+show-source = True
+exclude = .venv,.tox,dist,doc,build,*.egg
+
+[testenv:pep8]
+basepython = python3
+usedevelop = False
+skip_install = True
+deps =
+    hacking
+    flake8-bugbear<=19.3.0
+    flake8<3.6.0
+commands =
+    flake8
+
diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml
new file mode 100644
index 0000000..4ec098a
--- /dev/null
+++ b/zuul.d/jobs.yaml
@@ -0,0 +1,17 @@
+- job:
+    name: stx-zuul-jobs-linters
+    parent: openstack-zuul-jobs-linters
+    description: |
+      This job runs against starlingx/zuul-jobs so we can properly
+      lint our ansible playbooks / roles.
+    required-projects:
+      - opendev/base-jobs
+      - openstack/openstack-zuul-jobs
+      - openstack/project-config
+      - opendev/system-config
+      - zuul/zuul-jobs
+      - zuul/zuul
+    vars:
+      tox_envlist: linters
+      tox_environment:
+        ANSIBLE_ROLES_PATH: ~/src/opendev.org/starlingx/zuul-jobs/roles:~/src/opendev.org/opendev/base-jobs/roles:~/src/opendev.org/zuul/zuul-jobs/roles:~/src/opendev.org/openstack/openstack-zuul-jobs/roles:~/src/opendev.org/openstack/project-config/roles:~/src/opendev.org/opendev/system-config/roles
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index e7c200a..b9bd864 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -1,3 +1,11 @@
 - project:
     templates:
-      - noop-jobs
+      - build-openstack-docs-pti
+    check:
+      jobs:
+        - openstack-tox-linters
+        - openstack-tox-pep8
+    gate:
+      jobs:
+        - openstack-tox-linters
+        - openstack-tox-pep8