{"id":26696086,"url":"https://github.com/neurolibre/myst-libre","last_synced_at":"2026-02-19T19:00:42.023Z","repository":{"id":249664900,"uuid":"806191755","full_name":"neurolibre/myst-libre","owner":"neurolibre","description":"Streamline building  MyST articles in docker containers.","archived":false,"fork":false,"pushed_at":"2026-02-19T17:02:42.000Z","size":112,"stargazers_count":2,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-02-19T17:24:31.389Z","etag":null,"topics":["joss","jupyter","myst","neurolibre","openjournals","publishing"],"latest_commit_sha":null,"homepage":"https://neurolibre.org","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/neurolibre.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-05-26T16:20:55.000Z","updated_at":"2025-11-04T02:18:35.000Z","dependencies_parsed_at":"2024-08-09T22:39:58.989Z","dependency_job_id":"01c15117-e54f-4f16-a327-c38210acbd8a","html_url":"https://github.com/neurolibre/myst-libre","commit_stats":null,"previous_names":["neurolibre/myst-libre"],"tags_count":50,"template":false,"template_full_name":null,"purl":"pkg:github/neurolibre/myst-libre","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurolibre%2Fmyst-libre","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurolibre%2Fmyst-libre/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurolibre%2Fmyst-libre/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurolibre%2Fmyst-libre/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neurolibre","download_url":"https://codeload.github.com/neurolibre/myst-libre/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurolibre%2Fmyst-libre/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29627664,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T18:02:07.722Z","status":"ssl_error","status_checked_at":"2026-02-19T18:01:46.144Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["joss","jupyter","myst","neurolibre","openjournals","publishing"],"created_at":"2025-03-26T20:01:02.511Z","updated_at":"2026-02-19T19:00:42.016Z","avatar_url":"https://github.com/neurolibre.png","language":"Python","funding_links":[],"categories":["Tools"],"sub_categories":["Miscellaneuous"],"readme":"# MyST Libre\n\n![PyPI - Version](https://img.shields.io/pypi/v/myst-libre?style=flat\u0026logo=python\u0026logoColor=white\u0026logoSize=8\u0026labelColor=rgb(255%2C0%2C0)\u0026color=white)\n\nFollowing the [REES](https://repo2docker.readthedocs.io/en/latest/specification.html), `myst-libre` streamlines building [✨MyST articles✨](https://mystmd.org/) in containers.\n\n* A repository containing MyST sources\n* A Docker image (built by [`binderhub`](https://github.com/jupyterhub/binderhub)) in a public (or private) registry, including:\n  * Dependencies to execute notebooks/markdown files in the MyST repository\n  * JupyterHub (typically part of images built by `binderhub`)\n* Input data required by the executable content (optional)\n\nGiven these resources, myst-libre starts a Docker container, mounts the MyST repository and data (if available), and builds a MyST publication.\n\n\u003e [!NOTE]\n\u003e This project was started to support publishing MyST articles as living preprints on [`NeuroLibre`](https://neurolibre.org).\n\n## Installation\n\n### External dependencies \n\n\u003e [!IMPORTANT]\n\u003e Ensure the following prerequisites are installed:\n\n- Node.js (For MyST)  [installation guide](https://mystmd.org/guide/installing-prerequisites)\n- Docker              [installation guide](https://docs.docker.com/get-docker/)\n\n### Install myst-libre\n\n```\npip install myst-libre\n```\n\n**Set up environment variables:**\n\nIf you are using a private image registry and/or Curvenote CLI features, create a `.env` file in the project root and add the following:\n\n```env\nDOCKER_PRIVATE_REGISTRY_USERNAME=your_username\nDOCKER_PRIVATE_REGISTRY_PASSWORD=your_password\nCURVENOTE_TOKEN=your_curvenote_api_token\n```\n\nThe `CURVENOTE_TOKEN` is required for operations like `curvenote submit`, `curvenote deploy`, `curvenote pull`, etc. You can generate an API token from your [Curvenote profile settings](https://curvenote.com/profile?settings=true\u0026tab=profile-api\u0026subtab=general).\n\n## Quick Start\n\n**Import libraries and define REES resources**\n\nMinimal example to create a rees object:\n\n```python\nfrom myst_libre.tools import JupyterHubLocalSpawner, MystMD\nfrom myst_libre.rees import REES\nfrom myst_libre.builders import MystBuilder\n\nrees = REES(dict(\n                  registry_url=\"https://your-registry.io\",\n                  gh_user_repo_name = \"owner/repository\"\n                  ))\n```\n\nOther optional parameters that can be passed to the REES constructor:\n\n\n- `gh_repo_commit_hash`: Full SHA commit hash of the `gh_user_repo_name` repository (optional, default: latest commit)\n- `binder_image_tag`: Full SHA commit hash at which a binder tag is available for the \"found image name\" (optional, default: latest)\n- `binder_image_name_override`: Override the \"found image name\" whose container will be used to build the MyST article (optional, default: None)\n- `dotenv`: Path to a directory containing the .env file for authentication credentials to pull images from `registry_url` (optional, default: None)\n- `bh_image_prefix`: Binderhub names the images with a prefix, e.g., `\u003cprefix\u003eagahkarakuzu-2dmriscope-7a73fb`, typically set as `binder-`. This will be used in the regex pattern to find the \"binderhub built image name\" in the `registry_url`. See [reference docs](https://binderhub.readthedocs.io/en/latest/zero-to-binderhub/setup-binderhub.html) for more details. \n- `bh_project_name`: See [this issue ](https://github.com/jupyterhub/binderhub/issues/800) (optional, default: [`registry_url` without `http://` or `https://`])\n\n\nNote that in this context what is meant by \"prefix\" is not the same as in the reference docs. (optional, default: `binder-`)\n\n**Image Selection Order**\n\n1. If the `myst.yml` file in the `gh_user_repo_name` repository contains `project/thebe/binder/repo`, this image is prioritized.\n2. If `project/thebe/binder/repo` is not specified, the `gh_user_repo_name` is used as the image name.\n\nNote that if (2) is the case, your build command probably should not be `myst build`, but you can still use other builders, e.g., `jupyter-book build`.\n\nIf you specify `binder_image_name_override`, it will be used as the repository name to locate the image.\n\nThis allows you to build the MyST article using a runtime from a different repository than the one specified in `gh_user_repo_name`, as defined in `myst.yml` or overridden by `binder_image_name_override`.\n\nThe `binder_image_tag` set to `latest` refers to the most recent successful build of an image that meets the specified conditions. The repository content might be more recent than the `binder_image_tag` (e.g., `gh_repo_commit_hash`), but the same binder image can be reused.\n\n**Fetch resources and spawn JupyterHub in the respective container**\n\n```python\nhub = JupyterHubLocalSpawner(rees_resources,\n                             host_build_source_parent_dir = '/tmp/myst_repos',\n                             container_build_source_mount_dir = '/home/jovyan', #default\n                             host_data_parent_dir = \"/tmp/myst_data\", #optional\n                             container_data_mount_dir = '/home/jovyan/data', #optional\n                             )\nhub.spawn_jupyter_hub()\n```\n\n* MyST repository will be cloned at:\n\n```\ntmp/\n└── myst_repos/\n    └── owner/\n        └── repository/\n            └── full_commit_SHA_A/\n                ├── myst.yml\n                ├── _toc.yml\n                ├── binder/\n                │   ├── requirements.txt (or other REES dependencies)\n                │   └── data_requirement.json (optional)\n                ├── content/\n                │   ├── my_notebook.ipynb\n                │   └── my_myst_markdown.md\n                ├── paper.md\n                └── paper.bib\n```\n\nRepository will be mounted to the container as `/tmp/myst_repos/owner/repository/full_commit_SHA_A:/home/jovyan`.\n\n* If a [`repo2data`](https://github.com/SIMEXP/Repo2Data) manifest is found in the repository, the data will be downloaded to and cached at:\n\n```\ntmp/\n└── myst_data/\n    └── my-dataset\n```\n\notherwise, it can be manually defined for an existing data under `/tmp/myst_data` as follows:\n\n```\nrees_resources.dataset_name = \"my-dataset\"\n```\n\nIn either case, data will be mounted as `/tmp/myst_data/my-dataset:/home/jovyan/data/my-dataset`. If no data is provided, this step will be skipped.\n\n**Build your MyST article**\n\n```python\nMystBuilder(hub).build()\n```\n\n**Check out the built document**\n\nIn your terminal:\n\n```\nnpx serve /tmp/myst_repos/owner/repository/full_commit_SHA_A/_build/html\n```\n\nVisit ✨`http://localhost:3000`✨.\n\n## Table of Contents\n\n- [Myst Libre](#myst-libre)\n  - [Table of Contents](#table-of-contents)\n  - [Installation](#installation)\n  - [Usage](#usage)\n    - [Authentication](#authentication)\n    - [Docker Registry Client](#docker-registry-client)\n    - [Build Source Manager](#build-source-manager)\n    - [JupyterHub Local Spawner](#jupyterhub-local-spawner)\n    - [MyST Markdown Client](#myst-markdown-client)\n  - [Module and Class Descriptions](#module-and-class-descriptions)\n  - [Contributing](#contributing)\n  - [License](#license)\n\n## Usage\n\n### Authentication\n\nThe `Authenticator` class handles loading authentication credentials from environment variables.\n\n```python\nfrom myst_libre.tools.authenticator import Authenticator\n\nauth = Authenticator()\nprint(auth._auth)\n```\n\n\n### Docker Registry Client\n\nThe DockerRegistryClient class provides methods to interact with a Docker registry.\n\n```python\nfrom myst_libre.tools.docker_registry_client import DockerRegistryClient\n\nclient = DockerRegistryClient(registry_url='https://my-registry.example.com', gh_user_repo_name='user/repo')\ntoken = client.get_token()\nprint(token)\n```\n\n### Build Source Manager\n\nThe BuildSourceManager class manages source code repositories.\n\n```python\nfrom myst_libre.tools.build_source_manager import BuildSourceManager\n\nmanager = BuildSourceManager(gh_user_repo_name='user/repo', gh_repo_commit_hash='commit_hash')\nmanager.git_clone_repo('/path/to/clone')\nproject_name = manager.get_project_name()\nprint(project_name)\n```\n\n## Module and Class Descriptions\n\n### AbstractClass\n**Description**: Provides basic logging functionality and colored printing capabilities.\n\n### Authenticator\n**Description**: Handles authentication by loading credentials from environment variables.  \n**Inherited from**: AbstractClass  \n**Inputs**: Environment variables `DOCKER_PRIVATE_REGISTRY_USERNAME` and `DOCKER_PRIVATE_REGISTRY_PASSWORD`\n\n### RestClient\n**Description**: Provides a client for making REST API calls.  \n**Inherited from**: Authenticator\n\n### DockerRegistryClient\n**Description**: Manages interactions with a Docker registry.  \n**Inherited from**: Authenticator  \n**Inputs**:\n- `registry_url`: URL of the Docker registry\n- `gh_user_repo_name`: GitHub user/repository name\n- `auth`: Authentication credentials\n\n### BuildSourceManager\n**Description**: Manages source code repositories.  \n**Inherited from**: AbstractClass  \n**Inputs**:\n- `gh_user_repo_name`: GitHub user/repository name\n- `gh_repo_commit_hash`: Commit hash of the repository\n\n### JupyterHubLocalSpawner\n**Description**: Manages JupyterHub instances locally.  \n**Inherited from**: AbstractClass  \n**Inputs**:\n- `rees`: Instance of the REES class\n- `registry_url`: URL of the Docker registry\n- `gh_user_repo_name`: GitHub user/repository name\n- `auth`: Authentication credentials\n- `binder_image_tag`: Docker image tag\n- `build_src_commit_hash`: Commit hash of the repository\n- `container_data_mount_dir`: Directory to mount data in the container\n- `container_build_source_mount_dir`: Directory to mount build source in the container\n- `host_data_parent_dir`: Host directory for data\n- `host_build_source_parent_dir`: Host directory for build source\n\n### MystMD\n**Description**: Manages MyST markdown operations such as building and converting files.  \n**Inherited from**: AbstractClass  \n**Inputs**:\n- `build_dir`: Directory where the build will take place\n- `env_vars`: Environment variables needed for the build process\n- `executable`: Name of the MyST executable (default is 'myst')\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneurolibre%2Fmyst-libre","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneurolibre%2Fmyst-libre","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneurolibre%2Fmyst-libre/lists"}