* So `git-url-parse` can give us `owner()` and `repo()` through the provider. That's cleaner than manual string parsing. Let me present the options to you: **Option 1: `git-url-parse` crate** - Pros: Specifically designed for git URLs, gives owner/repo directly via provider - Cons: New dependency (though small) **Option 2: `gix-url` crate** - Pros: Part of gitoxide (well-maintained), robust parsing - Cons: New dependency, still need to extract owner/repo from path **Option 3: Keep current approach but improve it** - Use the `url` crate we already have for HTTPS URLs - Handle SSH URLs as a special case (they use `:` instead of `/`) - Less string magic, more structured **Option 4: Use `gh` CLI to parse** - `gh repo view <url> --json owner,name` - Pros: No new deps, `gh` handles all edge cases - Cons: Requires network/auth, slower Which approach would you prefer? I'd recommend **Option 1 (`git-url-parse`)** since it's purpose-built for this exact use case. * Cleanup script changes for workspace a07fdbcf-0608-4a84-a012-53d4fee6d115 * Let me provide a summary of all the changes made: ## Summary Fixed the hardcoded remote handling to support fork workflows. Here's what changed: ### 1. `crates/services/src/services/git.rs` - **`default_remote_name()`**: Now prefers "origin" (git's convention) instead of arbitrarily picking the first remote - **`get_remote_url()`**: New helper to get the URL of a specific remote by name - **`get_remote_url_from_branch_or_default()`**: New helper that gets the remote URL for a branch, falling back to default remote ### 2. `crates/services/src/services/git/cli.rs` - **`default_remote_name()`**: Same fix as above - prefers "origin" - **`get_remote_url()`**: New method to get remote URL by name ### 3. `crates/services/src/services/git_host/github/cli.rs` - **`get_repo_info_from_url()`**: New method that uses `gh repo view <url> --json owner,name` to parse owner/repo from a remote URL (no string magic!) ### 4. `crates/services/src/services/git_host/github/mod.rs` - **`get_repo_info_from_url()`**: Async wrapper for the new CLI method - **`create_pr()`**: Now uses `get_repo_info_from_url()` with the `remote_url` parameter to determine which repo to create the PR against ### 5. `crates/server/src/routes/task_attempts/pr.rs` - **Key fix**: Now extracts the target remote URL from the `target_branch` (e.g., `upstream/main`) instead of from `workspace.branch` (your task branch) - This enables fork workflows: push to your fork (`origin`), but create PR against upstream (the target branch's remote) ### How fork workflows now work: 1. User selects target branch like `upstream/main` 2. Code pushes task branch to `origin` (your fork) 3. Code extracts remote URL from `upstream` remote (the upstream repo) 4. PR is created against the upstream repo using `gh pr create --repo upstream-owner/repo` * Cleanup script changes for workspace a07fdbcf-0608-4a84-a012-53d4fee6d115 * Build passes. The response structs are now at module level alongside the other `Gh*` response types, which is cleaner and more consistent with the existing code style. * Build passes. Now `gh repo view <url>` is run from the repo directory, which helps with GitHub Enterprise authentication context. * Done. Removed all the redundant comments. * Build passes. * Build passes. Now the default remote logic follows git's behavior: 1. Check `remote.pushDefault` config first (user's explicit preference) 2. Fall back to "origin" if it exists (git's convention from `git clone`) 3. Fall back to first remote if no "origin" 4. Default to "origin" if no remotes exist * I've fixed the bug in `check_remote_branch_exists` at `git.rs:1454-1484`. The issue was that when checking if a remote branch exists, the function was: 1. Using `default_remote_name()` (which returns "origin") to strip the prefix from branch names like `upstream/main` 2. Looking up the URL from the default remote instead of the actual remote the branch belongs to Now the function: 1. For remote branches (like `upstream/main`), extracts the actual remote name from the branch using `get_remote_name_from_branch_name()` 2. Strips the correct prefix (`upstream/` not `origin/`) 3. Uses the correct remote's URL for the `git ls-remote` check This allows fork workflows where you select `upstream/main` as the target branch - it will now correctly check if `main` exists on the `upstream` remote's URL. * Cleanup script changes for workspace a07fdbcf-0608-4a84-a012-53d4fee6d115 * Fix cross-fork PR creation by formatting head branch with fork owner When creating a PR from a fork to upstream, GitHub requires the head branch to be formatted as "owner:branch" (e.g., "LSRCT:vk/feature-branch"). Added head_repo_url to CreatePrRequest and updated GitHubProvider to compare owners and prefix the head branch accordingly. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Refactor PR remote handling: simplify by moving logic to caller - Delete check_remote_branch_exists() from GitService (caller now composes the check directly using GitCli) - Add default_remote_name_for_path() convenience method - Rewrite pr.rs remote handling to be explicit and linear: 1. Get push_remote and target_remote names 2. Get their URLs 3. Strip prefix to get base_branch 4. Check, push, create PR The string split happens once, visibly at the call site. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Remove origin preference in default_remote_name Use first available remote instead of preferring "origin". The fallback to "origin" only applies when there are no remotes configured at all. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Fix PR creation when target branch not fetched locally When the target branch doesn't exist as a local remote-tracking ref (e.g., user types a branch name that exists on remote but isn't fetched), fall back to using the push remote instead of failing with BranchNotFound. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Reject cross-fork PRs for Azure DevOps Azure DevOps fork PRs require different handling (--fork-id parameter). Return a clear error instead of silently failing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Remove get_repo_info, always use explicit URL The parameterless get_repo_info relied on gh CLI guessing the repo from local git config. This is wrong for fork workflows where we need to operate on a specific remote's repo. Now list_prs_for_branch and get_pr_comments use the remote_url they're passed instead of ignoring it. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Format git service default remote helper * Fix clippy collapsible-if warnings * Route remote branch checks through git service * Remove Azure PR comment * Consolidate git remote helpers * Consolidate git remote resolution helpers * Remove unnecessary comments * Fix git service error match for remote check * Remove unused GitCli::default_remote_name GitService::default_remote_name (using git2) is used instead. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Refactor unused vars --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Get 10X more out of Claude Code, Gemini CLI, Codex, Amp and other coding agents...
We're hiring!
Overview
AI coding agents are increasingly writing the world's code and human engineers now spend the majority of their time planning, reviewing, and orchestrating tasks. Vibe Kanban streamlines this process, enabling you to:
- Easily switch between different coding agents
- Orchestrate the execution of multiple coding agents in parallel or in sequence
- Quickly review work and start dev servers
- Track the status of tasks that your coding agents are working on
- Centralise configuration of coding agent MCP configs
- Open projects remotely via SSH when running Vibe Kanban on a remote server
You can watch a video overview here.
Installation
Make sure you have authenticated with your favourite coding agent. A full list of supported coding agents can be found in the docs. Then in your terminal run:
npx vibe-kanban
Documentation
Please head to the website for the latest documentation and user guides.
Support
We use GitHub Discussions for feature requests. Please open a discussion to create a feature request. For bugs please open an issue on this repo.
Contributing
We would prefer that ideas and changes are first raised with the core team via GitHub Discussions or Discord, where we can discuss implementation details and alignment with the existing roadmap. Please do not open PRs without first discussing your proposal with the team.
Development
Prerequisites
Additional development tools:
cargo install cargo-watch
cargo install sqlx-cli
Install dependencies:
pnpm i
Running the dev server
pnpm run dev
This will start the backend. A blank DB will be copied from the dev_assets_seed folder.
Building the frontend
To build just the frontend:
cd frontend
pnpm build
Build from source (macOS)
- Run
./local-build.sh - Test with
cd npx-cli && node bin/cli.js
Environment Variables
The following environment variables can be configured at build time or runtime:
| Variable | Type | Default | Description |
|---|---|---|---|
POSTHOG_API_KEY |
Build-time | Empty | PostHog analytics API key (disables analytics if empty) |
POSTHOG_API_ENDPOINT |
Build-time | Empty | PostHog analytics endpoint (disables analytics if empty) |
PORT |
Runtime | Auto-assign | Production: Server port. Dev: Frontend port (backend uses PORT+1) |
BACKEND_PORT |
Runtime | 0 (auto-assign) |
Backend server port (dev mode only, overrides PORT+1) |
FRONTEND_PORT |
Runtime | 3000 |
Frontend dev server port (dev mode only, overrides PORT) |
HOST |
Runtime | 127.0.0.1 |
Backend server host |
DISABLE_WORKTREE_ORPHAN_CLEANUP |
Runtime | Not set | Disable git worktree cleanup (for debugging) |
Build-time variables must be set when running pnpm run build. Runtime variables are read when the application starts.
Remote Deployment
When running Vibe Kanban on a remote server (e.g., via systemctl, Docker, or cloud hosting), you can configure your editor to open projects via SSH:
- Access via tunnel: Use Cloudflare Tunnel, ngrok, or similar to expose the web UI
- Configure remote SSH in Settings → Editor Integration:
- Set Remote SSH Host to your server hostname or IP
- Set Remote SSH User to your SSH username (optional)
- Prerequisites:
- SSH access from your local machine to the remote server
- SSH keys configured (passwordless authentication)
- VSCode Remote-SSH extension
When configured, the "Open in VSCode" buttons will generate URLs like vscode://vscode-remote/ssh-remote+user@host/path that open your local editor and connect to the remote server.
See the documentation for detailed setup instructions.
