{"id":31572233,"url":"https://github.com/tiagomascosta/notion-github-sync","last_synced_at":"2026-04-28T23:38:40.211Z","repository":{"id":315340399,"uuid":"1059089499","full_name":"tiagomascosta/notion-github-sync","owner":"tiagomascosta","description":"Automatically sync Notion database pages to GitHub issues when status changes.","archived":false,"fork":false,"pushed_at":"2025-09-18T23:13:49.000Z","size":66,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-04-28T23:38:15.652Z","etag":null,"topics":["automation","fastapi","github","integration","notion","productivity","python","sync","workflow"],"latest_commit_sha":null,"homepage":"","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/tiagomascosta.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":"2025-09-18T01:37:11.000Z","updated_at":"2025-09-18T23:13:52.000Z","dependencies_parsed_at":"2025-09-18T04:12:47.650Z","dependency_job_id":"f9860c9b-e2b0-4c54-9f27-ae10b93a0dd5","html_url":"https://github.com/tiagomascosta/notion-github-sync","commit_stats":null,"previous_names":["tiagomascosta/notion-github-sync"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tiagomascosta/notion-github-sync","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tiagomascosta%2Fnotion-github-sync","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tiagomascosta%2Fnotion-github-sync/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tiagomascosta%2Fnotion-github-sync/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tiagomascosta%2Fnotion-github-sync/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tiagomascosta","download_url":"https://codeload.github.com/tiagomascosta/notion-github-sync/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tiagomascosta%2Fnotion-github-sync/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32404340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T19:38:08.556Z","status":"ssl_error","status_checked_at":"2026-04-28T19:37:55.688Z","response_time":56,"last_error":"SSL_read: 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":["automation","fastapi","github","integration","notion","productivity","python","sync","workflow"],"created_at":"2025-10-05T13:50:16.370Z","updated_at":"2026-04-28T23:38:40.190Z","avatar_url":"https://github.com/tiagomascosta.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Notion-GitHub Sync\n\n[![Python](https://img.shields.io/badge/Python-3.8+-blue.svg)](https://python.org)\n[![FastAPI](https://img.shields.io/badge/FastAPI-0.68+-green.svg)](https://fastapi.tiangolo.com)\n[![License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\n**Automatically sync Notion pages to GitHub issues with full content preservation, media support, and project integration.**\n\nTransform your Notion workflow into GitHub issues seamlessly. When you mark a Notion page as \"Validated\", it automatically creates a GitHub issue with the complete page content, including images, files, and formatting.\n\n## Features\n\n- **Automatic Sync**: Notion pages → GitHub issues\n- **Full Content**: Preserves headings, lists, code blocks, images, files, videos\n- **Smart Labels**: Automatic labeling based on Notion properties\n- **Project Integration**: Adds issues to GitHub Projects with proper status\n- **Error Handling**: Graceful handling of incomplete pages\n- **Real-time**: Continuous polling for new pages\n- **Customizable**: Easy to adapt for your workflow\n\n## Quick Start\n\n### 1. Clone the Repository\n\n```bash\ngit clone https://github.com/YOUR_USERNAME/notion-github-sync.git\ncd notion-github-sync\n```\n\n### 2. Install Dependencies\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate  # On Windows: .venv\\Scripts\\activate\npip install -r requirements.txt\n```\n\n### 3. Set Up Environment Variables\n\nCreate a `.env` file in the project root:\n\n```bash\n# Notion Configuration\nNOTION_TOKEN=your_notion_integration_token\nNOTION_DATABASE_ID=your_database_id\n\n# GitHub Configuration\nGITHUB_TOKEN=your_github_personal_access_token\nGITHUB_OWNER=your_github_username\nGITHUB_REPO=your_repository_name\n\n# GitHub Project (Optional)\nGITHUB_PROJECT_ID=your_project_id\nGITHUB_PROJECT_STATUS_FIELD_ID=your_status_field_id\nGITHUB_PROJECT_STATUS_BACKLOG_OPTION_ID=your_backlog_option_id\n\n# Settings\nPOLL_INTERVAL_SECONDS=120\nDRY_RUN=false\n```\n\n### 4. Run the Application\n\n**Option A: Manual Run**\n\n```bash\n# Load environment variables first\nset -a; source .env; set +a\n\n# Start the application\nuvicorn app:app --host 127.0.0.1 --port 8088\n```\n\n**Option B: Using the Run Script (Recommended)**\n\n```bash\n# Make the script executable (only needed once)\nchmod +x run.sh\n\n# Run the application in background:\nnohup ./run.sh \u003e sync.out 2\u003e\u00261 \u0026 echo $! \u003e sync.pid\n```\n\nThe `run.sh` script automatically:\n\n- Loads environment variables from `.env`\n- Activates the virtual environment\n- Starts the application on `http://127.0.0.1:8088`\n\n## Setup Guide\n\n### Notion Setup\n\n#### 1. Create a Notion Integration\n\n1. Go to [Notion Integrations](https://www.notion.so/my-integrations)\n2. Click **\"New integration\"**\n3. Fill in the details:\n   - **Name**: `GitHub-Sync` (or your preferred name)\n   - **Logo**: Optional\n   - **Associated workspace**: Select your workspace\n4. Click **\"Submit\"**\n5. Copy the **Internal Integration Token** (starts with `ntn_`)\n\n#### 2. Create Your Database\n\nCreate a Notion database with these properties:\n\n| Property Name                 | Type         | Required | Description                             |\n| ----------------------------- | ------------ | -------- | --------------------------------------- |\n| **Name**                | Title        | Required | Page title (becomes GitHub issue title) |\n| **Status**              | Select       | Required | Must include \"Validated\" option         |\n| **In Sync With Github** | Checkbox     | Required | Tracks sync status                      |\n| **Priority**            | Select       | Optional | \"Low\", \"Medium\", \"High\"                 |\n| **Size**                | Select       | Optional | \"XS\", \"S\", \"M\", \"L\", \"XL\"               |\n| **Company**             | Rich Text    | Optional | Company information                     |\n| **Customer Type**       | Multi-select | Optional | \"Type A\", \"Type B\", etc.                |\n\n#### 3. Share Database with Integration\n\n1. Open your database in Notion\n2. Click **\"Share\"** (top-right)\n3. Click **\"Add people, emails, groups, or integrations\"**\n4. Search for your integration name (`GitHub-Sync`)\n5. Select it and give **\"Can edit\"** permissions\n6. Click **\"Invite\"**\n\n#### 4. Get Database ID\n\n1. Open your database in a web browser\n2. Copy the URL: `https://www.notion.so/your-workspace/DATABASE_NAME?v=DATABASE_ID`\n3. Extract the `DATABASE_ID` (32-character string with hyphens)\n\n### GitHub Setup\n\n#### 1. Create Personal Access Token\n\n1. Go to [GitHub Settings \u0026gt; Developer settings \u0026gt; Personal access tokens](https://github.com/settings/tokens)\n2. Click **\"Generate new token (classic)\"**\n3. Set expiration and select scopes:\n   - ✅ **repo** (Full control of private repositories)\n   - ✅ **project** (Full control of user projects)\n   - ✅ **read:org** (Read org and team membership)\n4. Click **\"Generate token\"**\n5. Copy the token (starts with `ghp_`)\n\n#### 2. Get Repository Information\n\n```bash\n# Get your username\ngh api user --jq '.login'\n\n# Get repository name (if you don't know it)\ngh repo list --limit 10\n```\n\n#### 3. GitHub Project Setup (Optional)\n\nIf you want to use GitHub Projects:\n\n1. Go to your repository\n2. Click **\"Projects\"** tab\n3. Create a new project or use existing one\n4. Get the project ID using GraphQL:\n\n```bash\n# Install GitHub CLI if you haven't\ngh auth login\n\n# Get project ID\ngh api graphql -f query='\n{\n  repository(owner: \"YOUR_USERNAME\", name: \"YOUR_REPO\") {\n    projectsV2(first: 10) {\n      nodes {\n        id\n        title\n      }\n    }\n  }\n}'\n```\n\n5. Get field IDs:\n\n```bash\ngh api graphql -f query='\n{\n  node(id: \"YOUR_PROJECT_ID\") {\n    ... on ProjectV2 {\n      fields(first: 20) {\n        nodes {\n          ... on ProjectV2FieldCommon {\n            id\n            name\n          }\n          ... on ProjectV2SingleSelectField {\n            id\n            name\n            options {\n              id\n              name\n            }\n          }\n        }\n      }\n    }\n  }\n}'\n```\n\n## How It Works\n\n### Workflow\n\n1. **Create** a page in your Notion database\n2. **Set Status** to \"Validated\"\n3. **Add content** (text, images, files, etc.)\n4. **Wait** for the next polling cycle (default: 2 minutes)\n5. **GitHub issue** is automatically created with full content\n6. **Status** changes to \"Backlog\" in Notion\n7. **Issue** is added to GitHub Project (if configured)\n\n### Content Conversion\n\n| Notion Element | GitHub Markdown        |\n| -------------- | ---------------------- |\n| Headings       | `#`, `##`, `###` |\n| Bulleted Lists | `- item`             |\n| Numbered Lists | `1. item`            |\n| Checkboxes     | `- [ ]` / `- [x]`  |\n| Code Blocks    | ```language blocks     |\n| Images         | `![caption](url)`    |\n| Files          | `[filename](url)`    |\n| Videos         | `[video](url)`       |\n| Quotes         | `\u003e quote`            |\n| Callouts       | `\u003e **text**`         |\n\n## Customization\n\n### Custom Status Values\n\nEdit the status filter in `app.py`:\n\n```python\n# Line ~505: Change \"Validated\" to your preferred status\n{\"property\": \"Status\", \"select\": {\"equals\": \"Your Status\"}}\n```\n\n### Custom Priority/Size Mapping\n\nModify the mapping dictionaries:\n\n```python\n# Lines ~483-487: Customize the mappings\nPRIORITY_MAP_NOTION_TO_GH = {\n    \"Critical\": \"P0\",\n    \"High\": \"P1\", \n    \"Medium\": \"P2\",\n    \"Low\": \"P3\",\n}\n\nSIZE_MAP_NOTION_TO_GH = {\n    \"Tiny\": \"XS\",\n    \"Small\": \"S\", \n    \"Medium\": \"M\",\n    \"Large\": \"L\",\n    \"Huge\": \"XL\"\n}\n```\n\n### Custom Labels\n\nModify the `_labels_for_issue` function:\n\n```python\ndef _labels_for_issue(customer_types: List[str], priority: Optional[str], size: Optional[str]) -\u003e List[str]:\n    labels = []\n    labels.extend(customer_types or [])  # e.g., \"Type A\", \"Type B\"\n    if priority: labels.append(f\"priority-{priority.lower()}\")\n    if size: labels.append(f\"size-{size.lower()}\")\n    # Add custom labels\n    labels.append(\"notion-sync\")\n    return labels\n```\n\n### Custom Issue Body\n\nModify the issue body creation in `process_validated_page`:\n\n```python\nbody_parts = [\n    f\"Imported from Notion page `{page_id}`.\",\n    \"\",\n    \"---\",\n    \"\",\n    page_content,\n    \"\",\n    \"---\",\n    \"\",\n    \"## Additional Information\",\n    \"Add your custom sections here\",\n    \"\",\n    \"\u003e Created automatically when Notion Status moved to **Validated**.\"\n]\n```\n\n## Configuration Options\n\n| Environment Variable      | Default | Description                   |\n| ------------------------- | ------- | ----------------------------- |\n| `NOTION_TOKEN`          | -       | Notion integration token      |\n| `NOTION_DATABASE_ID`    | -       | Notion database ID            |\n| `GITHUB_TOKEN`          | -       | GitHub personal access token  |\n| `GITHUB_OWNER`          | -       | GitHub username/organization  |\n| `GITHUB_REPO`           | -       | GitHub repository name        |\n| `GITHUB_PROJECT_ID`     | -       | GitHub Project ID (optional)  |\n| `POLL_INTERVAL_SECONDS` | 120     | Polling interval in seconds   |\n| `DRY_RUN`               | false   | Test mode (no actual changes) |\n\n## Troubleshooting\n\n### Common Issues\n\n#### \"Could not find database with ID\"\n\n- Verify database is shared with your integration\n- Check database ID is correct (32 characters with hyphens)\n- Ensure integration has \"Can edit\" permissions\n\n#### \"Missing required fields\"\n\n- Ensure page has a title\n- Set Status to \"Validated\"\n- Check property names match exactly\n\n#### \"Failed to create issue\"\n\n- Verify GitHub token has `repo` scope\n- Check repository name and owner are correct\n- Ensure token hasn't expired\n\n#### \"Property type mismatch\"\n\n- Ensure Status property is \"Select\" type (not Multi-select)\n- Check property names match your database schema\n\n### Debug Mode\n\nEnable debug logging by setting `DRY_RUN=true` in your `.env` file to test without making changes.\n\n## Monitoring\n\nThe application provides a health endpoint:\n\n```bash\ncurl http://127.0.0.1:8088/health\n```\n\nResponse:\n\n```json\n{\n  \"status\": \"ok\",\n  \"poll_interval\": 120,\n  \"dry_run\": false\n}\n```\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Acknowledgments\n\n- [Notion API](https://developers.notion.com/) for the integration capabilities\n- [GitHub API](https://docs.github.com/en/rest) for issue and project management\n- [FastAPI](https://fastapi.tiangolo.com/) for the web framework\n- [SQLAlchemy](https://www.sqlalchemy.org/) for database management\n\n## Support\n\n- **Email**: tiagomendesalves.tc.tc@gmail.com\n\n---\n\n**Star this repository if you find it helpful!**\n\n*Made for the Notion and GitHub communities*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftiagomascosta%2Fnotion-github-sync","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftiagomascosta%2Fnotion-github-sync","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftiagomascosta%2Fnotion-github-sync/lists"}