iops-rooms
v0.5.9
Published
Rooms by I-Ops — local, inspectable shared rooms for agent sessions
Maintainers
Readme
Rooms by I-Ops
See who built your project — and which AI helped.
One of the layers of I-Ops, open sourced.
Point it at a git repo and find out who built it, and which agent signed the commit. No account, no server, no model deciding anything — the answer is recomputed from the repository every time.
npx iops-rooms weekiops-rooms · last 90d
124 commits · +17k −1.6k · 1 person
Claude 55 ██████████░░░░░░░░░░░░ 44%
Cursor 1 █░░░░░░░░░░░░░░░░░░░░░ 1%
no agent recorded 68 ████████████░░░░░░░░░░ 55%That is this repository, which is unusually well attributed because it is built by an agent that
writes the trailer. Most repositories look nothing like it. Here is anthropic-sdk-python, and
it is the more honest picture of what you should expect on a first run:
anthropic-sdk-python · last 3650d
500 commits · +161k −30k · 36 people
Claude 30 █░░░░░░░░░░░░░░░░░░░░░ 6%
Claude 26
Claude Code 1
Claude Opus 4.6 1
Claude Opus 4.7 1
and 1 more 1
co-author that says it is a bot 5 █░░░░░░░░░░░░░░░░░░░░░ 1%
co-author, no bot marker — usually a person 9 █░░░░░░░░░░░░░░░░░░░░░ 2%
no agent recorded 456 ████████████████████░░ 91%Six percent, in the repository of the company whose tool writes the trailer by default. Across six
well-known repositories — Anthropic's, OpenAI's, LangChain's, Astral's, Vercel's and tinygrad's —
1.5% of 3,000 commits carried a trailer this could attribute. If your repository comes back
mostly no agent recorded, that is the normal result and not a fault in your history. The
number is a floor, and on most repositories it is a very low one.
Four commands, all read-only, none of which needs a room:
| | |
|---|---|
| rooms week | what shipped this week and which agent helped, against last week |
| rooms branch | the mix for the commits on this branch — read it before you open the PR |
| rooms file src/auth.ts | who and which agent last touched a file that looks wrong |
| rooms badge --out agents.svg | a stacked bar for your README — like the one below |
Run them from anywhere inside the project. A repository is one project, so a command typed in
packages/web/src reports the whole repo — and rooms file app.ts still means the file next to
you, not one of the same name at the root.
no agent recorded is not no agent used. Cursor and Copilot often write no
Co-Authored-By trailer at all, so a plain commit only means none was recorded. Every share here is
a floor, never a measurement of how much of your code an AI wrote — and unlike a vendor
dashboard, it is blind to which vendor you use.
A trailer this tool does not recognise gets its own row rather than being folded into
no agent recorded. Ten agents are recognised by name today — Claude, Cursor, Codex, Copilot,
Devin, Gemini, Jules, aider, Amazon Q, Windsurf — and the eleventh appears in that row instead of
quietly lowering the floor.
There are two such rows, and neither of them says "agent". Until 0.5.7 there was one, labelled
co-author, not a known agent, and on astral-sh/uv it read 47% with a long bar sitting directly
above no agent recorded — so the page said, to any eye scanning it, that half the repository was
agent-written. Inside that row were Zanie Blue with 157 commits, Charlie Marsh with 14, and a
handful of release bots. Not one AI agent in the top twelve. The label was true and the number read
as something else, which is the failure this tool exists to refuse.
They are split on [bot], which GitHub appends to every App account, so it is the platform's own
marker rather than a guess about anybody's name. A release bot that does not mark itself lands with
the people — that understates automation instead of overstating it, and calling somebody's
colleague a robot is the more expensive mistake.
One row per agent; the model goes underneath it. anthropic-sdk-python reported Claude Code
five separate times — Claude, Claude Opus 4.6, Claude Opus 4.7, Claude Opus 4.7 (1M context)
and, from a hook that wrote its template instead of its value, Claude Code (${CLAUDE_PROJECT_DIR})
— so the one agent anybody was looking for never appeared as a number. The agent and the model are
two different questions; the row answers the first and the lines beneath it answer the second.
Counts can overlap; percentages cannot. A commit with two agents on it appears in both of their counts, because both of them were there. The percentages split that commit evenly so the rows always total 100, and the output says how many commits were split.
Then, when you want the picture rather than the number:
npm i -g iops-rooms
rooms openThe room lands at the root of the repository however deep in it you were standing, so everyone on
the project shares one. The first time, if you have the gh CLI signed in, it offers once to link
your GitHub account so your posts carry a verified name — after the board has opened, never before,
and never at all in a pipe, in CI, or a second time if you say no. ROOMS_NO_PROMPT=1 turns it off
outright. Nothing is uploaded either way.
Where that comes from, and what it is not. Claude Code and Cursor both write a
Co-Authored-By trailer on the commits they help with, so the attribution is already in your repo
and in every clone of it. Rooms reads git and nothing else — not .cursor/, not Claude's session
files, not any tool's private state. A commit with no trailer is shown as the person's own, not
as an unknown.
On top of that, a live room: a timeline with a row per branch and one zoomable time axis, a dot per commit and per post that opens into a list, and a shared transcript on disk that a team syncs through their own git remote. Terminal plus a static HTML board. Network off for individual use.
Runs on macOS, Linux and Windows, on Node 20, 22 and 24. Linux and Windows are tested on every change; macOS runs weekly and on demand, because it bills at ten times the minutes and is the platform this is developed on.
Pin a version. Do not run @latest.
What the board shows about your project
| | from | needs |
|---|---|---|
| Every commit, its author, its +/− lines | git log | nothing |
| Which agent co-authored it — Claude Opus 5, Fable, Cursor, Codex | Co-Authored-By trailers | nothing |
| Branches splitting from main and rejoining, with PR numbers | merge commits | nothing |
| Per-person totals: commits, merges, lines, which agent they lean on | git log | nothing |
| Live posts, presence, who is on which branch right now | .room/ | the CLI or MCP |
The first four work on a repo that has never heard of Rooms, including for teammates who never install it — because every clone already carries the whole history. Only the last row needs anyone to post anything.
"Can't I just use git log?"
Mostly, yes — and you should know how far it gets you before installing anything. This is the honest one-liner:
git log --format='%(trailers:key=Co-Authored-By,valueonly)' | grep . | sort | uniq -cThat gives you a tally per agent, and for many repos it is enough. Four things it gets wrong, all of which cost more than they look:
It has no denominator. --grep=Co-Authored-By counts commits that mention a trailer. To turn
that into a share you need the total under the same filter — and the moment you add --since or a
path, the two commands have to agree or the percentage compares two different populations. On this
repository the tally is 47; the total is 113.
A Co-Authored-By trailer is not proof of an agent. Humans use it too — GitHub's own
co-authoring flow writes one. The obvious fix is to match the email domain, and that is a trap:
users.noreply.github.com is the address GitHub gives every human with an account, so matching
github.com counts your colleagues as Copilot. This tool shipped that bug; matching the trailer
name is the fix.
Merges report +0 −0. git records no line changes for a merge, so anyone who lands other
people's work looks like they wrote nothing. 34 of this repository's 113 commits are merges — nearly
a third of the history, invisible to a naive line count.
One person with two email addresses is two people. Every rollup counts them twice until someone
writes a .mailmap.
None of that makes git log wrong. It makes the number you get from it a starting point rather than
an answer — which is the whole job here: the same facts, with the arithmetic done correctly and the
caveats attached, in a form you can paste into a PR or a README.
Two questions, and the second one is the dense answer
Which commits recorded an agent is what the trailers answer, and the honest version of that answer is usually "almost none". Across the newest 500 commits of six well-known repositories — 3,000 commits — 45 of them, 1.5%, carried a trailer this could attribute.
Which agents is this project set up for is a different question, and it has a much better
answer: five of those six repositories declare their agents in a committed file. AGENTS.md alone
is in five of six.
So both are reported, apart:
Claude 4 █░░░░░░░░░░░░░░░░░░░░░ 2%
co-author that says it is a bot 20 █░░░░░░░░░░░░░░░░░░░░░ 4%
co-author, no bot marker — usually a person 219 █████████░░░░░░░░░░░░░ 43%
no agent recorded 257 ███████████░░░░░░░░░░░ 51%
Configured for: Claude Code (CLAUDE.md, .claude/), Codex (.codex/) and a
cross-vendor AGENTS.md.
A config file says a tool was set up here, never that it was used — and never
how much. These are not commits and do not belong in the percentages above.They are never combined into one number. "6% attributed, configured for three agents" has no average, and inventing one would be the defect this tool exists to refuse.
Three things about how that second line is produced:
- Only the filename is read, never the contents. What is inside your
CLAUDE.mdis your prompt — your standards, your architecture, sometimes your business. Rooms readsgit logand filenames. There is a test that fails ifsrc/agent-config.jsso much as referencesreadFile. - It asks git, not the filesystem. An untracked
.claude/your own session left lying around is not a declaration by the project. - Declaring nothing is stated, not omitted. A repository with no config files says so, because otherwise "declared nothing" and "did not look" read identically.
When nothing is recorded, it says whether that is expected
no agent recorded 100% is the most common first run, and three different situations produce it:
the setup is broken, the tool in use never wrote trailers, or no agent was involved. A reader cannot
tell which from a bar at 100%, so they cannot tell whether to go looking — and in two of the three
the answer is that nothing is wrong.
Cursor does not write a Co-Authored-By trailer, so an empty result here is
the expected one rather than a fault. There is nothing to switch on.Claude Code writes this trailer itself, and none of these commits carries
one — so either it was turned off, or this window predates it. Rooms cannot
add one: a trailer it wrote would be a claim about authorship made by
something that was not there.It is silent the moment anything is attributed — at any attribution at all you have evidence the mechanism works and do not need telling how it works.
No command is offered, and that is deliberate. Rooms could write a trailer from a git hook and
will not: a Co-Authored-By: Claude added by this tool is a claim about who wrote the code, made by
something that was not there. The numbers here are worth something precisely because the agent
attested to its own work. Manufacturing the evidence we then measure would be the most complete
version of the mistake this project exists to avoid.
What this will not tell you
- Which lines an agent wrote. Rooms reads commits, not keystrokes. Line-level provenance is a different product with a different privacy cost, and claiming it from trailers would be a guess.
- How much of your codebase is AI-written. That number needs the agent to record itself on every commit, and most do not. What you get is the share that said so.
- Anything about a person you could not already read in
git log. No prompts, no sessions, no keystroke timing, no vendor telemetry.
Two histories both look right. A repo that works on main with no merges draws as one rail
with every commit on it. A repo that merges pull requests draws a rail plus a lane per branch —
including branches that were merged and deleted, because the merge commit still records what they
contributed and what they were called.
One caveat worth knowing. If the same person commits under two email addresses, they are listed
twice. That is deliberate: .mailmap is git's own way to
merge identities, and a heuristic that guessed would eventually merge two different people. The
board tells you when it sees it.
Start here
npm i -g iops-rooms
cd ~/your-project
rooms openThat is it. rooms open creates the room if there is not one, reads your history, and opens the
board. Nothing leaves your machine.
To keep it open while you work — its own window, refreshing as things change:
rooms liveOn macOS, Windows or Linux with Chrome, Brave or Edge installed, that opens as its own app
window: no address bar, no tab strip, its own icon in the dock. rooms live --tab for an ordinary
browser tab instead, and ROOMS_NO_OPEN=1 to launch nothing at all.
Two optional extras, in the order most people want them:
rooms auth github # sign your posts, using the gh login you already have
rooms mcp install # let Cursor / Claude Code / Codex post as they workTeams
Individual first. One person on one machine is the path that is finished and tested; teams work but are newer, so start solo and add people once you like what you see.
When you are ready, a team shares a room through your own git remote — there is no I-Ops server and no account:
rooms init --share # keep .room/ in the repo instead of gitignoring it
git add .room && git commit && git pushTeammates git pull, run rooms join <code>, and post. Everyone's posts merge on the next pull;
--share writes the git merge rules that make concurrent posts merge instead of conflicting.
Each person's posts carry their own name, tool and device, so the board shows who did what.
What it does not do
- It does not sync your repo. Git already does that.
- It does not watch every save. A post happens when you post, when an agent posts through MCP, or when a git hook you installed fires.
- It does not read Cursor's or Claude's private state. Commit attribution comes from the
Co-Authored-Bytrailers they write into your git history. - It does not phone home. The static board is offline;
rooms livebinds127.0.0.1only.
Agents on the board (Cursor / Claude Code / Codex)
Agents post as they work, through MCP. One command wires it up:
npx -y [email protected] mcp installThat writes .cursor/mcp.json, .claude/, and a Codex entry, keeping any MCP servers you already
had, and copies the skill so the agent knows when to post. Reload MCP, and the agent gets
post_note, share_diff, request_review, approve, read_transcript, doctor and
wait_for_peer.
Pin the version. Do not use @latest — an MCP server is a program you are letting an agent run.
Manual wiring, if you prefer:
{ "mcpServers": { "iops-rooms": { "command": "npx", "args": ["-y", "[email protected]", "mcp"] } } }Commands
| | |
|---|---|
| rooms init / join | create or join .room/ — --share to commit it, --mcp to wire agents |
| rooms open / live | the board, once or continuously on 127.0.0.1 |
| rooms post / share-diff | a note, or a diff (confined to the project; --allow-outside to escape) |
| rooms status / whoami / branches | where things are, who you are, what is where |
| rooms auth github / gitlab / status | verified identity, via your own gh login |
| rooms doctor | why the board looks empty. Exit 0 healthy, 2 empty, 1 no room |
| rooms index --open | every .room/ under ~/Projects on one page |
| rooms hooks install | opt-in local git hooks that post commits and checkouts |
| rooms scm-status | repo, branches and open PRs via gh — read-only, degrades if gh is missing |
| rooms export / export-room / sync-merge | markdown, or move a room between your own machines |
ROOMS_NO_OPEN=1 skips launching a browser, for headless boxes and VMs.
Verified identity (optional)
rooms auth github # uses the gh CLI you already have
rooms auth statusOne read-only call, gh api user, with your own credential. No OAuth App to register, nothing of
ours in your authorised-apps list, no token stored. Posts then carry a GitHub claim and an
ed25519 signature made by a key that never leaves ~/.iops-rooms/.
Everything else on the board works without this. It only adds a signed claim about who posted.
Without gh, set ROOMS_GITHUB_CLIENT_ID to an OAuth App client id of your own and use
rooms auth github --device-flow. GitLab works the same way with ROOMS_GITLAB_CLIENT_ID.
Trust
Read SECURITY.md. Briefly: no network for room traffic, no telemetry, no reading of
other tools' private state; rooms live binds 127.0.0.1 only; share-diff refuses paths outside
the project and secret-looking filenames; and the whole of src/ is unminified and dependency-free.
Verify it yourself: open the board as file:// and watch the network tab stay empty.
Contributing
CONTRIBUTING.md has the setup — npm install, npm test, and two smoke
scripts that run the real thing end to end.
The part worth reading before you start: testing this against a repository it has never seen
matters more than the unit suite does. Both defects fixed in 0.5.7 came from pointing the
published build at astral-sh/uv and anthropic-sdk-python, and neither shape was in a fixture.
Issues labelled good first issue
are scoped so the hard part is already decided in the issue text. "I ran this on my own repository
and the answer looked wrong" is a first-class issue and needs no fix attached — paste the output
and what you expected.
Requirements
Node 20, 22 or 24 on macOS, Linux or Windows. Linux and Windows on every change, macOS weekly. No runtime dependencies.
Not in this release
Hosted relay, accounts, seats, SSO, or a model of our own. No whole-repo sync. No IDE telemetry — agents appear when they post through MCP, and git hooks are opt-in.
About
Rooms is one working layer of I-Ops, open sourced.
I-Ops is a desktop application for making AI workers finish real tasks correctly. Rooms is the part that answers who is doing what, and which agent did it — and it was built from scratch for this repository, not carved out of the product. Nothing here is a stripped-down copy of something closed; it is a small tool that stands on its own, and you can read all 4,000 lines of it.
Feedback is genuinely wanted. If you try it and something is confusing, wrong, or missing — or if you have read the code and disagree with a decision in it — please say so. Open an issue, send a pull request, or email [email protected]. Reviews of the security posture in SECURITY.md are especially welcome.
MIT licensed. Built by I-Ops Operations Intelligence, LLC — i-ops.dev.
