Zero AI fingerprints in your git history.
Your AI pair leaks more than you think — co-author trailers, branch prefixes, telltale commit cadences, stray .agent-trace files. ghost-author strips it all before it reaches origin.
Run ghost-author on your feature branch, before pushing or opening a PR. That way every commit that lands on main/master is already clean — you never need to rewrite shared history.
# 1. Finish your work on the feature branch
git checkout my-feature
# 2. Audit for AI traces
ghost-author audit --branch my-feature
# 3. If traces are found, clean and push atomically
ghost-author clean --branch my-feature --sync--sync rewrites the commit history and immediately force-pushes the branch to origin so local and remote stay in sync. Without --sync the rebase changes all commit hashes, causing the branch to diverge from origin — you would need to run git push --force-with-lease origin my-feature manually.
Why does master diverge?
ghost-author cleanrunsgit rebaseto strip AI traces, which rewrites every affected commit hash. If the branch was already pushed, local and remote now point at different histories. Use--sync(or a manualgit push --force-with-lease) to reconcile. Never run clean on a branch that teammates have already checked out unless you can coordinate the force-push with them.
When to run clean — not after merging
Once commits land onmain/masterand others have pulled them, rewriting that history is disruptive. The right moment is before the PR is merged, while you still own the branch. Thepre-pushhook installed byghost-author initcatches any stray trailers as a final safety net on push.
# curl one-liner
curl -fsSL https://raw.githubusercontent.com/eshwarcvs/ghost-author/master/install.sh | bash
# or npx (no install)
npx ghost-author setupThat's it. Run it inside any git repo.
Eight defense layers, applied in order. Anything that survives one gets caught by the next.
| # | Layer | Where it runs | What it kills |
|---|---|---|---|
| 1 | Agent config injection | .claude/, .cursor/, AGENTS.md, CLAUDE.md |
Tells the model not to add trailers in the first place |
| 2 | prepare-commit-msg hook |
Local, every commit | Co-authored-by: trailers, Generated-by:, 🤖 markers |
| 3 | Branch-name sanitizer | Local, on checkout | claude/*, cursor/*, codex/*, aider/* prefixes |
| 4 | Author-email guard | Local, every commit | *@anthropic.com, *@openai.com, noreply@cursor.sh |
| 5 | .gitignore patches |
Repo | .agent-trace, .aider*, .cursor-tutor, .codex-cache |
| 6 | pre-push hook |
Local, before push | Anything 1–5 missed; configurable warn / block / silent |
| 7 | PR template | .github/ |
Strips telltale "Generated with…" footers from PR bodies |
| 8 | CI audit workflow | GitHub Actions | Last line of defense — fails the PR if a trailer slips in |
If you're wondering whether this is overkill, here's what a typical AI-assisted commit looks like in the wild:
- Branch names —
claude/fix-auth-bug-aB3xY,cursor-composer/refactor,codex/implement-… - Co-author trailers —
Co-authored-by: Claude <noreply@anthropic.com>,Co-authored-by: GitHub Copilot <…> - Commit message patterns — emoji prefixes, "Generated with Claude Code" footers, suspiciously balanced bullet lists
- PR descriptions —
## Summary/## Test planboilerplate,https://claude.ai/code/...links, "Co-Authored-By" footers - Stray files —
.agent-trace,.aider.chat.history.md,.cursor-tutor/,.codex-cache/ - Author emails — commits actually authored by
claude@anthropic.comorcopilot@github.cominstead of you
GitHub indexes all of this. Recruiters, auditors, and git log | grep notice.
Out of the box:
- Claude Code —
.claude/settings.local.json+CLAUDE.md - OpenAI Codex —
AGENTS.md - Cursor —
.cursor/rules/ghost-author.mdc - Windsurf —
.windsurfrules - Aider —
.aider.conf.yml+ ignore patterns - Devin — repo-level instructions
- GitHub Copilot — commit-message scrubbing (Copilot doesn't take repo rules, so we catch it at the hook)
New agent? Drop a config in configs/ and open a PR.
For people who don't trust install scripts (fair).
git clone https://github.com/eshwarcvs/yourname.git ~/.ghost-author
cd your-project
bash ~/.ghost-author/setup.shOr wire the hooks yourself:
cp ~/.ghost-author/hooks/prepare-commit-msg .git/hooks/
cp ~/.ghost-author/hooks/pre-push .git/hooks/
chmod +x .git/hooks/prepare-commit-msg .git/hooks/pre-push| Option | Commands | Description |
|---|---|---|
--branch <name> |
audit, clean |
Branch to operate on. Defaults to auto-detecting main or master; falls back to the current branch. Checks out the branch if you are not already on it. |
--sync |
clean |
After rewriting history, force-push the branch to origin with --force-with-lease. Keeps local and remote in sync automatically. |
--limit N |
audit, clean |
Number of recent commits to scan (default: 50). |
--yes / -y |
clean |
Skip the confirmation prompt before rewriting. |
--force |
init |
Overwrite existing AI-tool config files. |
Tune behavior with GHOST_AUTHOR_MODE:
| Value | Behavior |
|---|---|
block |
Hard-fail the push if AI trailers are found |
warn |
Print a warning, allow the push (default) |
silent |
Strip silently, never block |
Copy the audit workflow into your repo:
cp ci/ghost-audit.yml .github/workflows/
git add .github/workflows/ghost-audit.yml
git commit -m "ci: add ghost-author audit"This fails any PR whose commits contain Co-authored-by: lines pointing at known AI agents. Use it as a required check on main if you want belt-and-suspenders.
ghost-author uninstall # removes hooks and configs from the current repo
rm -rf ~/.ghost-author # or: npm uninstall -g ghost-authorIt leaves your commit history alone. If you want to retroactively rewrite history, that's git filter-repo territory and we won't do it for you.
Is this ethical? Yes. Ghostwriting has existed since writing did — speeches, books, code review comments, half of LinkedIn. The ideas, design decisions, and accountability are yours; the typing assistance is a tool, like an IDE or a linter. You don't credit your editor in a git trailer either.
Will this fool everyone? No. See limitations.
Does it modify already-pushed commits?
ghost-author clean rewrites commits via git rebase, which changes commit hashes. If the branch was already pushed you must follow up with git push --force-with-lease origin <branch> — or use --sync to do this automatically. On branches that teammates have pulled, coordinate the force-push with them first.
Why does my branch diverge after clean?
After clean rewrites history, local and remote have different commit graphs. This is expected. Run ghost-author clean --sync to rewrite and push in one step, or push manually: git push --force-with-lease origin <branch>. Never force-push a branch that others depend on without coordinating first.
Does it work with signed commits?
Yes — the prepare-commit-msg hook runs before signing.
ghost-author removes metadata fingerprints. It does not change the code you ship. Recent work on stylometric ML fingerprinting can identify AI-generated code from token distributions, comment density, and structural patterns alone — see arxiv:2601.17406 for a current overview. If you're trying to defeat that, you need to actually read and rework what the model produced. Which, frankly, you should be doing anyway.
This tool is for keeping your git log clean, not for academic dishonesty.
Issues and PRs welcome at github.com/eshwarcvs/ghost-author.
- New agent support → add a config under
configs/and a detection pattern inhooks/pre-push - Bug reports → include
ghost-author statusoutput and yourgit --version - Run
npm testbefore submitting
MIT — see LICENSE.