Wire host git identity into the devenv container

run-devenv-agentic now seeds the container's global git config from the
host on every bring-up so commits made inside the devenv (typically by
coding agents reached through start-coding-agent) carry a real
author/committer instead of the bare `penpot@<container>` fallback that
makes review unworkable.

New optional flags on run-devenv-agentic:

  --git-user-name NAME      author/committer name
  --git-user-email EMAIL    matching email

When a flag is omitted the value is resolved from the host's effective
`git config user.{name,email}` (plain `git config`, no --global) so a
per-repo override in <repo>/.git/config wins over ~/.gitconfig -- matching
what `git commit` on the host would actually record. If neither flag nor
host config provides a value the script prints a warning and continues;
in-container commits will fail until the user fixes it.

start-instance applies the values via two `docker exec ... git config
--global user.{name,email}` calls right after the container reaches
Running, before start-tmux.sh is launched. Keeps the write logic next to
the rest of the per-instance bring-up and out of the tmux script -- no
env-var contract between manage.sh and the tmux entry point is needed.

Docs updated in docs/technical-guide/developer/devenv.md (new "Git
identity inside the container" section) and the agentic-devenv guide.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael Panchenko 2026-05-27 13:37:45 +02:00 committed by alonso.torres
parent 5efec8fad5
commit ea5a2f6b4c
3 changed files with 86 additions and 4 deletions

View File

@ -85,6 +85,19 @@ instance up, so you don't need to compute the offsets by hand. See the
the workspace and lifecycle details (including the `--sync` flag and shutdown
shape).
**Git identity for agent commits.** Coding agents typically need to commit
inside the devenv, so `run-devenv-agentic` wires a Git identity into the
container's global config on every bring-up. By default it propagates the
host's effective `git config user.{name,email}` (local repo override wins
over `~/.gitconfig`, matching what `git commit` on the host would record).
Override either with `--git-user-name "Full Name"` /
`--git-user-email you@example.com` — useful when you want agent commits to
carry an identity different from your normal one. Without either source the
script warns and proceeds; commits made by the agent will fail until you fix
it. See the
[Dev environment guide](./devenv.md#git-identity-inside-the-container) for
the full mechanics.
> **Note:** the MCP and Serena tmux windows are only added when the session is
> first created. If you've already run `./manage.sh run-devenv` (non-agentic)
> in an instance, `run-devenv-agentic` errors out because the instance is

View File

@ -106,7 +106,27 @@ Container-internal ports stay fixed. Target a specific instance with
`start-coding-agent` (`--instance ws1` on `run-devenv-shell` /
`run-devenv`). The `--ws` flag accepts a **non-negative integer only**
`--ws main` or `--ws ws1` is rejected, keeping the flag shape uniform across
commands. `run-devenv-agentic` also accepts `--serena-context CTX`.
commands. `run-devenv-agentic` also accepts `--serena-context CTX` and
`--git-user-name NAME` / `--git-user-email EMAIL` (see below).
### Git identity inside the container
`run-devenv-agentic` wires a Git author identity into the container's
**global** git config (`git config --global user.{name,email}`) so commits
made from inside the devenv carry a real author/committer. Without this,
the container would commit as the unconfigured `penpot@<container>`
fallback — usable but useless for review.
The values come from `--git-user-name NAME` / `--git-user-email EMAIL`
when passed, or from your host's effective `git config user.{name,email}`
otherwise. "Effective" here means the values plain `git config user.X`
returns at the working directory `manage.sh` is invoked from — local
(`<repo>/.git/config`) overrides global (`~/.gitconfig`), matching what
`git commit` on the host would record. If neither is available the script
prints a warning and continues — commits will fail inside the container
until you set an identity. The values are applied every time
`run-devenv-agentic` brings an instance up (idempotent), so re-running
with different flags is the way to change the in-container identity.
### Shared state and workers

View File

@ -645,6 +645,8 @@ function parse-ws-integer {
function start-instance {
local instance="$1"
local serena_context="$2"
local git_user_name="${3:-}"
local git_user_email="${4:-}"
instance-compose "$instance" up -d --no-deps main redis
@ -660,6 +662,16 @@ function start-instance {
sleep 1
done
# Seed the container's global git config from the values resolved on the
# host so commits made inside the devenv carry a real author/committer. Empty
# values are skipped — the host-identity warning is the caller's job.
if [[ -n "$git_user_name" ]]; then
docker exec "$container" sudo -u penpot git config --global user.name "$git_user_name"
fi
if [[ -n "$git_user_email" ]]; then
docker exec "$container" sudo -u penpot git config --global user.email "$git_user_email"
fi
# Detached tmux so callers don't block on attach. Agentic mode is the only
# mode here, so MCP and Serena are always on.
docker exec -d \
@ -710,6 +722,14 @@ function print-instance-info {
# ws1+ also sync implicitly the first time when their workspace
# directory does not exist yet.
# --serena-context CTX passed to Serena (default: desktop-app).
# --git-user-name NAME Git author/committer name to wire into the
# container's global git config (so commits made inside the
# devenv carry a real identity). Defaults to the host's
# effective `git config user.name` when omitted (resolved at
# the current working directory, so a per-repo local override
# in <repo>/.git/config takes precedence over ~/.gitconfig).
# --git-user-email EMAIL matching email; defaults to the host's effective
# `git config user.email` (same local-over-global precedence).
#
# ws0 is the worker-bearer and must be running whenever any ws1+ is up. When
# starting ws1+, ws0 is brought up first automatically if it is not already
@ -718,6 +738,8 @@ function run-devenv-agentic {
local target="ws0"
local do_sync=false
local serena_context="desktop-app"
local git_user_name=""
local git_user_email=""
while [[ $# -gt 0 ]]; do
case "$1" in
@ -727,6 +749,10 @@ function run-devenv-agentic {
do_sync=true; shift;;
--serena-context)
serena_context="$2"; shift 2;;
--git-user-name)
git_user_name="$2"; shift 2;;
--git-user-email)
git_user_email="$2"; shift 2;;
*)
echo "run-devenv-agentic: unknown argument '$1'" >&2
return 1;;
@ -738,6 +764,26 @@ function run-devenv-agentic {
return 1
fi
# Fall back to the host developer's effective git identity when the
# respective flag is not provided. Plain `git config user.X` (no --global)
# honours the local->global->system precedence, so a per-repo override in
# <repo>/.git/config takes precedence over ~/.gitconfig -- matching what
# `git commit` on the host would actually record. `|| true` swallows the
# non-zero exit for a missing entry; the empty result is propagated
# untouched and surfaces as a no-op inside the container (start-tmux.sh
# skips `git config --global` when the env var is empty).
if [[ -z "$git_user_name" ]]; then
git_user_name="$(git config user.name 2>/dev/null || true)"
fi
if [[ -z "$git_user_email" ]]; then
git_user_email="$(git config user.email 2>/dev/null || true)"
fi
if [[ -z "$git_user_name" || -z "$git_user_email" ]]; then
echo "[$target] warning: host git identity is incomplete (name='${git_user_name}', email='${git_user_email}')." >&2
echo " Commits made inside the devenv will fail until you set it via --git-user-name / --git-user-email" >&2
echo " or 'git config user.{name,email}' on the host." >&2
fi
if devenv-main-running "$target"; then
echo "run-devenv-agentic: instance '$target' is already running." >&2
return 1
@ -753,7 +799,7 @@ function run-devenv-agentic {
echo "[ws0] not running; starting it first (workers run only on ws0)."
echo "Starting ws0..."
write-instance-mcp-configs "ws0"
start-instance "ws0" "$serena_context"
start-instance "ws0" "$serena_context" "$git_user_name" "$git_user_email"
print-instance-info "ws0"
fi
@ -772,7 +818,7 @@ function run-devenv-agentic {
echo "Starting $target..."
write-instance-mcp-configs "$target"
start-instance "$target" "$serena_context"
start-instance "$target" "$serena_context" "$git_user_name" "$git_user_email"
print-instance-info "$target"
}
@ -1185,7 +1231,10 @@ function usage {
echo " Auto-starts ws0 first when --ws N (N>=1) is requested (workers run only on ws0)."
echo " Options: --ws N (default: 0; non-negative integer only),"
echo " --sync (re-seed workspace from live repo; ws1+ only),"
echo " --serena-context CONTEXT (default: desktop-app)"
echo " --serena-context CONTEXT (default: desktop-app),"
echo " --git-user-name NAME / --git-user-email EMAIL"
echo " (default: host's effective 'git config user.{name,email}',"
echo " honouring per-repo local overrides)"
echo "- attach-devenv Attaches to the tmux session inside a running instance."
echo " Options: --ws N (default: 0; non-negative integer only)"
echo "- start-coding-agent <client> Launches an AI coding agent against one workspace with the right MCP config wired in."