krz/gitbay

A CLI-first git forge.

clone: git clone https://gitbay.org/krz/gitbay.git

24c0aad9bf75f925497b0f6de2c8e831e67eaac9

verified · cmc

author: Christian Cleberg <hello@cleberg.net> · 2026-08-24T00:14:19Z

rename: forge -> gitbay (gitbay.org)

- module path gitbay.org/gitbay; binaries gitbay and gitbayd
- config: /etc/gitbay/config.toml, /var/lib/gitbay, ~/.config/gitbay,
  gitbay.db, gitbay_session cookie, GITBAY_* hook/import env vars
- user-facing strings, usage text, ssh banner, test hostnames renamed;
  generic 'a code forge' prose kept where it means the category
- all tests updated and green
 .gitignore                           |  4 ++--
 cmd/{forge => gitbay}/local.go       | 36 ++++++++++++++++++------------------
 cmd/{forge => gitbay}/main.go        | 24 ++++++++++++------------
 cmd/{forge => gitbay}/ssh.go         |  8 ++++----
 cmd/{forged => gitbayd}/hook.go      | 10 +++++-----
 cmd/{forged => gitbayd}/main.go      | 30 +++++++++++++++---------------
 cmd/{forged => gitbayd}/system.go    | 10 +++++-----
 e2e/cli_test.go                      | 14 +++++++-------
 e2e/http_test.go                     |  2 +-
 e2e/mr_test.go                       |  2 +-
 e2e/sig_test.go                      |  4 ++--
 e2e/ssh_test.go                      | 26 +++++++++++++-------------
 e2e/system_test.go                   |  8 ++++----
 e2e/web_test.go                      |  2 +-
 go.mod                               |  2 +-
 internal/cliconfig/cliconfig.go      |  6 +++---
 internal/cliconfig/cliconfig_test.go | 20 ++++++++++----------
 internal/config/config.go            |  6 +++---
 internal/config/config_test.go       | 12 ++++++------
 internal/control/control.go          |  6 +++---
 internal/control/control_test.go     |  2 +-
 internal/control/identity.go         |  4 ++--
 internal/control/import.go           | 10 +++++-----
 internal/control/issue.go            |  6 +++---
 internal/control/mr.go               |  8 ++++----
 internal/control/repo.go             |  8 ++++----
 internal/control/sig.go              | 10 +++++-----
 internal/control/web.go              |  4 ++--
 internal/gitd/gitd.go                |  6 +++---
 internal/gitutil/gitutil.go          |  2 +-
 internal/gitutil/merge.go            |  2 +-
 internal/hookd/hookd.go              | 28 ++++++++++++++--------------
 internal/httpd/accounts.go           | 10 +++++-----
 internal/httpd/routes_test.go        |  4 ++--
 internal/httpd/smart.go              |  6 +++---
 internal/httpd/web.go                | 12 ++++++------
 internal/policy/access.go            |  2 +-
 internal/policy/access_test.go       |  2 +-
 internal/sshd/sshd.go                | 20 ++++++++++----------
 internal/store/signatures.go         |  2 +-
 internal/store/store_test.go         |  2 +-
 41 files changed, 191 insertions(+), 191 deletions(-)

diff --git a/.gitignore b/.gitignore
index 5990a7f..a8cf6e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
-/forge
-/forged
+/gitbay
+/gitbayd
 *.db
diff --git a/cmd/forge/local.go b/cmd/gitbay/local.go
similarity index 87%
rename from cmd/forge/local.go
rename to cmd/gitbay/local.go
index e4f90dd..7724133 100644
--- a/cmd/forge/local.go
+++ b/cmd/gitbay/local.go
@@ -9,8 +9,8 @@ import (
 
 	"golang.org/x/term"
 
-	"github.com/krazywarez/forge/internal/cliconfig"
-	"github.com/krazywarez/forge/internal/protocol"
+	"gitbay.org/gitbay/internal/cliconfig"
+	"gitbay.org/gitbay/internal/protocol"
 )
 
 // hasBodyFlag reports whether args already carry body/message input.
@@ -37,7 +37,7 @@ func maybeEditor(args []string, kind string) ([]string, *strings.Reader, bool, e
 		// failing — bodies are optional everywhere.
 		return args, nil, true, nil
 	}
-	f, err := os.CreateTemp("", "forge-"+kind+"-*.md")
+	f, err := os.CreateTemp("", "gitbay-"+kind+"-*.md")
 	if err != nil {
 		return nil, nil, false, err
 	}
@@ -75,7 +75,7 @@ func runGitLocal(args ...string) int {
 		if ee, ok := err.(*exec.ExitError); ok {
 			return ee.ExitCode()
 		}
-		fmt.Fprintln(os.Stderr, "forge:", err)
+		fmt.Fprintln(os.Stderr, "gitbay:", err)
 		return protocol.ExitFailure
 	}
 	return 0
@@ -84,12 +84,12 @@ func runGitLocal(args ...string) int {
 // cmdRepoClone implements `forge repo clone <owner/name> [dir]`.
 func cmdRepoClone(args []string) int {
 	if len(args) < 1 || strings.HasPrefix(args[0], "-") {
-		fmt.Fprintln(os.Stderr, "usage: forge repo clone <owner/name> [dir]")
+		fmt.Fprintln(os.Stderr, "usage: gitbay repo clone <owner/name> [dir]")
 		return protocol.ExitUsage
 	}
 	t, err := resolveTarget()
 	if err != nil {
-		fmt.Fprintln(os.Stderr, "forge:", err)
+		fmt.Fprintln(os.Stderr, "gitbay:", err)
 		return protocol.ExitFailure
 	}
 	gitArgs := append([]string{"clone", t.inst.CloneURL(args[0])}, args[1:]...)
@@ -103,7 +103,7 @@ func cmdRepoClone(args []string) int {
 // origin and check it out as a local branch.
 func cmdMRCheckout(args []string) int {
 	if len(args) != 1 {
-		fmt.Fprintln(os.Stderr, "usage: forge mr checkout <n>")
+		fmt.Fprintln(os.Stderr, "usage: gitbay mr checkout <n>")
 		return protocol.ExitUsage
 	}
 	n := args[0]
@@ -124,7 +124,7 @@ func cmdInit(args []string) int {
 		case a == "--private":
 			private = true
 		case strings.HasPrefix(a, "-"):
-			fmt.Fprintln(os.Stderr, "usage: forge init [name] [--private]")
+			fmt.Fprintln(os.Stderr, "usage: gitbay init [name] [--private]")
 			return protocol.ExitUsage
 		default:
 			name = a
@@ -133,7 +133,7 @@ func cmdInit(args []string) int {
 	if name == "" {
 		wd, err := os.Getwd()
 		if err != nil {
-			fmt.Fprintln(os.Stderr, "forge:", err)
+			fmt.Fprintln(os.Stderr, "gitbay:", err)
 			return protocol.ExitFailure
 		}
 		name = filepath.Base(wd)
@@ -141,12 +141,12 @@ func cmdInit(args []string) int {
 
 	cfg, err := cliconfig.Load()
 	if err != nil {
-		fmt.Fprintln(os.Stderr, "forge:", err)
+		fmt.Fprintln(os.Stderr, "gitbay:", err)
 		return protocol.ExitFailure
 	}
 	inst, _, err := cfg.DefaultInstance()
 	if err != nil {
-		fmt.Fprintln(os.Stderr, "forge:", err)
+		fmt.Fprintln(os.Stderr, "gitbay:", err)
 		return protocol.ExitFailure
 	}
 	t := target{inst: inst}
@@ -196,7 +196,7 @@ func captureSSH(t target, serverArgv []string) (string, int) {
 		if ee, ok := err.(*exec.ExitError); ok {
 			return "", ee.ExitCode()
 		}
-		fmt.Fprintln(os.Stderr, "forge: running ssh:", err)
+		fmt.Fprintln(os.Stderr, "gitbay: running ssh:", err)
 		return "", protocol.ExitProtocol
 	}
 	return string(out), 0
@@ -210,7 +210,7 @@ func quoteAll(args []string) []string {
 	return out
 }
 
-// cmdRemoteAdd implements `forge remote add <name> <host> [flags]`.
+// cmdRemoteAdd implements `gitbay remote add <name> <host> [flags]`.
 func cmdRemoteAdd(args []string) int {
 	var name, host, user string
 	var port int
@@ -250,19 +250,19 @@ func cmdRemoteAdd(args []string) int {
 			} else if host == "" {
 				host = a
 			} else {
-				fmt.Fprintln(os.Stderr, "usage: forge remote add <name> <host> [--port n] [--user u] [--ssh-option opt]... [--default]")
+				fmt.Fprintln(os.Stderr, "usage: gitbay remote add <name> <host> [--port n] [--user u] [--ssh-option opt]... [--default]")
 				return protocol.ExitUsage
 			}
 			i++
 		}
 	}
 	if name == "" || host == "" {
-		fmt.Fprintln(os.Stderr, "usage: forge remote add <name> <host> [--port n] [--user u] [--ssh-option opt]... [--default]")
+		fmt.Fprintln(os.Stderr, "usage: gitbay remote add <name> <host> [--port n] [--user u] [--ssh-option opt]... [--default]")
 		return protocol.ExitUsage
 	}
 	cfg, err := cliconfig.Load()
 	if err != nil {
-		fmt.Fprintln(os.Stderr, "forge:", err)
+		fmt.Fprintln(os.Stderr, "gitbay:", err)
 		return protocol.ExitFailure
 	}
 	cfg.Instances[name] = cliconfig.Instance{Host: host, Port: port, User: user, SSHOptions: sshOptions}
@@ -270,7 +270,7 @@ func cmdRemoteAdd(args []string) int {
 		cfg.Default = name
 	}
 	if err := cliconfig.Save(cfg); err != nil {
-		fmt.Fprintln(os.Stderr, "forge:", err)
+		fmt.Fprintln(os.Stderr, "gitbay:", err)
 		return protocol.ExitFailure
 	}
 	fmt.Printf("added instance %s (%s)\n", name, host)
@@ -280,7 +280,7 @@ func cmdRemoteAdd(args []string) int {
 func cmdRemoteList() int {
 	cfg, err := cliconfig.Load()
 	if err != nil {
-		fmt.Fprintln(os.Stderr, "forge:", err)
+		fmt.Fprintln(os.Stderr, "gitbay:", err)
 		return protocol.ExitFailure
 	}
 	for name, inst := range cfg.Instances {
diff --git a/cmd/forge/main.go b/cmd/gitbay/main.go
similarity index 92%
rename from cmd/forge/main.go
rename to cmd/gitbay/main.go
index ad6ed79..f0bd75f 100644
--- a/cmd/forge/main.go
+++ b/cmd/gitbay/main.go
@@ -13,12 +13,12 @@ import (
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra/doc"
 
-	"github.com/krazywarez/forge/internal/protocol"
+	"gitbay.org/gitbay/internal/protocol"
 )
 
 func main() {
 	root := &cobra.Command{
-		Use:           "forge",
+		Use:           "gitbay",
 		Short:         "CLI-first git forge client",
 		SilenceUsage:  true,
 		SilenceErrors: true,
@@ -36,7 +36,7 @@ func main() {
 	)
 
 	if err := root.Execute(); err != nil {
-		fmt.Fprintln(os.Stderr, "forge:", err)
+		fmt.Fprintln(os.Stderr, "gitbay:", err)
 		os.Exit(protocol.ExitUsage)
 	}
 }
@@ -72,13 +72,13 @@ func pass(use, short string, o passOpts) *cobra.Command {
 func runPass(o passOpts, args []string) int {
 	t, err := resolveTarget()
 	if err != nil {
-		fmt.Fprintln(os.Stderr, "forge:", err)
+		fmt.Fprintln(os.Stderr, "gitbay:", err)
 		return protocol.ExitFailure
 	}
 	if o.needsRepo {
 		args, err = withRepo(t, args)
 		if err != nil {
-			fmt.Fprintln(os.Stderr, "forge:", err)
+			fmt.Fprintln(os.Stderr, "gitbay:", err)
 			return protocol.ExitUsage
 		}
 	}
@@ -87,7 +87,7 @@ func runPass(o passOpts, args []string) int {
 	if o.editor != "" {
 		extended, body, ok, err := maybeEditor(args, o.editor)
 		if err != nil {
-			fmt.Fprintln(os.Stderr, "forge:", err)
+			fmt.Fprintln(os.Stderr, "gitbay:", err)
 			return protocol.ExitFailure
 		}
 		if !ok {
@@ -186,14 +186,14 @@ func authCmd() *cobra.Command {
 
 func repoCmd() *cobra.Command {
 	return group("repo", "create and manage repositories",
-		pass("create", "create a repository: forge repo create <owner/name> [--private]",
+		pass("create", "create a repository: gitbay repo create <owner/name> [--private]",
 			passOpts{server: []string{"repo", "create"}}),
 		pass("list", "list repositories you own or can access", passOpts{server: []string{"repo", "list"}}),
 		pass("show", "show repository details", passOpts{server: []string{"repo", "show"}, needsRepo: true}),
 		pass("log", "commit log with signature states", passOpts{server: []string{"repo", "log"}, needsRepo: true}),
 		pass("delete", "delete a repository (--yes)", passOpts{server: []string{"repo", "delete"}, needsRepo: true}),
 		pass("fork", "fork a repository under your account", passOpts{server: []string{"repo", "fork"}, needsRepo: true}),
-		local("clone", "clone via ssh: forge repo clone <owner/name> [dir]", cmdRepoClone),
+		local("clone", "clone via ssh: gitbay repo clone <owner/name> [dir]", cmdRepoClone),
 		importCmd(),
 		group("access", "manage access grants",
 			pass("grant", "grant access: ... <user> read|write|admin", passOpts{server: []string{"repo", "access", "grant"}, needsRepo: true}),
@@ -232,7 +232,7 @@ func mrCmd() *cobra.Command {
 		pass("list", "list merge requests [--state ...]", passOpts{server: []string{"mr", "list"}, needsRepo: true}),
 		pass("show", "show a merge request", passOpts{server: []string{"mr", "show"}, needsRepo: true}),
 		pass("diff", "show the diff", passOpts{server: []string{"mr", "diff"}, needsRepo: true}),
-		local("checkout", "fetch and check out the MR head locally: forge mr checkout <n>", cmdMRCheckout),
+		local("checkout", "fetch and check out the MR head locally: gitbay mr checkout <n>", cmdMRCheckout),
 		pass("comment", "comment on a merge request", passOpts{server: []string{"mr", "comment"}, needsRepo: true, stdinOK: true, editor: "comment"}),
 		pass("review", "review: --approve|--request-changes|--comment", passOpts{server: []string{"mr", "review"}, needsRepo: true}),
 		pass("merge", "merge (fast-forward or merge-commit): [--strategy ff|merge]", passOpts{server: []string{"mr", "merge"}, needsRepo: true}),
@@ -244,7 +244,7 @@ func mrCmd() *cobra.Command {
 func importCmd() *cobra.Command {
 	return &cobra.Command{
 		Use:                "import",
-		Short:              "server-side mirror of a foreign repo: forge repo import <owner/name> --from <url> [--private] [--token-stdin]",
+		Short:              "server-side mirror of a foreign repo: gitbay repo import <owner/name> --from <url> [--private] [--token-stdin]",
 		DisableFlagParsing: true,
 		RunE: func(cmd *cobra.Command, args []string) error {
 			for _, a := range args {
@@ -283,14 +283,14 @@ func webCmd() *cobra.Command {
 
 func remoteCmd() *cobra.Command {
 	return group("remote", "local instance profiles (no server contact)",
-		local("add", "add a named forge instance: forge remote add <name> <host> [--port n] [--user u] [--ssh-option o]... [--default]",
+		local("add", "add a named gitbay instance: gitbay remote add <name> <host> [--port n] [--user u] [--ssh-option o]... [--default]",
 			cmdRemoteAdd),
 		local("list", "list configured instances", func([]string) int { return cmdRemoteList() }),
 	)
 }
 
 func initCmd() *cobra.Command {
-	return local("init", "git init + repo create + set origin, in one step: forge init [name] [--private]", cmdInit)
+	return local("init", "git init + repo create + set origin, in one step: gitbay init [name] [--private]", cmdInit)
 }
 
 // manCmd generates man pages; a CLI-first tool without man pages is not
diff --git a/cmd/forge/ssh.go b/cmd/gitbay/ssh.go
similarity index 93%
rename from cmd/forge/ssh.go
rename to cmd/gitbay/ssh.go
index 051274b..53961b2 100644
--- a/cmd/forge/ssh.go
+++ b/cmd/gitbay/ssh.go
@@ -9,8 +9,8 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/krazywarez/forge/internal/cliconfig"
-	"github.com/krazywarez/forge/internal/protocol"
+	"gitbay.org/gitbay/internal/cliconfig"
+	"gitbay.org/gitbay/internal/protocol"
 )
 
 // context is the resolved target for a command: which instance to talk to
@@ -105,7 +105,7 @@ func runSSH(t target, serverArgv []string, stdin io.Reader) int {
 		}
 		return code
 	}
-	fmt.Fprintln(os.Stderr, "forge: running ssh:", err)
+	fmt.Fprintln(os.Stderr, "gitbay: running ssh:", err)
 	return protocol.ExitProtocol
 }
 
@@ -117,7 +117,7 @@ func withRepo(t target, args []string) ([]string, error) {
 		return args, nil // explicit owner/name
 	}
 	if t.repo == "" {
-		return nil, fmt.Errorf("no repository given and none inferable: pass <owner/name> or run inside a clone of a forge repository")
+		return nil, fmt.Errorf("no repository given and none inferable: pass <owner/name> or run inside a clone of a gitbay repository")
 	}
 	return append([]string{t.repo}, args...), nil
 }
diff --git a/cmd/forged/hook.go b/cmd/gitbayd/hook.go
similarity index 90%
rename from cmd/forged/hook.go
rename to cmd/gitbayd/hook.go
index f242219..6691134 100644
--- a/cmd/forged/hook.go
+++ b/cmd/gitbayd/hook.go
@@ -10,9 +10,9 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/krazywarez/forge/internal/gitutil"
-	"github.com/krazywarez/forge/internal/hookd"
-	"github.com/krazywarez/forge/internal/policy"
+	"gitbay.org/gitbay/internal/gitutil"
+	"gitbay.org/gitbay/internal/hookd"
+	"gitbay.org/gitbay/internal/policy"
 )
 
 // collectIncomingCommits lists the commits this push introduces and reads
@@ -58,7 +58,7 @@ func hookCmd() *cobra.Command {
 			repoID, err1 := strconv.ParseInt(os.Getenv(hookd.EnvRepoID), 10, 64)
 			userID, err2 := strconv.ParseInt(os.Getenv(hookd.EnvUserID), 10, 64)
 			if sock == "" || err1 != nil || err2 != nil {
-				return fmt.Errorf("missing FORGE_* environment; this command only runs as a git hook")
+				return fmt.Errorf("missing GITBAY_* environment; this command only runs as a git hook")
 			}
 
 			var updates []policy.RefUpdate
@@ -92,7 +92,7 @@ func hookCmd() *cobra.Command {
 				return collectIncomingCommits(updates)
 			})
 			if err != nil {
-				return fmt.Errorf("forge daemon unreachable: %w", err)
+				return fmt.Errorf("gitbay daemon unreachable: %w", err)
 			}
 			if !resp.Allow {
 				fmt.Fprintln(os.Stderr, resp.Message)
diff --git a/cmd/forged/main.go b/cmd/gitbayd/main.go
similarity index 90%
rename from cmd/forged/main.go
rename to cmd/gitbayd/main.go
index ce02986..e0a1ba1 100644
--- a/cmd/forged/main.go
+++ b/cmd/gitbayd/main.go
@@ -1,4 +1,4 @@
-// forged is the forge server daemon. The same binary also runs in hook mode
+// gitbayd is the forge server daemon. The same binary also runs in hook mode
 // (invoked by git via core.hooksPath) and hosts the host-local admin commands.
 package main
 
@@ -14,18 +14,18 @@ import (
 	"github.com/spf13/cobra"
 	"golang.org/x/crypto/ssh"
 
-	"github.com/krazywarez/forge/internal/config"
-	"github.com/krazywarez/forge/internal/control"
-	"github.com/krazywarez/forge/internal/gitd"
-	"github.com/krazywarez/forge/internal/hookd"
-	"github.com/krazywarez/forge/internal/httpd"
-	"github.com/krazywarez/forge/internal/policy"
-	"github.com/krazywarez/forge/internal/sshd"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/config"
+	"gitbay.org/gitbay/internal/control"
+	"gitbay.org/gitbay/internal/gitd"
+	"gitbay.org/gitbay/internal/hookd"
+	"gitbay.org/gitbay/internal/httpd"
+	"gitbay.org/gitbay/internal/policy"
+	"gitbay.org/gitbay/internal/sshd"
+	"gitbay.org/gitbay/internal/store"
 )
 
 func openStore(cfg config.Config) (*store.Store, error) {
-	s, err := store.Open(filepath.Join(cfg.Server.Root, "forge.db"))
+	s, err := store.Open(filepath.Join(cfg.Server.Root, "gitbay.db"))
 	if err != nil {
 		return nil, err
 	}
@@ -40,12 +40,12 @@ var configPath string
 
 func main() {
 	root := &cobra.Command{
-		Use:           "forged",
-		Short:         "forge server daemon",
+		Use:           "gitbayd",
+		Short:         "gitbay server daemon",
 		SilenceUsage:  true,
 		SilenceErrors: true,
 	}
-	root.PersistentFlags().StringVar(&configPath, "config", "/etc/forge/config.toml", "path to config file")
+	root.PersistentFlags().StringVar(&configPath, "config", "/etc/gitbay/config.toml", "path to config file")
 
 	root.AddCommand(
 		checkConfigCmd(),
@@ -58,7 +58,7 @@ func main() {
 	)
 
 	if err := root.Execute(); err != nil {
-		fmt.Fprintln(os.Stderr, "forged:", err)
+		fmt.Fprintln(os.Stderr, "gitbayd:", err)
 		os.Exit(1)
 	}
 }
@@ -173,7 +173,7 @@ func migrateCmd() *cobra.Command {
 			if err != nil {
 				return err
 			}
-			s, err := store.Open(cfg.Server.Root + "/forge.db")
+			s, err := store.Open(cfg.Server.Root + "/gitbay.db")
 			if err != nil {
 				return err
 			}
diff --git a/cmd/forged/system.go b/cmd/gitbayd/system.go
similarity index 88%
rename from cmd/forged/system.go
rename to cmd/gitbayd/system.go
index 5f589c5..3c649fb 100644
--- a/cmd/forged/system.go
+++ b/cmd/gitbayd/system.go
@@ -7,14 +7,14 @@ import (
 	"github.com/spf13/cobra"
 	"golang.org/x/crypto/ssh"
 
-	"github.com/krazywarez/forge/internal/config"
-	"github.com/krazywarez/forge/internal/protocol"
-	"github.com/krazywarez/forge/internal/sshd"
+	"gitbay.org/gitbay/internal/config"
+	"gitbay.org/gitbay/internal/protocol"
+	"gitbay.org/gitbay/internal/sshd"
 )
 
 // authorizedKeysCmd backs sshd's AuthorizedKeysCommand in system mode:
 //
-//	AuthorizedKeysCommand /usr/bin/forged --config /etc/forge/config.toml authorized-keys %t %k
+//	AuthorizedKeysCommand /usr/bin/gitbayd --config /etc/gitbay/config.toml authorized-keys %t %k
 //	AuthorizedKeysCommandUser git
 //
 // It prints a forced-command authorized_keys line for registered keys and
@@ -90,7 +90,7 @@ func shellCmd() *cobra.Command {
 
 			cmdline := os.Getenv("SSH_ORIGINAL_COMMAND")
 			if cmdline == "" {
-				fmt.Fprintf(os.Stderr, "forge control plane: interactive shells are not available.\nTry: ssh <host> help\n")
+				fmt.Fprintf(os.Stderr, "gitbay control plane: interactive shells are not available.\nTry: ssh <host> help\n")
 				os.Exit(protocol.ExitUsage)
 			}
 			code := sshd.Exec(cfg, st, user, key.Scope, cmdline, os.Stdin, os.Stdout, os.Stderr)
diff --git a/e2e/cli_test.go b/e2e/cli_test.go
index df74903..9d5073f 100644
--- a/e2e/cli_test.go
+++ b/e2e/cli_test.go
@@ -10,13 +10,13 @@ import (
 	"testing"
 )
 
-func buildForgeCLI(t *testing.T) string {
+func buildGitbayCLI(t *testing.T) string {
 	t.Helper()
-	bin := filepath.Join(t.TempDir(), "forge")
-	cmd := exec.Command("go", "build", "-o", bin, "github.com/krazywarez/forge/cmd/forge")
+	bin := filepath.Join(t.TempDir(), "gitbay")
+	cmd := exec.Command("go", "build", "-o", bin, "gitbay.org/gitbay/cmd/gitbay")
 	cmd.Dir = ".."
 	if out, err := cmd.CombinedOutput(); err != nil {
-		t.Fatalf("build forge: %v\n%s", err, out)
+		t.Fatalf("build gitbay: %v\n%s", err, out)
 	}
 	return bin
 }
@@ -51,7 +51,7 @@ func (c *cli) run(t *testing.T, dir, stdin string, args ...string) (string, stri
 	if ee, ok := err.(*exec.ExitError); ok {
 		code = ee.ExitCode()
 	} else if err != nil {
-		t.Fatalf("forge %v: %v", args, err)
+		t.Fatalf("gitbay %v: %v", args, err)
 	}
 	return out.String(), errOut.String(), code
 }
@@ -60,7 +60,7 @@ func (c *cli) must(t *testing.T, dir, stdin string, args ...string) string {
 	t.Helper()
 	out, errOut, code := c.run(t, dir, stdin, args...)
 	if code != 0 {
-		t.Fatalf("forge %v: exit %d\nstdout: %s\nstderr: %s", args, code, out, errOut)
+		t.Fatalf("gitbay %v: exit %d\nstdout: %s\nstderr: %s", args, code, out, errOut)
 	}
 	return out
 }
@@ -72,7 +72,7 @@ func TestCLI(t *testing.T) {
 		"--key", aliceKey+".pub", "--email", "alice@example.test", "--verified")
 
 	c := &cli{
-		bin:       buildForgeCLI(t),
+		bin:       buildGitbayCLI(t),
 		configDir: t.TempDir(),
 		inst:      inst,
 		key:       aliceKey,
diff --git a/e2e/http_test.go b/e2e/http_test.go
index 2eddd13..a8bd35a 100644
--- a/e2e/http_test.go
+++ b/e2e/http_test.go
@@ -90,7 +90,7 @@ func TestHTTPTransport(t *testing.T) {
 		}
 		if !strings.Contains(out, "remote error:") ||
 			!strings.Contains(out, "pushes to this forge go over SSH") ||
-			!strings.Contains(out, "git@forge.test:alice/pub.git") {
+			!strings.Contains(out, "git@gitbay.test:alice/pub.git") {
 			t.Fatalf("[%s] push refusal output:\n%s", gitBin, out)
 		}
 		for _, banned := range []string{"Username", "Password", "Authentication failed", "terminal prompts disabled", "401", "403"} {
diff --git a/e2e/mr_test.go b/e2e/mr_test.go
index c8b4438..53167e1 100644
--- a/e2e/mr_test.go
+++ b/e2e/mr_test.go
@@ -9,7 +9,7 @@ import (
 
 	"golang.org/x/crypto/ssh"
 
-	"github.com/krazywarez/forge/internal/sig"
+	"gitbay.org/gitbay/internal/sig"
 )
 
 type mrShow struct {
diff --git a/e2e/sig_test.go b/e2e/sig_test.go
index 02617b1..735ed9f 100644
--- a/e2e/sig_test.go
+++ b/e2e/sig_test.go
@@ -16,7 +16,7 @@ import (
 	"github.com/ProtonMail/go-crypto/openpgp/packet"
 	"golang.org/x/crypto/ssh"
 
-	"github.com/krazywarez/forge/internal/sig"
+	"gitbay.org/gitbay/internal/sig"
 )
 
 // --- fixture key helpers -------------------------------------------------
@@ -361,7 +361,7 @@ func TestSignatureVerification(t *testing.T) {
 		vc.Dir = dir
 		vc.Env = gpgEnv
 		if out, err := vc.CombinedOutput(); err != nil {
-			t.Errorf("git verify-commit disagrees with forge verification: %v\n%s", err, out)
+			t.Errorf("git verify-commit disagrees with gitbay verification: %v\n%s", err, out)
 		}
 	} else {
 		t.Log("gpg not installed; skipping git verify-commit cross-check")
diff --git a/e2e/ssh_test.go b/e2e/ssh_test.go
index ce05e88..8e18740 100644
--- a/e2e/ssh_test.go
+++ b/e2e/ssh_test.go
@@ -1,4 +1,4 @@
-// Package e2e drives a real forged with the real ssh and git clients.
+// Package e2e drives a real gitbayd with the real ssh and git clients.
 package e2e
 
 import (
@@ -14,7 +14,7 @@ import (
 )
 
 type instance struct {
-	forged   string // path to built binary
+	gitbayd   string // path to built binary
 	root     string
 	config   string
 	port     int
@@ -24,13 +24,13 @@ type instance struct {
 	sshDir   string // per-user client keys live here
 }
 
-func buildForged(t *testing.T) string {
+func buildGitbayd(t *testing.T) string {
 	t.Helper()
-	bin := filepath.Join(t.TempDir(), "forged")
-	cmd := exec.Command("go", "build", "-o", bin, "github.com/krazywarez/forge/cmd/forged")
+	bin := filepath.Join(t.TempDir(), "gitbayd")
+	cmd := exec.Command("go", "build", "-o", bin, "gitbay.org/gitbay/cmd/gitbayd")
 	cmd.Dir = ".."
 	if out, err := cmd.CombinedOutput(); err != nil {
-		t.Fatalf("build forged: %v\n%s", err, out)
+		t.Fatalf("build gitbayd: %v\n%s", err, out)
 	}
 	return bin
 }
@@ -53,7 +53,7 @@ func startInstance(t *testing.T) *instance {
 func startInstanceWith(t *testing.T, extra string) *instance {
 	t.Helper()
 	inst := &instance{
-		forged:   buildForged(t),
+		gitbayd:   buildGitbayd(t),
 		root:     t.TempDir(),
 		port:     freePort(t),
 		httpPort: freePort(t),
@@ -64,7 +64,7 @@ func startInstanceWith(t *testing.T, extra string) *instance {
 	cfg := fmt.Sprintf(`
 [server]
 root = %q
-site_url = "https://forge.test"
+site_url = "https://gitbay.test"
 [ssh]
 port = %d
 [http]
@@ -79,7 +79,7 @@ port = %d
 		t.Fatal(err)
 	}
 
-	inst.proc = exec.Command(inst.forged, "--config", inst.config, "serve")
+	inst.proc = exec.Command(inst.gitbayd, "--config", inst.config, "serve")
 	inst.proc.Stderr = os.Stderr
 	if err := inst.proc.Start(); err != nil {
 		t.Fatal(err)
@@ -98,19 +98,19 @@ port = %d
 			return inst
 		}
 		if time.Now().After(deadline) {
-			t.Fatal("forged did not start listening")
+			t.Fatal("gitbayd did not start listening")
 		}
 		time.Sleep(50 * time.Millisecond)
 	}
 }
 
-// admin runs a forged admin command against the instance's database.
+// admin runs a gitbayd admin command against the instance's database.
 func (i *instance) admin(t *testing.T, args ...string) string {
 	t.Helper()
-	cmd := exec.Command(i.forged, append([]string{"--config", i.config}, args...)...)
+	cmd := exec.Command(i.gitbayd, append([]string{"--config", i.config}, args...)...)
 	out, err := cmd.CombinedOutput()
 	if err != nil {
-		t.Fatalf("forged %v: %v\n%s", args, err, out)
+		t.Fatalf("gitbayd %v: %v\n%s", args, err, out)
 	}
 	return string(out)
 }
diff --git a/e2e/system_test.go b/e2e/system_test.go
index 906ceab..97f0094 100644
--- a/e2e/system_test.go
+++ b/e2e/system_test.go
@@ -24,14 +24,14 @@ func TestSystemSSHMode(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	// forged in system mode: no embedded SSH listener; hookd + http still run.
+	// gitbayd in system mode: no embedded SSH listener; hookd + http still run.
 	inst := startInstanceWith(t, "") // placeholder to reuse helpers; killed below
 	inst.proc.Process.Kill()
 	inst.proc.Wait()
 	cfg := fmt.Sprintf(`
 [server]
 root = %q
-site_url = "https://forge.test"
+site_url = "https://gitbay.test"
 [ssh]
 mode = "system"
 [http]
@@ -41,7 +41,7 @@ tls = "off"
 	if err := os.WriteFile(inst.config, []byte(cfg), 0o600); err != nil {
 		t.Fatal(err)
 	}
-	inst.proc = exec.Command(inst.forged, "--config", inst.config, "serve")
+	inst.proc = exec.Command(inst.gitbayd, "--config", inst.config, "serve")
 	inst.proc.Stderr = os.Stderr
 	if err := inst.proc.Start(); err != nil {
 		t.Fatal(err)
@@ -65,7 +65,7 @@ tls = "off"
 	// wrapper script argument — only the command path is ownership-checked.
 	wrapper := filepath.Join(sshdDir, "akc.sh")
 	script := fmt.Sprintf("#!/bin/sh\nexec %q --config %q authorized-keys \"$1\" \"$2\"\n",
-		inst.forged, inst.config)
+		inst.gitbayd, inst.config)
 	if err := os.WriteFile(wrapper, []byte(script), 0o755); err != nil {
 		t.Fatal(err)
 	}
diff --git a/e2e/web_test.go b/e2e/web_test.go
index 209664c..edb0016 100644
--- a/e2e/web_test.go
+++ b/e2e/web_test.go
@@ -12,7 +12,7 @@ import (
 
 	"golang.org/x/crypto/ssh"
 
-	"github.com/krazywarez/forge/internal/sig"
+	"gitbay.org/gitbay/internal/sig"
 )
 
 func (i *instance) get(t *testing.T, path string) (int, string) {
diff --git a/go.mod b/go.mod
index 54e370b..36ec733 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module github.com/krazywarez/forge
+module gitbay.org/gitbay
 
 go 1.27.0
 
diff --git a/internal/cliconfig/cliconfig.go b/internal/cliconfig/cliconfig.go
index e35ee07..2e0ec32 100644
--- a/internal/cliconfig/cliconfig.go
+++ b/internal/cliconfig/cliconfig.go
@@ -46,10 +46,10 @@ type Config struct {
 
 func Path() string {
 	if x := os.Getenv("XDG_CONFIG_HOME"); x != "" {
-		return filepath.Join(x, "forge", "config.toml")
+		return filepath.Join(x, "gitbay", "config.toml")
 	}
 	home, _ := os.UserHomeDir()
-	return filepath.Join(home, ".config", "forge", "config.toml")
+	return filepath.Join(home, ".config", "gitbay", "config.toml")
 }
 
 func Load() (Config, error) {
@@ -95,7 +95,7 @@ func (c Config) DefaultInstance() (Instance, string, error) {
 			return inst, name, nil
 		}
 	}
-	return Instance{}, "", fmt.Errorf("no forge instance configured; run: forge remote add <name> <host>")
+	return Instance{}, "", fmt.Errorf("no gitbay instance configured; run: gitbay remote add <name> <host>")
 }
 
 var (
diff --git a/internal/cliconfig/cliconfig_test.go b/internal/cliconfig/cliconfig_test.go
index 4646ae4..1cb2e39 100644
--- a/internal/cliconfig/cliconfig_test.go
+++ b/internal/cliconfig/cliconfig_test.go
@@ -11,12 +11,12 @@ func TestParseRemoteURL(t *testing.T) {
 		repo string
 		ok   bool
 	}{
-		{"ssh://git@forge.example/alice/proj.git", "forge.example", 0, "git", "alice/proj", true},
-		{"ssh://git@forge.example:2222/alice/proj.git", "forge.example", 2222, "git", "alice/proj", true},
-		{"ssh://forge.example/alice/proj", "forge.example", 0, "", "alice/proj", true},
-		{"git@forge.example:alice/proj.git", "forge.example", 0, "git", "alice/proj", true},
-		{"git@forge.example:alice/proj", "forge.example", 0, "git", "alice/proj", true},
-		{"https://forge.example/alice/proj.git", "", 0, "", "", false},
+		{"ssh://git@gitbay.example/alice/proj.git", "gitbay.example", 0, "git", "alice/proj", true},
+		{"ssh://git@gitbay.example:2222/alice/proj.git", "gitbay.example", 2222, "git", "alice/proj", true},
+		{"ssh://gitbay.example/alice/proj", "gitbay.example", 0, "", "alice/proj", true},
+		{"git@gitbay.example:alice/proj.git", "gitbay.example", 0, "git", "alice/proj", true},
+		{"git@gitbay.example:alice/proj", "gitbay.example", 0, "git", "alice/proj", true},
+		{"https://gitbay.example/alice/proj.git", "", 0, "", "", false},
 		{"/local/path/repo.git", "", 0, "", "", false},
 	}
 	for _, tc := range cases {
@@ -35,12 +35,12 @@ func TestParseRemoteURL(t *testing.T) {
 }
 
 func TestCloneURL(t *testing.T) {
-	i := Instance{Host: "forge.example"}
-	if got := i.CloneURL("a/b"); got != "ssh://git@forge.example/a/b.git" {
+	i := Instance{Host: "gitbay.example"}
+	if got := i.CloneURL("a/b"); got != "ssh://git@gitbay.example/a/b.git" {
 		t.Errorf("CloneURL = %s", got)
 	}
-	i = Instance{Host: "forge.example", Port: 2222, User: "u"}
-	if got := i.CloneURL("a/b"); got != "ssh://u@forge.example:2222/a/b.git" {
+	i = Instance{Host: "gitbay.example", Port: 2222, User: "u"}
+	if got := i.CloneURL("a/b"); got != "ssh://u@gitbay.example:2222/a/b.git" {
 		t.Errorf("CloneURL = %s", got)
 	}
 }
diff --git a/internal/config/config.go b/internal/config/config.go
index 382d501..293fa9a 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -1,4 +1,4 @@
-// Package config loads and validates the forged server configuration.
+// Package config loads and validates the gitbayd server configuration.
 package config
 
 import (
@@ -69,7 +69,7 @@ type Mail struct {
 // Default returns the configuration used when a key is absent from the file.
 func Default() Config {
 	return Config{
-		Server: Server{Root: "/var/lib/forge"},
+		Server: Server{Root: "/var/lib/gitbay"},
 		SSH:    SSH{Mode: "embedded", Port: 22},
 		HTTP:   HTTP{Addr: ":443", TLS: "acme"},
 		Web:    Web{Mode: "view_only"},
@@ -154,7 +154,7 @@ func (c Config) Validate() error {
 	}
 	if c.Web.PasswordAuth && c.Web.Mode == "accounts" {
 		errs = append(errs, errors.New(
-			"web.password_auth is not implemented yet; browser sessions are minted over SSH (forge web login)"))
+			"web.password_auth is not implemented yet; browser sessions are minted over SSH (gitbay web login)"))
 	}
 
 	return errors.Join(errs...)
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
index 89cc5a9..c1d45a8 100644
--- a/internal/config/config_test.go
+++ b/internal/config/config_test.go
@@ -18,8 +18,8 @@ func writeConfig(t *testing.T, body string) string {
 
 const minimal = `
 [server]
-root = "/var/lib/forge"
-site_url = "https://forge.example"
+root = "/var/lib/gitbay"
+site_url = "https://gitbay.example"
 `
 
 func TestLoadMinimal(t *testing.T) {
@@ -52,7 +52,7 @@ func TestContradictions(t *testing.T) {
 		},
 		{
 			"system ssh with open registration",
-			minimal + "\n[ssh]\nmode = \"system\"\n[registration]\nmode = \"open\"\n[mail]\nsmtp_host = \"mx.example\"\nfrom = \"forge@example\"\n",
+			minimal + "\n[ssh]\nmode = \"system\"\n[registration]\nmode = \"open\"\n[mail]\nsmtp_host = \"mx.example\"\nfrom = \"gitbay@example\"\n",
 			"requires registration.mode = \"closed\"",
 		},
 		{
@@ -72,12 +72,12 @@ func TestContradictions(t *testing.T) {
 		},
 		{
 			"unknown key",
-			"[server]\nroot = \"/var/lib/forge\"\nsite_url = \"https://forge.example\"\nbogus = 1\n",
+			"[server]\nroot = \"/var/lib/gitbay\"\nsite_url = \"https://gitbay.example\"\nbogus = 1\n",
 			"unknown config key",
 		},
 		{
 			"missing site_url",
-			"[server]\nroot = \"/var/lib/forge\"\n",
+			"[server]\nroot = \"/var/lib/gitbay\"\n",
 			"site_url",
 		},
 	}
@@ -101,7 +101,7 @@ func TestValidCombinations(t *testing.T) {
 	}{
 		{
 			"invite with smtp",
-			minimal + "\n[registration]\nmode = \"invite\"\n[mail]\nsmtp_host = \"mx.example\"\nfrom = \"forge@example\"\n",
+			minimal + "\n[registration]\nmode = \"invite\"\n[mail]\nsmtp_host = \"mx.example\"\nfrom = \"gitbay@example\"\n",
 		},
 		{
 			"system ssh closed registration",
diff --git a/internal/control/control.go b/internal/control/control.go
index 38859bd..e6fc544 100644
--- a/internal/control/control.go
+++ b/internal/control/control.go
@@ -10,9 +10,9 @@ import (
 	"reflect"
 	"slices"
 
-	"github.com/krazywarez/forge/internal/config"
-	"github.com/krazywarez/forge/internal/protocol"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/config"
+	"gitbay.org/gitbay/internal/protocol"
+	"gitbay.org/gitbay/internal/store"
 )
 
 type Ctx struct {
diff --git a/internal/control/control_test.go b/internal/control/control_test.go
index 37ddc30..25dcbff 100644
--- a/internal/control/control_test.go
+++ b/internal/control/control_test.go
@@ -4,7 +4,7 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/krazywarez/forge/internal/protocol"
+	"gitbay.org/gitbay/internal/protocol"
 )
 
 // TestEveryCommandReachableFromBareSSH asserts that each registered command's
diff --git a/internal/control/identity.go b/internal/control/identity.go
index e544714..e596b40 100644
--- a/internal/control/identity.go
+++ b/internal/control/identity.go
@@ -7,8 +7,8 @@ import (
 
 	"golang.org/x/crypto/ssh"
 
-	"github.com/krazywarez/forge/internal/protocol"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/protocol"
+	"gitbay.org/gitbay/internal/store"
 )
 
 func init() {
diff --git a/internal/control/import.go b/internal/control/import.go
index 61a0edd..c1dbafc 100644
--- a/internal/control/import.go
+++ b/internal/control/import.go
@@ -10,9 +10,9 @@ import (
 	"strings"
 	"time"
 
-	"github.com/krazywarez/forge/internal/gitutil"
-	"github.com/krazywarez/forge/internal/policy"
-	"github.com/krazywarez/forge/internal/protocol"
+	"gitbay.org/gitbay/internal/gitutil"
+	"gitbay.org/gitbay/internal/policy"
+	"gitbay.org/gitbay/internal/protocol"
 )
 
 func init() {
@@ -27,7 +27,7 @@ func init() {
 const askpassScript = `#!/bin/sh
 case "$1" in
   Username*) echo "x-access-token" ;;
-  *)         echo "${FORGE_IMPORT_TOKEN}" ;;
+  *)         echo "${GITBAY_IMPORT_TOKEN}" ;;
 esac
 `
 
@@ -96,7 +96,7 @@ func runRepoImport(c *Ctx, args []string) int {
 		}
 		env = []string{
 			"GIT_ASKPASS=" + askpass,
-			"FORGE_IMPORT_TOKEN=" + token,
+			"GITBAY_IMPORT_TOKEN=" + token,
 			"GIT_TERMINAL_PROMPT=0",
 		}
 	} else {
diff --git a/internal/control/issue.go b/internal/control/issue.go
index 7230656..3a68752 100644
--- a/internal/control/issue.go
+++ b/internal/control/issue.go
@@ -7,9 +7,9 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/krazywarez/forge/internal/policy"
-	"github.com/krazywarez/forge/internal/protocol"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/policy"
+	"gitbay.org/gitbay/internal/protocol"
+	"gitbay.org/gitbay/internal/store"
 )
 
 const maxBodyBytes = 64 << 10
diff --git a/internal/control/mr.go b/internal/control/mr.go
index ce92ea7..b27a3d7 100644
--- a/internal/control/mr.go
+++ b/internal/control/mr.go
@@ -7,10 +7,10 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/krazywarez/forge/internal/gitutil"
-	"github.com/krazywarez/forge/internal/policy"
-	"github.com/krazywarez/forge/internal/protocol"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/gitutil"
+	"gitbay.org/gitbay/internal/policy"
+	"gitbay.org/gitbay/internal/protocol"
+	"gitbay.org/gitbay/internal/store"
 )
 
 func init() {
diff --git a/internal/control/repo.go b/internal/control/repo.go
index ab5d02e..e42d81c 100644
--- a/internal/control/repo.go
+++ b/internal/control/repo.go
@@ -9,10 +9,10 @@ import (
 	"slices"
 	"strings"
 
-	"github.com/krazywarez/forge/internal/gitutil"
-	"github.com/krazywarez/forge/internal/policy"
-	"github.com/krazywarez/forge/internal/protocol"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/gitutil"
+	"gitbay.org/gitbay/internal/policy"
+	"gitbay.org/gitbay/internal/protocol"
+	"gitbay.org/gitbay/internal/store"
 )
 
 // RepoDir returns the on-disk path for a repository.
diff --git a/internal/control/sig.go b/internal/control/sig.go
index 11102b7..63d44d0 100644
--- a/internal/control/sig.go
+++ b/internal/control/sig.go
@@ -8,11 +8,11 @@ import (
 	"strconv"
 	"time"
 
-	"github.com/krazywarez/forge/internal/gitutil"
-	"github.com/krazywarez/forge/internal/policy"
-	"github.com/krazywarez/forge/internal/protocol"
-	"github.com/krazywarez/forge/internal/sig"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/gitutil"
+	"gitbay.org/gitbay/internal/policy"
+	"gitbay.org/gitbay/internal/protocol"
+	"gitbay.org/gitbay/internal/sig"
+	"gitbay.org/gitbay/internal/store"
 )
 
 func init() {
diff --git a/internal/control/web.go b/internal/control/web.go
index a925d90..7eed866 100644
--- a/internal/control/web.go
+++ b/internal/control/web.go
@@ -5,8 +5,8 @@ import (
 	"io"
 	"time"
 
-	"github.com/krazywarez/forge/internal/protocol"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/protocol"
+	"gitbay.org/gitbay/internal/store"
 )
 
 func newStoredToken() (token, hash string, err error) { return store.NewToken() }
diff --git a/internal/gitd/gitd.go b/internal/gitd/gitd.go
index 01c13e0..86b06b7 100644
--- a/internal/gitd/gitd.go
+++ b/internal/gitd/gitd.go
@@ -13,9 +13,9 @@ import (
 	"strings"
 	"time"
 
-	"github.com/krazywarez/forge/internal/config"
-	"github.com/krazywarez/forge/internal/control"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/config"
+	"gitbay.org/gitbay/internal/control"
+	"gitbay.org/gitbay/internal/store"
 )
 
 type Server struct {
diff --git a/internal/gitutil/gitutil.go b/internal/gitutil/gitutil.go
index 0e868f7..2bb7461 100644
--- a/internal/gitutil/gitutil.go
+++ b/internal/gitutil/gitutil.go
@@ -31,7 +31,7 @@ func InitBare(path, defaultBranch, hooksPath string) error {
 
 // Transport streams one git transport service (upload-pack, receive-pack,
 // upload-archive). extraEnv entries are appended to the process environment;
-// hooks read the FORGE_* variables from it.
+// hooks read the GITBAY_* variables from it.
 func Transport(service, repoPath string, stdin io.Reader, stdout, errW io.Writer, extraEnv []string) error {
 	var args []string
 	switch service {
diff --git a/internal/gitutil/merge.go b/internal/gitutil/merge.go
index 467f8a1..87bc9a9 100644
--- a/internal/gitutil/merge.go
+++ b/internal/gitutil/merge.go
@@ -137,7 +137,7 @@ func CommitFileChange(dir, branch, path string, content []byte, name, email, mes
 
 	// Stage the parent tree in a temporary index, splice the blob in, and
 	// write the new tree.
-	idx, err := os.CreateTemp("", "forge-index-*")
+	idx, err := os.CreateTemp("", "gitbay-index-*")
 	if err != nil {
 		return "", err
 	}
diff --git a/internal/hookd/hookd.go b/internal/hookd/hookd.go
index 47026eb..ebdd404 100644
--- a/internal/hookd/hookd.go
+++ b/internal/hookd/hookd.go
@@ -1,5 +1,5 @@
 // Package hookd is the unix-socket bridge between git hooks and the daemon.
-// The hook process (forged in hook mode) computes git facts — it inherits
+// The hook process (gitbayd in hook mode) computes git facts — it inherits
 // git's quarantine environment, which the daemon does not see — and sends
 // them here; the daemon answers with a policy decision.
 //
@@ -17,20 +17,20 @@ import (
 	"os"
 	"path/filepath"
 
-	"github.com/krazywarez/forge/internal/config"
-	"github.com/krazywarez/forge/internal/control"
-	"github.com/krazywarez/forge/internal/gitutil"
-	"github.com/krazywarez/forge/internal/policy"
-	"github.com/krazywarez/forge/internal/sig"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/config"
+	"gitbay.org/gitbay/internal/control"
+	"gitbay.org/gitbay/internal/gitutil"
+	"gitbay.org/gitbay/internal/policy"
+	"gitbay.org/gitbay/internal/sig"
+	"gitbay.org/gitbay/internal/store"
 )
 
 // Env variable names passed to git transport subprocesses and inherited by
 // hooks.
 const (
-	EnvSocket = "FORGE_HOOK_SOCKET"
-	EnvRepoID = "FORGE_REPO_ID"
-	EnvUserID = "FORGE_USER_ID"
+	EnvSocket = "GITBAY_HOOK_SOCKET"
+	EnvRepoID = "GITBAY_REPO_ID"
+	EnvUserID = "GITBAY_USER_ID"
 )
 
 type Request struct {
@@ -59,7 +59,7 @@ type Response struct {
 // SocketPath returns the hook socket location. It prefers the server root,
 // but unix socket paths are capped (~104 bytes on macOS, 108 on Linux), so
 // deep roots fall back to a hashed name under the system temp directory.
-// Hooks receive the chosen path via FORGE_HOOK_SOCKET, so both sides always
+// Hooks receive the chosen path via GITBAY_HOOK_SOCKET, so both sides always
 // agree.
 func SocketPath(root string) string {
 	p := filepath.Join(root, "hook.sock")
@@ -67,7 +67,7 @@ func SocketPath(root string) string {
 		return p
 	}
 	sum := sha256.Sum256([]byte(root))
-	return filepath.Join(os.TempDir(), fmt.Sprintf("forge-%x.sock", sum[:8]))
+	return filepath.Join(os.TempDir(), fmt.Sprintf("gitbay-%x.sock", sum[:8]))
 }
 
 type Server struct {
@@ -250,12 +250,12 @@ func Ask(socketPath string, req Request, commits func() (CommitsPayload, error))
 // WriteHookScripts (re)generates the shared hooks directory. Called at
 // daemon startup so a moved binary self-heals; every repo points here via
 // core.hooksPath.
-func WriteHookScripts(hooksDir, forgedPath string) error {
+func WriteHookScripts(hooksDir, gitbaydPath string) error {
 	if err := os.MkdirAll(hooksDir, 0o755); err != nil {
 		return err
 	}
 	for _, hook := range []string{"pre-receive", "post-receive"} {
-		script := fmt.Sprintf("#!/bin/sh\nexec %q hook %s\n", forgedPath, hook)
+		script := fmt.Sprintf("#!/bin/sh\nexec %q hook %s\n", gitbaydPath, hook)
 		if err := os.WriteFile(filepath.Join(hooksDir, hook), []byte(script), 0o755); err != nil {
 			return err
 		}
diff --git a/internal/httpd/accounts.go b/internal/httpd/accounts.go
index 15b05db..36cef71 100644
--- a/internal/httpd/accounts.go
+++ b/internal/httpd/accounts.go
@@ -7,13 +7,13 @@ import (
 	"strings"
 	"time"
 
-	"github.com/krazywarez/forge/internal/control"
-	"github.com/krazywarez/forge/internal/gitutil"
-	"github.com/krazywarez/forge/internal/policy"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/control"
+	"gitbay.org/gitbay/internal/gitutil"
+	"gitbay.org/gitbay/internal/policy"
+	"gitbay.org/gitbay/internal/store"
 )
 
-const sessionCookie = "forge_session"
+const sessionCookie = "gitbay_session"
 
 // viewer returns the logged-in user, or a zero User for anonymous visitors.
 // Only meaningful in accounts mode; in view_only no session route exists so
diff --git a/internal/httpd/routes_test.go b/internal/httpd/routes_test.go
index c161349..23fe506 100644
--- a/internal/httpd/routes_test.go
+++ b/internal/httpd/routes_test.go
@@ -4,8 +4,8 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/krazywarez/forge/internal/config"
-	"github.com/krazywarez/forge/internal/policy"
+	"gitbay.org/gitbay/internal/config"
+	"gitbay.org/gitbay/internal/policy"
 )
 
 // TestViewOnlyHasNoMutatingRoutes is the structural guarantee from the plan:
diff --git a/internal/httpd/smart.go b/internal/httpd/smart.go
index 381288a..bb5371a 100644
--- a/internal/httpd/smart.go
+++ b/internal/httpd/smart.go
@@ -14,9 +14,9 @@ import (
 	"os/exec"
 	"strings"
 
-	"github.com/krazywarez/forge/internal/config"
-	"github.com/krazywarez/forge/internal/control"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/config"
+	"gitbay.org/gitbay/internal/control"
+	"gitbay.org/gitbay/internal/store"
 )
 
 type Server struct {
diff --git a/internal/httpd/web.go b/internal/httpd/web.go
index 146cbe6..6e35ed6 100644
--- a/internal/httpd/web.go
+++ b/internal/httpd/web.go
@@ -4,7 +4,7 @@ import (
 	"bytes"
 	"fmt"
 
-	"github.com/krazywarez/forge/internal/policy"
+	"gitbay.org/gitbay/internal/policy"
 	"html/template"
 	"net/http"
 	"path"
@@ -17,11 +17,11 @@ import (
 	"github.com/alecthomas/chroma/v2/styles"
 	"github.com/yuin/goldmark"
 
-	"github.com/krazywarez/forge/internal/control"
-	"github.com/krazywarez/forge/internal/gitutil"
-	"github.com/krazywarez/forge/internal/sig"
-	"github.com/krazywarez/forge/internal/store"
-	"github.com/krazywarez/forge/internal/web"
+	"gitbay.org/gitbay/internal/control"
+	"gitbay.org/gitbay/internal/gitutil"
+	"gitbay.org/gitbay/internal/sig"
+	"gitbay.org/gitbay/internal/store"
+	"gitbay.org/gitbay/internal/web"
 )
 
 const maxRenderBytes = 1 << 20 // largest blob rendered inline
diff --git a/internal/policy/access.go b/internal/policy/access.go
index d9cc60f..f791eff 100644
--- a/internal/policy/access.go
+++ b/internal/policy/access.go
@@ -3,7 +3,7 @@ package policy
 import (
 	"strings"
 
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/store"
 )
 
 // CanRead reports whether user may read repo over an authenticated channel.
diff --git a/internal/policy/access_test.go b/internal/policy/access_test.go
index a71c456..1d93158 100644
--- a/internal/policy/access_test.go
+++ b/internal/policy/access_test.go
@@ -3,7 +3,7 @@ package policy
 import (
 	"testing"
 
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/store"
 )
 
 var (
diff --git a/internal/sshd/sshd.go b/internal/sshd/sshd.go
index 4057c4a..be33e1c 100644
--- a/internal/sshd/sshd.go
+++ b/internal/sshd/sshd.go
@@ -17,13 +17,13 @@ import (
 
 	"golang.org/x/crypto/ssh"
 
-	"github.com/krazywarez/forge/internal/config"
-	"github.com/krazywarez/forge/internal/control"
-	"github.com/krazywarez/forge/internal/gitutil"
-	"github.com/krazywarez/forge/internal/hookd"
-	"github.com/krazywarez/forge/internal/policy"
-	"github.com/krazywarez/forge/internal/protocol"
-	"github.com/krazywarez/forge/internal/store"
+	"gitbay.org/gitbay/internal/config"
+	"gitbay.org/gitbay/internal/control"
+	"gitbay.org/gitbay/internal/gitutil"
+	"gitbay.org/gitbay/internal/hookd"
+	"gitbay.org/gitbay/internal/policy"
+	"gitbay.org/gitbay/internal/protocol"
+	"gitbay.org/gitbay/internal/store"
 )
 
 type Server struct {
@@ -37,7 +37,7 @@ func New(cfg config.Config, st *store.Store) (*Server, error) {
 
 	sc := &ssh.ServerConfig{
 		PublicKeyCallback: s.authenticate,
-		ServerVersion:     "SSH-2.0-forged",
+		ServerVersion:     "SSH-2.0-gitbayd",
 	}
 	signers, err := loadHostKeys(cfg)
 	if err != nil {
@@ -158,7 +158,7 @@ func (s *Server) handleSession(sconn *ssh.ServerConn, ch ssh.Channel, reqs <-cha
 			return
 		case "shell":
 			req.Reply(true, nil)
-			fmt.Fprintf(ch, "forge control plane: interactive shells are not available.\nTry: ssh %s help\n", s.cfg.Server.SiteURL)
+			fmt.Fprintf(ch, "gitbay control plane: interactive shells are not available.\nTry: ssh %s help\n", s.cfg.Server.SiteURL)
 			sendExit(ch, protocol.ExitUsage)
 			return
 		case "pty-req", "env":
@@ -190,7 +190,7 @@ func (s *Server) runExec(sconn *ssh.ServerConn, ch ssh.Channel, cmdline string)
 
 // Exec runs one SSH exec command line for an authenticated key. It is the
 // single dispatch path shared by the embedded listener and the system-sshd
-// forced command (forged shell).
+// forced command (gitbayd shell).
 func Exec(cfg config.Config, st *store.Store, user store.User, scope, cmdline string,
 	stdin io.Reader, stdout, stderr io.Writer) int {
 	argv, err := protocol.Tokenize(cmdline)
diff --git a/internal/store/signatures.go b/internal/store/signatures.go
index b962ad6..01533dd 100644
--- a/internal/store/signatures.go
+++ b/internal/store/signatures.go
@@ -5,7 +5,7 @@ import (
 	"errors"
 	"time"
 
-	"github.com/krazywarez/forge/internal/sig"
+	"gitbay.org/gitbay/internal/sig"
 )
 
 // AddPGPKey registers an OpenPGP key and bumps the key epoch.
diff --git a/internal/store/store_test.go b/internal/store/store_test.go
index 7a2e74c..be51ddf 100644
--- a/internal/store/store_test.go
+++ b/internal/store/store_test.go
@@ -8,7 +8,7 @@ import (
 
 func open(t *testing.T) *Store {
 	t.Helper()
-	s, err := Open(filepath.Join(t.TempDir(), "forge.db"))
+	s, err := Open(filepath.Join(t.TempDir(), "gitbay.db"))
 	if err != nil {
 		t.Fatal(err)
 	}