Skip to main content

project-hub

Multi-repo workspace manager that unifies local git state and forge data (MRs, issues, pipelines, vulnerabilities) into a single MCP server + web dashboard.

Designed for engineers managing many repos under one parent directory — across multiple forges.

Dashboard

Killer features

aka why I built this

GitLab, GitHub, Bitbucket, Forgejo in a single interface. No more context-switching between forges. project-hub reads each repo's remote, recognizes the public forges and any host with the forge in its name, and asks you about the rest once. Then it talks to all of them — MRs, issues, pipelines, everything in one dashboard. A repo on Bitbucket, another on GitLab, a third on your team's Forgejo: same view, same tools, same agent.

Vulnerabilities that make sense. GitLab's vulnerability report is per-repo, noisy, and doesn't tell you what's already being fixed. project-hub aggregates vulns across all your repos, cross-references them with open MR branches to flag what's already fixed but not yet merged ("fixed in branch"), and lets you filter by severity, state, or hide already-handled ones. You see what actually needs work, not what's already in flight.

Stale branch detection. After merging an MR you often forget to switch back to the default branch locally. project-hub detects repos still sitting on stale feature branches and shows ahead/behind relative to the default branch — with a one-click checkout to clean up.

Events, not inbox. Stop reminding yourself to check your cluttered GitLab inbox. project-hub diffs state on every refresh cycle and surfaces what changed: review requested from you, MR approved or merged, new comment or push, issue opened/closed/assigned, pipeline failed or fixed, new or resolved vuln, stale branch, auth expiry. Events live in a slide-in panel on the dashboard and persist across sessions until dismissed.

MCP-powered multi-repo agent. Everything visible in the dashboard is exposed as MCP tools. Claude Code sees your repos, MRs, issues, pipelines, job logs, vulns, and events, and can fetch and safely pull your local repos. Forge access is read-only: the agent never approves, merges, or comments. Events surface as MCP notifications, making the agent proactive instead of reactive.

Features

  • Unified dashboard — git status, MRs, issues, pipelines, vulns across all repos in one view
  • Merge request, issue & pipeline views — cross-repo tables with filters (mine/all, MRs waiting for your review, failed only, current branches only)
  • Per-repo detail page — MRs, issues, pipelines, active vulns for a single repo
  • Web UI (htmx) with real-time sync, sortable tables, persistent filters
  • Non-destructive pull — conflict detection via git merge-tree, no worktree mutations
  • Pin & reorder repos, drag-and-drop card layout
  • Bulk actions — pull all, unstale all in one click

Quick start

1. Register the MCP server once, for all directories:

claude mcp add --scope user project-hub -- uvx project-hub --mcp

From source instead (picks up local changes without cache issues):

claude mcp add --scope user project-hub -- \
  uv run --project /path/to/project-hub project-hub --mcp

2. Store a token for each forge you use. Tokens are global (OS keyring, keyed by host), not per workspace:

uvx project-hub auth login gitlab.com
uvx project-hub auth login github.com
uvx project-hub auth login bitbucket.org
uvx project-hub auth login git.example.org --type forgejo   # self-hosted: which API validates the token

--type only picks how the token is checked. The workspace learns each host's forge type at init (step 3).

3. Open Claude Code in the parent directory of your repos and ask:

Initialize a project-hub workspace here, then annotate each repo with its role and domain.

The agent calls init, which discovers the repos, writes .project-hub/config.yaml, and starts the refresh loop and the dashboard. Annotating is not optional: most tools skip or refuse a repo without a role and domain, because those annotations are what give the agent its context. List the repos that need no context under annotation_not_required in config.yaml.

init assumes GitLab for a self-hosted host it can't recognize and tells the agent so. Say which forge it really is ("git.example.org is a Forgejo") and the agent fixes it with configure_forge.

4. The dashboard opens in your browser at http://localhost:8400, or the next free port when 8400 is taken. Closed the tab? Ask the agent for the dashboard URL.

Without an agent, the CLI does the same and opens the browser:

cd ~/Projects                    # parent dir containing your repos
uvx project-hub init             # creates .project-hub/, prompts for unrecognized hosts
uvx project-hub                  # launch dashboard

How the MCP server behaves per directory

Installing with --scope user is safe — the server adapts to the current directory:

Directory state Behavior
Has .project-hub/ Active — full tools + refresh
Parent has .project-hub/ Disabled — zero tools (sub-repo)
Has .no-project-hub Disabled — zero tools (opt-out)
Neither Dormant — only init tool
touch ~/some-project/.no-project-hub   # force disable in a specific dir

MCP tools

Tool Description
init Bootstrap .project-hub/ workspace
list_repos List discovered repos with forge info and annotation status
repo_status Git status (branch, ahead/behind, dirty)
fetch_all Trigger full refresh cycle
pull_safe Pull with conflict detection
list_mrs Merge requests (repo, state, author, awaiting-review filters)
list_issues Issues (repo, state, author, label filters)
list_pipelines Pipelines (repo, status, ref filters)
get_vulnerabilities Vulns — defaults to high/critical + detected, includes solutions
get_pipeline_jobs Jobs for a specific pipeline
get_job_log Fetch log output for a specific CI job
annotate_repo Set per-repo annotations (role, domain, links, notes)
acknowledge_alerts Mark events as seen
rescan Re-scan workspace for new/removed repos
auth_status Check forge authentication
auth_login Store PAT for a forge instance
configure_forge Configure forge host mapping

Web dashboard

Route Description
/ Dashboard with repo cards, pinning, drag-and-drop, events panel
/mrs Merge requests table (mine/all filter)
/issues Issues table (mine/all filter)
/pipelines Pipelines table (failed only, current branches only)
/vulns Vulnerabilities (severity, state, fixed-in-branch filters)
/repo/{name} Per-repo detail: MRs, issues, pipelines, active vulns
/settings Exclude/include repos, rescan workspace

All filters and table sort are persisted in localStorage.

Architecture

Single Python process, dual interfaces: MCP (stdio) + HTTP (FastAPI/htmx). Background asyncio task refreshes git+forge data on a TTL cycle, diffs with SQLite cache to generate events.

project_hub/
  cli.py              # Click entry points
  core/
    workspace.py       # Orchestrator: discover -> refresh loop -> stop
    cache.py           # SQLite (WAL mode, aiosqlite)
    config.py          # YAML config with defaults
    discovery.py       # Scan for .git/ repos, classify forges
    models.py          # Dataclasses: Repo, MR, Issue, Pipeline, Vulnerability, Event
    events.py          # Diff old vs new state -> Event list
  forge/
    provider.py        # ForgeProvider ABC (shared interface for all forges)
    auth.py            # Token resolution: keyring -> auth.json -> env vars -> ~/.python-gitlab.cfg
    gitlab.py          # python-gitlab + GraphQL
    github.py          # PyGithub
    bitbucket.py       # atlassian-python-api (Cloud)
    forgejo.py         # REST v1 over requests (Forgejo >= 16 for CI)
  git/
    ops.py             # fetch, status, pull_safe (merge-tree conflict detection)
  mcp/
    server.py          # FastMCP tools + resources
  web/
    app.py             # FastAPI factory, routes, htmx fragments
    templates/         # Jinja2 templates
    static/            # CSS + vendored JS

Requirements

  • Python 3.11+
  • Git 2.38+ (for git merge-tree --write-tree)
  • A token for each forge you use:
    • GitLab: PAT with read_api scope
    • GitHub: PAT with repo scope
    • Bitbucket Cloud: API token (app passwords deprecated June 2026)
    • Forgejo: token with read:repository, read:issue, read:user

Tokens

auth login stores tokens in the OS keyring, or in ~/.config/project-hub/auth.json when no keyring is available. Without a stored token, project-hub falls back to environment variables: GITLAB_TOKEN (gitlab.com only, then ~/.python-gitlab.cfg for any GitLab host), GITHUB_TOKEN, BITBUCKET_TOKEN, FORGEJO_TOKEN.

Forge notes

  • Self-hosted forges are recognized only when the forge's name is in the hostname (gitlab.example.com, forgejo.example.org) or for codeberg.org. Declare the others in .project-hub/config.yaml:

    forges:
      git.example.org:
        type: forgejo
    
  • Vulnerabilities come from GitLab and GitHub only. Bitbucket and Forgejo have PRs, issues and pipelines.

  • Forgejo CI needs Forgejo 16 or later, the first release with an API for Actions jobs and logs. Older instances keep PRs and issues, and the pipelines tab shows "CI disabled".

Behind a TLS-intercepting proxy

A corporate proxy (Zscaler and the like) re-signs TLS with its own root, which Python's bundled CA list doesn't know: forge calls then fail with CERTIFICATE_VERIFY_FAILED. When IT has installed that root in the system store, point Python at it:

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt

Put it in /etc/environment (read at login) so that the MCP server, started by Claude Code, inherits it too.

Development

uv run pytest tests/ -v
uv run --with 'pyflakes>=4,<5' pyflakes project_hub/
uv run --with 'pylint>=4,<5' pylint project_hub/
uv run --with 'radon>=6,<7' radon cc project_hub/ -s -n D   # must print nothing

CI runs the same commands as its lint and test gates.

License

Unlicense — public domain.

Metadata

Release files for project-hub 0.18.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for project-hub 0.18.1
File Size Uploaded Provenance Actions
project_hub-0.18.1.tar.gz 458.4 kB Without provenance Details for project_hub-0.18.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for project-hub 0.18.1
File Interpreter ABI Platform Actions
project_hub-0.18.1-py3-none-any.whl Python 3 none any Details for project_hub-0.18.1-py3-none-any.whl

Total release size: 637.8 kB

Release files / project_hub-0.18.1.tar.gz

Download URL project_hub-0.18.1.tar.gz
Size 458.4 kB
Tags Source
SHA-256 checksum
How to use checksums
778a51ca364f409f2dd2bbc0b32ce5fdb4e499d4f3cefd4acdc32867e89393ee
BLAKE2b-256 checksum
How to use checksums
d7c9717c7874a3656694990d82773afc6ccdfead523c431ea137ed6e1a24577c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / project_hub-0.18.1-py3-none-any.whl

Download URL project_hub-0.18.1-py3-none-any.whl
Size 179.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4568c635230acdd58f814525cfbc623fbb70a74dcda2582a3120b6d018ac5c01
BLAKE2b-256 checksum
How to use checksums
253685e381c93609db7b671e2b746c1cc5f6e6c74bebb0ba3d7d36192bcae2cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for project-hub 0.18.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.18.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page