Workflow Commit Identity Reference¶
This reference describes Amplihack workflow commit identity behavior. The shared
identity contract is implemented by amplifier-bundle/tools/git-identity.sh.
Every Amplihack recipe path that creates a commit uses that helper before
invoking git commit.
Contents¶
- Configuration variables
- Identity resolution order
- Validation rules
- Provider inference
- Shell helper API
- Helper script location resolution
- Recipe contract
- Failures
Configuration variables¶
Use explicit Amplihack identity variables when the repository cannot provide a safe local identity or when provider inference is not desired.
| Environment variable | Config key | Required | Description |
|---|---|---|---|
AMPLIHACK_GIT_AUTHOR_NAME |
git_identity.author_name |
Yes, for explicit author config | Author name for workflow-created commits. |
AMPLIHACK_GIT_AUTHOR_EMAIL |
git_identity.author_email |
Yes, for explicit author config | Author email for workflow-created commits. |
AMPLIHACK_GIT_COMMITTER_NAME |
git_identity.committer_name |
Optional pair | Committer name. Defaults to the author name only when both committer fields are omitted. |
AMPLIHACK_GIT_COMMITTER_EMAIL |
git_identity.committer_email |
Optional pair | Committer email. Defaults to the author email only when both committer fields are omitted. |
Example:
export AMPLIHACK_GIT_AUTHOR_NAME="Mona Example"
export AMPLIHACK_GIT_AUTHOR_EMAIL="mona@example.com"
export AMPLIHACK_GIT_COMMITTER_NAME="Mona Example"
export AMPLIHACK_GIT_COMMITTER_EMAIL="mona@example.com"
amplihack recipe run default-workflow \
-c repo_path=. \
-c task_description="Update provider-safe workflow commits"
Environment variables apply only to the workflow process and its child commit
steps. Amplihack config lives in ~/.amplihack/config as JSON:
{
"git_identity": {
"author_name": "Mona Example",
"author_email": "mona@example.com",
"committer_name": "Mona Example",
"committer_email": "mona@example.com"
}
}
Environment variables override config-file values. Amplihack does not write global Git configuration.
Partial explicit configuration is invalid. Set both author fields. Set both committer fields or omit both committer fields to use the author identity for the committer.
Identity resolution order¶
Before each Amplihack-created git commit, the workflow resolves a complete
author identity and a complete committer identity in this order:
- Explicit Amplihack environment variables and config:
AMPLIHACK_GIT_AUTHOR_*,AMPLIHACK_GIT_COMMITTER_*, andgit_identity.*. - Existing complete and safe Git environment variables for advanced callers:
GIT_AUTHOR_NAME,GIT_AUTHOR_EMAIL,GIT_COMMITTER_NAME, andGIT_COMMITTER_EMAIL. - Safe repository-local Git configuration from
user.nameanduser.email. - Authenticated provider context for the detected remote host.
- Fail-fast with remediation instructions.
Every source is validated before use. Unsafe values are rejected even when they come from explicit environment variables.
Validation rules¶
Amplihack requires complete names and email addresses for both author and committer identities. Missing committer fields default from the author only when both committer fields are absent; providing exactly one committer field fails validation.
An identity is rejected when any required field is missing or unsafe:
| Unsafe value | Examples |
|---|---|
| Missing name or email | Empty user.name, unset GIT_AUTHOR_EMAIL. |
| Malformed email | mona, mona@, mona example@example.com. |
| Localhost or machine-local email | mona@localhost, mona@vm, mona@localdomain. |
| VM account identity | azureuser@..., generated VM hostnames. |
| Service-looking email | Generic service, runner, build, or automation account emails. |
The check is intentionally fail-closed. If Amplihack cannot prove that the identity is user-intended, it stops before the commit instead of creating a misattributed commit.
Provider inference¶
Provider inference is used only after explicit variables, existing safe Git environment, and repository-local Git config are unavailable.
GitHub¶
For GitHub remotes, Amplihack uses the authenticated gh account when needed.
It prefers the account's public email when one is available. When the public
email is hidden, Amplihack uses the authenticated account's GitHub noreply
address.
For the name, Amplihack prefers a non-empty public profile name. If the profile name is absent, Amplihack falls back to the authenticated login. The resulting name and email must pass the same safety checks as explicit identities.
Example inferred identity:
GIT_AUTHOR_NAME=Mona Example
GIT_AUTHOR_EMAIL=12345678+mona@users.noreply.github.com
GIT_COMMITTER_NAME=Mona Example
GIT_COMMITTER_EMAIL=12345678+mona@users.noreply.github.com
GitHub inference fails if gh is unavailable, unauthenticated, or returns an
identity that does not pass validation.
Azure DevOps (azdo)¶
The canonical recipe host type for Azure DevOps is azdo. User-facing
azure-devops may be accepted as an input alias by workflow preparation, but
identity code and recipe context use azdo.
For Azure DevOps remotes, Amplihack first expects explicit Amplihack identity variables or safe repository-local Git config. If those are unavailable and the Azure CLI is authenticated, Amplihack may use the Azure CLI account identity only when it exposes a safe user email address.
Example safe Azure CLI account:
Example rejected Azure CLI accounts:
For Azure CLI inference, Amplihack uses the safe account email for both the Git name and email because the CLI does not consistently expose a separate human display name.
Azure DevOps inference is conservative because Azure-hosted development environments often expose VM-local identities that are not the user's intended commit attribution.
Shell helper API¶
Recipes source the shared helper:
amplihack_prepare_git_commit_identity¶
Resolves, validates, and exports all Git identity variables required for a commit:
On success, the function exports:
On failure, it prints a clear remediation message to stderr and returns nonzero.
amplihack_resolve_git_identity¶
Resolves the candidate author and committer identity using the documented
precedence order. This function is used by
amplihack_prepare_git_commit_identity and by tests that need to inspect
resolution without creating a commit.
amplihack_validate_git_identity¶
Validates a name and email pair. The function rejects incomplete, malformed, localhost-style, VM-looking, and service-looking identities.
amplihack_detect_remote_host_type¶
Classifies the repository remote as github, azdo, or unknown.
Provider inference uses this value to decide whether gh or Azure CLI identity
lookup is allowed.
Helper script location resolution¶
Before a recipe can source git-identity.sh, it must first find the file on
disk. The installed bundle layout differs across execution contexts, so every
commit-producing recipe step resolves the helper path with the same ordered
fallback chain rather than assuming a single location. This makes commit and
checkpoint steps robust when AMPLIHACK_HOME points at a downstream repository
checkout that does not itself contain an amplifier-bundle/ tree (for example,
a project consuming an installed amplihack), while the helper is present under
${HOME}/.amplihack/ or ${HOME}/.copilot/.
Resolution order¶
Each recipe step assigns GIT_IDENTITY_HELPER to the first candidate path that
exists, checked in this exact order. The chain adopts the same home-directory
fallback tail ($(pwd), then ~/.copilot, then ~/.amplihack) and
last-resort ordering as the sibling RUNTIME_ARTIFACT_HELPER chain used for
workflow_runtime_artifacts.sh. The leading candidates differ intentionally:
git-identity resolution uses git rev-parse --show-toplevel for the repository
top level, whereas the runtime-artifact helper uses ${REPO_PATH:-$(pwd)}:
| # | Candidate path | Resolves when |
|---|---|---|
| 1 | ${AMPLIHACK_HOME:-${REPO_PATH:-$(git rev-parse --show-toplevel)}}/amplifier-bundle/tools/git-identity.sh |
AMPLIHACK_HOME (or REPO_PATH, or the repo top level) contains the bundle. |
| 2 | $(git rev-parse --show-toplevel)/amplifier-bundle/tools/git-identity.sh |
The current repository root contains the bundle. |
| 3 | $(pwd)/amplifier-bundle/tools/git-identity.sh |
The working directory contains the bundle (worktrees where pwd differs from the top level). |
| 4 | ${HOME:-/root}/.copilot/amplifier-bundle/tools/git-identity.sh |
The bundle is installed under the Copilot home. |
| 5 | ${HOME:-/root}/.amplihack/amplifier-bundle/tools/git-identity.sh |
The bundle is installed under the amplihack home. |
Higher-trust, workflow-scoped locations (AMPLIHACK_HOME, REPO_PATH, repo top
level) are always tried first. The user-home install locations are tried last so
they never shadow an explicitly configured bundle path.
Candidate #1 is preserved verbatim per recipe and is not universal:
workflow-pr-review.yaml intentionally uses ${AMPLIHACK_HOME:-$(git rev-parse
--show-toplevel)} (no REPO_PATH) as its base. Only the three home-based
fallbacks (#3–#5) are appended identically across every recipe; see
Coverage.
The single-line form used in the commit steps is:
GIT_IDENTITY_HELPER="${AMPLIHACK_HOME:-${REPO_PATH:-$(git rev-parse --show-toplevel)}}/amplifier-bundle/tools/git-identity.sh"
[ -f "$GIT_IDENTITY_HELPER" ] || GIT_IDENTITY_HELPER="$(git rev-parse --show-toplevel)/amplifier-bundle/tools/git-identity.sh"
[ -f "$GIT_IDENTITY_HELPER" ] || GIT_IDENTITY_HELPER="$(pwd)/amplifier-bundle/tools/git-identity.sh"
[ -f "$GIT_IDENTITY_HELPER" ] || GIT_IDENTITY_HELPER="${HOME:-/root}/.copilot/amplifier-bundle/tools/git-identity.sh"
[ -f "$GIT_IDENTITY_HELPER" ] || GIT_IDENTITY_HELPER="${HOME:-/root}/.amplihack/amplifier-bundle/tools/git-identity.sh"
[ -f "$GIT_IDENTITY_HELPER" ] || { echo "ERROR: git identity helper not found: $GIT_IDENTITY_HELPER" >&2; exit 2; }
. "$GIT_IDENTITY_HELPER"
All candidate assignments and every [ -f "$GIT_IDENTITY_HELPER" ] guard are
double-quoted to prevent word-splitting and glob expansion. The chain performs
no eval, adds no command substitution beyond the existing $(pwd) and
$(git rev-parse --show-toplevel), and never parses the contents of the helper
during resolution.
Fail-visible behavior¶
Resolution is fail-visible, never silent-degrade. When every candidate is
absent, the step prints
ERROR: git identity helper not found: <path> to stderr and exits 2. The
terminal exit 2 runs only after the full chain is exhausted, so a genuinely
missing helper still stops the workflow loudly instead of producing an
unattributed or skipped commit.
workflow-publish.yaml additionally documents a multi-line commit example in an
inline retry block. That block uses the same five candidate paths to locate the
helper before sourcing it, and by design it does not add an exit 2 guard — it
retains its original fail-open-to-source shape and only benefits from the added
resolution paths.
Coverage¶
The five-candidate chain is applied consistently in every recipe step that
sources git-identity.sh:
| Recipe | Step context |
|---|---|
workflow-finalize.yaml |
Finalization and cleanup commit step. |
workflow-refactor-review.yaml |
Review-feedback checkpoint commit step. |
workflow-pr-review.yaml |
PR review remediation commit step (base candidate omits REPO_PATH by design). |
workflow-tdd.yaml |
Implementation checkpoint commit step. |
workflow-publish.yaml |
Publish commit step and the multi-line outside-in retry example. |
consensus-publish.yaml |
Consensus result publication commit step. |
consensus-pr-feedback.yaml |
PR feedback publication commit step. |
Leading candidates are preserved verbatim per recipe: workflow-pr-review.yaml
intentionally starts from ${AMPLIHACK_HOME:-$(git rev-parse --show-toplevel)}
without REPO_PATH, and the three home-based fallbacks are appended without
rewriting it.
Regression contract¶
A regression test asserts that the helper is located via the
${HOME}/.amplihack/amplifier-bundle/tools/git-identity.sh fallback when both
AMPLIHACK_HOME and the repository top level lack an amplifier-bundle/ tree.
The test also keeps a negative control proving that a fully missing helper still
exits 2 (fail-visible), and static assertions that every recipe listed above
carries the complete five-candidate chain. The test uses a temporary HOME and
a disposable repository with trap ... EXIT cleanup and never writes to the
real ~/.amplihack or ~/.copilot.
Recipe contract¶
Every Amplihack recipe path that creates a commit calls
amplihack_prepare_git_commit_identity immediately before git commit.
The guard applies to every recipe with an executable git commit call. Current
known commit-producing recipe paths are:
| Recipe | Commit path |
|---|---|
workflow-publish.yaml |
Publish commits and follow-up publish commits. |
workflow-finalize.yaml |
Finalization and cleanup commits. |
workflow-pr-review.yaml |
PR review remediation commits. |
workflow-tdd.yaml |
Implementation checkpoint commits. |
workflow-refactor-review.yaml |
Review-feedback checkpoint commits. |
consensus-publish.yaml |
Consensus result publication commits. |
consensus-pr-feedback.yaml |
PR feedback publication commits. |
Recipes may stage files before identity preparation, but they must not run
git commit until the helper has exported a complete author and committer
identity for the current shell step.
Static coverage should search all recipe YAML files for executable git commit
calls and fail when a commit path does not prepare identity first. This prevents
future recipes from bypassing the helper.
Failures¶
When no safe identity is available, the workflow stops before the commit with a message that points to explicit configuration:
Amplihack could not determine a safe Git commit identity.
Set AMPLIHACK_GIT_AUTHOR_NAME and AMPLIHACK_GIT_AUTHOR_EMAIL, or configure
repository-local git user.name and user.email.
Recommended remediation:
export AMPLIHACK_GIT_AUTHOR_NAME="Mona Example"
export AMPLIHACK_GIT_AUTHOR_EMAIL="mona@example.com"
amplihack recipe run workflow-publish \
-c repo_path=. \
-c task_description="Publish completed workflow changes"
For persistent repository-local configuration without changing global Git config:
Do not fix this by setting global Git config on a shared VM. Global VM config can affect unrelated repositories and does not prove the identity was intended for the current workflow commit.
A commit step can also stop earlier, before identity resolution runs, when the helper script itself cannot be located on disk:
This is the separate, fail-visible exit 2 described under
Helper script location resolution. It
means every candidate path was absent, not that the identity was unsafe.
Remediation for that case is covered in the how-to guide's
"Fix a 'git identity helper not found' failure" section.