Add a `git_user:` block to the example bottle frontmatter with a
one-paragraph note on what it does + that either field can be
set independently. Other doc surfaces (manifest module docstring,
provisioner module docstrings) were updated alongside the
implementation commits.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mirror the docker backend's third provisioning subcase in
`backend/smolmachines/provision/git.py`:
_provision_git_user(plan, target)
Runs `smolvm machine exec --name <M> -e HOME=/home/node -e
USER=node -- runuser -u node -- git config --global user.<X>
<value>` for each git_user field. No-op when
`git_user.is_empty()`.
`runuser -u node --` switches the UID without invoking a login
shell (matching the existing `Bottle.exec_claude` pattern).
HOME / USER are forced via `smolvm -e` because bare runuser
inherits root's HOME=/root, which would put --global in
/root/.gitconfig instead of /home/node/.gitconfig (where the
existing `_provision_git_gate_config` writes).
4 unit tests in test_smolmachines_provision.TestProvisionGitUser:
no-op, both-set (asserts runuser prefix + HOME/USER env),
name-only, email-only. 661 unit tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a third provisioning subcase to
`backend/docker/provision/git.py`:
_provision_git_user(plan, target)
Runs `docker exec -u node <container> git config --global
user.{name,email} <value>` for each field the bottle's
`git_user` declares. No-op when `git_user.is_empty()`.
`-u node` so `--global` lands in /home/node/.gitconfig (matching
the existing `_provision_git_gate_config` write location, so
agent-side `git` reads both configs from the same dotfile).
Name and email apply independently — a bottle declaring only
name runs just the user.name line, etc.
4 unit tests in `test_docker_provision_git_user.py`: no-op,
both-set, name-only, email-only. 657 unit tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per-bottle `git config --global user.name` / `user.email` pair
so the agent's commits inside the bottle land with a known
identity rather than the agent image's default (no user, or
whatever the image dropped in).
Schema:
git_user:
name: "Eric Bauerfeld"
email: "eric+claude@dideric.is"
Either field can be set independently — name-only / email-only
configs are valid and apply just the field that's set. An
explicit `git_user:` block with both fields empty dies at parse
time rather than silently no-op'ing; an omitted block is the
no-op path (default GitUser is empty, provisioner skips).
Parse-time validation:
- Unknown sub-keys die (e.g., typo of `username`).
- Non-string name/email dies.
- Both-empty dies (half-finished edit hint).
11 unit tests in `test_manifest_git_user.py`; 653 unit tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>