How eng.town works
How to get set up, then how every part of it works.
eng.town keeps every AI-agent session you run, so none of it is lost. A small program on your Mac finds the transcripts your agents leave behind, removes secrets, and uploads the ones about work repos. Everything after that — reading, searching, costing, analysing — happens here.
your Mac eng.town
-------- --------
Claude Code \
Codex > eng-town --> sessions --> read / search / copy
Buzz, etc. / (asks first) |
+--------> analytics (tokens, cost)
+--------> insights (weekly agent)
+--------> MCP (your agents read it back)New here? Get set up is the five-minute version: sign up, install the collector, connect your agents.
Two things are worth knowing before anything else. Nothing is uploaded without your say-so — see Consent model. And your sessions are private to you unless you share one, enforced inside the database rather than by this website — see Team management.
Get set up
One command, or one prompt for the agent you already have open
Everything is one command. It installs the collector, enrolls this Mac, puts eng-town on your PATH, registers the MCP server so your agents can read your archive, and checks its own work at the end. About two minutes, most of it waiting.
Before anything works, you need a team. Signing in for the first time creates one for you, and an invite link from a teammate's admin puts you on theirs instead. Sort that out first, then run this.
curl -fsSL https://ejbzechmcxthivgclakh.supabase.co/storage/v1/object/public/releases/install.sh | shPaste this into Claude Code, Codex or whatever you have open. It runs the command, waits while you approve this Mac in the browser, then checks the result and tells you what is left to do.
Read it first
Please set up eng.town on this Mac for me, then check that it works.
eng.town is a tool that archives my AI-agent chat transcripts (Claude Code, Codex, Buzz, Conductor)
for work repositories only, so I can search and re-read them later. Run this single command — it
installs the collector, enrolls this machine, registers an hourly background job and a Claude Code
hook, adds the command to my PATH, registers its MCP server, and self-checks at the end:
curl -fsSL https://ejbzechmcxthivgclakh.supabase.co/storage/v1/object/public/releases/install.sh | sh
Three things to know while it runs:
1. It prints a notice about what it will and will not collect and waits for Enter. Read it out to me
and press Enter.
2. It then prints an enrollment URL with a code, e.g.
"Open https://app.eng.town/enroll?code=ABCD-1234-WXYZ". **I have to open that link in my browser and
confirm the code — you cannot do it for me.** Show me the URL and the code clearly and wait; the
installer polls and continues on its own once I confirm.
3. It asks one yes/no question about AI analysis of my sessions. Ask me before answering — do not
answer it on my behalf.
When it finishes, verify it and report back:
- Run `eng-town doctor` and tell me if anything failed.
- Run `eng-town status` and tell me how many sessions are waiting for a decision.
- Confirm an "eng-town" entry exists in ~/.claude.json under mcpServers.
Then tell me, in a few lines:
- whether the install succeeded, and anything that did not,
- that I should open a new terminal (or run `exec $SHELL`) for `eng-town` to be on my PATH,
- that I should restart Claude Code for the MCP server to load,
- that nothing has been uploaded yet, and `eng-town review` is how I choose what to share.
Rules: do not change any of my other configuration, do not upload or share any sessions, and do not
run `eng-town review` or answer any consent prompt for me — those are my decisions. If a step fails,
stop and show me the exact output rather than trying to work around it.What it does, in order
- Shows you what it will and will not collect, and waits for Enter. Only allowlisted work repos are eligible; everything else stays on your machine.
- Asks you to approve this Mac. It prints a link and a code — open the link, confirm the code, and it carries on by itself. This is the step that grants the machine permission to upload, and you can revoke it later from Devices.
- Asks one question: may eng.town run AI analysis on the sessions you share? Enter for yes,
nfor no, changeable any time in Settings. If nobody is at the keyboard — a scripted or fleet install — it stays off and asks you next time. - Sets everything up: the hourly background job, the Claude Code hook, the
/sync-sessionscommand,eng-townon your PATH, and theeng-townMCP server in~/.claude.json. - Classifies the history already on your machine and tells you how many sessions are eligible. It uploads none of it.
- Self-checks and prints what, if anything, is wrong.
Two things to do afterwards
- Open a new terminal (or run
exec $SHELL) so your shell picks up the PATH change, and restart Claude Code so it loads the MCP server. - Choose what to share. Nothing from your history has gone anywhere yet:
eng-town reviewIt lists what is waiting, grouped by repo, with select-all per repo. Or use /sync-sessions inside Claude Code. From then on you are asked as each session ends, and you can set a repo to automatic if you would rather not be.
What your agents get
The MCP server registers as eng-town and adds five read-only tools: search your sessions, list recent ones, summarise one, fetch one, and find related work. It reuses the device key from the install, so there is nothing new to log into. Ask your agent “what did I do about the webhook last week?” and it can go and look instead of asking you.
Is it working?
The dot in the top right of this app is your collector. Green means it synced in the last four hours, amber means it has been quiet for a while, red means nothing for two days. On the machine itself:
eng-town status # what is synced, staged and skipped
eng-town doctor # config, background job, hook, server — all in oneDoing it by hand instead
The one command is eng-town install with the download in front of it, so every step has a switch. --no-path leaves your shell config alone, --no-mcp skips the ~/.claude.json entry, --skip-hooks and --skip-launchd do what they say. Re-running eng-town install is safe: every step checks before it acts, so it repairs what is missing and leaves the rest alone.
One name, two spellings
The command is eng-town. The older name agent-sync still works and still names the folder on disk (~/.agent-sync) — the background job and the Claude Code hook point at it, so it stays put rather than being renamed underneath a working install.
The collector
The program on your Mac that finds transcripts, cleans them, and uploads them
eng-town is a single binary that runs quietly on each Mac. It finds the transcripts your agents leave behind, keeps only the ones about allowlisted repos, removes secrets, and uploads what is left. Everything you see in eng.town got here through it.
When it runs
- Every hour, from a launchd job.
- The moment a Claude Code session ends, from a hook — so a session you just finished is usually here before you have switched windows.
- Whenever you ask:
eng-town now.
What it reads
| App | Where its transcripts live |
|---|---|
| Claude Code | ~/.claude/projects/ — main sessions and their sub-agents |
| Codex | ~/.codex/sessions/ and archived sessions |
| Buzz, Conductor, company-os | their own stores, inside allowlisted checkouts |
How it decides a session belongs here
A session is uploaded only if it is about a repo on the allowlist. The collector works that out the same way git does: it resolves the session's working directory to a checkout, and worktrees, Conductor workspaces and Codex worktrees all resolve back to their parent repo.
Some sessions have no useful working directory — Buzz runs from ~/.buzz, for instance. For those, the collector looks at which files the agent actually edited. Reads alone are never enough; at least one write into an allowlisted repo is required.
Anything it cannot place is left alone and listed by eng-town unresolved, so a mis-classification is visible rather than silent. eng-town explain <session> prints the full reasoning for one transcript.
What is removed before anything leaves your Mac
- Secrets are redacted, replaced in place with
[REDACTED:anthropic]and the like. Fourteen pattern families are matched — Anthropic, OpenAI and GitHub tokens, AWS keys, Slack and Google tokens, Stripe keys, JWTs, bearer headers, private key blocks, passwords inside URLs, andSOMETHING_SECRET=…style assignments. - Long tool output is truncated to about 4 KB — the head and the tail, with a marker saying how much was dropped. Your text and the agent's text are never truncated.
- Images and attachments are dropped at parse time.
It only ever sends what is new
The collector remembers how far it got in each session and sends only the messages after that point. If a run is interrupted it picks up where it stopped; if it sends something twice the server recognises it and writes it once. A long-running session is uploaded as it grows.
Commands worth knowing
| Command | What it does |
|---|---|
eng-town status | what is synced, staged, skipped, and whether the server is reachable |
eng-town review | list sessions waiting for a decision, grouped by repo, and choose |
eng-town explain | why one transcript was included or excluded |
eng-town doctor | checks config, permissions, launchd, hooks, server |
eng-town mcp --install | let your agents read your past sessions — see below |
Your agents can read this archive
eng-town mcp --install registers eng.town as an MCP server in Claude Code. It adds five read-only tools — search sessions, list recent ones, summarise one, fetch one, and find related work — so an agent can pull context out of what you did last week instead of asking you to explain it again. It reuses the device key you already have; there is nothing new to log into.
Analytics
Tokens and cost over time, by person, app, model and repo
Analytics answers “where did the tokens go?” Pick a period, and the page shows headline numbers, a daily bar chart, three ranked breakdowns, and a per-person table. Members see the page scoped to themselves; admins see everyone.
What each number means
These definitions are worth reading once, because two people looking at the same chart should agree on what it says.
| Metric | Definition |
|---|---|
| Session | one top-level chat. Sub-agents are not counted separately. |
| User turn | a message you actually typed — automatic and system messages do not count |
| Total tokens | input + cache read + cache write + output |
| Context tokens | input + cache read + cache write — what the model read |
| Cache-hit rate | cache read as a share of everything the model read |
| Tool calls per turn | how much work the agent did per instruction from you |
| Short first prompt | share of your sessions that opened with under 200 characters |
Sub-agent usage is folded into its parent
When an agent spawns sub-agents, their tokens and cost are added to the session that started them. A session's number is the whole cost of that piece of work, not just the top-level conversation. If any sub-agent used a model with no price, the parent's cost is shown as unpriced rather than as a number that is quietly too low.
What the people table is for
Average prompt length, short-first-prompt rate, cache-hit rate and tool calls per turn are there to answer one question: is this person giving their agents enough context? A very short first prompt and a low cache-hit rate usually means an agent that had to rediscover the problem. There is deliberately no automatic “quality score” — the columns are raw material for a conversation, not a ranking.
Insights
A weekly agent that reads your sessions and writes findings you can act on
Once a week, a Claude agent reads your last seven days of sessions and writes up what it found — patterns in how you work, where time went, and what to do differently. Every finding carries a verbatim quote from a real session and a paste-ready prompt. It is off until you turn it on.
How a run works
Monday 08:00 export your week -> upload -> start the agent -> hang up
(a coordinator on Opus 5, reading via Haiku 4.5 workers)
~15 min later the agent writes insights.json and goes idle
-> Anthropic calls our webhook
-> we download it, validate it against a schema, write the rows
you refresh the Insights tab has your week on itIf the webhook never arrives, a sweep on the hourly tick finishes the run properly instead. The result lands later, never not at all.
When it runs
| Trigger | When |
|---|---|
| Weekly | Monday morning, if you have any sessions the last run did not see |
| Mid-week | when 10 or more new sessions have piled up since the last run |
| On demand | the Generate insights button, up to three times a day |
The rule that makes it trustworthy: the model does not supply facts
- Every number is computed here, not written by the agent. Session counts, tokens, cost and dates are derived from the database using the session ids the agent grouped. The model is good at grouping and bad at arithmetic, and we already have the arithmetic.
- Every quote is checked against the session it cites. A finding links to the transcript it came from, so you can always go and read the original.
- Output is validated before anything is stored. The agent's file is parsed and checked against a schema first; a run that fails validation is marked failed and writes nothing at all, rather than storing model output as if it were data.
What it costs, and what stops it running away
- A real run over a full week measures roughly $6 and takes 10 to 15 minutes.
- Each run has a hard $10 cap enforced by the platform. It cannot exceed it.
- After three consecutive failures automatic runs stop until one succeeds — so a structurally broken run costs at most $30 once, not $30 an hour. The Generate button still works, and a successful manual run clears the block.
Using your own Anthropic key
You can supply your own key on the Insights tab, and your runs are then billed to your Anthropic account. The key is write-only by construction: nothing in the stack can return it to any browser — including yours, and including an admin's. You can replace it or clear it, never read it back.
Cost calculation
How every dollar figure on this site is worked out — and what it is not
Every cost in eng.town is API-equivalent list price: what those tokens would have cost had they been billed through the API. It is computed in the database from a price table, so it can be recomputed whenever prices change.
The formula
cost = ( input x price_in
+ output x price_out
+ cache_read x price_cache_read
+ cache_write_5m x price_5m
+ cache_write_1h x price_1h ) / 1,000,000Cache tokens are priced differently from fresh ones. Against the input price: a cache read costs a tenth, a five-minute cache write 1.25 times, and a one-hour cache write twice. That is why a session with a high cache-hit rate can be enormous in tokens and modest in dollars.
Where the prices come from
A price table you can edit, under Admin. Each row matches a family of model names, so a new point release inherits its family's price automatically. Changing a price changes the numbers everywhere, because the cost was never baked into the session row by the uploader.
An unknown model shows a dash, never a guess
If a session used a model with no price on file, its cost is null — the table shows — and the totals carry a footnote saying how many sessions were unpriced. Tokens are still counted. We would rather show you a visible gap than a total that is silently too low.
The caveat that matters
This is not your bill. Claude Code on a subscription does not charge per token, so the dollar figure will not reconcile against an invoice. It is the right number for comparing — this session against that one, this week against last, one person's usage against another's — and the wrong number for accounting.
The one exception is Insights: those runs go through the Anthropic API and are genuinely billed. The cost shown on a run is what it actually cost.
Storage
Where your transcripts physically live, and who can reach them
Everything lives in one private Supabase project — a Postgres database for the structured transcript, and a private bucket for the original file. Nothing is deleted automatically, ever.
The database
| Table | One row per |
|---|---|
sessions | chat, with its token totals, cost, repo, app and model |
messages | turn or tool event — full-text indexed, which is what search reads |
tool_calls | tool the agent used, with its input and (truncated) output |
devices, sync_runs | enrolled Mac, and every collector run it made |
team_members, repos, model_prices | who may sign in, what is collectible, what things cost |
The raw archive
Alongside the parsed version, the collector keeps a gzipped copy of the original transcript — already redacted, the same as everything else. It goes into a private bucket that no browser can read directly. When you download one, the dashboard first checks in the database that you are allowed to see that session, then mints a link that expires in 60 seconds.
Nothing expires
There is no retention policy and no automatic cleanup. Revoking a device does not remove the sessions it uploaded. The archive is the point of the product — a session from six months ago should still be there.
You can delete your own sessions from the dashboard. Deleting one also records a tombstone, so the collector on your Mac will not helpfully upload it again on the next run.
Consent model
Ask, do not assume — nothing leaves a Mac without a decision
The default is to ask. A session is only uploaded once you have said so, or because you set that repo to automatic yourself. This is the part of eng.town that most needs to be boring and predictable, so here is exactly how it behaves.
Three modes, set per repo
| Mode | Behaviour |
|---|---|
ask (default) | sessions wait on your Mac until you decide |
auto | upload without asking — you chose this for this repo |
never | never offered, never uploaded |
When you get asked
- At the end of a Claude Code session, a small dialog shows what it was — the title, the repo, the app, how many messages, and your first few prompts — with Sync, Skip, or Always for this repo.
- Once an hour, if several are waiting, a single list to tick through. Never more than one list open at a time.
- Whenever you want:
eng-town review, or the/sync-sessionsskill inside Claude Code.
Not answering is not a yes. A dialog you ignore for 60 seconds closes and asks again later.
Marking something private
Type #private or #nosync anywhere in a chat, or drop an .agent-sync-ignore file in a folder, and those sessions are never offered and never uploaded — even inside a work repo. The folder rule also covers any session that reads or edits a file in that folder, wherever it was started. If one was already uploaded, it is retracted from the server.
Your history is not swept up at install
Installing the collector classifies what is on your machine but uploads none of it. It tells you how many sessions are waiting and points you at eng-town review, where you can go repo by repo.
AI analysis is a separate decision
Insights sends your transcripts to the Claude API, which is a different thing from storing them in your own database — so it is asked separately, in plain words, and it is off until you say yes. If nobody is at the keyboard — a scripted install, a fleet push — it stays off and un-asked rather than being decided on your behalf. You can change it any time on the Insights tab. Turning it off stops the next run; insights you already have are kept.
Sharing with the team
Your sessions are yours by default. Teammates cannot see them. If you want one to be readable by everyone — because the way you got the agent there is worth copying — the Share control on the transcript makes that one session visible to the team, and you can turn it off again.
What an admin sees
Admins can see each Mac's mode and how many sessions were skipped. They cannot see what was in them — a skipped session never left the machine, so there is nothing to see.
Team management
Who can sign in, what they can see, and how that is enforced
Every team on eng.town is its own sealed org with two roles, enforced by the database rather than by the user interface. A bug in the dashboard cannot show you someone else's transcripts, because the dashboard is not what is stopping it.
Signing in
A magic link sent to your work email, or Google when it is enabled on the deployment. Your first sign-in creates a team of your own — unless an admin invited your email first, in which case you land on their team. Invite links come from the Admin → Team page.
Two roles
| Role | Can see |
|---|---|
member | their own sessions and devices, plus anything a teammate has shared |
admin | everything in their own team, plus the team and repo screens — never another team |
Three layers, not one
- A database trigger places every new account into a team the moment it is created — a pending invite, or a fresh team of its own.
- The dashboard checks on every request — so deactivating someone locks them out on their very next click, without waiting for a session to expire.
- Row-level security is the last line: every query is filtered by the signed-in email inside Postgres. This is the one that actually protects the data.
Deactivating a member does not delete anything. Their sessions stay; they simply cannot sign in.
Devices
A Mac never signs in with Google. It enrols with a short code that its owner claims in the dashboard, and gets a random 256-bit key in return. The server stores only a hash of that key. The key can upload sessions for its owner and nothing else.
An admin can revoke a device. The next time it calls in it is refused and switches itself off. Sessions it already uploaded are kept.
What an admin deliberately cannot do
- Read a teammate's Anthropic key. Enforced by column privileges in Postgres, not by our code being careful about it.
- Turn on AI analysis for someone else. Consent an admin can grant on your behalf is not consent.
- See a session that was never uploaded. Skipped stays on the machine.
The repo allowlist
Admin → Repos decides what is collectible at all. A session in a repo that is not on that list is never uploaded by anyone's Mac. It is the widest control in the product and the first place to look if something you expected is missing.