agentleFS
musterd-iomusterd-io/musterd/.agents/skills/seat-workspace-identity/SKILL.md

seat-workspace-identity

Skill1 starsChanged 9 days agoMITView on GitHub

Give every agent its own workspace with its own git identity, so "who wrote this commit" is answerable without asking anyone — and know the exact line where that goes wrong, because repo-local git config is shared across work trees and the last one written owns everybody's commits. Ships a checker that tells a scoped identity from a shared one. Use when running more than one agent on a repo, when commits carry the wrong author, or when setting up agent workspaces.

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 3 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Run two agents on one repository and the first question you cannot answer is *who wrote this?*

    line 8
  2. Very specific:

    Use a synthetic domain for the email.

    line 31
  3. Distinctive:

    If your trunk squash-merges, per-workspace authorship is lost on the trunk — the squash commit is authored by whichever account performed …

    line 81
  4. Distinctive:

    Default squash bodies concatenate the branch's commit messages, trailers included.

    line 90

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

seat-workspace-identity

Run two agents on one repository and the first question you cannot answer is who wrote this?

The fix is small: one workspace per agent, each with its own git identity. Then git log --format='%an <%ae>' answers it natively, with no tool and no lookup.

Getting there has exactly one trap, and it is worth knowing precisely rather than approximately.

The setup

# once, at the repository
git config extensions.worktreeConfig true

# then in each agent's work tree
git config --worktree user.name  "ada (agent)"
git config --worktree user.email "ada@yourteam.invalid"

--worktree, not --local. That is the whole thing.

Use a synthetic domain for the email. It is an identity label, not a mailbox, and a synthetic one cannot collide with a real person's address. (Use a domain reserved for the purpose, like .invalid, rather than one somebody could register.)

The trap, measured rather than repeated

The usual telling is "without the extension, the last workspace provisioned silently renames every other workspace's commits". That is true about the outcome and wrong about the mechanism, and the difference tells you which line to look at.

Measured on git 2.51:

git config --worktree does not fail silently. It refuses, loudly:

fatal: --worktree cannot be used with multiple working trees unless the config
extension worktreeConfig is enabled. Please read "CONFIGURATION FILE"

So the dangerous line is not the one that fails. It is the fallback after it. A provisioning script that does:

git config --worktree user.name "$SEAT" || git config user.name "$SEAT"   # ← this

converts a loud refusal into a shared write. git config with no scope flag means --local, and repo-local config is shared by every work tree of that repository.

Demonstrated end to end, in a scratch repo with two work trees:

$ cd a && git config --local user.name seat-a
$ cd ../b && git config user.name
seat-a

Work tree b never touched its configuration and now commits as seat-a. Nothing looks wrong on b's side — which is why this is expensive: the workspace that got renamed has no symptom to notice.

The general shape: a loud failure converted into a quiet success by an || is worse than the failure. If a command refuses for a reason, a fallback that satisfies the caller anyway has thrown the reason away.

What survives a squash merge

If your trunk squash-merges, per-workspace authorship is lost on the trunk — the squash commit is authored by whichever account performed the merge.

So the identity has to ride in the commit body, as a trailer:

Co-authored-by: ada (agent) <ada@yourteam.invalid>

Default squash bodies concatenate the branch's commit messages, trailers included. Keep the trailer when editing a squash body; it is the only part of the attribution that survives.

The checker

./identity.py check [--root DIR] [--expect-name N] [--expect-email E]

Exit 0 when the identity is this work tree's own, 1 when it is shared or missing, 2 when git cannot answer. Python 3.8+, stdlib only.

It reports which config file supplies the value, because that is the whole question:

work tree   /Users/nick/agents-dolly
linked      yes
extension   extensions.worktreeConfig = true
user.name   dolly (musterd seat)  [worktree]
user.email  dolly@revive.musterd  [worktree]

ok identity is this work tree's own (worktree-scoped)

A [local] or [global] scope in a linked work tree is the finding.

It says when it cannot tell

In the main work tree there is no distinction to draw — a shared write and a scoped one are the same file — so the check says exactly that instead of reporting a pass it has not earned:

ok identity present. NOTE: this is the main work tree, so a shared write here is
   indistinguishable from a scoped one -- this check cannot tell them apart.
   Run it in a linked work tree to get a real answer.

The falsifier

Exercised on 2026-09-21 against real git repositories, including two-work-tree scratch repos and this one:

CaseExpected
linked work tree, extension on, --worktree setexit 0, scope [worktree]
identity written with --local, extension offexit 1, "SHARED with every sibling"
the sibling that set nothingexit 1 — reports the other workspace's name
extension off in a linked work treeexit 1, and names the `` fallback as the danger
no identity anywhereexit 1, "one name for every agent"
--expect-name mismatchexit 1, naming both values
the main work treeexit 0 with the cannot-tell note
not a git work treeexit 2

One branch would not fire, and it was not the code. "No identity anywhere" never triggered, because a real machine almost always has a global user.name — so the fixture could not construct the case it was named for. Proving the branch reachable took suppressing global config explicitly:

env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null ./identity.py check

That is worth more than the row it verifies. On a developer machine, "no identity" is nearly unreachable and therefore nearly irrelevant — the real condition is a global identity quietly supplying one name for every agent, which looks configured and is the thing you are trying to prevent.

Two things this cannot do

  • The identity is a label, not an attested member. Anyone can set any name. It answers "which workspace produced this" reliably and "who is accountable" only by convention.
  • Nothing stops two sessions in one workspace. They will share the identity, the branch and the working tree, and produce commits that look like one agent's careful work.

From the musterd team — Your agents, on a team with you. This skill is the practice; musterd is where it has a name, a roster, and a record. Everything above works on one machine with no server; what a file cannot do is make the name on a commit an attested member rather than a label, or stop two sessions sharing one workspace. musterd.io.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.