Capxul · Delivery · 31 August 2026
We build them into the SDK now — the published set of ready-made pieces that any app can drop in, ours or somebody else's. The pieces are headless components: they carry all of the behaviour and none of the appearance. That sounds like an internal detail. It is the most consequential thing that happened this week.
Until this week, the difficult part of a feature lived inside the screen that showed it. Contacts logic lived in the contacts screen. Working out what somebody is allowed to do was written into every screen that needed to know — slightly differently in each one.
We paid both costs of that. A bug had to be fixed in four places, and we usually found three. And every new screen started from nothing, because there was nothing to reuse.
Now it is built once, in the SDK, and it draws nothing. One piece knows how to load your contacts, add one, rename one, hide one, what to do while it is loading, and what to report when it fails. It does not know what any of that looks like. Whoever places it supplies the look.
This is the contacts capability, as a developer uses it. It is worth looking at even if you do not read code, because the shape of it is the whole argument.
// Everything about contacts. Draws nothing.
<CapxulContacts actor={me} onAdded={toast} onFailed={showError}>
// The count tile.
<CapxulContacts.Summary>
{({ total, activeCount }) => <YourStatTile value={total} sub={activeCount} />}
</CapxulContacts.Summary>
// The list. Five rows on a dashboard, all of them on a full screen.
<CapxulContacts.List limit={5}>
{({ rows, isLoading }) => rows.map((r) => (
<YourContactRow
key={r.id}
name={r.name}
initials={r.initials}
onRename={r.rename}
onHide={r.hide}
/>
))}
</CapxulContacts.List>
</CapxulContacts>
Three things are true in that snippet, and they are the reason this matters.
total, activeCount, rows,
initials — already fetched, already correct, already consistent
between the dashboard and the full screen. Nobody writes that twice.
r.rename and r.hide are wired to the backend, with the
loading and failure cases handled. You attach them to a button. You do not implement
them.
YourStatTile and YourContactRow are whatever you like
— our design, a partner's design, a completely different product's design. We
never say what a contact looks like.
Permissions are the same idea, smaller. This is a real button that only exists for somebody allowed to spend:
<CapxulOrgMember.Can action="spend">
{({ allowed }) => allowed && <YourPayButton />}
</CapxulOrgMember.Can>
allowed is false until the real answer arrives, deliberately.
A pay button can never flash into view for somebody who is not allowed to press it. That
rule now lives in one place instead of being re-remembered on every screen.
A component that carries no appearance is one anyone can restyle completely. They are not adopting our design, our brand, or our layout — they take the behaviour and draw their own product on top. Payments, contacts, permissions, spending limits and history stop being things they have to build.
And it makes Capxul something an agent can build with. This is the part worth sitting with. An AI agent asked to build a payments screen today has to understand payments, permissions, balances and the blockchain, and it will get some of that subtly wrong. Given these pieces it does not have to understand any of it.
Every piece announces exactly what it hands over — the values, the actions, the failure cases. An agent reads that and knows what it is allowed to do. There is nothing to guess and nothing to reinvent.
Which is the part agents are genuinely good at. The money logic underneath is ours, already correct, already tested. It cannot be got subtly wrong by a confident guess.
Someone should be able to point an agent at Capxul and have a working, styled payments product back, without that agent touching a single line of money handling. Every capability we move into the SDK makes that more true. It is the same work we would have done anyway, done in a better place.
Fitting one of this week's capabilities into Capxul deleted around 2,700 lines and added around 1,500. The app came out roughly 1,200 lines lighter and gained the feature.
That is not a vanity number. It is fewer places for something to break, and less to read before anyone — or any agent — can change anything.
Because these components bring no appearance with them, Capxul still looks exactly like Capxul. The designs did not change. We connected finished screens to real behaviour rather than redrawing them.
That is a deliberate rule while the capabilities land, not a happy accident.
Four capabilities went in this week. Each one is a root that holds the behaviour, plus named parts a screen arranges however it likes.
An address book where a person stays the same person after they sign up, so their payout details never orphan.
One send flow serving both a person and an organisation, instead of two that drift apart.
Whether somebody may manage people or spend money, and which budgets they hold, with the real limit on each.
Whether this person may be here at all, decided once rather than guessed by each screen.
Beneath them sit around forty smaller building blocks — balances, holdings, payments, invitations, permissions — that any screen can use directly.
These are the eight on the queue. Each is a complete thing a person can do, and each now gets built the same way — into the SDK first, then placed into our screens.
An address book where a person stays the same person after they sign up.
Standing, permissions and budgets, answered in one place instead of guessed per screen.
The money feed — filters, export, notes, receipts, and a payslip for the person who was paid.
One send flow serving both a person and an organisation, rather than two that drift apart.
Rosters, pay runs, run records, payslips.
Issue and settle, and a payment link for the person being billed.
The screen is missing. Everything behind it already exists.
Taking money in from outside Capxul.
Five more sit behind these — scheduled and streaming payments, treasury, withdrawals, organisation membership. Eight further ones are parked on purpose and carry no work at all.
Four releases went out in seven days. Before this week, releases carried foundation work — necessary, invisible, impossible to demonstrate. These four carried capabilities.
Contacts goes out. The address book stops being a guess.
Access goes out. Permissions and budgets answered honestly, in one place.
Two more, hardening the money path — interrupted setups recover, invitations activate on the spot, permission grants retry until the chain confirms them.
That is the cadence we are holding: a capability leaves the SDK, the app picks it up, and the app gets simpler each time it does. Repeat until the queue is empty.
One supplier also left the building. Reading somebody's balance no longer goes through a paid third party — it goes through our own node, which we already run.
Four of the eight are moving. The other four have not had their turn, and nothing about them is blocked — we are simply not starting a fifth while four are in flight. Each goes through the same three stages before any code is written: map what exists, answer every unknown, agree the shape.
That gate is the reason this week did not stall. Skipping it is exactly what cost us three weeks in August.