diff --git a/Api/ContentInstallerInterface.php b/Api/ContentInstallerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..4b846f6554bdd75f619ff83906105a90fdff6b72
--- /dev/null
+++ b/Api/ContentInstallerInterface.php
@@ -0,0 +1,14 @@
+<?php
+declare(strict_types=1);
+
+namespace Firegento\ContentProvisioning\Api;
+
+interface ContentInstallerInterface
+{
+    /**
+     * Apply all configured CMS content changes
+     *
+     * @return void
+     */
+    public function install(): void;
+}
diff --git a/Model/Config/Converter.php b/Model/Config/Converter.php
new file mode 100644
index 0000000000000000000000000000000000000000..4e96bbdb9c0a5024d03ab64d3c74db41b087133c
--- /dev/null
+++ b/Model/Config/Converter.php
@@ -0,0 +1,15 @@
+<?php
+declare(strict_types=1);
+
+namespace Firegento\ContentProvisioning\Model\Config;
+
+class Converter implements \Magento\Framework\Config\ConverterInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function convert($source)
+    {
+
+    }
+}
diff --git a/Model/Config/Data.php b/Model/Config/Data.php
new file mode 100644
index 0000000000000000000000000000000000000000..57d371fb6f17d1ba136059c0225a04f3d154c46a
--- /dev/null
+++ b/Model/Config/Data.php
@@ -0,0 +1,9 @@
+<?php
+declare(strict_types=1);
+
+namespace Firegento\ContentProvisioning\Model\Config;
+
+class Data extends \Magento\Framework\Config\Data
+{
+
+}
\ No newline at end of file
diff --git a/Model/Config/SchemaLocator.php b/Model/Config/SchemaLocator.php
new file mode 100644
index 0000000000000000000000000000000000000000..afc553b885de1af514ecaf59033a4d27cb62b4a2
--- /dev/null
+++ b/Model/Config/SchemaLocator.php
@@ -0,0 +1,54 @@
+<?php
+declare(strict_types=1);
+
+namespace Firegento\ContentProvisioning\Model\Config;
+
+class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface
+{
+    /**
+     * Path to corresponding XSD file with validation rules for merged config
+     *
+     * @var string
+     */
+    protected $_schema = null;
+
+    /**
+     * Path to corresponding XSD file with validation rules for separate config files
+     *
+     * @var string
+     */
+    protected $_perFileSchema = null;
+
+    /**
+     * @param \Magento\Framework\Module\Dir\Reader $moduleReader
+     */
+    public function __construct(\Magento\Framework\Module\Dir\Reader $moduleReader)
+    {
+        $etcDir = $moduleReader->getModuleDir(
+            \Magento\Framework\Module\Dir::MODULE_ETC_DIR,
+            'Firegento_ContentProvisioning'
+        );
+        $this->_schema = $etcDir . '/content_provisioning.xsd';
+        $this->_perFileSchema = $etcDir . '/content_provisioning.xsd';
+    }
+
+    /**
+     * Get path to merged config schema
+     *
+     * @return string|null
+     */
+    public function getSchema()
+    {
+        return $this->_schema;
+    }
+
+    /**
+     * Get path to per file validation schema
+     *
+     * @return string|null
+     */
+    public function getPerFileSchema()
+    {
+        return $this->_perFileSchema;
+    }
+}
diff --git a/Setup/Recurring.php b/Setup/Recurring.php
new file mode 100644
index 0000000000000000000000000000000000000000..588f6859b48299c2c98dc9cab4e3fcf8fa484107
--- /dev/null
+++ b/Setup/Recurring.php
@@ -0,0 +1,37 @@
+<?php
+declare(strict_types=1);
+
+namespace Firegento\ContentProvisioning\Setup;
+
+use Firegento\ContentProvisioning\Api\ContentInstallerInterface;
+use Magento\Framework\Setup\InstallSchemaInterface;
+use Magento\Framework\Setup\ModuleContextInterface;
+use Magento\Framework\Setup\SchemaSetupInterface;
+
+/**
+ * Class Recurring
+ */
+class Recurring implements InstallSchemaInterface
+{
+    /**
+     * @var ContentInstallerInterface
+     */
+    private $contentInstaller;
+
+    /**
+     * @param ContentInstallerInterface $contentInstaller
+     */
+    public function __construct(
+        ContentInstallerInterface $contentInstaller
+    ) {
+        $this->contentInstaller = $contentInstaller;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
+    {
+        $this->contentInstaller->install();
+    }
+}
diff --git a/etc/content_provisioning.xml b/etc/content_provisioning.xml
new file mode 100644
index 0000000000000000000000000000000000000000..66d111baf123ff6182953371e182571d5b6884e6
--- /dev/null
+++ b/etc/content_provisioning.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Firegento/ContentProvisioning/etc/content_provisioning.xsd">
+    <page identifier="foobar" maintained="true">
+        <stores>
+            <store code="default" />
+        </stores>
+        <content type="file">path/to/file.html</content>
+    </page>
+    <page identifier="test" maintained="false">
+        <stores>
+            <store code="*" />
+        </stores>
+        <content><![CDATA[this is some sample content...]]></content>
+    </page>
+    <block identifier="test" maintained="false">
+        <stores>
+            <store code="*" />
+        </stores>
+        <content><![CDATA[this is some sample content...]]></content>
+    </block>
+    <block identifier="test2" maintained="false">
+        <content><![CDATA[this is some sample content...]]></content>
+        <stores>
+            <store code="default" />
+            <store code="admin" />
+        </stores>
+    </block>
+</config>
diff --git a/etc/content_provisioning.xsd b/etc/content_provisioning.xsd
new file mode 100644
index 0000000000000000000000000000000000000000..419ecc0fc99b209a02074d63268c78fdb43f15fe
--- /dev/null
+++ b/etc/content_provisioning.xsd
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <xs:element name="config">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:choice minOccurs="1" maxOccurs="unbounded">
+                    <xs:element type="cms_entity" name="page" />
+                    <xs:element type="cms_entity" name="block" />
+                </xs:choice>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+
+    <xs:complexType name="cms_entity">
+        <xs:choice maxOccurs="unbounded">
+            <xs:element minOccurs="0" maxOccurs="1" type="stores" name="stores" />
+            <xs:element minOccurs="1" maxOccurs="1" type="content" name="content" />
+        </xs:choice>
+        <xs:attribute name="identifier" type="identifier" use="required" />
+        <xs:attribute name="maintained" type="xs:boolean" use="optional" />
+    </xs:complexType>
+
+    <xs:simpleType name="identifier">
+        <xs:annotation>
+            <xs:documentation>
+                Unique identifier for cms entities
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="[a-zA-Z0-9_\\]{1,}" />
+            <xs:minLength value="2" />
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="stores">
+        <xs:sequence>
+            <xs:element minOccurs="1" maxOccurs="unbounded" type="store" name="store" />
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="store">
+        <xs:attribute name="code" type="xs:string" use="required" />
+    </xs:complexType>
+
+    <xs:complexType name="content">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="type" type="content_type" use="optional" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="content_type">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="file"/>
+        </xs:restriction>
+    </xs:simpleType>
+</xs:schema>
\ No newline at end of file
diff --git a/etc/di.xml b/etc/di.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7caef290ee8e2555d13d72c7fd237916a5bff78b
--- /dev/null
+++ b/etc/di.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
+    <virtualType name="Firegento\ContentProvisioning\Model\Config\Reader" type="Magento\Framework\Config\Reader\Filesystem">
+        <arguments>
+            <argument name="fileName" xsi:type="string">content_provisioning.xml</argument>
+            <argument name="converter" xsi:type="object">Firegento\ContentProvisioning\Model\Config\Converter</argument>
+            <argument name="schemaLocator" xsi:type="object">Firegento\ContentProvisioning\Model\Config\SchemaLocator</argument>
+            <argument name="idAttributes" xsi:type="array">
+                <item name="/config/page" xsi:type="string">identifier</item>
+                <item name="/config/block" xsi:type="string">identifier</item>
+            </argument>
+        </arguments>
+    </virtualType>
+    <type name="Firegento\ContentProvisioning\Model\Config\Data">
+        <arguments>
+            <argument name="reader" xsi:type="object">Firegento\ContentProvisioning\Model\Config\Reader</argument>
+            <argument name="cacheId" xsi:type="string">content_provisioning_config</argument>
+        </arguments>
+    </type>
+</config>