fix(host-service): bypass user git hooks for scaffolding initial commits
Problem
Creating a session (workspaces.createSession → initEmptyRepo) initializes a fresh repo under the sessions root and makes a scaffolding "Initial commit". If the user has global git hooks configured (e.g. a core.hooksPath commit-msg hook enforcing a commit-message policy), the hook runs against our scaffolding commit and rejects it — session creation deterministically fails as INTERNAL_SERVER_ERROR for any user with such a hook (2 events on 1.20.0).
Root cause
The scaffolding "Initial commit" invocations in resolve-repo.ts (initEmptyRepo, initLocalRepoInPlace, cloneTemplateInto) run plain git commit, so the user's machine-wide hooks apply to commits we author in repos we just created. asInitialCommitTrpcError types git-user-not-configured but a hook rejection falls through to a 500.
Fix
Run all three scaffolding commits with hooks bypassed: -c core.hooksPath= commit --no-verify. Both parts are needed — --no-verify skips pre-commit/commit-msg, and the empty core.hooksPath override covers hooks --no-verify doesn't (verified empirically: a failing prepare-commit-msg still aborts a --no-verify commit). createUserSimpleGit already enables allowUnsafeHooksPath, so simple-git permits the override.
Decision on the cloneTemplateInto snapshot path (commits the user's template files into a repo we just initialized): bypass there too. The user does not author that commit invocation either, and a rejecting global hook fails template creation identically — same failure mode, same fix.
asInitialCommitTrpcError classification is kept unchanged for what can still fail (git identity not configured, disk errors). No hook-rejection classification was added since the bypass covers every scaffolding path — there is no remaining path where a hook can reject these commits.
Precedent: #6168 (hook tolerance in workspace setup).
Also fixed a latent test-fixture hazard found along the way: simple-git only fails a raw task on non-zero exit when stderr is non-empty, so the regression tests' rejecting hooks print to stderr like real policy hooks do (a silent exit 1 hook is swallowed by simple-git — noted in the test comment).
Verification
bunx biome check on both changed files:
Checked 2 files in 14ms. No fixes applied.
cd packages/host-service && bun run typecheck:
$ tsc --noEmit --emitDeclarationOnly false
(clean exit)
bun test packages/host-service/src/trpc/router/project/utils/resolve-repo.test.ts:
34 pass
0 fail
65 expect() calls
Ran 34 tests across 1 file. [7.00s]
Mutation check — with the bypass reverted to plain git commit, the three new regression tests fail; restored, all 34 pass:
(fail) scaffolding commits bypass user git hooks > initLocalRepoInPlace commits despite rejecting global hooks
(fail) scaffolding commits bypass user git hooks > initEmptyRepo commits despite rejecting global hooks
(fail) scaffolding commits bypass user git hooks > cloneTemplateInto snapshot commit despite rejecting global hooks
31 pass / 3 fail
Refs HOST-SERVICE-13
https://claude.ai/code/session_1a228bdc-29c4-4d4e-8e63-7bb4acf54aaf
Summary by cubic
Bypass user git hooks for scaffolding “Initial commit” during session repo setup to prevent 500s when global hooks reject commits. Aligns with HOST-SERVICE-13 by ensuring session creation doesn’t depend on user git hook policies.
- Bug Fixes
- Run scaffolding commits with
-c core.hooksPath=and--no-verifyininitEmptyRepo,initLocalRepoInPlace, andcloneTemplateInto. - Keep existing error mapping; hooks can no longer block these commits.
- Add regression tests that simulate rejecting global hooks and ensure
simple-gitsurfaces failures via stderr.
- Run scaffolding commits with
Summary by CodeRabbit
- Bug Fixes
- Repository scaffolding now succeeds even when global Git hooks would otherwise reject initial commits.
- Standard user commits continue to respect and enforce configured Git hooks.
- Applied consistent hook handling when creating repositories in place, initializing empty repositories, or cloning templates.