for agencies
Fifteen clients, and no path between them
One account, one team moving between brands, and a seat that reaches the clients you named and nothing else in it. The rules you set as an agency hold across all fifteen and no client can weaken them. And the record you hand Client A is about Client A alone — the file naming the other fourteen is never generated.
This page is for an agency running brands on behalf of clients.
Running your own brands instead? →Separation
The boundary between two clients is a seat, not a setting
Owner, editor and viewer are seats in your account and each of them reaches every client in it. The fourth is the one this product was shaped around: a limited seat has no account-wide reach at all, and reaches exactly the client brands you named.
| Seat | Who you hand it to | What it reaches |
|---|---|---|
| Owner | The principal. | Every client. The only seat that can change the agency’s own rules, issue an API key, or invite anyone. |
| Editor | Your staff, who move between accounts all week. | Every client in the account, and may edit — including brands they hold no grant on. |
| Viewer | Somebody who reads and does not write. | Every client, read only. A viewer cannot post a comment or record a sign-off either: the policies refuse both, so this is not the seat for a client who has to approve. |
| Limited | A client contact, or a freelancer in for one account. | Exactly the client brands you granted, one at a time. No account roster, no account-wide overview, no access map, no invitations, and the account’s own rules are refused outright. |
- 4seats
- And one of them stops at a brand. The other three each reach every client in the account, which is why none of them is the right one to hand outside the agency.
- 1step
- The client brands and the level of access are written onto the invitation itself, so the grants land the moment the seat is accepted rather than in a second pass somebody has to remember afterwards.
- 0clients by default
- A limited seat holding no grant reaches no client at all. It can see the account it is inside and find that account in its own switcher, and that is the whole of it.
A grant reaches one client and every campaign in it
It cannot be widened from the brand — an account-wide seat is a different decision, taken on the seat rather than on the client. The two levels of grant are read and comment, or edit.
And it cannot be issued sideways
Somebody holding a brand grant cannot grant themselves another. An account editor cannot hand out grants at all. And a grant cannot be issued to anyone holding no seat in the account, which is enforced by a trigger rather than by a screen.
A freelancer who also works for another agency
They hold a separate seat in each agency’s account and switch between them. Switching account changes the governance regime entirely — different rules, different colleagues, different audit trail. Switching client changes which brand; switching campaign changes which launch. Three different acts, three different controls.
Handing the agency over is allowed; locking yourself out is not
The last owner of an account cannot demote themselves or delete their own seat. Two owners can, so a principal stepping down once somebody else holds the keys is an ordinary act rather than a support ticket.
Isolation
The answer to “how do you know Client A cannot see Client B”
Not a filter in the application, and not an undertaking. Every table is row-level secured through one membership check, and the boundary is re-asserted on every deploy against the real database — as a signed-in user, through the interface the API uses.
assertions, and never fewer. They run against the live schema inside a transaction that is rolled back, and the deploy gate will not pass with one of them failing.
The interface is not the control. A button that does not render is a courtesy; what stops the request is the policy underneath. What each assertion asks, and the data processing terms.
Fifteen brands, one team
Nothing is shared between two clients except your people
Access is the half everyone asks about. The other half is quieter and costs more when it goes wrong: a default that leaks one client’s look into another, a source list re-entered per campaign, a brief that reaches the writer with no idea which client it is for.
The kit is stored on the client, not on your agency
Colours, type, logo and voice sit on that client’s own row. Your agency level carries rules and nothing visual, so there is no house look for a client to pick up by accident — the one thing that travels down from you is the thing you meant to travel.
A palette generated from the client’s own accent
The Brand colourway synthesises a full surface set — paper, tint, accent and an inverted dark — from that client’s accent colour, rather than six near-identical tints of one hue. Six tints is exactly what made every colourway look the same, and a client’s brand deserves the range a built-in palette gets.
Sources belong to the client
The domains a claim is checked against — investor relations, the newsroom — are a property of that company rather than of a campaign, so they are entered once on the client. Research reads only the domains they nominated, not the open web, so a conflict is a conflict with their own published position.
Context accumulates, and says which level it came from
The writer is handed how your agency writes for anyone, then what this client is, then what this campaign is for — three headings, ordered widest to narrowest. Undifferentiated, a model will happily write a client’s post about your agency’s house style.
A campaign brief every post in it inherits
Written once on the launch and reaching the writer under its own heading, rather than retyped into each post and drifting between them.
Your client’s reviewers are not seats
The person at the client who has to look at it before it goes out is sent a link, not a login. It reaches one post, needs no account, and expires. What that means for the invoice.
The one thing that does cross all fifteen
Set once at the agency, and a client can only make it stricter
Everything above this is about keeping clients apart. Your own standards are the deliberate exception: the rule you will not have broken on anyone’s account — no competitor names, the disclaimer always carried, no figure without a source — is set once and every client brand inherits it. A client may sharpen it. Nothing below can weaken it.
| Set at | Which is | What it reaches | Who can change it |
|---|---|---|---|
| Your agency | the account | Every client brand you run, and every campaign inside every one of them. | The account owner, and nobody else in the account. |
| One client | the brand | That client, and every campaign inside it. | Anyone who can edit that client — including a limited seat granted only that one, which is the point of it. |
| One campaign | the project | That launch and no other. An embargo cannot outlive the campaign it was written for. | Anyone who can edit the client the campaign sits in. |
What a client brand may do to a rule it inherited
The direction is the whole contract, and a direction is the one thing a sentence is worst at. So: the two lists, side by side.
Allowed
- Add a rule of its own. A client’s rule applies to that client and to every campaign inside it; a campaign’s applies to that launch and no other.
- Raise an inherited rule from advisory to blocking. Stored as the rule’s id and the harder severity — never a copy, so the wording above goes on tracking the level that set it.
- Do the same one level further down, on a single campaign. It is the same fold handed a third array, so the contract does not change on the way down.
Refused
- Reword an inherited rule. A collision on the same rule id keeps the definition from above — statement, pattern, replacement wording, the lot — so a client cannot restate your rule in words of their own while appearing to obey it.
- Remove one, or drop it from blocking to advisory. The attempt is named — removed or downgraded, rule by rule — and reported back rather than silently undone, so nobody finds out at export.
- Reach the rules you set as an agency at all. Setting those is refused from inside a client, by the guarded function rather than by a hidden button.
Your rule cannot fork into fifteen private copies
Inherited rules are folded in when a client’s kit is read and stripped back out before it is written. Without the strip, opening each client once would copy your rules into fifteen brands, where they become ordinary editable brand rules and stop tracking you — and you would find out by rewording one and watching nothing change.
A tightening survives the round trip
It is stored as an override rather than as a copy, so a client that raised your advisory rule to blocking keeps the stricter severity and still reads your wording after you reword it.
A campaign’s rule cannot leak into the client
A launch’s rules are folded onto the kit while one of its posts is open and taken back off before anything is written, so an embargo written for one campaign cannot copy itself into the client — where it would apply to every other launch and could no longer be lifted by ending the one it was for.
A client you have not set up yet is still governed
An unconfigured brand has no kit, and the screen that administers it still reports the rules your agency imposes on it. Reporting “no rules” there would be the one thing that is not true.
The nine rule types, and how a finding is tiered into what code decided, what a model reviewed, and what was never inspected: governance.
The artefact you hand over
Client A’s record names Client A, and nobody else
Every agency in a regulated sector is eventually asked to produce one. Generating it was never the hard part — the problem is that a file naming all fifteen clients is the wrong thing to attach to an email addressed to one of them, and for a long time it was the only file that existed here. There are two now, and the difference between them is the useful part.
Account-wide
Every client you run, in one file
The right file for the person accountable for all of them, and the wrong one to send anywhere: it names every other client, their campaigns, their release times and the rules they waived. Owner or editor only, and the filename says all-brands in it — the last thing anyone reads before choosing an attachment.
One client
One client, and nothing about any other
Not a filtered view of the file beside it — that one is never run — so there is no payload holding the other fourteen for a filter to be trusted to strip. No other client is named, counted, or read to produce it.
| What the client’s file carries | Why it is there |
|---|---|
| Every release for that client in the window | The person recorded as releasing it, the format, the number of frames, a fingerprint of what shipped, and the wording they agreed to. |
| The campaign each one belongs to | Where the account-wide file has to put a brand name on every row because its rows come from fifteen brands. Here the client is stated once at the top and the campaign is the distinction that is left. |
| The rules in force at that moment | Snapshotted at release, so editing that client’s kit later cannot re-describe what a past release was checked against. |
| The audit that ran | Every finding with its tier — and whether the review pass ran at all, with the model named. |
| What was waived, and why | A blocking rule released over takes a written reason, and the reason is in the file. |
| What was set aside without a reason | Under its own key, apart from the waivers. Pooling the two would erase the distinction the record exists to preserve, and a release with three findings quietly set aside would read as a clean one. |
| Its own scope, in words, inside the file | What it covers and what it excludes. It arrives in a client’s inbox as JSON with no interface around it to explain itself, so a reader holding only the attachment knows what they may conclude from it. |
Guarded on reaching the client, not on rank
The check is whether the caller can reach that one brand, rather than whether they hold a seat of some grade in the account. So a limited seat granted one client can produce that client’s record — and is refused every other client in your account by the same predicate.
Thirty days, ninety days, or a year
Generated on demand for the period you choose, and it comes back as JSON without asking us for it.
The screen states the scope before it generates, not after
Both files look identical at a glance — same shape, same keys, same summary tile — and somebody is about to attach one of them to an email. So what the chosen file will and will not contain is written out in words first, and an account-wide file is marked as not for sending while there is more than one client in it.
Nobody can edit their own record
Release records carry a policy for reading and a policy for inserting, and none for updating or deleting — so an update or a delete affects no rows, for anyone, including the person who released. A trail the audited party can rewrite is not a trail.
Run it on something you already published for a client.
Six minutes, no account, nothing transmitted. It will tell you more about whether this fits the way your accounts actually run than the rest of this site put together.