Repository: airtai/nbdev-mkdocs (language: python)

Issue:
Use AI to generate social image



Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index a0f70433..07d45ac5 100644
--- a/README.md
+++ b/README.md
@@ -189,14 +189,15 @@ nbdev_mkdocs --help
     │ --help                        Show this message and exit.                    │
     ╰──────────────────────────────────────────────────────────────────────────────╯
     ╭─ Commands ───────────────────────────────────────────────────────────────────╮
-    │ docs     Prepares files in **mkdocs/docs** and then runs **mkdocs build**    │
-    │          command on them                                                     │
-    │ new      Creates files in **mkdocs** subdirectory needed for other           │
-    │          **nbdev_mkdocs** subcommands                                        │
-    │ prepare  Runs tests and prepares files in **mkdocs/docs** and then runs      │
-    │          **mkdocs build** command on them                                    │
-    │ preview  Prepares files in **mkdocs/docs** and then runs **mkdocs serve**    │
-    │          command on them                                                     │
+    │ docs                   Prepares files in **mkdocs/docs** and then runs       │
+    │                        **mkdocs build** command on them                      │
+    │ generate-social-image  Generate a custom social share image                  │
+    │ new                    Creates files in **mkdocs** subdirectory needed for   │
+    │                        other **nbdev_mkdocs** subcommands                    │
+    │ prepare                Runs tests and prepares files in **mkdocs/docs** and  │
+    │                        then runs **mkdocs build** command on them            │
+    │ preview                Prepares files in **mkdocs/docs** and then runs       │
+    │                        **mkdocs serve** command on them                      │
     ╰──────────────────────────────────────────────────────────────────────────────╯
 
 ### Setup
diff --git a/mkdocs/docs_overrides/images/default_social_logo.png b/mkdocs/docs_overrides/images/default_social_logo.png
new file mode 100644
index 00000000..d53cbad1
Binary files /dev/null and b/mkdocs/docs_overrides/images/default_social_logo.png differ
diff --git a/mkdocs/docs_overrides/images/social_image.png b/mkdocs/docs_overrides/images/social_image.png
new file mode 100644
index 00000000..7b7b6a55
Binary files /dev/null and b/mkdocs/docs_overrides/images/social_image.png differ
diff --git a/mkdocs/mkdocs.yml b/mkdocs/mkdocs.yml
index 38281a50..fa5b8788 100644
--- a/mkdocs/mkdocs.yml
+++ b/mkdocs/mkdocs.yml
@@ -100,4 +100,4 @@ extra:
   analytics:
     provider: google
     property: G-0DTVVPJ60K
-  social_image: https://opengraph.githubassets.com/1670780981.299176/airtai/nbdev-mkdocs
+  social_image: overrides/images/social_image.png
diff --git a/mkdocs/site_overrides/main.html b/mkdocs/site_overrides/main.html
index 9a5ad916..a5fb6e20 100644
--- a/mkdocs/site_overrides/main.html
+++ b/mkdocs/site_overrides/main.html
@@ -7,7 +7,7 @@
   {% elif page and page.title and not page.is_homepage %}
     {% set title = title ~ " - " ~ page.title | striptags %}
   {% endif %}
-  {% set image_url = config.extra.social_image %}
+  {% set image_url = page.canonical_url ~ "" ~ config.extra.social_image %}
   <meta property="og:type" content="website" />
   <meta property="og:title" content="{{ title }}" />
   <meta property="og:description" content="{{ config.site_description }}" />
diff --git a/nbdev_mkdocs/_cli.py b/nbdev_mkdocs/_cli.py
index c1648c20..87d11193 100644
--- a/nbdev_mkdocs/_cli.py
+++ b/nbdev_mkdocs/_cli.py
@@ -1,11 +1,12 @@
 # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/CLI.ipynb.
 
 # %% auto 0
-__all__ = ['new', 'prepare', 'preview', 'docs']
+__all__ = ['new', 'prepare', 'preview', 'docs', 'generate_social_image']
 
 # %% ../nbs/CLI.ipynb 1
 from typing import *
 from pathlib import Path
+from asyncio import run as aiorun
 
 import typer
 
@@ -69,3 +70,40 @@ def docs(root_path: str = typer.Option(".", help="Project's root path.")):
     except Exception as e:
         typer.secho(f"Unexpected internal error: {e}", err=True, fg=typer.colors.RED)
         raise typer.Exit(1)
+
+
+@_app.command(
+    help="Generate a custom social share image",
+)
+def generate_social_image(
+    root_path: str = typer.Option(".", help="Project's root path."),
+    generator: nbdev_mkdocs.social_image_generator._IMG_Generator = typer.Option(
+        "file",
+        help="Generator to use to create the social image. Valid options are: 'file' and 'dall_e'. Choose 'file' if you want to use an existing image from your local machine in the social share image.",
+    ),
+    prompt: Optional[str] = typer.Option(
+        "Cute animal wearing hoodie sitting in high chair in purple room, browsing computer, 3d render",
+        help="The prompt to use for generating the image.",
+    ),
+    image_path: Optional[str] = typer.Option(
+        None,
+        help="Image file path to use in the social share image. If None, then the default image will be used.",
+    ),
+):
+    """CLI command for generating a custom social share image"""
+
+    async def _generate_social_image(root_path, generator, prompt, image_path):
+        try:
+            await nbdev_mkdocs.social_image_generator.generate_social_image(
+                root_path=root_path,
+                generator=generator,
+                prompt=prompt,
+                image_path=image_path,
+            )
+        except Exception as e:
+            typer.secho(
+                f"Unexpected internal error: {e}", err=True, fg=typer.colors.RED
+            )
+            raise typer.Exit(1)
+
+    aiorun(_generate_social_image(root_path, generator, prompt, image_path))
diff --git a/nbdev_mkdocs/_helpers/utils.py b/nbdev_mkdocs/_helpers/utils.py
new file mode 100644
index 00000000..352e8622
--- /dev/null
+++ b/nbdev_mkdocs/_helpers/utils.py
@@ -0,0 +1,54 @@
+# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/Utils.ipynb.
+
+# %% auto 0
+__all__ = ['set_cwd', 'get_value_from_config', 'is_local_path']
+
+# %% ../../nbs/Utils.ipynb 1
+import os
+from typing import *
+from urllib.parse import urlparse
+from contextlib import contextmanager
+from pathlib import Path
+
+import nbdev
+from configparser import ConfigParser
+
+# %% ../../nbs/Utils.ipynb 3
+@contextmanager
+def set_cwd(cwd_path: Union[Path, str]):
+
+    cwd_path = Path(cwd_path)
+    original_cwd = os.getcwd()
+    os.chdir(cwd_path)
+
+    try:
+        nbdev.config.get_config.cache_clear()
+        yield
+    finally:
+        os.chdir(original_cwd)
+
+# %% ../../nbs/Utils.ipynb 5
+def get_value_from_config(root_path: str, config_name: str) -> str:
+    """Get the value from settings.ini file"""
+
+    settings_path = Path(root_path) / "settings.ini"
+    config = ConfigParser()
+    config.read(settings_path)
+    if not config.has_option("DEFAULT", config_name):
+        return ""
+    return config["DEFAULT"][config_name]
+
+# %% ../../nbs/Utils.ipynb 7
+def is_local_path(path):
+    # Check if the path is an absolute path
+    if os.path.isabs(path):
+        return True
+
+    # Check if the path is a URL with a scheme (e.g. http, https, ftp)
+    parsed_url = urlparse(path)
+    if parsed_url.scheme:
+        return False
+
+    # If the path is not an absolute path and does not have a URL scheme,
+    # it is assumed to be a local path
+    return True
diff --git a/nbdev_mkdocs/_modidx.py b/nbdev_mkdocs/_modidx.py
index ca7b3e70..b6bda6d1 100644
--- a/nbdev_mkdocs/_modidx.py
+++ b/nbdev_mkdocs/_modidx.py
@@ -17,6 +17,12 @@
                                                                                                         'nbdev_mkdocs/_helpers/cli_doc.py'),
                                                'nbdev_mkdocs._helpers.cli_doc.generate_cli_doc': ( 'cli_doc_helper.html#generate_cli_doc',
                                                                                                    'nbdev_mkdocs/_helpers/cli_doc.py')},
+            'nbdev_mkdocs._helpers.utils': { 'nbdev_mkdocs._helpers.utils.get_value_from_config': ( 'utils.html#get_value_from_config',
+                                                                                                    'nbdev_mkdocs/_helpers/utils.py'),
+                                             'nbdev_mkdocs._helpers.utils.is_local_path': ( 'utils.html#is_local_path',
+                                                                                            'nbdev_mkdocs/_helpers/utils.py'),
+                                             'nbdev_mkdocs._helpers.utils.set_cwd': ( 'utils.html#set_cwd',
+                                                                                      'nbdev_mkdocs/_helpers/utils.py')},
             'nbdev_mkdocs.docstring': { 'nbdev_mkdocs.docstring._extract_examples_from_docstring': ( 'docstring.html#_extract_examples_from_docstring',
                                                                                                      'nbdev_mkdocs/docstring.py'),
                                         'nbdev_mkdocs.docstring._format_output': ( 'docstring.html#_format_output',
@@ -52,8 +58,6 @@
                                                                                                'nbdev_mkdocs/mkdocs.py'),
                                      'nbdev_mkdocs.mkdocs._get_title_from_notebook': ( 'mkdocs.html#_get_title_from_notebook',
                                                                                        'nbdev_mkdocs/mkdocs.py'),
-                                     'nbdev_mkdocs.mkdocs._get_value_from_config': ( 'mkdocs.html#_get_value_from_config',
-                                                                                     'nbdev_mkdocs/mkdocs.py'),
                                      'nbdev_mkdocs.mkdocs._replace_all': ('mkdocs.html#_replace_all', 'nbdev_mkdocs/mkdocs.py'),
                                      'nbdev_mkdocs.mkdocs._replace_ghp_deploy_action': ( 'mkdocs.html#_replace_ghp_deploy_action',
                                                                                          'nbdev_mkdocs/mkdocs.py'),
@@ -84,5 +88,22 @@
                                      'nbdev_mkdocs.mkdocs.prepare': ('mkdocs.html#prepare', 'nbdev_mkdocs/mkdocs.py'),
                                      'nbdev_mkdocs.mkdocs.prepare_cli': ('mkdocs.html#prepare_cli', 'nbdev_mkdocs/mkdocs.py'),
                                      'nbdev_mkdocs.mkdocs.preview': ('mkdocs.html#preview', 'nbdev_mkdocs/mkdocs.py'),
-                                     'nbdev_mkdocs.mkdocs.preview_cli': ('mkdocs.html#preview_cli', 'nbdev_mkdocs/mkdocs.py'),
-                                     'nbdev_mkdocs.mkdocs.set_cwd': ('mkdocs.html#set_cwd', 'nbdev_mkdocs/mkdocs.py')}}}
+                                     'nbdev_mkdocs.mkdocs.preview_cli': ('mkdocs.html#preview_cli', 'nbdev_mkdocs/mkdocs.py')},
+            'nbdev_mkdocs.social_image_generator': { 'nbdev_mkdocs.social_image_generator._IMG_Generator': ( 'social_image_generator.html#_img_generator',
+                                                                                                             'nbdev_mkdocs/social_image_generator.py'),
+                                                     'nbdev_mkdocs.social_image_generator._capture_and_save_screenshot': ( 'social_image_generator.html#_capture_and_save_screenshot',
+                                                                                                                           'nbdev_mkdocs/social_image_generator.py'),
+                                                     'nbdev_mkdocs.social_image_generator._create_social_image': ( 'social_image_generator.html#_create_social_image',
+                                                                                                                   'nbdev_mkdocs/social_image_generator.py'),
+                                                     'nbdev_mkdocs.social_image_generator._generate_ai_image': ( 'social_image_generator.html#_generate_ai_image',
+                                                                                                                 'nbdev_mkdocs/social_image_generator.py'),
+                                                     'nbdev_mkdocs.social_image_generator._generate_html_str': ( 'social_image_generator.html#_generate_html_str',
+                                                                                                                 'nbdev_mkdocs/social_image_generator.py'),
+                                                     'nbdev_mkdocs.social_image_generator._generate_image_url': ( 'social_image_generator.html#_generate_image_url',
+                                                                                                                  'nbdev_mkdocs/social_image_generator.py'),
+                                                     'nbdev_mkdocs.social_image_generator._update_social_image_in_mkdocs_yml': ( 'social_image_generator.html#_update_social_image_in_mkdocs_yml',
+                                                                                                                                 'nbdev_mkdocs/social_image_generator.py'),
+                                                     'nbdev_mkdocs.social_image_generator._update_social_image_in_site_overrides': ( 'social_image_generator.html#_update_social_image_in_site_overrides',
+                                                                                                                                     'nbdev_mkdocs/social_image_generator.py'),
+                                                     'nbdev_mkdocs.social_image_generator.generate_social_image': ( 'social_image_generator.html#generate_social_image',
+                                                                                                                    'nbdev_mkdocs/social_image_generator.py')}}}
diff --git a/nbdev_mkdocs/mkdocs.py b/nbdev_mkdocs/mkdocs.py
index 635c0096..85728436 100644
--- a/nbdev_mkdocs/mkdocs.py
+++ b/nbdev_mkdocs/mkdocs.py
@@ -1,7 +1,7 @@
 # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/Mkdocs.ipynb.
 
 # %% auto 0
-__all__ = ['set_cwd', 'new', 'new_cli', 'get_submodules', 'generate_api_doc_for_submodule', 'generate_api_docs_for_module',
+__all__ = ['new', 'new_cli', 'get_submodules', 'generate_api_doc_for_submodule', 'generate_api_docs_for_module',
            'generate_cli_doc_for_submodule', 'generate_cli_docs_for_module', 'build_summary', 'copy_cname_if_needed',
            'nbdev_mkdocs_docs', 'nbdev_mkdocs_docs_cli', 'prepare', 'prepare_cli', 'preview', 'preview_cli']
 
@@ -23,7 +23,6 @@
 import multiprocessing
 import datetime
 
-from ruamel.yaml import YAML
 import typer
 from typer.testing import CliRunner
 
@@ -44,19 +43,10 @@
 
 from ._package_data import get_root_data_path
 from ._helpers.cli_doc import generate_cli_doc
+from ._helpers.utils import set_cwd, get_value_from_config
+from .social_image_generator import _update_social_image_in_mkdocs_yml
 
-# %% ../nbs/Mkdocs.ipynb 4
-def _get_value_from_config(root_path: str, config_name: str) -> str:
-    """Get the value from settings.ini file"""
-
-    settings_path = Path(root_path) / "settings.ini"
-    config = ConfigParser()
-    config.read(settings_path)
-    if not config.has_option("DEFAULT", config_name):
-        return ""
-    return config["DEFAULT"][config_name]
-
-# %% ../nbs/Mkdocs.ipynb 8
+# %% ../nbs/Mkdocs.ipynb 5
 def _add_requirements_to_settings(root_path: str):
     """Adds requirments needed for mkdocs to settings.ini
 
@@ -127,7 +117,7 @@ def remove_leading_spaces(s: str) -> str:
 
     return
 
-# %% ../nbs/Mkdocs.ipynb 11
+# %% ../nbs/Mkdocs.ipynb 8
 def _create_mkdocs_dir(root_path: str):
     mkdocs_template_path = get_root_data_path() / "mkdocs_template"
     if not mkdocs_template_path.exists():
@@ -149,14 +139,14 @@ def _create_mkdocs_dir(root_path: str):
             f"Directory {dst_path.resolve()} created.",
         )
 
-# %% ../nbs/Mkdocs.ipynb 14
+# %% ../nbs/Mkdocs.ipynb 11
 _mkdocs_template_path = get_root_data_path() / "mkdocs_template.yml"
 
-# %% ../nbs/Mkdocs.ipynb 16
+# %% ../nbs/Mkdocs.ipynb 13
 with open(_mkdocs_template_path, "r") as f:
     _mkdocs_template = f.read()
 
-# %% ../nbs/Mkdocs.ipynb 18
+# %% ../nbs/Mkdocs.ipynb 15
 def _get_kwargs_from_settings(
     settings_path: Path, mkdocs_template: Optional[str] = None
 ) -> Dict[str, str]:
@@ -168,7 +158,7 @@ def _get_kwargs_from_settings(
     kwargs = {k: config["DEFAULT"][k] for k in keys}
     return kwargs
 
-# %% ../nbs/Mkdocs.ipynb 20
+# %% ../nbs/Mkdocs.ipynb 17
 def _create_mkdocs_yaml(root_path: str):
     try:
         # create mkdocs folder if necessary
@@ -197,7 +187,7 @@ def _create_mkdocs_yaml(root_path: str):
         )
         raise typer.Exit(code=3)
 
-# %% ../nbs/Mkdocs.ipynb 23
+# %% ../nbs/Mkdocs.ipynb 20
 _summary_template = """- [Home](index.md)
 {guides}
 {api}
@@ -231,7 +221,7 @@ def _create_summary_template(root_path: str):
         )
         raise typer.Exit(code=3)
 
-# %% ../nbs/Mkdocs.ipynb 25
+# %% ../nbs/Mkdocs.ipynb 22
 def _replace_ghp_deploy_action(root_path: str):
     """Replace the default gh-pages deploy action file with the custom action template file
 
@@ -254,24 +244,7 @@ def _replace_ghp_deploy_action(root_path: str):
     dst_path = Path(workflows_path) / "deploy.yaml"
     shutil.copyfile(src_path, dst_path)
 
-# %% ../nbs/Mkdocs.ipynb 27
-from contextlib import contextmanager
-
-
-@contextmanager
-def set_cwd(cwd_path: Union[Path, str]):
-
-    cwd_path = Path(cwd_path)
-    original_cwd = os.getcwd()
-    os.chdir(cwd_path)
-
-    try:
-        nbdev.config.get_config.cache_clear()
-        yield
-    finally:
-        os.chdir(original_cwd)
-
-# %% ../nbs/Mkdocs.ipynb 30
+# %% ../nbs/Mkdocs.ipynb 25
 def _update_gitignore_file(root_path: str):
     """Update the .gitignore file to include the autogenerated mkdocs directories
 
@@ -296,7 +269,7 @@ def _update_gitignore_file(root_path: str):
     with open(gitignore_path, "a") as f:
         f.write(_new_paths_to_ignore)
 
-# %% ../nbs/Mkdocs.ipynb 32
+# %% ../nbs/Mkdocs.ipynb 27
 def _generate_default_social_image_link(root_path: str):
     """Generating default social sharing image link and add it to the mkdocs yaml file
 
@@ -305,27 +278,15 @@ def _generate_default_social_image_link(root_path: str):
     """
 
     with set_cwd(root_path):
-        repo = _get_value_from_config(root_path, "repo")
-        user = _get_value_from_config(root_path, "user")
+        repo = get_value_from_config(root_path, "repo")
+        user = get_value_from_config(root_path, "user")
 
         timestamp = datetime.datetime.now().timestamp()
         img_url = f"https://opengraph.githubassets.com/{timestamp}/{user}/{repo}"
 
-        mkdocs_yml_path = Path(root_path) / "mkdocs" / "mkdocs.yml"
-        if not mkdocs_yml_path.exists():
-            typer.secho(
-                f"Unexpected error: path {mkdocs_yml_path.resolve()} does not exists!",
-                err=True,
-                fg=typer.colors.RED,
-            )
-            raise typer.Exit(code=1)
-
-        yaml = YAML()
-        config = yaml.load(mkdocs_yml_path)
-        config["extra"]["social_image"] = img_url
-        yaml.dump(config, mkdocs_yml_path)
+        _update_social_image_in_mkdocs_yml(root_path, img_url)
 
-# %% ../nbs/Mkdocs.ipynb 35
+# %% ../nbs/Mkdocs.ipynb 30
 def new(root_path: str):
     """Initialize mkdocs project files
 
@@ -342,10 +303,11 @@ def new(root_path: str):
     _create_summary_template(root_path)
     _replace_ghp_deploy_action(root_path)
     _update_gitignore_file(root_path)
+    _generate_default_social_image_link(root_path)
 
 
 @call_parse
-def new_cli(root_path: str):
+def new_cli(root_path: str = "."):
     """Initialize mkdocs project files
 
     Creates **mkdocs** directory in the **root_path** directory and populates
@@ -354,7 +316,7 @@ def new_cli(root_path: str):
     """
     new(root_path)
 
-# %% ../nbs/Mkdocs.ipynb 39
+# %% ../nbs/Mkdocs.ipynb 34
 def _get_nbs_for_markdown_conversion(cache: Path):
     """Get a list of notebooks that needs to be converted to markdown.
 
@@ -363,7 +325,7 @@ def _get_nbs_for_markdown_conversion(cache: Path):
     """
     return list(cache.glob("index.ipynb")) + list(cache.glob("./guides/*.ipynb"))
 
-# %% ../nbs/Mkdocs.ipynb 41
+# %% ../nbs/Mkdocs.ipynb 36
 def _sprun(cmd):
     try:
         # nosemgrep: python.lang.security.audit.subprocess-shell-true.subprocess-shell-true
@@ -376,7 +338,7 @@ def _sprun(cmd):
             f"CMD Failed: e={e}\n e.returncode={e.returncode}\n e.output={e.output}\n e.stderr={e.stderr}\n cmd={cmd}"
         )
 
-# %% ../nbs/Mkdocs.ipynb 42
+# %% ../nbs/Mkdocs.ipynb 37
 def _generate_markdown_from_nbs(root_path: str):
 
     doc_path = Path(root_path) / "mkdocs" / "docs"
@@ -384,7 +346,7 @@ def _generate_markdown_from_nbs(root_path: str):
 
     with set_cwd(root_path):
 
-        nbs_path = _get_value_from_config(root_path, "nbs_path")
+        nbs_path = get_value_from_config(root_path, "nbs_path")
         path = Path(root_path) / nbs_path
 
         cache = proc_nbs()
@@ -402,7 +364,7 @@ def _generate_markdown_from_nbs(root_path: str):
             src_md = cache / "_docs" / f"{nb.stem}.md"
             shutil.move(src_md, dst_md)
 
-# %% ../nbs/Mkdocs.ipynb 44
+# %% ../nbs/Mkdocs.ipynb 39
 def _replace_all(text: str, dir_prefix: str) -> str:
     """Replace the images relative path in the markdown text
 
@@ -430,7 +392,7 @@ def _replace_all(text: str, dir_prefix: str) -> str:
 
     return text
 
-# %% ../nbs/Mkdocs.ipynb 46
+# %% ../nbs/Mkdocs.ipynb 41
 def _update_path_in_markdown(cache: Path, doc_path: Path):
     """Update guide images relative path in the markdown files
 
@@ -488,7 +450,7 @@ def _copy_guide_images_to_docs_dir(root_path: str):
 
         _update_path_in_markdown(cache, doc_path)
 
-# %% ../nbs/Mkdocs.ipynb 50
+# %% ../nbs/Mkdocs.ipynb 45
 def _get_title_from_notebook(nb_name: str) -> str:
     cache = proc_nbs()
     nb_path = Path(cache) / "guides" / f"{nb_name}.ipynb"
@@ -505,7 +467,7 @@ def _get_title_from_notebook(nb_name: str) -> str:
     nbp.process()
     return nbp.nb.frontmatter_["title"]
 
-# %% ../nbs/Mkdocs.ipynb 52
+# %% ../nbs/Mkdocs.ipynb 47
 def _generate_summary_for_guides(root_path: str) -> str:
     doc_path = Path(root_path) / "mkdocs" / "docs"
     mds = sorted(
@@ -523,7 +485,7 @@ def _generate_summary_for_guides(root_path: str) -> str:
     else:
         return ""
 
-# %% ../nbs/Mkdocs.ipynb 55
+# %% ../nbs/Mkdocs.ipynb 50
 def get_submodules(package_name: str) -> List[str]:
     # nosemgrep: python.lang.security.audit.non-literal-import.non-literal-import
     m = importlib.import_module(package_name)
@@ -538,7 +500,7 @@ def get_submodules(package_name: str) -> List[str]:
     ]
     return submodules
 
-# %% ../nbs/Mkdocs.ipynb 57
+# %% ../nbs/Mkdocs.ipynb 52
 def generate_api_doc_for_submodule(root_path: str, submodule: str) -> str:
     subpath = "API/" + submodule.replace(".", "/") + ".md"
     path = Path(root_path) / "mkdocs" / "docs" / subpath
@@ -568,7 +530,7 @@ def generate_api_docs_for_module(root_path: str, module_name: str) -> str:
 
     return "- API\n" + textwrap.indent(submodule_summary, prefix=" " * 4)
 
-# %% ../nbs/Mkdocs.ipynb 59
+# %% ../nbs/Mkdocs.ipynb 54
 def _restrict_line_length(s: str, width: int = 80) -> str:
     """Restrict the line length of the given string.
 
@@ -592,7 +554,7 @@ def _restrict_line_length(s: str, width: int = 80) -> str:
                 _s += "\n" + line + "\n" if line.endswith(":") else " " + line + "\n"
     return _s
 
-# %% ../nbs/Mkdocs.ipynb 61
+# %% ../nbs/Mkdocs.ipynb 56
 def generate_cli_doc_for_submodule(root_path: str, cmd: str) -> str:
 
     cli_app_name = cmd.split("=")[0]
@@ -633,7 +595,7 @@ def generate_cli_doc_for_submodule(root_path: str, cmd: str) -> str:
 
 def generate_cli_docs_for_module(root_path: str, module_name: str) -> str:
     shutil.rmtree(Path(root_path) / "mkdocs" / "docs" / "CLI", ignore_errors=True)
-    console_scripts = _get_value_from_config(root_path, "console_scripts")
+    console_scripts = get_value_from_config(root_path, "console_scripts")
 
     if not console_scripts:
         return ""
@@ -647,7 +609,7 @@ def generate_cli_docs_for_module(root_path: str, module_name: str) -> str:
 
     return "- CLI\n" + textwrap.indent(submodule_summary, prefix=" " * 4)
 
-# %% ../nbs/Mkdocs.ipynb 63
+# %% ../nbs/Mkdocs.ipynb 58
 def _copy_change_log_if_exists(
     root_path: Union[Path, str], docs_path: Union[Path, str]
 ) -> str:
@@ -659,7 +621,7 @@ def _copy_change_log_if_exists(
         changelog = "- [Releases](CHANGELOG.md)"
     return changelog
 
-# %% ../nbs/Mkdocs.ipynb 66
+# %% ../nbs/Mkdocs.ipynb 61
 def build_summary(
     root_path: str,
     module: str,
@@ -703,7 +665,7 @@ def build_summary(
     with open(docs_path / "SUMMARY.md", mode="w") as f:
         f.write(summary)
 
-# %% ../nbs/Mkdocs.ipynb 69
+# %% ../nbs/Mkdocs.ipynb 64
 def copy_cname_if_needed(root_path: str):
     cname_path = Path(root_path) / "CNAME"
     dst_path = Path(root_path) / "mkdocs" / "docs" / "CNAME"
@@ -718,7 +680,7 @@ def copy_cname_if_needed(root_path: str):
             f"File '{cname_path.resolve()}' not found, skipping copying..",
         )
 
-# %% ../nbs/Mkdocs.ipynb 71
+# %% ../nbs/Mkdocs.ipynb 66
 def _copy_docs_overrides(root_path: str):
     """Copy lib assets inside mkodcs/docs directory
 
@@ -739,7 +701,7 @@ def _copy_docs_overrides(root_path: str):
     shutil.rmtree(dst_path, ignore_errors=True)
     shutil.copytree(src_path, dst_path)
 
-# %% ../nbs/Mkdocs.ipynb 73
+# %% ../nbs/Mkdocs.ipynb 68
 def nbdev_mkdocs_docs(root_path: str, refresh_quarto_settings: bool = False):
     """Prepares mkdocs documentation
 
@@ -758,18 +720,18 @@ def nbdev_mkdocs_docs(root_path: str, refresh_quarto_settings: bool = False):
 
         _copy_docs_overrides(root_path)
 
-        lib_name = _get_value_from_config(root_path, "lib_name")
-        lib_path = _get_value_from_config(root_path, "lib_path")
+        lib_name = get_value_from_config(root_path, "lib_name")
+        lib_path = get_value_from_config(root_path, "lib_path")
 
         build_summary(root_path, lib_path)
-        _generate_default_social_image_link(root_path)
+        #         _generate_default_social_image_link(root_path)
 
         cmd = f"mkdocs build -f \"{(Path(root_path) / 'mkdocs' / 'mkdocs.yml').resolve()}\""
         _sprun(cmd)
 
 
 @call_parse
-def nbdev_mkdocs_docs_cli(root_path: str):
+def nbdev_mkdocs_docs_cli(root_path: str = "."):
     """Prepares mkdocs documentation"""
     nbdev_mkdocs_docs(root_path, refresh_quarto_settings=True)
 
@@ -794,11 +756,11 @@ def prepare(root_path: str, no_test: bool = False):
 
 
 @call_parse
-def prepare_cli(root_path: str):
+def prepare_cli(root_path: str = "."):
     """Prepares mkdocs for serving"""
     prepare(root_path)
 
-# %% ../nbs/Mkdocs.ipynb 76
+# %% ../nbs/Mkdocs.ipynb 71
 def preview(root_path: str, port: Optional[int] = None):
     """Previes mkdocs documentation
 
@@ -833,6 +795,6 @@ def preview(root_path: str, port: Optional[int] = None):
 
 
 @call_parse
-def preview_cli(root_path: str, port: Optional[int] = None):
+def preview_cli(root_path: str = ".", port: Optional[int] = None):
     """Previes mkdocs documentation"""
     preview(root_path, port)
diff --git a/nbdev_mkdocs/package_data/custom-social-image-template.html b/nbdev_mkdocs/package_data/custom-social-image-template.html
new file mode 100644
index 00000000..fec4d100
--- /dev/null
+++ b/nbdev_mkdocs/package_data/custom-social-image-template.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <link rel="preload" href='https://fonts.googleapis.com/css?family=Source Sans Pro' rel='stylesheet'/>
+        <style>
+            body {
+                margin: 0px;
+                width: 1280px;
+                height: 640px;
+                font-family: 'Source Sans Pro', sans-serif;
+            }
+            #container {
+                display: flex;
+                height: 640px;
+            }
+            #container div:first-child{
+                flex-basis: 704px;
+                padding-top: 40px;
+            }
+            #container div:first-child h1{
+                font-size: 85px;
+                margin: 74px 0px 64px 60px;
+                color: #2E363D;
+            }
+            #container div:first-child h1 span{
+                font-weight: 100;
+            }
+            #container div:first-child p {
+                font-size: 30px;
+                color: #6E7681;
+                margin: 64px 0px 64px 64px;
+            }
+            #container div:last-child img{
+                margin: 64px 64px 64px 0px;
+                border-radius: 50px;
+            }
+        </style>
+      </head>
+      <body>
+      <div id="container">
+         <div>
+            <h1><span>fill_in_author_name/</span>fill_in_project_name</h1>
+            <p>fill_in_project_description</p>
+         </div>
+         <div>
+            <img src="fill_in_image_url" />
+         </div>
+      </div>
+   </body>
+</html>
diff --git a/nbdev_mkdocs/package_data/mkdocs_template.yml b/nbdev_mkdocs/package_data/mkdocs_template.yml
index ad84cab4..22a6d539 100644
--- a/nbdev_mkdocs/package_data/mkdocs_template.yml
+++ b/nbdev_mkdocs/package_data/mkdocs_template.yml
@@ -86,11 +86,14 @@ theme:
 #     admonition:
 #         <type>: <icon> 
   favicon: overrides/images/compass-outline.png
+  
 extra_css:
   - overrides/css/extra.css
 
 extra_javascript:
   - overrides/js/extra.js
-  
+  - overrides/js/mathjax.js
+  - https://polyfill.io/v3/polyfill.min.js?features=es6
+  - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js  
 extra:
   social_image: ""
diff --git a/nbdev_mkdocs/package_data/mkdocs_template/docs_overrides/images/default_social_logo.png b/nbdev_mkdocs/package_data/mkdocs_template/docs_overrides/images/default_social_logo.png
new file mode 100644
index 00000000..d53cbad1
Binary files /dev/null and b/nbdev_mkdocs/package_data/mkdocs_template/docs_overrides/images/default_social_logo.png differ
diff --git a/nbdev_mkdocs/package_data/mkdocs_template/docs_overrides/js/math.js b/nbdev_mkdocs/package_data/mkdocs_template/docs_overrides/js/math.js
new file mode 100644
index 00000000..1d586b35
--- /dev/null
+++ b/nbdev_mkdocs/package_data/mkdocs_template/docs_overrides/js/math.js
@@ -0,0 +1,18 @@
+window.MathJax = {
+  tex: {
+    inlineMath: [["\\(", "\\)"]],
+    displayMath: [["\\[", "\\]"]],
+    processEscapes: true,
+    processEnvironments: true
+  },
+  options: {
+    ignoreHtmlClass: ".*|",
+    processHtmlClass: "arithmatex"
+  }
+};
+
+document$.subscribe(() => {
+  MathJax.typesetPromise()
+})
+
+
diff --git a/nbdev_mkdocs/package_data/requirements.txt b/nbdev_mkdocs/package_data/requirements.txt
index a3b40397..1eea00c7 100644
--- a/nbdev_mkdocs/package_data/requirements.txt
+++ b/nbdev_mkdocs/package_data/requirements.txt
@@ -6,3 +6,5 @@ mkdocs-section-index>=0.3.4
 configupdater>=3.1.1
 griffe>=0.24.1
 ruamel.yaml>=0.17.21
+openai>=0.25.0
+playwright>=1.28.0
diff --git a/nbdev_mkdocs/social_image_generator.py b/nbdev_mkdocs/social_image_generator.py
new file mode 100644
index 00000000..f5f1f275
--- /dev/null
+++ b/nbdev_mkdocs/social_image_generator.py
@@ -0,0 +1,258 @@
+# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/Social_Image_Generator.ipynb.
+
+# %% auto 0
+__all__ = ['generate_social_image']
+
+# %% ../nbs/Social_Image_Generator.ipynb 1
+from typing import *
+from pathlib import Path
+import re
+import os
+import asyncio
+import shutil
+from tempfile import TemporaryDirectory
+from enum import Enum
+
+import openai
+import typer
+from playwright.async_api import async_playwright
+from ruamel.yaml import YAML
+
+from ._helpers.utils import set_cwd, get_value_from_config, is_local_path
+from ._package_data import get_root_data_path
+
+# %% ../nbs/Social_Image_Generator.ipynb 3
+def _generate_ai_image(prompt: str) -> str:
+    """Generate an image for social card using the OpenAI Image API.
+
+    Args:
+        prompt: The prompt to use for generating the image.
+
+    Returns:
+        The URL of the generated image.
+    """
+    response = openai.Image.create(prompt=prompt, n=1, size="512x512")
+    image_url = response["data"][0]["url"]
+    return image_url
+
+# %% ../nbs/Social_Image_Generator.ipynb 5
+def _generate_html_str(root_path: str, image_url: str) -> str:
+    """Generate html string for the social card
+
+    Args:
+        root_path: The root path of the project.
+        image_url: The image URL to be included in the HTML.
+    """
+
+    with set_cwd(root_path):
+
+        _custom_social_image_template_path = (
+            get_root_data_path() / "custom-social-image-template.html"
+        )
+
+        with open(_custom_social_image_template_path, "r") as f:
+            _html_template = f.read()
+
+        author_name = get_value_from_config(root_path, "author")
+        project_name = get_value_from_config(root_path, "repo")
+        project_description = get_value_from_config(root_path, "description")
+
+        image_url = Path(image_url).name if is_local_path(image_url) else image_url
+
+        d = dict(
+            fill_in_author_name=author_name,
+            fill_in_project_name=project_name,
+            fill_in_project_description=project_description,
+            fill_in_image_url=image_url,
+        )
+
+        for k, v in d.items():
+            _html_template = _html_template.replace(k, v)
+
+        return _html_template
+
+# %% ../nbs/Social_Image_Generator.ipynb 8
+async def _capture_and_save_screenshot(src_path: str, dst_path: str):
+    """Capture screenshot of an HTML file from source directory and save the
+    output in destination directory
+
+    Args:
+        src_path: The source path of the HTML file that will be used to generate the PNG image.
+        dst_path: The destination path where the generated screenshot image will be saved.
+    """
+    playwright = await async_playwright().start()
+    browser = await playwright.chromium.launch()
+
+    try:
+        page = await browser.new_page()
+
+        html_path = Path(src_path) / "social_image.html"
+        await page.goto(f"file://{str(html_path.resolve())}")
+
+        output_path = (
+            Path(dst_path) / "mkdocs" / "docs_overrides" / "images" / "social_image.png"
+        )
+        await page.locator("#container").screenshot(path=str(output_path.resolve()))
+
+        typer.echo(f"Social share image generated and saved at: '{output_path}'")
+
+    finally:
+        await browser.close()
+
+# %% ../nbs/Social_Image_Generator.ipynb 10
+async def _create_social_image(root_path: str, image_url: str):
+    """Create social image for the project
+
+    Args:
+        root_path: The root path of the project.
+        image_url: The image URL to be included in the social image.
+    """
+    html_str = _generate_html_str(root_path, image_url)
+
+    with TemporaryDirectory() as d:
+
+        html_path = Path(d) / "social_image.html"
+        with open(html_path, "w") as f:
+            f.write(html_str)
+
+        if is_local_path(image_url):
+            shutil.copyfile(Path(image_url), Path(d) / Path(image_url).name)
+
+        await _capture_and_save_screenshot(d, root_path)
+
+# %% ../nbs/Social_Image_Generator.ipynb 12
+def _update_social_image_in_mkdocs_yml(root_path: str, image_url: str):
+    """Update social image link in mkdocs yml file
+
+    Args:
+        root_path: The root path of the project.
+        image_url: The image URL to update in the mkdocs yml file.
+    """
+
+    image_url = (
+        "overrides/images/social_image.png" if is_local_path(image_url) else image_url
+    )
+
+    yaml = YAML()
+    mkdocs_yml_path = Path(root_path) / "mkdocs" / "mkdocs.yml"
+    config = yaml.load(mkdocs_yml_path)
+    config["extra"]["social_image"] = image_url
+    yaml.dump(config, mkdocs_yml_path)
+
+# %% ../nbs/Social_Image_Generator.ipynb 14
+def _update_social_image_in_site_overrides(root_path: str, image_url: str):
+    """Update social image link in site_overrides HTML template
+
+    Args:
+        root_path: The root path of the project.
+        image_url: The image URL to update in the site_overrides HTML template.
+    """
+
+    _replace_str = (
+        'page.canonical_url ~ "" ~ config.extra.social_image '
+        if is_local_path(image_url)
+        else "config.extra.social_image "
+    )
+
+    with set_cwd(root_path):
+        site_overrides_path = (
+            Path(root_path) / "mkdocs" / "site_overrides" / "main.html"
+        )
+        if not site_overrides_path.exists():
+            typer.secho(
+                f"Unexpected error: path {site_overrides_path.resolve()} does not exists!",
+                err=True,
+                fg=typer.colors.RED,
+            )
+            raise typer.Exit(code=1)
+
+        with open(site_overrides_path, "r") as f:
+            _new_text = f.read()
+            _pattern = re.compile(r".*?{%.*?image_url = (.*)%}")
+            _match = re.search(_pattern, _new_text)
+            _new_text = _new_text.replace(_match.group(1), _replace_str)  # type: ignore
+
+        with open(site_overrides_path, "w") as f:
+            f.write(_new_text)
+
+# %% ../nbs/Social_Image_Generator.ipynb 17
+class _IMG_Generator(str, Enum):
+    file = "file"
+    dall_e = "dall_e"
+
+
+def _generate_image_url(
+    root_path: str, generator: str, prompt: str, image_path: Optional[str] = None
+) -> str:
+    """Generate image url based on the generator
+
+    Args:
+        root_path: The root path of the project.
+        generator: Generator to use to create the social image. Valid options are: 'file' and 'dall_e'.
+        prompt: The prompt to use for generating the image.
+        image_path: Image file path to use in the social share image. If None, then the default image will be used.
+
+    Returns:
+        The image url
+    """
+    if generator not in _IMG_Generator._member_names_:
+        raise ValueError(
+            "Invalid Option for generator. Valid options are: 'file' and 'dall_e'"
+        )
+
+    elif generator == _IMG_Generator.dall_e.value:
+        image_url = _generate_ai_image(prompt=prompt)
+
+    else:
+        with set_cwd(root_path):
+            if image_path is not None:
+                _image_path = Path(
+                    os.path.normpath(Path(root_path).joinpath(image_path))
+                ).resolve()
+
+                if not _image_path.exists():
+                    typer.secho(
+                        f"Unexpected error: path {_image_path.resolve()} does not exists!",
+                        err=True,
+                        fg=typer.colors.RED,
+                    )
+                    raise typer.Exit(code=1)
+
+                image_url = str(_image_path)
+
+            else:
+                image_url = str(
+                    (
+                        Path(root_path)
+                        / "mkdocs"
+                        / "docs_overrides"
+                        / "images"
+                        / "default_social_logo.png"
+                    ).resolve()
+                )
+
+    return image_url
+
+# %% ../nbs/Social_Image_Generator.ipynb 24
+async def generate_social_image(
+    root_path: str,
+    generator: str = "file",
+    prompt: str = "Cute animal wearing hoodie sitting in high chair in purple room, browsing computer, 3d render",
+    image_path: Optional[str] = None,
+):
+    """Generate a custom image for social card using the OpenAI Image API.
+
+    Args:
+        root_path: The root path of the project.
+        generator: Generator to use to create the social image. Valid options are: 'file' and 'dall_e'.
+        prompt: The prompt to use for generating the image.
+        image_path: Image file path to use in the social share image. If None, then the default image will be used.
+    """
+
+    image_url = _generate_image_url(root_path, generator, prompt, image_path)
+
+    await _create_social_image(root_path, image_url)
+
+    _update_social_image_in_mkdocs_yml(root_path, image_url)
+
+    _update_social_image_in_site_overrides(root_path, image_url)
diff --git a/nbs/CLI.ipynb b/nbs/CLI.ipynb
index e05c6e76..54ad78b0 100644
--- a/nbs/CLI.ipynb
+++ b/nbs/CLI.ipynb
@@ -21,6 +21,7 @@
     "\n",
     "from typing import *\n",
     "from pathlib import Path\n",
+    "from asyncio import run as aiorun\n",
     "\n",
     "import typer\n",
     "\n",
@@ -104,7 +105,44 @@
     "        )\n",
     "    except Exception as e:\n",
     "        typer.secho(f\"Unexpected internal error: {e}\", err=True, fg=typer.colors.RED)\n",
-    "        raise typer.Exit(1)\n"
+    "        raise typer.Exit(1)\n",
+    "\n",
+    "\n",
+    "@_app.command(\n",
+    "    help=\"Generate a custom social share image\",\n",
+    ")\n",
+    "def generate_social_image(\n",
+    "    root_path: str = typer.Option(\".\", help=\"Project's root path.\"),\n",
+    "    generator: nbdev_mkdocs.social_image_generator._IMG_Generator = typer.Option(\n",
+    "        \"file\",\n",
+    "        help=\"Generator to use to create the social image. Valid options are: 'file' and 'dall_e'. Choose 'file' if you want to use an existing image from your local machine in the social share image.\",\n",
+    "    ),\n",
+    "    prompt: Optional[str] = typer.Option(\n",
+    "        \"Cute animal wearing hoodie sitting in high chair in purple room, browsing computer, 3d render\",\n",
+    "        help=\"The prompt to use for generating the image.\",\n",
+    "    ),\n",
+    "    image_path: Optional[str] = typer.Option(\n",
+    "        None,\n",
+    "        help=\"Image file path to use in the social share image. If None, then the default image will be used.\",\n",
+    "    ),\n",
+    "):\n",
+    "    \"\"\"CLI command for generating a custom social share image\"\"\"\n",
+    "\n",
+    "    async def _generate_social_image(root_path, generator, prompt, image_path):\n",
+    "        try:\n",
+    "            await nbdev_mkdocs.social_image_generator.generate_social_image(\n",
+    "                root_path=root_path,\n",
+    "                generator=generator,\n",
+    "                prompt=prompt,\n",
+    "                image_path=image_path,\n",
+    "            )\n",
+    "        except Exception as e:\n",
+    "            typer.secho(\n",
+    "                f\"Unexpected internal error: {e}\", err=True, fg=typer.colors.RED\n",
+    "            )\n",
+    "            raise typer.Exit(1)\n",
+    "\n",
+    "    aiorun(_generate_social_image(root_path, generator, prompt, image_path))\n"
    ]
   },
   {
@@ -155,19 +193,23 @@
      "data": {
       "text/html": [
        "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">╭─ Commands ──────────────────────────────────────────────────────────────────────────────────────────────────────╮</span>\n",
-       "<span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">docs     </span> Prepares files in **mkdocs/docs** and then runs **mkdocs build** command on them                      <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span>\n",
-       "<span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">new      </span> Creates files in **mkdocs** subdirectory needed for other **nbdev_mkdocs** subcommands                <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span>\n",
-       "<span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">prepare  </span> Runs tests and prepares files in **mkdocs/docs** and then runs **mkdocs build** command on them       <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span>\n",
-       "<span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">preview  </span> Prepares files in **mkdocs/docs** and then runs **mkdocs serve** command on them                      <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span>\n",
+       "<span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">docs                  </span> Prepares files in **mkdocs/docs** and then runs **mkdocs build** command on them         <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span>\n",
+       "<span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">generate-social-image </span> Generate a custom image for social card                                                  <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span>\n",
+       "<span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">new                   </span> Creates files in **mkdocs** subdirectory needed for other **nbdev_mkdocs** subcommands   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span>\n",
+       "<span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">prepare               </span> Runs tests and prepares files in **mkdocs/docs** and then runs **mkdocs build** command  <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span>\n",
+       "<span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">                      </span> on them                                                                                  <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span>\n",
+       "<span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">preview               </span> Prepares files in **mkdocs/docs** and then runs **mkdocs serve** command on them         <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│</span>\n",
        "<span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
        "</pre>\n"
       ],
       "text/plain": [
        "\u001b[2m╭─\u001b[0m\u001b[2m Commands \u001b[0m\u001b[2m─────────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n",
-       "\u001b[2m│\u001b[0m \u001b[1;36mdocs    \u001b[0m\u001b[1;36m \u001b[0m Prepares files in **mkdocs/docs** and then runs **mkdocs build** command on them                      \u001b[2m│\u001b[0m\n",
-       "\u001b[2m│\u001b[0m \u001b[1;36mnew     \u001b[0m\u001b[1;36m \u001b[0m Creates files in **mkdocs** subdirectory needed for other **nbdev_mkdocs** subcommands                \u001b[2m│\u001b[0m\n",
-       "\u001b[2m│\u001b[0m \u001b[1;36mprepare \u001b[0m\u001b[1;36m \u001b[0m Runs tests and prepares files in **mkdocs/docs** and then runs **mkdocs build** command on them       \u001b[2m│\u001b[0m\n",
-       "\u001b[2m│\u001b[0m \u001b[1;36mpreview \u001b[0m\u001b[1;36m \u001b[0m Prepares files in **mkdocs/docs** and then runs **mkdocs serve** command on them                      \u001b[2m│\u001b[0m\n",
+       "\u001b[2m│\u001b[0m \u001b[1;36mdocs                 \u001b[0m\u001b[1;36m \u001b[0m Prepares files in **mkdocs/docs** and then runs **mkdocs build** command on them         \u001b[2m│\u001b[0m\n",
+       "\u001b[2m│\u001b[0m \u001b[1;36mgenerate-social-image\u001b[0m\u001b[1;36m \u001b[0m Generate a custom image for social card                                                  \u001b[2m│\u001b[0m\n",
+       "\u001b[2m│\u001b[0m \u001b[1;36mnew                  \u001b[0m\u001b[1;36m \u001b[0m Creates files in **mkdocs** subdirectory needed for other **nbdev_mkdocs** subcommands   \u001b[2m│\u001b[0m\n",
+       "\u001b[2m│\u001b[0m \u001b[1;36mprepare              \u001b[0m\u001b[1;36m \u001b[0m Runs tests and prepares files in **mkdocs/docs** and then runs **mkdocs build** command  \u001b[2m│\u001b[0m\n",
+       "\u001b[2m│\u001b[0m \u001b[1;36m                      \u001b[0m on them                                                                                  \u001b[2m│\u001b[0m\n",
+       "\u001b[2m│\u001b[0m \u001b[1;36mpreview              \u001b[0m\u001b[1;36m \u001b[0m Prepares files in **mkdocs/docs** and then runs **mkdocs serve** command on them         \u001b[2m│\u001b[0m\n",
        "\u001b[2m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
       ]
      },
diff --git a/nbs/Mkdocs.ipynb b/nbs/Mkdocs.ipynb
index a37cc348..08ca5493 100644
--- a/nbs/Mkdocs.ipynb
+++ b/nbs/Mkdocs.ipynb
@@ -36,7 +36,6 @@
     "import multiprocessing\n",
     "import datetime\n",
     "\n",
-    "from ruamel.yaml import YAML\n",
     "import typer\n",
     "from typer.testing import CliRunner\n",
     "\n",
@@ -56,7 +55,9 @@
     "from fastcore.shutil import move\n",
     "\n",
     "from nbdev_mkdocs._package_data import get_root_data_path\n",
-    "from nbdev_mkdocs._helpers.cli_doc import generate_cli_doc\n"
+    "from nbdev_mkdocs._helpers.cli_doc import generate_cli_doc\n",
+    "from nbdev_mkdocs._helpers.utils import set_cwd, get_value_from_config\n",
+    "from nbdev_mkdocs.social_image_generator import _update_social_image_in_mkdocs_yml\n"
    ]
   },
   {
@@ -75,68 +76,6 @@
     "from nbdev.config import nbdev_create_config\n"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "id": "b7495942",
-   "metadata": {},
-   "source": [
-    "# Helpers"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "7e3c43ef",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# | export\n",
-    "\n",
-    "\n",
-    "def _get_value_from_config(root_path: str, config_name: str) -> str:\n",
-    "    \"\"\"Get the value from settings.ini file\"\"\"\n",
-    "\n",
-    "    settings_path = Path(root_path) / \"settings.ini\"\n",
-    "    config = ConfigParser()\n",
-    "    config.read(settings_path)\n",
-    "    if not config.has_option(\"DEFAULT\", config_name):\n",
-    "        return \"\"\n",
-    "    return config[\"DEFAULT\"][config_name]\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "8fe19cd4",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "nbdev_mkdocs\n",
-      "nbdev-mkdocs\n",
-      "airtai\n"
-     ]
-    }
-   ],
-   "source": [
-    "with TemporaryDirectory() as d:\n",
-    "    settings_path = Path(d) / \"settings.ini\"\n",
-    "    shutil.copyfile(Path(\"..\") / \"settings.ini\", settings_path)\n",
-    "    ret_val = _get_value_from_config(d, \"lib_path\")\n",
-    "    print(ret_val)\n",
-    "    assert ret_val == \"nbdev_mkdocs\", ret_val\n",
-    "    \n",
-    "    ret_val = _get_value_from_config(d, \"repo\")\n",
-    "    print(ret_val)\n",
-    "    assert ret_val == \"nbdev-mkdocs\", ret_val\n",
-    "    \n",
-    "    ret_val = _get_value_from_config(d, \"user\")\n",
-    "    print(ret_val)\n",
-    "    assert ret_val == \"airtai\", ret_val\n"
-   ]
-  },
   {
    "cell_type": "markdown",
    "id": "6c8c26c4",
@@ -244,8 +183,8 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpz939df5c/settings.ini'.\u001b[0m\n",
-      "Requirements already added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpz939df5c/settings.ini'.\u001b[0m\n",
+      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpe64cviqb/settings.ini'.\u001b[0m\n",
+      "Requirements already added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpe64cviqb/settings.ini'.\u001b[0m\n",
       "[DEFAULT]\n",
       "# All sections below are required unless otherwise specified.\n",
       "# See https://github.com/fastai/nbdev/blob/master/settings.ini for examples.\n",
@@ -295,7 +234,10 @@
       "    mkdocs-literate-nav>=0.5.0 \\\n",
       "    mkdocs-section-index>=0.3.4 \\\n",
       "    configupdater>=3.1.1 \\\n",
-      "    griffe>=0.24.1\n",
+      "    griffe>=0.24.1 \\\n",
+      "    ruamel.yaml>=0.17.21 \\\n",
+      "    openai>=0.25.0 \\\n",
+      "    playwright>=1.28.0\n",
       "\n",
       "dev_requirements = \\\n",
       "    bandit>=1.7.4 \\\n",
@@ -396,18 +338,20 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs created.\u001b[0m\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs/site_overrides\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs/.ipynb_checkpoints\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs/docs_overrides\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs/site_overrides/main.html\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs/docs_overrides/css\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs/docs_overrides/images\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs/docs_overrides/js\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs/docs_overrides/css/extra.css\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs/docs_overrides/images/compass-outline.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs/docs_overrides/images/.ipynb_checkpoints\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpjltulco4/mkdocs/docs_overrides/js/extra.js\n"
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs created.\u001b[0m\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/site_overrides\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/.ipynb_checkpoints\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/docs_overrides\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/site_overrides/main.html\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/docs_overrides/css\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/docs_overrides/images\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/docs_overrides/js\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/docs_overrides/css/extra.css\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/docs_overrides/images/default_social_logo.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/docs_overrides/images/compass-outline.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/docs_overrides/images/.ipynb_checkpoints\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/docs_overrides/js/extra.js\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1kn6xuew/mkdocs/docs_overrides/js/math.js\n"
      ]
     }
    ],
@@ -562,12 +506,15 @@
       "#     admonition:\n",
       "#         <type>: <icon> \n",
       "  favicon: overrides/images/compass-outline.png\n",
+      "  \n",
       "extra_css:\n",
       "  - overrides/css/extra.css\n",
       "\n",
       "extra_javascript:\n",
       "  - overrides/js/extra.js\n",
-      "  \n",
+      "  - overrides/js/mathjax.js\n",
+      "  - https://polyfill.io/v3/polyfill.min.js?features=es6\n",
+      "  - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js  \n",
       "extra:\n",
       "  social_image: \"\"\n",
       "\n"
@@ -683,7 +630,7 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp9xe7ebox/mkdocs/mkdocs.yml' generated.\u001b[0m\n"
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpizycp7t6/mkdocs/mkdocs.yml' generated.\u001b[0m\n"
      ]
     },
     {
@@ -742,7 +689,10 @@
        "   'logo': 'material/compass-outline'},\n",
        "  'favicon': 'overrides/images/compass-outline.png'},\n",
        " 'extra_css': ['overrides/css/extra.css'],\n",
-       " 'extra_javascript': ['overrides/js/extra.js'],\n",
+       " 'extra_javascript': ['overrides/js/extra.js',\n",
+       "  'overrides/js/mathjax.js',\n",
+       "  'https://polyfill.io/v3/polyfill.min.js?features=es6',\n",
+       "  'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js'],\n",
        " 'extra': {'social_image': ''}}"
       ]
      },
@@ -825,8 +775,8 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1frm5n_9/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1frm5n_9/mkdocs/summary_template.txt' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpefe35sug/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpefe35sug/mkdocs/summary_template.txt' generated.\u001b[0m\n",
       "- [Home](index.md)\n",
       "- Guides\n",
       "    - [Guide one](docs/guide_1.md)\n",
@@ -914,46 +864,6 @@
     "    assert (Path(d) / \".github\" / \"workflows\" / \"deploy.yaml\").exists()\n"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "d81ad4a3",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# | export\n",
-    "\n",
-    "from contextlib import contextmanager\n",
-    "\n",
-    "\n",
-    "@contextmanager\n",
-    "def set_cwd(cwd_path: Union[Path, str]):\n",
-    "\n",
-    "    cwd_path = Path(cwd_path)\n",
-    "    original_cwd = os.getcwd()\n",
-    "    os.chdir(cwd_path)\n",
-    "\n",
-    "    try:\n",
-    "        nbdev.config.get_config.cache_clear()\n",
-    "        yield\n",
-    "    finally:\n",
-    "        os.chdir(original_cwd)\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "43cdc16d",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "with TemporaryDirectory() as d:\n",
-    "    with set_cwd(d):\n",
-    "        assert (\n",
-    "            Path(os.getcwd()) == Path(d).resolve()\n",
-    "        ), f\"{os.getcwd()}, {Path(d).resolve()}\"\n"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -965,17 +875,17 @@
     "\n",
     "    path = Path(\".\") if Path(\"settings.ini\").exists() else Path(\"..\")\n",
     "    Path(Path(d) / \"nbs\").mkdir(exist_ok=True)\n",
-    "    \n",
+    "\n",
     "    # Create a sample .gitignore file\n",
     "    gitignore_path = Path(d) / \".gitignore\"\n",
     "    sample_git_ignore = (\n",
-    "        \"_docs/\" \\\n",
-    "        \"_proc/\\n\" \\\n",
-    "        \"*.bak\\n\" \\\n",
-    "        \"# Byte-compiled / optimized / DLL files\\n\" \\\n",
+    "        \"_docs/\"\n",
+    "        \"_proc/\\n\"\n",
+    "        \"*.bak\\n\"\n",
+    "        \"# Byte-compiled / optimized / DLL files\\n\"\n",
     "        \"__pycache__/\"\n",
     "    )\n",
-    "    \n",
+    "\n",
     "    with gitignore_path.open(\"w\", encoding=\"utf-8\") as f:\n",
     "        f.write(sample_git_ignore)\n",
     "\n",
@@ -1020,12 +930,12 @@
     "    Args:\n",
     "        root_path: Project's root path\n",
     "    \"\"\"\n",
-    "    \n",
+    "\n",
     "    _mkdocs_gitignore_path = get_root_data_path() / \"gitignore.txt\"\n",
     "    with open(_mkdocs_gitignore_path, \"r\") as f:\n",
     "        _new_paths_to_ignore = f.read()\n",
     "        _new_paths_to_ignore = \"\\n\\n\" + _new_paths_to_ignore\n",
-    "    \n",
+    "\n",
     "    gitignore_path = Path(root_path) / \".gitignore\"\n",
     "    if not gitignore_path.exists():\n",
     "        typer.secho(\n",
@@ -1034,7 +944,7 @@
     "            fg=typer.colors.RED,\n",
     "        )\n",
     "        raise typer.Exit(code=1)\n",
-    "        \n",
+    "\n",
     "    with open(gitignore_path, \"a\") as f:\n",
     "        f.write(_new_paths_to_ignore)\n"
    ]
@@ -1093,7 +1003,7 @@
    ],
    "source": [
     "with TemporaryDirectory() as d:\n",
-    "    \n",
+    "\n",
     "    run_nbdev_new(d)\n",
     "\n",
     "    gitignore_path = Path(d) / \".gitignore\"\n",
@@ -1121,33 +1031,22 @@
    "source": [
     "# | export\n",
     "\n",
+    "\n",
     "def _generate_default_social_image_link(root_path: str):\n",
     "    \"\"\"Generating default social sharing image link and add it to the mkdocs yaml file\n",
     "\n",
     "    Args:\n",
     "        root_path: Project's root path\n",
     "    \"\"\"\n",
-    "    \n",
+    "\n",
     "    with set_cwd(root_path):\n",
-    "        repo = _get_value_from_config(root_path, \"repo\")\n",
-    "        user = _get_value_from_config(root_path, \"user\")\n",
-    "        \n",
+    "        repo = get_value_from_config(root_path, \"repo\")\n",
+    "        user = get_value_from_config(root_path, \"user\")\n",
+    "\n",
     "        timestamp = datetime.datetime.now().timestamp()\n",
     "        img_url = f\"https://opengraph.githubassets.com/{timestamp}/{user}/{repo}\"\n",
-    "        \n",
-    "        mkdocs_yml_path = Path(root_path) / \"mkdocs\" / \"mkdocs.yml\"\n",
-    "        if not mkdocs_yml_path.exists():\n",
-    "            typer.secho(\n",
-    "                f\"Unexpected error: path {mkdocs_yml_path.resolve()} does not exists!\",\n",
-    "                err=True,\n",
-    "                fg=typer.colors.RED,\n",
-    "            )\n",
-    "            raise typer.Exit(code=1)    \n",
-    "        \n",
-    "        yaml=YAML()\n",
-    "        config = yaml.load(mkdocs_yml_path)\n",
-    "        config['extra']['social_image'] = img_url\n",
-    "        yaml.dump(config, mkdocs_yml_path)"
+    "\n",
+    "        _update_social_image_in_mkdocs_yml(root_path, img_url)\n"
    ]
   },
   {
@@ -1183,10 +1082,10 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpsdwz9650/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpsdwz9650/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpsdwz9650/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpsdwz9650/mkdocs/summary_template.txt' generated.\u001b[0m\n",
+      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpg_o8y1a_/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpg_o8y1a_/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpg_o8y1a_/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpg_o8y1a_/mkdocs/summary_template.txt' generated.\u001b[0m\n",
       "# Site\n",
       "site_name: repo\n",
       "site_url: https://user.github.io/repo\n",
@@ -1274,14 +1173,17 @@
       "#     admonition:\n",
       "#         <type>: <icon> \n",
       "  favicon: overrides/images/compass-outline.png\n",
+      "\n",
       "extra_css:\n",
       "- overrides/css/extra.css\n",
       "\n",
       "extra_javascript:\n",
       "- overrides/js/extra.js\n",
-      "\n",
+      "- overrides/js/mathjax.js\n",
+      "- https://polyfill.io/v3/polyfill.min.js?features=es6\n",
+      "- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js\n",
       "extra:\n",
-      "  social_image: https://opengraph.githubassets.com/1670391298.852567/user/repo\n"
+      "  social_image: https://opengraph.githubassets.com/1670826206.190687/user/repo\n"
      ]
     },
     {
@@ -1313,7 +1215,7 @@
     "\n",
     "    assert y['extra']['social_image'] != \"\"\n",
     "\n",
-    "    !cat {d}/mkdocs/mkdocs.yml"
+    "    !cat {d}/mkdocs/mkdocs.yml\n"
    ]
   },
   {
@@ -1350,10 +1252,11 @@
     "    _create_summary_template(root_path)\n",
     "    _replace_ghp_deploy_action(root_path)\n",
     "    _update_gitignore_file(root_path)\n",
+    "    _generate_default_social_image_link(root_path)\n",
     "\n",
     "\n",
     "@call_parse\n",
-    "def new_cli(root_path: str):\n",
+    "def new_cli(root_path: str = \".\"):\n",
     "    \"\"\"Initialize mkdocs project files\n",
     "\n",
     "    Creates **mkdocs** directory in the **root_path** directory and populates\n",
@@ -1396,10 +1299,10 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1vk0vw5d/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1vk0vw5d/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1vk0vw5d/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp1vk0vw5d/mkdocs/summary_template.txt' generated.\u001b[0m\n",
+      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3ji2598o/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3ji2598o/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3ji2598o/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3ji2598o/mkdocs/summary_template.txt' generated.\u001b[0m\n",
       "_docs/_proc/\n",
       "*.bak\n",
       "# Byte-compiled / optimized / DLL files\n",
@@ -1434,13 +1337,18 @@
     "    assert (mkdocs_path / \"mkdocs.yml\").exists()\n",
     "    assert (mkdocs_path / \"site_overrides\" / \"main.html\").exists()\n",
     "    assert (mkdocs_path / \"summary_template.txt\").exists()\n",
-    "    \n",
+    "\n",
     "    gitignore_path = Path(d) / \".gitignore\"\n",
     "    with open(gitignore_path) as f:\n",
     "        contents = f.read()\n",
     "        print(contents)\n",
     "        assert \"mkdocs/docs/\" in contents\n",
     "        assert \"mkdocs/site/\" in contents\n",
+    "        \n",
+    "    with open(Path(d) / \"mkdocs/mkdocs.yml\") as f:\n",
+    "        y = yaml.safe_load(f)\n",
+    "\n",
+    "    assert y['extra']['social_image'] != \"\"\n",
     "\n",
     "#     !ls {d}\n",
     "#     !ls {d}/nbs\n"
@@ -1514,11 +1422,11 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmprataxqj2/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmprataxqj2/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmprataxqj2/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmprataxqj2/mkdocs/summary_template.txt' generated.\u001b[0m\n",
-      "['/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmprataxqj2/nbs/index.ipynb', '/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmprataxqj2/nbs/guides/guide_index.ipynb']\n"
+      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpoj4miy5p/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpoj4miy5p/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpoj4miy5p/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpoj4miy5p/mkdocs/summary_template.txt' generated.\u001b[0m\n",
+      "['/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpoj4miy5p/nbs/index.ipynb', '/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpoj4miy5p/nbs/guides/guide_index.ipynb']\n"
      ]
     },
     {
@@ -1594,7 +1502,7 @@
     "\n",
     "    with set_cwd(root_path):\n",
     "\n",
-    "        nbs_path = _get_value_from_config(root_path, \"nbs_path\")\n",
+    "        nbs_path = get_value_from_config(root_path, \"nbs_path\")\n",
     "        path = Path(root_path) / nbs_path\n",
     "\n",
     "        cache = proc_nbs()\n",
@@ -1646,10 +1554,10 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmphjenomfb/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmphjenomfb/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmphjenomfb/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmphjenomfb/mkdocs/summary_template.txt' generated.\u001b[0m\n"
+      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpgk7cdcwy/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpgk7cdcwy/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpgk7cdcwy/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpgk7cdcwy/mkdocs/summary_template.txt' generated.\u001b[0m\n"
      ]
     },
     {
@@ -1687,8 +1595,8 @@
      "output_type": "stream",
      "text": [
       "Checks:\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmphjenomfb/mkdocs/docs/index.md\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmphjenomfb/mkdocs/docs/guides/guide_index.md\n"
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpgk7cdcwy/mkdocs/docs/index.md\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpgk7cdcwy/mkdocs/docs/guides/guide_index.md\n"
      ]
     },
     {
@@ -1962,28 +1870,28 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "../nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb\n",
-      "../nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb\n",
-      "../nbs/guides/images/say_hello.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/say_hello.png\n",
-      "../nbs/guides/images/git_repo_clone_page.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/git_repo_clone_page.png\n",
-      "../nbs/guides/images/CLI_command.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/CLI_command.png\n",
-      "../nbs/guides/images/foo_doc_string.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/foo_doc_string.png\n",
-      "../nbs/guides/images/guide_notebook.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/guide_notebook.png\n",
-      "../nbs/guides/images/jupyter_home.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/jupyter_home.png\n",
-      "../nbs/guides/images/hello_class.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/hello_class.png\n",
-      "../nbs/guides/images/guide_3.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/guide_3.png\n",
-      "../nbs/guides/images/guide_2.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/guide_2.png\n",
-      "../nbs/guides/images/guide_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/guide_1.png\n",
-      "../nbs/guides/images/releases.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/releases.png\n",
-      "../nbs/guides/images/nbdev_mkdocs_preview_dark_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
-      "../nbs/guides/images/guide_4.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/guide_4.png\n",
-      "../nbs/guides/images/empty_git_repo.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/empty_git_repo.png\n",
-      "../nbs/guides/images/nbdev_mkdocs_preview_light_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
-      "../nbs/guides/images/enable_gh_pages.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/nbs/guides/images/enable_gh_pages.png\n",
-      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/summary_template.txt' generated.\u001b[0m\n"
+      "../nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb\n",
+      "../nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb\n",
+      "../nbs/guides/images/say_hello.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/say_hello.png\n",
+      "../nbs/guides/images/git_repo_clone_page.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/git_repo_clone_page.png\n",
+      "../nbs/guides/images/CLI_command.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/CLI_command.png\n",
+      "../nbs/guides/images/foo_doc_string.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/foo_doc_string.png\n",
+      "../nbs/guides/images/guide_notebook.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/guide_notebook.png\n",
+      "../nbs/guides/images/jupyter_home.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/jupyter_home.png\n",
+      "../nbs/guides/images/hello_class.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/hello_class.png\n",
+      "../nbs/guides/images/guide_3.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/guide_3.png\n",
+      "../nbs/guides/images/guide_2.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/guide_2.png\n",
+      "../nbs/guides/images/guide_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/guide_1.png\n",
+      "../nbs/guides/images/releases.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/releases.png\n",
+      "../nbs/guides/images/nbdev_mkdocs_preview_dark_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
+      "../nbs/guides/images/guide_4.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/guide_4.png\n",
+      "../nbs/guides/images/empty_git_repo.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/empty_git_repo.png\n",
+      "../nbs/guides/images/nbdev_mkdocs_preview_light_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
+      "../nbs/guides/images/enable_gh_pages.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/nbs/guides/images/enable_gh_pages.png\n",
+      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/summary_template.txt' generated.\u001b[0m\n"
      ]
     },
     {
@@ -2023,25 +1931,25 @@
      "output_type": "stream",
      "text": [
       "Checks for images:\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/say_hello.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/git_repo_clone_page.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/CLI_command.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/foo_doc_string.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/guide_notebook.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/jupyter_home.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/hello_class.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/guide_3.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/guide_2.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/guide_1.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/releases.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/guide_4.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/empty_git_repo.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/images/nbs/guides/images/enable_gh_pages.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/say_hello.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/git_repo_clone_page.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/CLI_command.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/foo_doc_string.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/guide_notebook.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/jupyter_home.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/hello_class.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/guide_3.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/guide_2.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/guide_1.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/releases.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/guide_4.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/empty_git_repo.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/images/nbs/guides/images/enable_gh_pages.png\n",
       "Checks for markdown:\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/index.md\n",
-      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp7nd89ikg/mkdocs/docs/guides/Guide_01_End_To_End_Walkthrough.md\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/index.md\n",
+      "/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpl8exqkyw/mkdocs/docs/guides/Guide_01_End_To_End_Walkthrough.md\n",
       "OK.\n"
      ]
     }
@@ -2184,28 +2092,28 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "../nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb\n",
-      "../nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb\n",
-      "../nbs/guides/images/say_hello.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/say_hello.png\n",
-      "../nbs/guides/images/git_repo_clone_page.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/git_repo_clone_page.png\n",
-      "../nbs/guides/images/CLI_command.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/CLI_command.png\n",
-      "../nbs/guides/images/foo_doc_string.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/foo_doc_string.png\n",
-      "../nbs/guides/images/guide_notebook.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/guide_notebook.png\n",
-      "../nbs/guides/images/jupyter_home.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/jupyter_home.png\n",
-      "../nbs/guides/images/hello_class.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/hello_class.png\n",
-      "../nbs/guides/images/guide_3.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/guide_3.png\n",
-      "../nbs/guides/images/guide_2.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/guide_2.png\n",
-      "../nbs/guides/images/guide_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/guide_1.png\n",
-      "../nbs/guides/images/releases.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/releases.png\n",
-      "../nbs/guides/images/nbdev_mkdocs_preview_dark_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
-      "../nbs/guides/images/guide_4.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/guide_4.png\n",
-      "../nbs/guides/images/empty_git_repo.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/empty_git_repo.png\n",
-      "../nbs/guides/images/nbdev_mkdocs_preview_light_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
-      "../nbs/guides/images/enable_gh_pages.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/nbs/guides/images/enable_gh_pages.png\n",
-      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8ny_bkbq/mkdocs/summary_template.txt' generated.\u001b[0m\n"
+      "../nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb\n",
+      "../nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb\n",
+      "../nbs/guides/images/say_hello.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/say_hello.png\n",
+      "../nbs/guides/images/git_repo_clone_page.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/git_repo_clone_page.png\n",
+      "../nbs/guides/images/CLI_command.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/CLI_command.png\n",
+      "../nbs/guides/images/foo_doc_string.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/foo_doc_string.png\n",
+      "../nbs/guides/images/guide_notebook.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/guide_notebook.png\n",
+      "../nbs/guides/images/jupyter_home.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/jupyter_home.png\n",
+      "../nbs/guides/images/hello_class.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/hello_class.png\n",
+      "../nbs/guides/images/guide_3.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/guide_3.png\n",
+      "../nbs/guides/images/guide_2.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/guide_2.png\n",
+      "../nbs/guides/images/guide_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/guide_1.png\n",
+      "../nbs/guides/images/releases.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/releases.png\n",
+      "../nbs/guides/images/nbdev_mkdocs_preview_dark_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
+      "../nbs/guides/images/guide_4.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/guide_4.png\n",
+      "../nbs/guides/images/empty_git_repo.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/empty_git_repo.png\n",
+      "../nbs/guides/images/nbdev_mkdocs_preview_light_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
+      "../nbs/guides/images/enable_gh_pages.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/nbs/guides/images/enable_gh_pages.png\n",
+      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp96rc1mf9/mkdocs/summary_template.txt' generated.\u001b[0m\n"
      ]
     },
     {
@@ -2331,28 +2239,28 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "../nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb\n",
-      "../nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb\n",
-      "../nbs/guides/images/say_hello.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/say_hello.png\n",
-      "../nbs/guides/images/git_repo_clone_page.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/git_repo_clone_page.png\n",
-      "../nbs/guides/images/CLI_command.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/CLI_command.png\n",
-      "../nbs/guides/images/foo_doc_string.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/foo_doc_string.png\n",
-      "../nbs/guides/images/guide_notebook.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/guide_notebook.png\n",
-      "../nbs/guides/images/jupyter_home.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/jupyter_home.png\n",
-      "../nbs/guides/images/hello_class.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/hello_class.png\n",
-      "../nbs/guides/images/guide_3.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/guide_3.png\n",
-      "../nbs/guides/images/guide_2.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/guide_2.png\n",
-      "../nbs/guides/images/guide_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/guide_1.png\n",
-      "../nbs/guides/images/releases.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/releases.png\n",
-      "../nbs/guides/images/nbdev_mkdocs_preview_dark_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
-      "../nbs/guides/images/guide_4.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/guide_4.png\n",
-      "../nbs/guides/images/empty_git_repo.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/empty_git_repo.png\n",
-      "../nbs/guides/images/nbdev_mkdocs_preview_light_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
-      "../nbs/guides/images/enable_gh_pages.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/nbs/guides/images/enable_gh_pages.png\n",
-      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp3sz8_2kr/mkdocs/summary_template.txt' generated.\u001b[0m\n"
+      "../nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb\n",
+      "../nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb\n",
+      "../nbs/guides/images/say_hello.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/say_hello.png\n",
+      "../nbs/guides/images/git_repo_clone_page.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/git_repo_clone_page.png\n",
+      "../nbs/guides/images/CLI_command.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/CLI_command.png\n",
+      "../nbs/guides/images/foo_doc_string.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/foo_doc_string.png\n",
+      "../nbs/guides/images/guide_notebook.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/guide_notebook.png\n",
+      "../nbs/guides/images/jupyter_home.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/jupyter_home.png\n",
+      "../nbs/guides/images/hello_class.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/hello_class.png\n",
+      "../nbs/guides/images/guide_3.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/guide_3.png\n",
+      "../nbs/guides/images/guide_2.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/guide_2.png\n",
+      "../nbs/guides/images/guide_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/guide_1.png\n",
+      "../nbs/guides/images/releases.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/releases.png\n",
+      "../nbs/guides/images/nbdev_mkdocs_preview_dark_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
+      "../nbs/guides/images/guide_4.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/guide_4.png\n",
+      "../nbs/guides/images/empty_git_repo.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/empty_git_repo.png\n",
+      "../nbs/guides/images/nbdev_mkdocs_preview_light_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
+      "../nbs/guides/images/enable_gh_pages.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/nbs/guides/images/enable_gh_pages.png\n",
+      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpf2oxodnf/mkdocs/summary_template.txt' generated.\u001b[0m\n"
      ]
     },
     {
@@ -2750,7 +2658,7 @@
     "\n",
     "def generate_cli_docs_for_module(root_path: str, module_name: str) -> str:\n",
     "    shutil.rmtree(Path(root_path) / \"mkdocs\" / \"docs\" / \"CLI\", ignore_errors=True)\n",
-    "    console_scripts = _get_value_from_config(root_path, \"console_scripts\")\n",
+    "    console_scripts = get_value_from_config(root_path, \"console_scripts\")\n",
     "\n",
     "    if not console_scripts:\n",
     "        return \"\"\n",
@@ -2798,10 +2706,10 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Requirements already added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmplg0w5j9l/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmplg0w5j9l/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmplg0w5j9l/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmplg0w5j9l/mkdocs/summary_template.txt' generated.\u001b[0m\n"
+      "Requirements already added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpyg0fw9gv/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpyg0fw9gv/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpyg0fw9gv/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpyg0fw9gv/mkdocs/summary_template.txt' generated.\u001b[0m\n"
      ]
     },
     {
@@ -2828,7 +2736,7 @@
    "source": [
     "with TemporaryDirectory() as d:\n",
     "    run_nbdev_new(d)\n",
-    "    \n",
+    "\n",
     "    settings_path = Path(d) / \"settings.ini\"\n",
     "    shutil.copyfile(Path(\"..\") / \"settings.ini\", settings_path)\n",
     "\n",
@@ -2899,10 +2807,10 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Requirements already added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmphpnigmdy/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmphpnigmdy/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmphpnigmdy/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmphpnigmdy/mkdocs/summary_template.txt' generated.\u001b[0m\n",
+      "Requirements already added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpoyekleo1/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpoyekleo1/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpoyekleo1/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpoyekleo1/mkdocs/summary_template.txt' generated.\u001b[0m\n",
       "change_log=\n",
       "change_log=- [Releases](CHANGELOG.md)\n"
      ]
@@ -2918,9 +2826,9 @@
    ],
    "source": [
     "with TemporaryDirectory() as d:\n",
-    "    \n",
+    "\n",
     "    run_nbdev_new(d)\n",
-    "    \n",
+    "\n",
     "    settings_path = Path(d) / \"settings.ini\"\n",
     "    shutil.copyfile(Path(\"..\") / \"settings.ini\", settings_path)\n",
     "\n",
@@ -3037,10 +2945,10 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Requirements already added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpniyfl10o/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpniyfl10o/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpniyfl10o/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpniyfl10o/mkdocs/summary_template.txt' generated.\u001b[0m\n"
+      "Requirements already added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpk2fe_cwc/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpk2fe_cwc/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpk2fe_cwc/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpk2fe_cwc/mkdocs/summary_template.txt' generated.\u001b[0m\n"
      ]
     },
     {
@@ -3071,6 +2979,7 @@
       "- API\n",
       "    - [nbdev_mkdocs.docstring](API/nbdev_mkdocs/docstring.md)\n",
       "    - [nbdev_mkdocs.mkdocs](API/nbdev_mkdocs/mkdocs.md)\n",
+      "    - [nbdev_mkdocs.social_image_generator](API/nbdev_mkdocs/social_image_generator.md)\n",
       "- CLI\n",
       "    - [nbdev_mkdocs](CLI/nbdev_mkdocs.md)\n",
       "    - [nbdev_mkdocs_new](CLI/nbdev_mkdocs_new.md)\n",
@@ -3084,7 +2993,7 @@
    "source": [
     "with TemporaryDirectory() as d:\n",
     "    run_nbdev_new(d)\n",
-    "    \n",
+    "\n",
     "    settings_path = Path(d) / \"settings.ini\"\n",
     "    for fname in [\"settings.ini\", \"README.md\", \"CHANGELOG.md\"]:\n",
     "        shutil.copyfile(Path(\"..\") / fname, Path(d) / fname)\n",
@@ -3144,8 +3053,8 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp4v5hik8j/CNAME' copied to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp4v5hik8j/mkdocs/docs/CNAME'.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpp83tcsr7/CNAME' not found, skipping copying..\u001b[0m\n"
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp72w8mg2a/CNAME' copied to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp72w8mg2a/mkdocs/docs/CNAME'.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpfo2cmb4c/CNAME' not found, skipping copying..\u001b[0m\n"
      ]
     }
    ],
@@ -3189,7 +3098,7 @@
     "            fg=typer.colors.RED,\n",
     "        )\n",
     "        raise typer.Exit(code=1)\n",
-    "        \n",
+    "\n",
     "    shutil.rmtree(dst_path, ignore_errors=True)\n",
     "    shutil.copytree(src_path, dst_path)\n"
    ]
@@ -3227,10 +3136,10 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpu24k_xmo/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpu24k_xmo/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpu24k_xmo/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpu24k_xmo/mkdocs/summary_template.txt' generated.\u001b[0m\n"
+      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpcez3oqdi/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpcez3oqdi/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpcez3oqdi/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpcez3oqdi/mkdocs/summary_template.txt' generated.\u001b[0m\n"
      ]
     },
     {
@@ -3296,18 +3205,18 @@
     "\n",
     "        _copy_docs_overrides(root_path)\n",
     "\n",
-    "        lib_name = _get_value_from_config(root_path, \"lib_name\")\n",
-    "        lib_path = _get_value_from_config(root_path, \"lib_path\")\n",
+    "        lib_name = get_value_from_config(root_path, \"lib_name\")\n",
+    "        lib_path = get_value_from_config(root_path, \"lib_path\")\n",
     "\n",
     "        build_summary(root_path, lib_path)\n",
-    "        _generate_default_social_image_link(root_path)\n",
+    "        #         _generate_default_social_image_link(root_path)\n",
     "\n",
     "        cmd = f\"mkdocs build -f \\\"{(Path(root_path) / 'mkdocs' / 'mkdocs.yml').resolve()}\\\"\"\n",
     "        _sprun(cmd)\n",
     "\n",
     "\n",
     "@call_parse\n",
-    "def nbdev_mkdocs_docs_cli(root_path: str):\n",
+    "def nbdev_mkdocs_docs_cli(root_path: str = \".\"):\n",
     "    \"\"\"Prepares mkdocs documentation\"\"\"\n",
     "    nbdev_mkdocs_docs(root_path, refresh_quarto_settings=True)\n",
     "\n",
@@ -3332,7 +3241,7 @@
     "\n",
     "\n",
     "@call_parse\n",
-    "def prepare_cli(root_path: str):\n",
+    "def prepare_cli(root_path: str = \".\"):\n",
     "    \"\"\"Prepares mkdocs for serving\"\"\"\n",
     "    prepare(root_path)\n"
    ]
@@ -3370,28 +3279,28 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "../nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb\n",
-      "../nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb\n",
-      "../nbs/guides/images/say_hello.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/say_hello.png\n",
-      "../nbs/guides/images/git_repo_clone_page.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/git_repo_clone_page.png\n",
-      "../nbs/guides/images/CLI_command.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/CLI_command.png\n",
-      "../nbs/guides/images/foo_doc_string.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/foo_doc_string.png\n",
-      "../nbs/guides/images/guide_notebook.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/guide_notebook.png\n",
-      "../nbs/guides/images/jupyter_home.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/jupyter_home.png\n",
-      "../nbs/guides/images/hello_class.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/hello_class.png\n",
-      "../nbs/guides/images/guide_3.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/guide_3.png\n",
-      "../nbs/guides/images/guide_2.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/guide_2.png\n",
-      "../nbs/guides/images/guide_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/guide_1.png\n",
-      "../nbs/guides/images/releases.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/releases.png\n",
-      "../nbs/guides/images/nbdev_mkdocs_preview_dark_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
-      "../nbs/guides/images/guide_4.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/guide_4.png\n",
-      "../nbs/guides/images/empty_git_repo.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/empty_git_repo.png\n",
-      "../nbs/guides/images/nbdev_mkdocs_preview_light_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
-      "../nbs/guides/images/enable_gh_pages.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/nbs/guides/images/enable_gh_pages.png\n",
-      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/mkdocs/summary_template.txt' generated.\u001b[0m\n"
+      "../nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb\n",
+      "../nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb\n",
+      "../nbs/guides/images/say_hello.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/say_hello.png\n",
+      "../nbs/guides/images/git_repo_clone_page.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/git_repo_clone_page.png\n",
+      "../nbs/guides/images/CLI_command.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/CLI_command.png\n",
+      "../nbs/guides/images/foo_doc_string.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/foo_doc_string.png\n",
+      "../nbs/guides/images/guide_notebook.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/guide_notebook.png\n",
+      "../nbs/guides/images/jupyter_home.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/jupyter_home.png\n",
+      "../nbs/guides/images/hello_class.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/hello_class.png\n",
+      "../nbs/guides/images/guide_3.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/guide_3.png\n",
+      "../nbs/guides/images/guide_2.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/guide_2.png\n",
+      "../nbs/guides/images/guide_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/guide_1.png\n",
+      "../nbs/guides/images/releases.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/releases.png\n",
+      "../nbs/guides/images/nbdev_mkdocs_preview_dark_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
+      "../nbs/guides/images/guide_4.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/guide_4.png\n",
+      "../nbs/guides/images/empty_git_repo.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/empty_git_repo.png\n",
+      "../nbs/guides/images/nbdev_mkdocs_preview_light_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
+      "../nbs/guides/images/enable_gh_pages.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/nbs/guides/images/enable_gh_pages.png\n",
+      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/mkdocs/summary_template.txt' generated.\u001b[0m\n"
      ]
     },
     {
@@ -3406,7 +3315,7 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/CNAME' copied to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/mkdocs/docs/CNAME'.\u001b[0m\n"
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/CNAME' copied to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/mkdocs/docs/CNAME'.\u001b[0m\n"
      ]
     },
     {
@@ -3444,8 +3353,8 @@
       "    warnings.warn(\n",
       "\n",
       "INFO     -  Cleaning site directory\n",
-      "INFO     -  Building documentation to directory: /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp2ookcaog/mkdocs/site\n",
-      "INFO     -  Documentation built in 0.57 seconds\n"
+      "INFO     -  Building documentation to directory: /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpkeegb_y1/mkdocs/site\n",
+      "INFO     -  Documentation built in 1.87 seconds\n"
      ]
     }
    ],
@@ -3528,7 +3437,7 @@
     "\n",
     "\n",
     "@call_parse\n",
-    "def preview_cli(root_path: str, port: Optional[int] = None):\n",
+    "def preview_cli(root_path: str = \".\", port: Optional[int] = None):\n",
     "    \"\"\"Previes mkdocs documentation\"\"\"\n",
     "    preview(root_path, port)\n"
    ]
@@ -3566,29 +3475,29 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "../nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb\n",
-      "../nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb\n",
-      "../nbs/guides/images/say_hello.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/say_hello.png\n",
-      "../nbs/guides/images/git_repo_clone_page.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/git_repo_clone_page.png\n",
-      "../nbs/guides/images/CLI_command.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/CLI_command.png\n",
-      "../nbs/guides/images/foo_doc_string.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/foo_doc_string.png\n",
-      "../nbs/guides/images/guide_notebook.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/guide_notebook.png\n",
-      "../nbs/guides/images/jupyter_home.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/jupyter_home.png\n",
-      "../nbs/guides/images/hello_class.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/hello_class.png\n",
-      "../nbs/guides/images/guide_3.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/guide_3.png\n",
-      "../nbs/guides/images/guide_2.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/guide_2.png\n",
-      "../nbs/guides/images/guide_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/guide_1.png\n",
-      "../nbs/guides/images/releases.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/releases.png\n",
-      "../nbs/guides/images/nbdev_mkdocs_preview_dark_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
-      "../nbs/guides/images/guide_4.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/guide_4.png\n",
-      "../nbs/guides/images/empty_git_repo.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/empty_git_repo.png\n",
-      "../nbs/guides/images/nbdev_mkdocs_preview_light_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
-      "../nbs/guides/images/enable_gh_pages.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/nbs/guides/images/enable_gh_pages.png\n",
-      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/settings.ini'.\u001b[0m\n",
-      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/mkdocs created.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/mkdocs/summary_template.txt' generated.\u001b[0m\n",
-      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/CNAME' not found, skipping copying..\u001b[0m\n"
+      "../nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/Guide_01_End_To_End_Walkthrough.ipynb\n",
+      "../nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/.ipynb_checkpoints/Guide_01_End_To_End_Walkthrough-checkpoint.ipynb\n",
+      "../nbs/guides/images/say_hello.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/say_hello.png\n",
+      "../nbs/guides/images/git_repo_clone_page.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/git_repo_clone_page.png\n",
+      "../nbs/guides/images/CLI_command.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/CLI_command.png\n",
+      "../nbs/guides/images/foo_doc_string.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/foo_doc_string.png\n",
+      "../nbs/guides/images/guide_notebook.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/guide_notebook.png\n",
+      "../nbs/guides/images/jupyter_home.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/jupyter_home.png\n",
+      "../nbs/guides/images/hello_class.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/hello_class.png\n",
+      "../nbs/guides/images/guide_3.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/guide_3.png\n",
+      "../nbs/guides/images/guide_2.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/guide_2.png\n",
+      "../nbs/guides/images/guide_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/guide_1.png\n",
+      "../nbs/guides/images/releases.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/releases.png\n",
+      "../nbs/guides/images/nbdev_mkdocs_preview_dark_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/nbdev_mkdocs_preview_dark_1.png\n",
+      "../nbs/guides/images/guide_4.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/guide_4.png\n",
+      "../nbs/guides/images/empty_git_repo.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/empty_git_repo.png\n",
+      "../nbs/guides/images/nbdev_mkdocs_preview_light_1.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/nbdev_mkdocs_preview_light_1.png\n",
+      "../nbs/guides/images/enable_gh_pages.png, /var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/nbs/guides/images/enable_gh_pages.png\n",
+      "Requirements added to '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/settings.ini'.\u001b[0m\n",
+      "Directory /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/mkdocs created.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/mkdocs/mkdocs.yml' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/mkdocs/summary_template.txt' generated.\u001b[0m\n",
+      "File '/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/CNAME' not found, skipping copying..\u001b[0m\n"
      ]
     },
     {
@@ -3628,8 +3537,8 @@
       "    warnings.warn(\n",
       "\n",
       "INFO     -  Cleaning site directory\n",
-      "INFO     -  Building documentation to directory: /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/mkdocs/site\n",
-      "INFO     -  Documentation built in 0.48 seconds\n",
+      "INFO     -  Building documentation to directory: /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/mkdocs/site\n",
+      "INFO     -  Documentation built in 0.55 seconds\n",
       "\u001b[33mWARNING  -  \u001b[0mConfig value 'dev_addr': The use of the IP address '0.0.0.0' suggests a production environment or the use of a proxy to connect to the MkDocs server. However, the MkDocs' server is intended for local development purposes only. Please use a third party production-ready server instead.\n",
       "INFO     -  Building documentation...\n",
       "INFO     -  UserWarning: The 'python-legacy' extra of mkdocstrings will become mandatory in the next release. We have no way to detect if you already specify it, so if you do, please ignore this warning. You can globally disable it with the PYTHONWARNINGS environment variable: PYTHONWARNINGS=ignore::UserWarning:mkdocstrings.handlers.python\n",
@@ -3639,12 +3548,10 @@
       "    warnings.warn(\n",
       "\n",
       "INFO     -  Cleaning site directory\n",
-      "INFO     -  Documentation built in 0.46 seconds\n",
-      "INFO     -  [11:05:28] Watching paths for changes: '/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/mkdocs/docs', '/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpddaj3adm/mkdocs/mkdocs.yml'\n",
-      "INFO     -  [11:05:28] Serving on http://0.0.0.0:4000/repo/\n",
-      "INFO     -  [11:05:30] Browser connected: http://0.0.0.0:4000/repo/\n",
-      "\u001b[33mWARNING  -  \u001b[0m[11:05:39] \"GET /repo/https://opengraph.githubassets.com/1670391325.459418/user/repo HTTP/1.1\" code 404\n",
-      "\u001b[33mWARNING  -  \u001b[0m[11:05:43] \"GET /repo/https://opengraph.githubassets.com/1670391325.459418/user/repo.png HTTP/1.1\" code 404\n",
+      "INFO     -  Documentation built in 0.57 seconds\n",
+      "INFO     -  [11:53:59] Watching paths for changes: '/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/mkdocs/docs', '/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpthj9u33m/mkdocs/mkdocs.yml'\n",
+      "INFO     -  [11:53:59] Serving on http://0.0.0.0:4000/repo/\n",
+      "INFO     -  [11:54:00] Browser connected: http://0.0.0.0:4000/nbdev-mkdocs/guides/Guide_01_End_To_End_Walkthrough/\n",
       "INFO     -  Shutting down...\n"
      ]
     },
@@ -3655,8 +3562,8 @@
      "traceback": [
       "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
       "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
-      "Cell \u001b[0;32mIn [64], line 13\u001b[0m\n\u001b[1;32m      9\u001b[0m copy_guides(Path(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m) \u001b[38;5;28;01mif\u001b[39;00m Path(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msettings.ini\u001b[39m\u001b[38;5;124m\"\u001b[39m)\u001b[38;5;241m.\u001b[39mexists() \u001b[38;5;28;01melse\u001b[39;00m Path(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m..\u001b[39m\u001b[38;5;124m\"\u001b[39m), d)\n\u001b[1;32m     11\u001b[0m new(d)\n\u001b[0;32m---> 13\u001b[0m \u001b[43mpreview\u001b[49m\u001b[43m(\u001b[49m\u001b[43md\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mport\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m4000\u001b[39;49m\u001b[43m)\u001b[49m\n",
-      "Cell \u001b[0;32mIn [63], line 25\u001b[0m, in \u001b[0;36mpreview\u001b[0;34m(root_path, port)\u001b[0m\n\u001b[1;32m     16\u001b[0m     cmd \u001b[38;5;241m=\u001b[39m cmd \u001b[38;5;241m+\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m:\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mport\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m     18\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m subprocess\u001b[38;5;241m.\u001b[39mPopen(  \u001b[38;5;66;03m# nosec B603:subprocess_without_shell_equals_true\u001b[39;00m\n\u001b[1;32m     19\u001b[0m     shlex\u001b[38;5;241m.\u001b[39msplit(cmd),\n\u001b[1;32m     20\u001b[0m     stdout\u001b[38;5;241m=\u001b[39msubprocess\u001b[38;5;241m.\u001b[39mPIPE,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m     23\u001b[0m     universal_newlines\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m,\n\u001b[1;32m     24\u001b[0m ) \u001b[38;5;28;01mas\u001b[39;00m p:\n\u001b[0;32m---> 25\u001b[0m     \u001b[38;5;28;01mfor\u001b[39;00m line \u001b[38;5;129;01min\u001b[39;00m p\u001b[38;5;241m.\u001b[39mstdout:  \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m     26\u001b[0m         \u001b[38;5;28mprint\u001b[39m(line, end\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m     28\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m p\u001b[38;5;241m.\u001b[39mreturncode \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m0\u001b[39m:\n",
+      "Cell \u001b[0;32mIn [60], line 13\u001b[0m\n\u001b[1;32m      9\u001b[0m copy_guides(Path(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m) \u001b[38;5;28;01mif\u001b[39;00m Path(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msettings.ini\u001b[39m\u001b[38;5;124m\"\u001b[39m)\u001b[38;5;241m.\u001b[39mexists() \u001b[38;5;28;01melse\u001b[39;00m Path(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m..\u001b[39m\u001b[38;5;124m\"\u001b[39m), d)\n\u001b[1;32m     11\u001b[0m new(d)\n\u001b[0;32m---> 13\u001b[0m \u001b[43mpreview\u001b[49m\u001b[43m(\u001b[49m\u001b[43md\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mport\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m4000\u001b[39;49m\u001b[43m)\u001b[49m\n",
+      "Cell \u001b[0;32mIn [59], line 25\u001b[0m, in \u001b[0;36mpreview\u001b[0;34m(root_path, port)\u001b[0m\n\u001b[1;32m     16\u001b[0m     cmd \u001b[38;5;241m=\u001b[39m cmd \u001b[38;5;241m+\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m:\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mport\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m     18\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m subprocess\u001b[38;5;241m.\u001b[39mPopen(  \u001b[38;5;66;03m# nosec B603:subprocess_without_shell_equals_true\u001b[39;00m\n\u001b[1;32m     19\u001b[0m     shlex\u001b[38;5;241m.\u001b[39msplit(cmd),\n\u001b[1;32m     20\u001b[0m     stdout\u001b[38;5;241m=\u001b[39msubprocess\u001b[38;5;241m.\u001b[39mPIPE,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m     23\u001b[0m     universal_newlines\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m,\n\u001b[1;32m     24\u001b[0m ) \u001b[38;5;28;01mas\u001b[39;00m p:\n\u001b[0;32m---> 25\u001b[0m     \u001b[38;5;28;01mfor\u001b[39;00m line \u001b[38;5;129;01min\u001b[39;00m p\u001b[38;5;241m.\u001b[39mstdout:  \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m     26\u001b[0m         \u001b[38;5;28mprint\u001b[39m(line, end\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m     28\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m p\u001b[38;5;241m.\u001b[39mreturncode \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m0\u001b[39m:\n",
       "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
      ]
     }
diff --git a/nbs/Social_Image_Generator.ipynb b/nbs/Social_Image_Generator.ipynb
new file mode 100644
index 00000000..772b2d36
--- /dev/null
+++ b/nbs/Social_Image_Generator.ipynb
@@ -0,0 +1,1102 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "3b88dc68",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | default_exp social_image_generator\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "7a4ecbe0",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "from typing import *\n",
+    "from pathlib import Path\n",
+    "import re\n",
+    "import os\n",
+    "import asyncio\n",
+    "import shutil\n",
+    "from tempfile import TemporaryDirectory\n",
+    "from enum import Enum\n",
+    "\n",
+    "import openai\n",
+    "import typer\n",
+    "from playwright.async_api import async_playwright\n",
+    "from ruamel.yaml import YAML\n",
+    "\n",
+    "from nbdev_mkdocs._helpers.utils import set_cwd, get_value_from_config, is_local_path\n",
+    "from nbdev_mkdocs._package_data import get_root_data_path\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "786ad0bb",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pytest\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "173c89fa",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "\n",
+    "def _generate_ai_image(prompt: str) -> str:\n",
+    "    \"\"\"Generate an image for social card using the OpenAI Image API.\n",
+    "\n",
+    "    Args:\n",
+    "        prompt: The prompt to use for generating the image.\n",
+    "\n",
+    "    Returns:\n",
+    "        The URL of the generated image.\n",
+    "    \"\"\"\n",
+    "    response = openai.Image.create(prompt=prompt, n=1, size=\"512x512\")\n",
+    "    image_url = response[\"data\"][0][\"url\"]\n",
+    "    return image_url\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "a72d2ef9",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "InvalidRequestError(message='Billing hard limit has been reached', param=None, code='billing_hard_limit_reached', http_status=400, request_id=None)"
+      ]
+     },
+     "execution_count": null,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "prompt = \"cute animal, browsing computer, high tech, flat, digital art\"\n",
+    "\n",
+    "with pytest.raises(Exception) as e:\n",
+    "    _generate_ai_image(prompt=prompt)\n",
+    "\n",
+    "e.value\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c4397a37",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "\n",
+    "\n",
+    "\n",
+    "def _generate_html_str(root_path: str, image_url: str) -> str:\n",
+    "    \"\"\"Generate html string for the social card\n",
+    "\n",
+    "    Args:\n",
+    "        root_path: The root path of the project.\n",
+    "        image_url: The image URL to be included in the HTML.\n",
+    "    \"\"\"\n",
+    "\n",
+    "    with set_cwd(root_path):\n",
+    "\n",
+    "        _custom_social_image_template_path = (\n",
+    "            get_root_data_path() / \"custom-social-image-template.html\"\n",
+    "        )\n",
+    "\n",
+    "        with open(_custom_social_image_template_path, \"r\") as f:\n",
+    "            _html_template = f.read()\n",
+    "\n",
+    "        author_name = get_value_from_config(root_path, \"author\")\n",
+    "        project_name = get_value_from_config(root_path, \"repo\")\n",
+    "        project_description = get_value_from_config(root_path, \"description\")\n",
+    "\n",
+    "        image_url = (\n",
+    "            Path(image_url).name\n",
+    "            if is_local_path(image_url)\n",
+    "            else image_url\n",
+    "        )\n",
+    "                \n",
+    "        d = dict(\n",
+    "            fill_in_author_name=author_name,\n",
+    "            fill_in_project_name=project_name,\n",
+    "            fill_in_project_description=project_description,\n",
+    "            fill_in_image_url=image_url,\n",
+    "        )\n",
+    "        \n",
+    "        for k, v in d.items():\n",
+    "            _html_template = _html_template.replace(k, v)\n",
+    "\n",
+    "        \n",
+    "        return _html_template\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c0f93300",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "<!DOCTYPE html>\n",
+      "<html>\n",
+      "    <head>\n",
+      "        <link rel=\"preload\" href='https://fonts.googleapis.com/css?family=Source Sans Pro' rel='stylesheet'/>\n",
+      "        <style>\n",
+      "            body {\n",
+      "                margin: 0px;\n",
+      "                width: 1280px;\n",
+      "                height: 640px;\n",
+      "                font-family: 'Source Sans Pro', sans-serif;\n",
+      "            }\n",
+      "            #container {\n",
+      "                display: flex;\n",
+      "                height: 640px;\n",
+      "            }\n",
+      "            #container div:first-child{\n",
+      "                flex-basis: 704px;\n",
+      "                padding-top: 40px;\n",
+      "            }\n",
+      "            #container div:first-child h1{\n",
+      "                font-size: 85px;\n",
+      "                margin: 64px 0px 64px 64px;\n",
+      "                color: #2E363D;\n",
+      "            }\n",
+      "            #container div:first-child h1 span{\n",
+      "                font-weight: 100;\n",
+      "            }\n",
+      "            #container div:first-child p {\n",
+      "                font-size: 30px;\n",
+      "                color: #6E7681;\n",
+      "                margin: 64px 0px 64px 64px;\n",
+      "            }\n",
+      "            #container div:last-child img{\n",
+      "                margin: 64px 64px 64px 0px;\n",
+      "                border-radius: 50px;\n",
+      "            }\n",
+      "        </style>\n",
+      "      </head>\n",
+      "      <body>\n",
+      "      <div id=\"container\">\n",
+      "         <div>\n",
+      "            <h1><span>airt/</span>nbdev-mkdocs</h1>\n",
+      "            <p>Extension of nbdev for generating documentation using Material for Mkdocs instead of Quarto</p>\n",
+      "         </div>\n",
+      "         <div>\n",
+      "            <img src=\"https://sample-image.png\" />\n",
+      "         </div>\n",
+      "      </div>\n",
+      "   </body>\n",
+      "</html>\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "\n",
+    "    shutil.copyfile(Path(\"..\") / \"settings.ini\", Path(d) / \"settings.ini\")\n",
+    "\n",
+    "    author_name = get_value_from_config(d, \"author\")\n",
+    "    project_name = get_value_from_config(d, \"repo\")\n",
+    "    project_description = get_value_from_config(d, \"description\")\n",
+    "\n",
+    "    image_url = \"https://sample-image.png\"\n",
+    "    actual = _generate_html_str(d, image_url)\n",
+    "    print(actual)\n",
+    "\n",
+    "    assert f\"{author_name}/\" in actual\n",
+    "    assert project_name in actual\n",
+    "    assert image_url in actual\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "6dd1b7bb",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "<!DOCTYPE html>\n",
+      "<html>\n",
+      "    <head>\n",
+      "        <link rel=\"preload\" href='https://fonts.googleapis.com/css?family=Source Sans Pro' rel='stylesheet'/>\n",
+      "        <style>\n",
+      "            body {\n",
+      "                margin: 0px;\n",
+      "                width: 1280px;\n",
+      "                height: 640px;\n",
+      "                font-family: 'Source Sans Pro', sans-serif;\n",
+      "            }\n",
+      "            #container {\n",
+      "                display: flex;\n",
+      "                height: 640px;\n",
+      "            }\n",
+      "            #container div:first-child{\n",
+      "                flex-basis: 704px;\n",
+      "                padding-top: 40px;\n",
+      "            }\n",
+      "            #container div:first-child h1{\n",
+      "                font-size: 85px;\n",
+      "                margin: 64px 0px 64px 64px;\n",
+      "                color: #2E363D;\n",
+      "            }\n",
+      "            #container div:first-child h1 span{\n",
+      "                font-weight: 100;\n",
+      "            }\n",
+      "            #container div:first-child p {\n",
+      "                font-size: 30px;\n",
+      "                color: #6E7681;\n",
+      "                margin: 64px 0px 64px 64px;\n",
+      "            }\n",
+      "            #container div:last-child img{\n",
+      "                margin: 64px 64px 64px 0px;\n",
+      "                border-radius: 50px;\n",
+      "            }\n",
+      "        </style>\n",
+      "      </head>\n",
+      "      <body>\n",
+      "      <div id=\"container\">\n",
+      "         <div>\n",
+      "            <h1><span>airt/</span>nbdev-mkdocs</h1>\n",
+      "            <p>Extension of nbdev for generating documentation using Material for Mkdocs instead of Quarto</p>\n",
+      "         </div>\n",
+      "         <div>\n",
+      "            <img src=\"sample-image.png\" />\n",
+      "         </div>\n",
+      "      </div>\n",
+      "   </body>\n",
+      "</html>\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "\n",
+    "    shutil.copyfile(Path(\"..\") / \"settings.ini\", Path(d) / \"settings.ini\")\n",
+    "\n",
+    "    author_name = get_value_from_config(d, \"author\")\n",
+    "    project_name = get_value_from_config(d, \"repo\")\n",
+    "    project_description = get_value_from_config(d, \"description\")\n",
+    "\n",
+    "    image_url = Path(d) / \"sample-image.png\"\n",
+    "    actual = _generate_html_str(d, image_url)\n",
+    "    print(actual)\n",
+    "\n",
+    "    assert f\"{author_name}/\" in actual\n",
+    "    assert project_name in actual\n",
+    "    assert str(image_url) not in actual\n",
+    "    assert \"sample-image.png\" in actual\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c8d0fe31",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "\n",
+    "async def _capture_and_save_screenshot(src_path: str, dst_path: str):\n",
+    "    \"\"\"Capture screenshot of an HTML file from source directory and save the\n",
+    "    output in destination directory\n",
+    "\n",
+    "    Args:\n",
+    "        src_path: The source path of the HTML file that will be used to generate the PNG image.\n",
+    "        dst_path: The destination path where the generated screenshot image will be saved.\n",
+    "    \"\"\"\n",
+    "    playwright = await async_playwright().start()\n",
+    "    browser = await playwright.chromium.launch()\n",
+    "\n",
+    "    try:\n",
+    "        page = await browser.new_page()\n",
+    "\n",
+    "        html_path = Path(src_path) / \"social_image.html\"\n",
+    "        await page.goto(f\"file://{str(html_path.resolve())}\")\n",
+    "\n",
+    "        output_path = (\n",
+    "            Path(dst_path) / \"mkdocs\" / \"docs_overrides\" / \"images\" / \"social_image.png\"\n",
+    "        )\n",
+    "        await page.locator('#container').screenshot(path=str(output_path.resolve()))\n",
+    "\n",
+    "        typer.echo(f\"Social share image generated and saved at: '{output_path}'\")\n",
+    "\n",
+    "    finally:\n",
+    "        await browser.close()\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b39aa521",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Social share image generated and saved at: '/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpzrazqte8/dst_path/mkdocs/docs_overrides/images/social_image.png'\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "\n",
+    "    html_path = Path(d) / \"social_image.html\"\n",
+    "    with open(html_path, \"w\") as f:\n",
+    "        f.write(\"<html><body><div id = 'container'><p>This is a sample text</p></div></body></html>\")\n",
+    "\n",
+    "    png_path = Path(d) / \"dst_path\" / \"mkdocs\" / \"docs_overrides\" / \"images\"\n",
+    "    png_path.mkdir(parents=True)\n",
+    "\n",
+    "    dst_path = Path(d) / \"dst_path\"\n",
+    "    await _capture_and_save_screenshot(d, dst_path)\n",
+    "\n",
+    "    assert (png_path / \"social_image.png\").exists()\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "ace281ae",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "async def _create_social_image(root_path: str, image_url: str):\n",
+    "    \"\"\"Create social image for the project\n",
+    "\n",
+    "    Args:\n",
+    "        root_path: The root path of the project.\n",
+    "        image_url: The image URL to be included in the social image.\n",
+    "    \"\"\"\n",
+    "    html_str = _generate_html_str(root_path, image_url)\n",
+    "\n",
+    "    with TemporaryDirectory() as d:\n",
+    "\n",
+    "        html_path = Path(d) / \"social_image.html\"\n",
+    "        with open(html_path, \"w\") as f:\n",
+    "            f.write(html_str)\n",
+    "\n",
+    "        if is_local_path(image_url):\n",
+    "            shutil.copyfile(Path(image_url), Path(d) / Path(image_url).name)\n",
+    "            \n",
+    "        await _capture_and_save_screenshot(d, root_path)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "61587599",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Social share image generated and saved at: '/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpfuspi9et/mkdocs/docs_overrides/images/social_image.png'\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "\n",
+    "    mkdocs_dir_path = Path(d) / \"mkdocs\" / \"docs_overrides\" / \"images\"\n",
+    "    mkdocs_dir_path.mkdir(parents=True)\n",
+    "\n",
+    "    shutil.copyfile(\n",
+    "        Path(\"..\") / \"mkdocs\" / \"docs_overrides\" / \"images\" / \"default_social_logo.png\",\n",
+    "        Path(d) / \"default_social_logo.png\",\n",
+    "    )\n",
+    "\n",
+    "    image_url = (Path(d) / \"default_social_logo.png\").resolve()\n",
+    "    await _create_social_image(root_path = d, image_url = image_url)\n",
+    "\n",
+    "    png_path = mkdocs_dir_path / \"social_image.png\"\n",
+    "    assert png_path.exists()\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "15d3b665",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "\n",
+    "def _update_social_image_in_mkdocs_yml(root_path: str, image_url: str):\n",
+    "    \"\"\"Update social image link in mkdocs yml file\n",
+    "\n",
+    "    Args:\n",
+    "        root_path: The root path of the project.\n",
+    "        image_url: The image URL to update in the mkdocs yml file.\n",
+    "    \"\"\"\n",
+    "\n",
+    "    image_url = (\n",
+    "        \"overrides/images/social_image.png\"\n",
+    "        if is_local_path(image_url)\n",
+    "        else image_url\n",
+    "    )\n",
+    "    \n",
+    "    yaml = YAML()\n",
+    "    mkdocs_yml_path = Path(root_path) / \"mkdocs\" / \"mkdocs.yml\"\n",
+    "    config = yaml.load(mkdocs_yml_path)\n",
+    "    config[\"extra\"][\"social_image\"] = image_url\n",
+    "    yaml.dump(config, mkdocs_yml_path)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "63dc5d71",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Social share image generated and saved at: '/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpyck53zje/mkdocs/docs_overrides/images/social_image.png'\n",
+      "https://my-random-domain/sample.png\n",
+      "overrides/images/social_image.png\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "\n",
+    "    mkdocs_dir_path = Path(d) / \"mkdocs\" / \"docs_overrides\" / \"images\"\n",
+    "    mkdocs_dir_path.mkdir(parents=True)\n",
+    "\n",
+    "    shutil.copyfile(\n",
+    "        Path(\"..\") / \"mkdocs\" / \"docs_overrides\" / \"images\" / \"default_social_logo.png\",\n",
+    "        Path(d) / \"default_social_logo.png\",\n",
+    "    )\n",
+    "\n",
+    "    image_url = (Path(d) / \"default_social_logo.png\").resolve()\n",
+    "    await _create_social_image(root_path = d, image_url = image_url)\n",
+    "\n",
+    "    png_path = mkdocs_dir_path / \"social_image.png\"\n",
+    "    assert png_path.exists()\n",
+    "\n",
+    "\n",
+    "    mkdocs_yml_path = Path(d) / \"mkdocs\"\n",
+    "    shutil.copyfile(\n",
+    "        Path(\"..\") / \"mkdocs\" / \"mkdocs.yml\", (mkdocs_yml_path / \"mkdocs.yml\")\n",
+    "    )\n",
+    "\n",
+    "    image_url = \"https://my-random-domain/sample.png\"\n",
+    "    _update_social_image_in_mkdocs_yml(d, image_url)\n",
+    "\n",
+    "    yaml = YAML()\n",
+    "    config = yaml.load((Path(d) / \"mkdocs/mkdocs.yml\"))\n",
+    "    print(config[\"extra\"][\"social_image\"])\n",
+    "    assert config[\"extra\"][\"social_image\"] == image_url, config[\"extra\"][\"social_image\"]\n",
+    "\n",
+    "\n",
+    "    image_url = Path(d) / \"sample-image.png\"\n",
+    "    _update_social_image_in_mkdocs_yml(d, image_url)\n",
+    "\n",
+    "    yaml = YAML()\n",
+    "    config = yaml.load((Path(d) / \"mkdocs/mkdocs.yml\"))\n",
+    "    print(config[\"extra\"][\"social_image\"])\n",
+    "    assert (\n",
+    "        config[\"extra\"][\"social_image\"] == \"overrides/images/social_image.png\"\n",
+    "    ), config[\"extra\"][\"social_image\"]\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b1f9a6bd",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "\n",
+    "def _update_social_image_in_site_overrides(root_path: str, image_url: str):\n",
+    "    \"\"\"Update social image link in site_overrides HTML template\n",
+    "\n",
+    "    Args:\n",
+    "        root_path: The root path of the project.\n",
+    "        image_url: The image URL to update in the site_overrides HTML template.\n",
+    "    \"\"\"\n",
+    "    \n",
+    "    _replace_str = (\n",
+    "        'page.canonical_url ~ \"\" ~ config.extra.social_image '\n",
+    "        if is_local_path(image_url)\n",
+    "        else 'config.extra.social_image '\n",
+    "    )\n",
+    "    \n",
+    "    with set_cwd(root_path):\n",
+    "        site_overrides_path = (\n",
+    "            Path(root_path) / \"mkdocs\" / \"site_overrides\" / \"main.html\"\n",
+    "        )\n",
+    "        if not site_overrides_path.exists():\n",
+    "            typer.secho(\n",
+    "                f\"Unexpected error: path {site_overrides_path.resolve()} does not exists!\",\n",
+    "                err=True,\n",
+    "                fg=typer.colors.RED,\n",
+    "            )\n",
+    "            raise typer.Exit(code=1)\n",
+    "\n",
+    "        with open(site_overrides_path, \"r\") as f:\n",
+    "            _new_text = f.read()\n",
+    "            _pattern = re.compile(r\".*?{%.*?image_url = (.*)%}\")\n",
+    "            _match = re.search(_pattern, _new_text)\n",
+    "            _new_text = _new_text.replace(\n",
+    "                _match.group(1), _replace_str  # type: ignore\n",
+    "            )\n",
+    "\n",
+    "        with open(site_overrides_path, \"w\") as f:\n",
+    "            f.write(_new_text)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0b9c4de9",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{% extends \"base.html\" %}\n",
+      "\n",
+      "{% block extrahead %}\n",
+      "  {% set title = config.site_name %}\n",
+      "  {% if page and page.meta and page.meta.title %}\n",
+      "    {% set title = title ~ \" - \" ~ page.meta.title %}\n",
+      "  {% elif page and page.title and not page.is_homepage %}\n",
+      "    {% set title = title ~ \" - \" ~ page.title | striptags %}\n",
+      "  {% endif %}\n",
+      "  {% set image_url = page.canonical_url ~ \"\" ~ config.extra.social_image %}\n",
+      "  <meta property=\"og:type\" content=\"website\" />\n",
+      "  <meta property=\"og:title\" content=\"{{ title }}\" />\n",
+      "  <meta property=\"og:description\" content=\"{{ config.site_description }}\" />\n",
+      "  <meta property=\"og:url\" content=\"{{ page.canonical_url }}\" />\n",
+      "  <meta property=\"og:image\" content=\"{{ image_url }}\" />\n",
+      "  <meta property=\"og:image:type\" content=\"image/png\" />\n",
+      "  <meta property=\"og:image:width\" content=\"1200\" />\n",
+      "  <meta property=\"og:image:height\" content=\"600\" />\n",
+      "\n",
+      "  <meta name=\"twitter:card\" content=\"summary_large_image\" />\n",
+      "  <meta name=\"twitter:title\" content=\"{{ title }}\" />\n",
+      "  <meta name=\"twitter:description\" content=\"{{ config.site_description }}\" />\n",
+      "  <meta name=\"twitter:image\" content=\"{{ image_url }}\" />\n",
+      "{% endblock %}\n",
+      "\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "\n",
+    "    site_overrides_path = Path(d) / \"mkdocs\" / \"site_overrides\"\n",
+    "    site_overrides_path.mkdir(exist_ok=True, parents=True)\n",
+    "    shutil.copyfile(\n",
+    "        Path(\"..\") / \"mkdocs\" / \"site_overrides\" / \"main.html\",\n",
+    "        (site_overrides_path / \"main.html\"),\n",
+    "    )\n",
+    "\n",
+    "    image_url = Path(d) / \"random-image.png\"\n",
+    "    _update_social_image_in_site_overrides(d, image_url)\n",
+    "\n",
+    "    with open((site_overrides_path / \"main.html\")) as f:\n",
+    "        actual = f.read()\n",
+    "\n",
+    "    print(actual)\n",
+    "\n",
+    "    assert (\n",
+    "        '{% set image_url = page.canonical_url ~ \"\" ~ config.extra.social_image %}'\n",
+    "        in actual\n",
+    "    ), actual\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f7649b01",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{% extends \"base.html\" %}\n",
+      "\n",
+      "{% block extrahead %}\n",
+      "  {% set title = config.site_name %}\n",
+      "  {% if page and page.meta and page.meta.title %}\n",
+      "    {% set title = title ~ \" - \" ~ page.meta.title %}\n",
+      "  {% elif page and page.title and not page.is_homepage %}\n",
+      "    {% set title = title ~ \" - \" ~ page.title | striptags %}\n",
+      "  {% endif %}\n",
+      "  {% set image_url = config.extra.social_image %}\n",
+      "  <meta property=\"og:type\" content=\"website\" />\n",
+      "  <meta property=\"og:title\" content=\"{{ title }}\" />\n",
+      "  <meta property=\"og:description\" content=\"{{ config.site_description }}\" />\n",
+      "  <meta property=\"og:url\" content=\"{{ page.canonical_url }}\" />\n",
+      "  <meta property=\"og:image\" content=\"{{ image_url }}\" />\n",
+      "  <meta property=\"og:image:type\" content=\"image/png\" />\n",
+      "  <meta property=\"og:image:width\" content=\"1200\" />\n",
+      "  <meta property=\"og:image:height\" content=\"600\" />\n",
+      "\n",
+      "  <meta name=\"twitter:card\" content=\"summary_large_image\" />\n",
+      "  <meta name=\"twitter:title\" content=\"{{ title }}\" />\n",
+      "  <meta name=\"twitter:description\" content=\"{{ config.site_description }}\" />\n",
+      "  <meta name=\"twitter:image\" content=\"{{ image_url }}\" />\n",
+      "{% endblock %}\n",
+      "\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "\n",
+    "    site_overrides_path = Path(d) / \"mkdocs\" / \"site_overrides\"\n",
+    "    site_overrides_path.mkdir(exist_ok=True, parents=True)\n",
+    "    shutil.copyfile(\n",
+    "        Path(\"..\") / \"mkdocs\" / \"site_overrides\" / \"main.html\",\n",
+    "        (site_overrides_path / \"main.html\"),\n",
+    "    )\n",
+    "\n",
+    "    image_url = \"https://random-domain/random-image.png\"\n",
+    "    _update_social_image_in_site_overrides(d, image_url)\n",
+    "\n",
+    "    with open((site_overrides_path / \"main.html\")) as f:\n",
+    "        actual = f.read()\n",
+    "\n",
+    "    print(actual)\n",
+    "\n",
+    "    assert (\n",
+    "        '{% set image_url = config.extra.social_image %}'\n",
+    "        in actual\n",
+    "    ), actual\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "ac6e1b41",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "\n",
+    "class _IMG_Generator(str, Enum):\n",
+    "    file = \"file\"\n",
+    "    dall_e = \"dall_e\"\n",
+    "    \n",
+    "\n",
+    "def _generate_image_url(\n",
+    "    root_path: str, generator: str, prompt: str, image_path: Optional[str] = None\n",
+    ") -> str:\n",
+    "    \"\"\"Generate image url based on the generator\n",
+    "\n",
+    "    Args:\n",
+    "        root_path: The root path of the project.\n",
+    "        generator: Generator to use to create the social image. Valid options are: 'file' and 'dall_e'.\n",
+    "        prompt: The prompt to use for generating the image.\n",
+    "        image_path: Image file path to use in the social share image. If None, then the default image will be used.\n",
+    "\n",
+    "    Returns:\n",
+    "        The image url\n",
+    "    \"\"\"\n",
+    "    if generator not in _IMG_Generator._member_names_:\n",
+    "        raise ValueError(\n",
+    "            \"Invalid Option for generator. Valid options are: 'file' and 'dall_e'\"\n",
+    "        )\n",
+    "\n",
+    "    elif generator == _IMG_Generator.dall_e.value:\n",
+    "        image_url = _generate_ai_image(prompt=prompt)\n",
+    "\n",
+    "    else:\n",
+    "        with set_cwd(root_path):\n",
+    "            if image_path is not None:\n",
+    "                _image_path = Path(\n",
+    "                    os.path.normpath(Path(root_path).joinpath(image_path))\n",
+    "                ).resolve()\n",
+    "\n",
+    "                if not _image_path.exists():\n",
+    "                    typer.secho(\n",
+    "                        f\"Unexpected error: path {_image_path.resolve()} does not exists!\",\n",
+    "                        err=True,\n",
+    "                        fg=typer.colors.RED,\n",
+    "                    )\n",
+    "                    raise typer.Exit(code=1)\n",
+    "                \n",
+    "                image_url = str(_image_path)\n",
+    "                \n",
+    "            else:\n",
+    "                image_url = str((\n",
+    "                    Path(root_path)\n",
+    "                    / \"mkdocs\"\n",
+    "                    / \"docs_overrides\"\n",
+    "                    / \"images\"\n",
+    "                    / \"default_social_logo.png\"\n",
+    "                ).resolve())\n",
+    "\n",
+    "    return image_url\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "676205ef",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Invalid Option for generator. Valid options are: 'file' and 'dall_e'\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "    with pytest.raises(ValueError) as e:\n",
+    "        generator = \"random_name\"\n",
+    "        image_path = None\n",
+    "        prompt = \"Cute animal wearing hoodie sitting in high chair in purple room, browsing computer, 3d render\"\n",
+    "        _generate_image_url(d, generator, prompt)\n",
+    "        \n",
+    "    print(e.value)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "ed201922",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Billing hard limit has been reached\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "    prompt = \"The quick brown fox jumps over a lazy dog\"\n",
+    "    generator = \"dall_e\"\n",
+    "    prompt = \"Cute animal wearing hoodie sitting in high chair in purple room, browsing computer, 3d render\"\n",
+    "\n",
+    "    with pytest.raises(Exception) as e:\n",
+    "        _generate_image_url(root_path=d, generator=generator, prompt=prompt)\n",
+    "    print(e.value)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "16462c12",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\u001b[31mUnexpected error: path /private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp8zbhex29/invalid_image_path.png does not exists!\u001b[0m\n"
+     ]
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "    generator = \"file\"\n",
+    "    image_path = \"invalid_image_path.png\"\n",
+    "    prompt = \"Cute animal wearing hoodie sitting in high chair in purple room, browsing computer, 3d render\"\n",
+    "    with pytest.raises(typer.Exit) as e:\n",
+    "        _generate_image_url(root_path=d, generator=generator, prompt=prompt, image_path=image_path)\n",
+    "        \n",
+    "    print(e.value)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "91c020fa",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpxwhru3pe/valid_image_path.png\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "\n",
+    "    prompt = \"The quick brown fox jumps over a lazy dog\"\n",
+    "    generator = \"file\"\n",
+    "    image_path = \"./valid_image_path.png\"\n",
+    "    prompt = \"Cute animal wearing hoodie sitting in high chair in purple room, browsing computer, 3d render\"\n",
+    "    shutil.copyfile(\n",
+    "        Path(\"..\") / \"mkdocs\" / \"docs_overrides\" / \"images\" / \"compass-outline.png\",\n",
+    "        Path(d) / \"valid_image_path.png\",\n",
+    "    )\n",
+    "\n",
+    "    image_url = _generate_image_url(root_path=d, generator=generator, prompt=prompt, image_path=image_path)\n",
+    "\n",
+    "    print(image_url)\n",
+    "\n",
+    "    assert image_url == str(Path(d).resolve() / image_path), str(Path(d).resolve() / image_path)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "27c38014",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpmlg0f3fr/valid_image_path.png\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "\n",
+    "    shutil.copyfile(\n",
+    "        Path(\"..\") / \"mkdocs\" / \"docs_overrides\" / \"images\" / \"compass-outline.png\",\n",
+    "        Path(d) / \"valid_image_path.png\",\n",
+    "    )\n",
+    "\n",
+    "    prompt = \"Cute animal wearing hoodie sitting in high chair in purple room, browsing computer, 3d render\"\n",
+    "    generator = \"file\"\n",
+    "\n",
+    "    d_tmp = Path(d) / \"tmp\"\n",
+    "    d_tmp.mkdir(parents=True)\n",
+    "\n",
+    "    image_path = \"../valid_image_path.png\"\n",
+    "\n",
+    "    image_url = _generate_image_url(root_path=d_tmp, generator=generator, prompt=prompt, image_path=image_path)\n",
+    "\n",
+    "    print(image_url)\n",
+    "\n",
+    "    assert image_url == str(Path(d).resolve() / \"valid_image_path.png\"), str(\n",
+    "        Path(d).resolve() / \"valid_image_path.png\"\n",
+    "    )\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "7a764832",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "/private/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmpczme7ecb/mkdocs/docs_overrides/images/default_social_logo.png\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "    generator = \"file\"\n",
+    "    prompt = \"Cute animal wearing hoodie sitting in high chair in purple room, browsing computer, 3d render\"\n",
+    "    image_url = _generate_image_url(root_path=d, generator=generator, prompt=prompt)\n",
+    "    print(image_url)\n",
+    "    assert (\n",
+    "        image_url\n",
+    "        == str((\n",
+    "            Path(d) / \"mkdocs\" / \"docs_overrides\" / \"images\" / \"default_social_logo.png\"\n",
+    "        ).resolve())\n",
+    "    ), image_url\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1736deab",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "\n",
+    "\n",
+    "async def generate_social_image(\n",
+    "    root_path: str,\n",
+    "    generator: str = \"file\",\n",
+    "    prompt: str = \"Cute animal wearing hoodie sitting in high chair in purple room, browsing computer, 3d render\",\n",
+    "    image_path: Optional[str] = None,\n",
+    "):\n",
+    "    \"\"\"Generate a custom image for social card using the OpenAI Image API.\n",
+    "\n",
+    "    Args:\n",
+    "        root_path: The root path of the project.\n",
+    "        generator: Generator to use to create the social image. Valid options are: 'file' and 'dall_e'.\n",
+    "        prompt: The prompt to use for generating the image.\n",
+    "        image_path: Image file path to use in the social share image. If None, then the default image will be used.\n",
+    "    \"\"\"\n",
+    "\n",
+    "    image_url = _generate_image_url(root_path, generator, prompt, image_path)\n",
+    "\n",
+    "    await _create_social_image(root_path, image_url)\n",
+    "\n",
+    "    _update_social_image_in_mkdocs_yml(root_path, image_url)\n",
+    "\n",
+    "    _update_social_image_in_site_overrides(root_path, image_url)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "6be315b6",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Social share image generated and saved at: '/var/folders/6n/3rjds7v52cd83wqkd565db0h0000gn/T/tmp13dql6n6/mkdocs/docs_overrides/images/social_image.png'\n",
+      "overrides/images/social_image.png\n",
+      "{% extends \"base.html\" %}\n",
+      "\n",
+      "{% block extrahead %}\n",
+      "  {% set title = config.site_name %}\n",
+      "  {% if page and page.meta and page.meta.title %}\n",
+      "    {% set title = title ~ \" - \" ~ page.meta.title %}\n",
+      "  {% elif page and page.title and not page.is_homepage %}\n",
+      "    {% set title = title ~ \" - \" ~ page.title | striptags %}\n",
+      "  {% endif %}\n",
+      "  {% set image_url = page.canonical_url ~ \"\" ~ config.extra.social_image %}\n",
+      "  <meta property=\"og:type\" content=\"website\" />\n",
+      "  <meta property=\"og:title\" content=\"{{ title }}\" />\n",
+      "  <meta property=\"og:description\" content=\"{{ config.site_description }}\" />\n",
+      "  <meta property=\"og:url\" content=\"{{ page.canonical_url }}\" />\n",
+      "  <meta property=\"og:image\" content=\"{{ image_url }}\" />\n",
+      "  <meta property=\"og:image:type\" content=\"image/png\" />\n",
+      "  <meta property=\"og:image:width\" content=\"1200\" />\n",
+      "  <meta property=\"og:image:height\" content=\"600\" />\n",
+      "\n",
+      "  <meta name=\"twitter:card\" content=\"summary_large_image\" />\n",
+      "  <meta name=\"twitter:title\" content=\"{{ title }}\" />\n",
+      "  <meta name=\"twitter:description\" content=\"{{ config.site_description }}\" />\n",
+      "  <meta name=\"twitter:image\" content=\"{{ image_url }}\" />\n",
+      "{% endblock %}\n",
+      "\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "\n",
+    "    mkdocs_dir_path = Path(d) / \"mkdocs\" / \"docs_overrides\" / \"images\"\n",
+    "    mkdocs_dir_path.mkdir(exist_ok=True, parents=True)\n",
+    "\n",
+    "    mkdocs_yml_path = Path(d) / \"mkdocs\"\n",
+    "    shutil.copyfile(\n",
+    "        Path(\"..\") / \"mkdocs\" / \"mkdocs.yml\", (mkdocs_yml_path / \"mkdocs.yml\")\n",
+    "    )\n",
+    "\n",
+    "    site_overrides_path = Path(d) / \"mkdocs\" / \"site_overrides\"\n",
+    "    site_overrides_path.mkdir(exist_ok=True, parents=True)\n",
+    "    shutil.copyfile(\n",
+    "        Path(\"..\") / \"mkdocs\" / \"site_overrides\" / \"main.html\",\n",
+    "        (site_overrides_path / \"main.html\"),\n",
+    "    )\n",
+    "\n",
+    "    shutil.copyfile(\n",
+    "        Path(\"..\") / \"mkdocs\" / \"docs_overrides\" / \"images\" / \"default_social_logo.png\",\n",
+    "        mkdocs_dir_path / \"default_social_logo.png\",\n",
+    "    )\n",
+    "\n",
+    "    prompt = \"The quick brown fox jumps over a lazy dog\"\n",
+    "    await generate_social_image(root_path=d, prompt=prompt)\n",
+    "\n",
+    "    png_path = mkdocs_dir_path / \"social_image.png\"\n",
+    "\n",
+    "    assert png_path.exists()\n",
+    "\n",
+    "    yaml = YAML()\n",
+    "    config = yaml.load((Path(d) / \"mkdocs/mkdocs.yml\"))\n",
+    "    print(config[\"extra\"][\"social_image\"])\n",
+    "    assert (\n",
+    "        config[\"extra\"][\"social_image\"] == \"overrides/images/social_image.png\"\n",
+    "    ), config[\"extra\"][\"social_image\"]\n",
+    "\n",
+    "    with open((site_overrides_path / \"main.html\")) as f:\n",
+    "        actual = f.read()\n",
+    "\n",
+    "    print(actual)\n",
+    "\n",
+    "    assert (\n",
+    "        '{% set image_url = page.canonical_url ~ \"\" ~ config.extra.social_image %}'\n",
+    "        in actual\n",
+    "    ), actual\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5fa1d500",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/nbs/Utils.ipynb b/nbs/Utils.ipynb
new file mode 100644
index 00000000..fb89c2f4
--- /dev/null
+++ b/nbs/Utils.ipynb
@@ -0,0 +1,183 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "56a6cb4a",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | default_exp _helpers.utils"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "a697536c",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "\n",
+    "import os\n",
+    "from typing import *\n",
+    "from urllib.parse import urlparse\n",
+    "from contextlib import contextmanager\n",
+    "from pathlib import Path\n",
+    "\n",
+    "import nbdev\n",
+    "from configparser import ConfigParser\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c70f326a",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import shutil\n",
+    "from tempfile import TemporaryDirectory\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "7f3f76d6",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "\n",
+    "@contextmanager\n",
+    "def set_cwd(cwd_path: Union[Path, str]):\n",
+    "\n",
+    "    cwd_path = Path(cwd_path)\n",
+    "    original_cwd = os.getcwd()\n",
+    "    os.chdir(cwd_path)\n",
+    "\n",
+    "    try:\n",
+    "        nbdev.config.get_config.cache_clear()\n",
+    "        yield\n",
+    "    finally:\n",
+    "        os.chdir(original_cwd)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5ac4ecc1",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "    with set_cwd(d):\n",
+    "        assert (\n",
+    "            Path(os.getcwd()) == Path(d).resolve()\n",
+    "        ), f\"{os.getcwd()}, {Path(d).resolve()}\"\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "7d9cfc40",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "\n",
+    "def get_value_from_config(root_path: str, config_name: str) -> str:\n",
+    "    \"\"\"Get the value from settings.ini file\"\"\"\n",
+    "\n",
+    "    settings_path = Path(root_path) / \"settings.ini\"\n",
+    "    config = ConfigParser()\n",
+    "    config.read(settings_path)\n",
+    "    if not config.has_option(\"DEFAULT\", config_name):\n",
+    "        return \"\"\n",
+    "    return config[\"DEFAULT\"][config_name]\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "72989ce9",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "nbdev_mkdocs\n",
+      "nbdev-mkdocs\n",
+      "airtai\n"
+     ]
+    }
+   ],
+   "source": [
+    "with TemporaryDirectory() as d:\n",
+    "    settings_path = Path(d) / \"settings.ini\"\n",
+    "    shutil.copyfile(Path(\"..\") / \"settings.ini\", settings_path)\n",
+    "    ret_val = get_value_from_config(d, \"lib_path\")\n",
+    "    print(ret_val)\n",
+    "    assert ret_val == \"nbdev_mkdocs\", ret_val\n",
+    "\n",
+    "    ret_val = get_value_from_config(d, \"repo\")\n",
+    "    print(ret_val)\n",
+    "    assert ret_val == \"nbdev-mkdocs\", ret_val\n",
+    "\n",
+    "    ret_val = get_value_from_config(d, \"user\")\n",
+    "    print(ret_val)\n",
+    "    assert ret_val == \"airtai\", ret_val\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0fdc5efd",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# | export\n",
+    "\n",
+    "def is_local_path(path):\n",
+    "    # Check if the path is an absolute path\n",
+    "    if os.path.isabs(path):\n",
+    "        return True\n",
+    "    \n",
+    "    # Check if the path is a URL with a scheme (e.g. http, https, ftp)\n",
+    "    parsed_url = urlparse(path)\n",
+    "    if parsed_url.scheme:\n",
+    "        return False\n",
+    "    \n",
+    "    # If the path is not an absolute path and does not have a URL scheme,\n",
+    "    # it is assumed to be a local path\n",
+    "    return True"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "bc4b8f12",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "\n",
+    "assert is_local_path(\"/tmp/abc/file.txt\")\n",
+    "\n",
+    "assert not is_local_path(\"http://www.example.com\")"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/nbs/index.ipynb b/nbs/index.ipynb
index b4b74ecb..1c3b3bd5 100644
--- a/nbs/index.ipynb
+++ b/nbs/index.ipynb
@@ -201,26 +201,27 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "\u001b[1m                                                                                \u001b[0m\r\n",
-      "\u001b[1m \u001b[0m\u001b[1;33mUsage: \u001b[0m\u001b[1mnbdev_mkdocs [OPTIONS] COMMAND [ARGS]...\u001b[0m\u001b[1m                               \u001b[0m\u001b[1m \u001b[0m\r\n",
-      "\u001b[1m                                                                                \u001b[0m\r\n",
-      "\u001b[2m╭─\u001b[0m\u001b[2m Options \u001b[0m\u001b[2m───────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-install\u001b[0m\u001b[1;36m-completion\u001b[0m          Install completion for the current shell.      \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-show\u001b[0m\u001b[1;36m-completion\u001b[0m             Show completion for the current shell, to copy \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m                               it or customize the installation.              \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-help\u001b[0m                        Show this message and exit.                    \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\r\n",
-      "\u001b[2m╭─\u001b[0m\u001b[2m Commands \u001b[0m\u001b[2m──────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m \u001b[1;36mdocs   \u001b[0m\u001b[1;36m \u001b[0m Prepares files in **mkdocs/docs** and then runs **mkdocs build**    \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m \u001b[1;36m        \u001b[0m command on them                                                     \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m \u001b[1;36mnew    \u001b[0m\u001b[1;36m \u001b[0m Creates files in **mkdocs** subdirectory needed for other           \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m \u001b[1;36m        \u001b[0m **nbdev_mkdocs** subcommands                                        \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m \u001b[1;36mprepare\u001b[0m\u001b[1;36m \u001b[0m Runs tests and prepares files in **mkdocs/docs** and then runs      \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m \u001b[1;36m        \u001b[0m **mkdocs build** command on them                                    \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m \u001b[1;36mpreview\u001b[0m\u001b[1;36m \u001b[0m Prepares files in **mkdocs/docs** and then runs **mkdocs serve**    \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m│\u001b[0m \u001b[1;36m        \u001b[0m command on them                                                     \u001b[2m│\u001b[0m\r\n",
-      "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\r\n",
-      "\r\n"
+      "\u001b[1m                                                                                \u001b[0m\n",
+      "\u001b[1m \u001b[0m\u001b[1;33mUsage: \u001b[0m\u001b[1mnbdev_mkdocs [OPTIONS] COMMAND [ARGS]...\u001b[0m\u001b[1m                               \u001b[0m\u001b[1m \u001b[0m\n",
+      "\u001b[1m                                                                                \u001b[0m\n",
+      "\u001b[2m╭─\u001b[0m\u001b[2m Options \u001b[0m\u001b[2m───────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-install\u001b[0m\u001b[1;36m-completion\u001b[0m          Install completion for the current shell.      \u001b[2m│\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-show\u001b[0m\u001b[1;36m-completion\u001b[0m             Show completion for the current shell, to copy \u001b[2m│\u001b[0m\n",
+      "\u001b[2m│\u001b[0m                               it or customize the installation.              \u001b[2m│\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-help\u001b[0m                        Show this message and exit.                    \u001b[2m│\u001b[0m\n",
+      "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n",
+      "\u001b[2m╭─\u001b[0m\u001b[2m Commands \u001b[0m\u001b[2m──────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36mdocs                 \u001b[0m\u001b[1;36m \u001b[0m Prepares files in **mkdocs/docs** and then runs       \u001b[2m│\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36m                      \u001b[0m **mkdocs build** command on them                      \u001b[2m│\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36mgenerate-social-image\u001b[0m\u001b[1;36m \u001b[0m Generate a custom social share image                  \u001b[2m│\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36mnew                  \u001b[0m\u001b[1;36m \u001b[0m Creates files in **mkdocs** subdirectory needed for   \u001b[2m│\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36m                      \u001b[0m other **nbdev_mkdocs** subcommands                    \u001b[2m│\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36mprepare              \u001b[0m\u001b[1;36m \u001b[0m Runs tests and prepares files in **mkdocs/docs** and  \u001b[2m│\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36m                      \u001b[0m then runs **mkdocs build** command on them            \u001b[2m│\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36mpreview              \u001b[0m\u001b[1;36m \u001b[0m Prepares files in **mkdocs/docs** and then runs       \u001b[2m│\u001b[0m\n",
+      "\u001b[2m│\u001b[0m \u001b[1;36m                      \u001b[0m **mkdocs serve** command on them                      \u001b[2m│\u001b[0m\n",
+      "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n",
+      "\n"
      ]
     }
    ],
diff --git a/package_data/custom-social-image-template.html b/package_data/custom-social-image-template.html
new file mode 100644
index 00000000..fec4d100
--- /dev/null
+++ b/package_data/custom-social-image-template.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <link rel="preload" href='https://fonts.googleapis.com/css?family=Source Sans Pro' rel='stylesheet'/>
+        <style>
+            body {
+                margin: 0px;
+                width: 1280px;
+                height: 640px;
+                font-family: 'Source Sans Pro', sans-serif;
+            }
+            #container {
+                display: flex;
+                height: 640px;
+            }
+            #container div:first-child{
+                flex-basis: 704px;
+                padding-top: 40px;
+            }
+            #container div:first-child h1{
+                font-size: 85px;
+                margin: 74px 0px 64px 60px;
+                color: #2E363D;
+            }
+            #container div:first-child h1 span{
+                font-weight: 100;
+            }
+            #container div:first-child p {
+                font-size: 30px;
+                color: #6E7681;
+                margin: 64px 0px 64px 64px;
+            }
+            #container div:last-child img{
+                margin: 64px 64px 64px 0px;
+                border-radius: 50px;
+            }
+        </style>
+      </head>
+      <body>
+      <div id="container">
+         <div>
+            <h1><span>fill_in_author_name/</span>fill_in_project_name</h1>
+            <p>fill_in_project_description</p>
+         </div>
+         <div>
+            <img src="fill_in_image_url" />
+         </div>
+      </div>
+   </body>
+</html>
diff --git a/package_data/mkdocs_template/docs_overrides/images/default_social_logo.png b/package_data/mkdocs_template/docs_overrides/images/default_social_logo.png
new file mode 100644
index 00000000..d53cbad1
Binary files /dev/null and b/package_data/mkdocs_template/docs_overrides/images/default_social_logo.png differ
diff --git a/package_data/requirements.txt b/package_data/requirements.txt
index a3b40397..1eea00c7 100644
--- a/package_data/requirements.txt
+++ b/package_data/requirements.txt
@@ -6,3 +6,5 @@ mkdocs-section-index>=0.3.4
 configupdater>=3.1.1
 griffe>=0.24.1
 ruamel.yaml>=0.17.21
+openai>=0.25.0
+playwright>=1.28.0
diff --git a/settings.ini b/settings.ini
index 9e60b133..e6e47576 100644
--- a/settings.ini
+++ b/settings.ini
@@ -49,7 +49,9 @@ requirements =     \
     mkdocs-section-index>=0.3.4 \
     configupdater>=3.1.1 \
     griffe>=0.24.1 \
-    ruamel.yaml>=0.17.21
+    ruamel.yaml>=0.17.21 \
+    openai>=0.25.0 \
+    playwright>=1.28.0
 
 dev_requirements = \
     bandit>=1.7.4 \


Test patch:
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index cac9324a..d93514ae 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -29,6 +29,10 @@ jobs:
             wget -q https://www.quarto.org/download/latest/quarto-macos.pkg
             sudo installer -pkg quarto-macos.pkg -target /
           fi
+      - name: Install playwright
+        run: |
+          pip3 install playwright
+          playwright install chromium
       - uses: fastai/workflows/nbdev-ci@master
         with:
           version: ${{ matrix.version }}
@@ -45,3 +49,4 @@ jobs:
             exit 1
           fi
 
+