Package Exports
- ghost-github-portfolio
- ghost-github-portfolio/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (ghost-github-portfolio) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Auto-sync your GitHub repositories to a Ghost CMS portfolio page.
What it does
ghost-github-portfolio fetches your public GitHub repositories, sorts them by stars, generates beautiful portfolio cards with banners and badges, and pushes the result to a Ghost page via the Admin API.
Run it daily via cron, GitHub Actions, or Docker to keep your portfolio always up to date.
Features:
- Fetches repos sorted by stars, filtered by configurable minimum
- Auto-detects banner images (
docs/images/banner.svg,media/banner.svg, etc.) - Dynamic shields.io badges (stars, forks, license, Docker pulls, website, awesome-list)
- Per-repo overrides (custom description, badges, Docker image, tech stack)
- Ghost lexical editor format (the current Ghost editor)
- Dry-run mode for previewing changes
- Runs as CLI, Docker container, or GitHub Action
Quick start
1. Install
# npm (global)
npm install -g ghost-github-portfolio
# npx (no install)
npx ghost-github-portfolio
# Docker
docker pull drumsergio/ghost-github-portfolio:0.3.02. Create a config
ghost-github-portfolio initThis generates a config.yml with all available options. Edit it with your GitHub username and Ghost API credentials.
3. Get your Ghost Admin API key
- Go to your Ghost Admin panel > Settings > Integrations
- Create a new Custom Integration
- Copy the Admin API Key (format:
KEY_ID:SECRET)
4. Run
# Preview (no changes to Ghost)
ghost-github-portfolio sync --config config.yml --dry-run --verbose
# Sync to Ghost
ghost-github-portfolio sync --config config.yml --verboseConfiguration
github:
username: YOUR_GITHUB_USERNAME
# token: ghp_xxx # Optional: higher rate limits (env: GHOST_GITHUB_TOKEN)
ghost:
url: https://your-ghost-blog.com
adminApiKey: "KEY_ID:SECRET_HEX"
pageSlug: portfolio # or pageId: "hex_id"
portfolio:
minStars: 2
maxRepos: 50
includeForked: false
badgeStyle: for-the-badge # flat, flat-square, for-the-badge, plastic, social
showBanner: true
centerContent: true
defaultBannerPath: docs/images/banner.svg
bannerPaths:
awesome-spain: media/banner.svg # Override per repo
excludeRepos:
- .github
repos:
my-project:
description: "Custom description"
dockerImage: myuser/my-project # Adds Docker pulls badge
techStack: "Python, Docker, Redis"
badges:
- type: website
url: https://my-project.com
- type: awesome-list
- type: platform
label: macOS
logo: apple
- type: docs
url: https://docs.my-project.com
- type: custom
label: MCP
value: Official Registry
color: E6522C
footer:
showStats: true
showViewAll: trueEnvironment variables
| Variable | Description |
|---|---|
GHOST_GITHUB_TOKEN |
GitHub token for private repos / higher rate limits |
GHOST_ADMIN_API_KEY |
Ghost Admin API key (overrides config file) |
Docker
docker run --rm \
-v /path/to/config.yml:/config/config.yml \
drumsergio/ghost-github-portfolio:0.3.0Docker Compose (daily cron)
services:
ghost-portfolio:
image: drumsergio/ghost-github-portfolio:0.3.0
volumes:
- ./config.yml:/config/config.yml:ro
# Run daily at 6 AM via external cron or restart policyGitHub Action
Create .github/workflows/portfolio.yml in any repo:
name: Update Portfolio
on:
schedule:
- cron: "0 6 * * *" # Daily at 6 AM UTC
workflow_dispatch: # Manual trigger
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npx ghost-github-portfolio sync --config config.yml --verbose
env:
GHOST_GITHUB_TOKEN: ${{ secrets.GHOST_GITHUB_TOKEN }}Store config.yml in the repo (without secrets) and use environment variables for the API keys.
How it works
- Fetches all public repos for the configured GitHub user via the REST API
- Filters by minimum stars, excludes forks and blocklisted repos
- Sorts by star count (descending)
- Detects banner images by checking common paths (
docs/images/banner.svg,media/banner.svg, etc.) - Generates HTML cards with: banner, name, dynamic badges, description, tech stack
- Composes a Ghost lexical JSON document (the format Ghost's editor uses internally)
- Updates the target Ghost page via the Admin API with JWT authentication
Badges are dynamic (served by shields.io) — stars, forks, and Docker pulls update automatically on every page view without re-running the tool.
Badge types
| Type | Auto-detected | Description |
|---|---|---|
| Stars | Yes | Always shown |
| Forks | Yes | Always shown |
| License | Yes | From GitHub repo metadata |
| Docker pulls | Config | Set dockerImage in repo overrides |
| Website | Yes | From GitHub homepage field |
| Awesome list | Yes | If repo has awesome-list topic |
| Docs | Yes | If homepage is a GitHub Pages URL |
| Platform | Config | Custom platform badge (macOS, Linux, etc.) |
| Custom | Config | Any shields.io-compatible badge |
Roadmap
See docs/ROADMAP.md for the full roadmap — themes, multi-CMS support, AI features, analytics, team portfolios, and more.