Skip to content
CodeLifter Forum

How can a team enforce an Assisted-by trailer on commits?

Staff answerWritten by CodeLifter editors · 0 replies · updated

Short answer

Check for the trailer in two places: a commit-msg hook that stops the commit on the developer's machine, and a CI job that checks every commit in a pull request and blocks the merge. The hook is a convenience that can be skipped; the CI check is the rule. Neither can tell whether the line is true.

CiteCodeLifter Forum, "How can a team enforce an Assisted-by trailer on commits?", https://forum.codelifter.com/posts/how-can-a-team-enforce-an-assisted-by-trailer-on-commits/, accessed 2026-10-16.
Written by CodeLifter editors · Staff, CodeLifter ·
  1. Staff, CodeLifter ·

    Decide what the rule actually says

    A check can only test for text, so write the rule first. Three decisions matter:

    1. Which key. The Linux kernel asks AI-assisted contributions to include an Assisted-by tag. Mesa uses Assisted-by, keeps Generated-by for commits where almost all the code was generated, and reserves Co-authored-by for human co-authors. The Apache Software Foundation recommends a Generated-by: token. Pick one key and write it down.
    2. Every commit or only assisted ones. A check cannot detect assisted commits that leave the trailer out. If you want enforcement, the workable form is to require the trailer on every commit, with an explicit value such as Assisted-by: none when no tool helped. That none value is a team convention, not something the kernel or Mesa specify; projects that follow those documents only add the trailer when a tool was used.
    3. What the value must contain. The kernel's guidance and LLVM's policy both keep the human contributor responsible for the change, and LLVM gives an Assisted-by line as its example of labelling tool-generated content. A free-text value naming the tool is enough for most teams; a team that wants to count usage can require a fixed list of tool names.

    The policy tracker at CodeLifter's AI-code policy tracker lists which projects ask for which label, if you want to align with an upstream you contribute to.

    How Git reads a trailer

    The git-interpret-trailers manual defines a trailer as a key-value pair with a colon as the separator, in a block at the end of the message that must be preceded by a blank line. Its --parse option prints only the trailers it finds. That is the part to check, rather than searching the whole message, because a body line that happens to start with Assisted-by: in the middle of a paragraph is not a trailer.

    A valid message looks like this:

    feat: add keyboard support to the slideshow
    
    Arrow keys move between slides; focus stays on the controls.
    
    Assisted-by: code assistant (tests written by hand)
    

    To add the line to a message file from a script, the same manual documents git interpret-trailers --trailer "Assisted-by: none" --in-place msg.txt.

    Step 1: a commit-msg hook on each machine

    The githooks documentation says the commit-msg hook receives one parameter, the file holding the proposed message, and that a non-zero exit aborts the commit. Save this as .githooks/commit-msg in the repository and make it executable with chmod +x .githooks/commit-msg:

    #!/bin/sh
    # Reject the commit if the message has no Assisted-by trailer.
    if ! git interpret-trailers --parse "$1" | grep -qi '^Assisted-by: '; then
      echo "commit-msg: add an Assisted-by: trailer (Assisted-by: none if no tool helped)" >&2
      exit 1
    fi
    

    Each developer then runs git config core.hooksPath .githooks once in their clone. By default hooks live in $GIT_DIR/hooks, and core.hooksPath is the documented way to point Git somewhere else, which lets you keep the hook under version control.

    Two limits, both in the same documentation: the hook only runs where someone has set it up, and commit-msg can be bypassed with --no-verify. Commits created through a hosting service's API do not pass through anyone's local Git, so local hooks never see them, which matters if an agent commits through an MCP server; see who is the author of a commit made through an MCP server.

    Step 2: a CI check on every pull request

    This is the step that enforces the rule. Save the script as scripts/check-trailers.sh:

    #!/bin/sh
    # usage: scripts/check-trailers.sh <base> <head>
    fail=0
    for c in $(git rev-list --no-merges "$1..$2"); do
      if ! git log -1 --format=%B "$c" | git interpret-trailers --parse | grep -qi '^Assisted-by: '; then
        echo "missing Assisted-by trailer: $(git log -1 --format='%h %s' "$c")"
        fail=1
      fi
    done
    exit $fail
    

    Then:

    1. In your CI configuration, make sure the checkout includes the history between the target branch and the pull request. A shallow checkout of one commit does not contain the range the script walks; look for a fetch depth setting.
    2. Run sh scripts/check-trailers.sh origin/main HEAD, replacing main with your target branch.
    3. Make the merge depend on that job passing. The setting has a different name on each hosting service, so look for required or blocking status checks in your repository's branch settings.
    4. If your repository squash-merges, the commit that lands is a new one with its own message. Check that message too, or the trailer can be lost at the last step.

    Step 3: a server hook if you host Git yourself

    On a self-hosted server you can run the same loop in a pre-receive hook. The githooks documentation says pre-receive reads one line per ref on standard input, in the form <old-oid> <new-oid> <ref-name>, and that a non-zero exit means none of the refs are updated. Feed each old and new pair to the loop above. For a new branch the old value is all zeroes, so compare against your main branch instead.

    What enforcement cannot do

    Check Stops a missing trailer Can be skipped Proves the trailer is true
    commit-msg hook On machines where it is set up Yes, with --no-verify No
    CI check on pull requests Yes, if the merge requires it By whoever can change the merge rules No
    pre-receive hook (self-hosted) Yes, at push time Only by the server admin No

    Every row ends in "No" for the same reason: a trailer is a statement a person makes. The value of the check is that the statement always exists and someone signed off on it. If a reviewer later doubts it, the conversation is about the code and the person, as covered in a detector flagged code written in 2019 as AI. For how projects word the disclosure itself, see disclosing AI help in commits.

    0
    ReplyLink

Write a reply

Plain text or simple Markdown. Links are nofollow. Your email is never shown.