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
- Distinctive: line 8
Run two agents on one repository and the first question you cannot answer is *who wrote this?*
- Very specific: line 31
Use a synthetic domain for the email.
- Distinctive: line 81
If your trunk squash-merges, per-workspace authorship is lost on the trunk — the squash commit is authored by whichever account performed …
- Distinctive: line 90
Default squash bodies concatenate the branch's commit messages, trailers included.
≈ “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.
Files
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" # ← thisconverts 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-aWork 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:
| Case | Expected | ||
linked work tree, extension on, --worktree set | exit 0, scope [worktree] | ||
identity written with --local, extension off | exit 1, "SHARED with every sibling" | ||
| the sibling that set nothing | exit 1 — reports the other workspace's name | ||
| extension off in a linked work tree | exit 1, and names the ` | ` fallback as the danger | |
| no identity anywhere | exit 1, "one name for every agent" | ||
--expect-name mismatch | exit 1, naming both values | ||
| the main work tree | exit 0 with the cannot-tell note | ||
| not a git work tree | exit 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 checkThat 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.
In this repository30 other files it gives its agents.
- AGENTS.mdAGENTS.md
- a-finding-is-not-a-fix-requestSkill
- building-a-role-skillSkill
- capture-rough-explore-onceSkill
- claims-ledgerSkill
- commsSkill
- controls-in-forceSkill
- courierSkill
- dated-and-falsifiableSkill
- decision-recordsSkill
- definition-of-doneSkill
- designerSkill
- docs-that-catch-driftSkill
- dreamingSkill
- emitted-is-not-publishedSkill
- hooks-that-reach-the-modelSkill
- ios-engineerSkill
- mast-checklistSkill
- measure-agents-honestlySkill
- observerSkill
- plannerSkill
- platformSkill
- pre-registered-watchSkill
- security-portableSkill
- securitySkill
- skill-home-and-provenanceSkill
- squigSkill
- stewardSkill
- the-team-agreementSkill
- two-consumersSkill
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.

