Install once, use everywhere
One FlowForge install covers every repo on your machine. This page covers the day-to-day workflow: registering repos, switching between them in the TUI, handling Git worktrees, and unregistering cleanly when a project ends.
If you work across multiple client projects, open-source repos, and your own SaaS, that means one FlowForge install handles all of them — no reinstalling, no version drift between projects, no configuration files duplicated across repos.
Each registered repo gets a thin shim layer (five Git hooks, a small .claude/ directory) and nothing else. All session state, billing, audit log, and per-developer data lives under ~/.flowforge/repos/<repo-id>/ — well outside your customer repo’s working tree.
The conceptual model
Section titled “The conceptual model”~/.flowforge/ ← installed once, owned by you├── bin/flowforge ← the binary├── agents/, slash-commands/ ← single source of truth (FF-managed)├── repos/│ ├── index.json ← registry: repo-id → worktree path│ ├── a3f2b8e91c4d/ ← state for repo #1│ ├── 9f1c4d3b8e92/ ← state for repo #2│ └── 2c8b9f1e4a3d/ ← state for repo #3└── ...
~/customer-project-1/ ← stays clean; structural floor only├── .git/hooks/│ ├── pre-commit ← 29-line shim → ~/.flowforge/bin/flowforge-hook│ ├── post-commit ← same│ ├── pre-push ← same│ ├── commit-msg ← same│ └── post-checkout ← same└── .claude/ ├── agents → ~/.flowforge/agents (symlink) ├── commands → ~/.flowforge/slash-commands (symlink) └── settings.json ← rendered (references this worktree path)This is the floor — there is no other touch. No .flowforge/ directory in your repo. No third-party dependency manifests added. No node_modules/, no package.json, no Python virtualenv. Your git status after a fresh registration shows only the .claude/ additions (untracked unless you choose to commit them).
The hook shims are byte-identical across every repo you register, for a given FlowForge version.
No per-repo logic to drift. No per-repo install path to keep in sync. That’s the structural fix v1.0 ships.
Register a new repo
Section titled “Register a new repo”Two paths: the TUI, or the CLI.
Via the TUI (recommended)
Section titled “Via the TUI (recommended)”cd /path/to/new-projectflowforge tuiIf you have no active repo, you land on the Repo Switcher panel. Press r to open the Register Repo modal:
╭─ FlowForge 3.0 — Repo Switcher ──────────────────────────── TIME: 00:02:14 ─╮│ ││ Select a repo to start working, or register a new one. ││ ││ ┌─ Registered Repos (3) ──────────────────────────────────────────────────┐ ││ │ │ ││ │ ▶ myorg/flowforge ● #1011 install-arch active 2m │ ││ │ ~/.flowforge/repos/a3f2b8e91c4d/ │ ││ │ │ ││ │ acme/api-service ○ ─ ─ 3h ago │ ││ │ ~/.flowforge/repos/9f1c4d3b8e92/ │ ││ │ │ ││ │ acme/frontend ○ ─ ─ 1d ago │ ││ │ ~/.flowforge/repos/2c8b9f1e4a3d/ │ ││ │ │ ││ └──────────────────────────────────────────────────────────────────────────┘ ││ │╰─ [Enter] switch [r] register [u] unregister [m] migrate [?] help [q] quit ╯Visual cues:
●= timer running on that repo○= idle⚠ FF v<X> (drift)= the repo was registered against a different FF version than the one currently installed
The Register Repo modal validates as you type (300 ms debounced async): “Path is a Git repo? Yes. Remote URL detected? github.com/myorg/new-project. Repo ID computed? 7e2a1f9c4d3b. Already registered? No.” Press Enter and the registration completes — typically under one second on local disk; up to a couple of seconds on NFS or sshfs.
Via the CLI
Section titled “Via the CLI”flowforge register-repo /path/to/new-projectSame effect, no TUI. Useful in scripts and CI bootstrap (though for CI, the v1.0 hook shims fail-open in environments without FlowForge installed, so CI runners do not need to register).
Repo identity, briefly
Section titled “Repo identity, briefly”The repo ID is sha256(canonical_remote_url)[:12]. Two consequences:
- Forks are different repos. Forking
myorg/flowforgetoacme/flowforgeyields a different remote URL and therefore a different repo ID; FlowForge sees them as distinct projects (which they are, for billing). Different remote URL = new repo ID, state resets. - Renames preserve identity. If you rename a repo on GitHub and accept the redirect, the canonical remote URL stays the same after canonicalization, and FlowForge keeps treating the repo as the same registration.
If two repos collide on the 48-bit hash (probability ~10⁻⁹ for 1000 repos on one machine), flowforge register-repo refuses and offers a --id-salt <user-string> override. The salt is recorded in meta.json for audit purposes.
Switch between repos
Section titled “Switch between repos”In the TUI, the Repo Switcher is always one keystroke away:
| Key | Action |
|---|---|
j / ↓ | move cursor down the list |
k / ↑ | move cursor up |
Enter | activate the highlighted repo (transitions to the four-panel cockpit scoped to that repo) |
r | open Register Repo modal |
u | unregister the highlighted repo (with confirm) |
m | migrate a legacy .flowforge/ install at pwd (only enabled when one is detected — see the migration guide) |
s | sync (refresh index.json from disk) |
Esc (from the cockpit) | return to the Repo Switcher |
q / Ctrl+C | quit FlowForge |
Activating a repo updates the four cockpit panels — workers, logs, merge queue, controller — to scope to that repo. The header banner shows PROJECT: <owner>/<repo> so you always know which repo is active.
The repo state under ~/.flowforge/repos/<repo-id>/ is what scopes everything: your billing, your developer partition, your sessions, your audit trail, your tasks cache. Switching repos in the TUI does not move data between repos; each repo’s state is fully separated.
Working with Git worktrees
Section titled “Working with Git worktrees”FlowForge is worktree-aware. If you have multiple worktrees of the same repo (e.g., git worktree add /srv/projects/myproject-feature-x feature/x), all worktrees share the same registered repo — they have the same canonical remote URL and therefore the same repo ID.
The hook router resolves the active worktree per invocation. The shim does this with git rev-parse --show-toplevel, which returns the worktree’s actual path — not the main checkout’s path. The router then sets:
FF_REPO_ID— the registered repo IDFF_REPO_WORKTREE— the absolute path of the worktree this hook is firing inFLOWFORGE_BILLING_ROOT—~/.flowforge/repos/<repo-id>/
The FLOWFORGE_BILLING_ROOT env override is the compatibility seam with task-time.sh; it was introduced for worktree-aware billing in #982 and is preserved exactly under the v1.0 architecture. Your time tracking, your audit trail, and your developer-partitioned billing all keep working across worktrees without configuration.
This structurally fixes the worktree drift bug tracked in #849: per-repo hooks no longer hardcode any worktree path, because they have no logic — they hand off to the router, which resolves the worktree at invocation time.
What does not land in your customer repo
Section titled “What does not land in your customer repo”Just as important as what does land:
- No
.flowforge/directory. All FlowForge state lives under~/.flowforge/repos/<repo-id>/. - No bundled agents, commands, or skills. Those are global, under
~/.flowforge/. - No JavaScript runtime artifacts. No
package.json, nonode_modules/, nopackage-lock.json. - No vendored Python. The statusline and helpers run from
~/.flowforge/bin/. - No license keys or auth tokens in your repo. Authentication artifacts (when applicable) live under
~/.flowforge/.agent-auth/at the global level. - No FlowForge-specific Git config in your repo’s
.git/config. The hook shims are inside.git/hooks/, which is per-clone state Git does not track or sync.
Your .gitignore does not need a FlowForge section. Your CI does not need FlowForge installed (the hook shims fail-open without it). Your teammates who don’t use FlowForge see the .claude/ directory and the .git/hooks/ shims and either ignore them or use them — the shims are inert without ~/.flowforge/bin/flowforge-hook on the machine.
Unregister a repo
Section titled “Unregister a repo”flowforge tui# highlight the repo, press [u]Unregistering removes the entry from ~/.flowforge/repos/index.json and removes the hook shims and .claude/ symlinks from the customer repo’s working tree. The unregister flow includes a “preserve state? y/N” prompt — answer “yes” to keep ~/.flowforge/repos/<repo-id>/ (your billing history and audit trail) in case you re-register later, or “no” to delete the per-repo state directory entirely.
The customer repo is byte-equivalent to its pre-registration state after unregister, modulo any .claude/ files you authored yourself in that directory (FlowForge only removes what it created — its symlinks and its rendered settings.json entries tagged _flowforge_managed).
Customizing routing for your stack
Section titled “Customizing routing for your stack”FlowForge ships out-of-the-box routing for Python, Node.js, and Go projects — your Write/Edit operations dispatch to the right specialist agent (fft-backend, fft-frontend, etc.) based on path and extension conventions. For other stacks (Rust, Rails, Vue, Elixir, monorepos with non-standard layouts), a 30-second config override is the supported path.
Drop a .flowforge/config.json at your repo root:
{ "routing": { "paths": { "src/**": "fft-backend", "tests/**": "fft-qa" } }}Your routing.paths rules win over FF-shipped defaults (customer sovereignty in the customer’s working tree). When the hook can’t classify a file, it emits a non-blocking advisory to ~/.flowforge/logs/routing-advisory.jsonl — the write proceeds; the advisory tells you “consider adding a rule for this path.”
See the routing guide for the full schema, worked examples for five stacks, conflict-resolution rules (longest-literal-prefix-wins), and Rule #38 escalation discipline.
Next steps
Section titled “Next steps”- Migrating from a legacy install — if you have an existing per-project
.flowforge/install, the migration guide walks you through the cutover with a dry run, automatic backup, and rollback support. - Installation reference — the standalone architecture’s offline-stable and paid-layer model, for context on what your FlowForge install includes.
- Customizing routing — override agent dispatch for non-standard project layouts.
References
Section titled “References”- ADR-0025: Single-Install Architecture — the canonical decision.
- TUI-PANELS-SPEC.md — Repo Switcher and Register Repo panel design.
- HOOK-SHIM-CONTRACT.md — what’s in those five hook shims and how the router resolves worktrees.
- OPTIONS.md §α.2 — repo identity computation.