1 account mgr · agency-bot
Agency architecture · one plan, many rooms
One Claude Max subscription sits with the agency owner. A single bot carries that credential into a Discord server, gives every client and every teammate the same shelf of skills, and lands the actual work as commits in private GitHub repos. Each skill runs against one client’s context and nobody else’s.
The only thing in the server allowed to call Claude. Runs on a small VPS as
agency-bot; the API token never leaves that box and never appears in a message.
One table, one row per asset and per job, client_id on every row. That column is what makes the seal enforceable in code rather than by habit.
One private repo per client. This is the layer the model actually reads, and the layer a human can review before it ships.
Every original: before and afters, phone video, raw uploads. One prefix per client, keyed by job. Never in git, never in the database.
Clients drop files where they already know how. A watcher files them into R2 and writes the index row. Nothing of record lives in Drive.
It receives the upload, processes it, pushes the originals, commits the facts, writes the row. If it dies you rebuild it in an hour and lose nothing.
A skill carries the method — the steps, the format, the standard you hold the work to. It carries no facts about anybody and no keys to anything. The facts come from whichever room it was run in, and so do the accounts it is allowed to publish to. Same command, different work, landing in a different place every time.
High energy, written for parents. Pulls last season’s lap data and the two questions that come up at the counter every Saturday.
Plain and price forward. Pulls the current rate card and photos from three jobs finished last month, because this audience wants the number before the story.
Premium and seasonal. Pulls the install gallery and the territory calendar, so the offer only names neighbourhoods with crews still open.
The instinct is to put everything in one place. The numbers argue against it, and they argue in a specific direction: split by what the data is, not by which vendor you like.
The index. A few hundred bytes a row, and the only thing you ever run a query against.
One database for the whole agency, with client_id doing the isolation.
The facts. This is what the model reads and what a person reviews, so it wants history, diffs, and a revert button. A year of one client comes to single-digit megabytes.
The originals. Sixty-six megabytes a job, ten gigabytes a client a year. Blobs in a database is the classic mistake, and git rejects anything past a hundred megabytes.
Per-client databases buy isolation you already get from a filter, and cost you a set of migrations, backups, and credentials per account. Revisit it when a contract demands it.
The same seven steps run whether the sender is a client or a teammate. Only step 3 changes, and it is the step that keeps accounts apart.
/write-blog-post in a channel. Client or employee, no difference. No app to install, no login to hand out.
That ID alone decides whose room this is. Identity comes from the room, not from a password.
Only summit.context is in scope inside #summit-workspace. The other stores are not reachable from here.
Same steps and same standard in every room. Fix the skill once and all four rooms get the better version.
One credential, one invoice. Nobody downstream sees a key or gets a bill.
The reply lands in the thread and the new detail is written back, so tomorrow’s answer starts smarter.
Copy, pages and configs land in agency/summit as a pull request the account manager can read before it ships.
Clients and staff get capability, not access. Removing someone is a Discord permission change, not a key rotation.
A store is bound to its channel. If a request cannot name the room, it cannot read the memory — which is what makes competing clients safe in the same server.
New account, new channel, new empty store, new repo. No new subscription, no seat math, no onboarding call about which tool to install.
A skill never stores anything about a client, which is exactly why it is safe to share one
across competitors. Improve /reply-to-reviews on a Tuesday and every account
gets the better version on Tuesday.
A connector is a credential to something the client already owns — their listing, their
page, their sub-account. It is sealed exactly like the context, and it lives encrypted in the
index, never in a repo. /post-to-gbp is one skill; which listing it posts to is
decided entirely by the room it was run in.
Discord is where the conversation happens; GitHub is where it survives. Every answer worth keeping becomes a diff you can review, revert, and hand to the next person.
The editable source is a draw.io file — open it at diagrams.net, drag the boxes around, and swap the client names for your own.