End the fragmentation of information.
We build Fable — a unified workspace that brings mail, chat, calendar, files and AI into a single surface — in house, from architecture through implementation and operations. The same team also takes on research, consulting and contract development.
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
const url = new URL(request.url);
if (url.pathname.startsWith('/api/')) {
const identity = await verifyAccessJwt(request, env);
if (!identity) return json({ error: 'unauthorized' }, 401);
return route(url, request, env, identity);
}
// Same origin serves the SPA. There is no CORS.
return env.ASSETS.fetch(request);
},
} satisfies ExportedHandler<Env>; export async function syncAccount(account: Account, env: Env) {
const adapter = adapters[account.provider]; // gmail | slack | line …
const cursor = await readCursor(env.DB, account.id);
try {
const page = await adapter.pull({ account, cursor });
await upsertConversations(env.DB, page.conversations);
await writeCursor(env.DB, account.id, page.nextCursor);
return { synced: page.conversations.length };
} catch (err) {
if (isInvalidCursor(err)) return resync(account, env); // full resync
if (isTokenExpired(err)) return reconnect(account, env);
throw err;
}
} -- Track hidden conversations. Existing rows stay visible.
ALTER TABLE conversations
ADD COLUMN hidden_at TEXT DEFAULT NULL;
CREATE INDEX IF NOT EXISTS idx_conversations_owner_visible
ON conversations (owner_id, hidden_at, last_message_at DESC);
-- Enforce the owner-only read path at the index level too.
CREATE INDEX IF NOT EXISTS idx_conversations_owner
ON conversations (owner_id); Runs on
- TypeScript
- React 19
- Next.js
- Cloudflare
- Go
- Node.js
- D1 / SQLite
- Docker
- Terraform
- AWS
What we do
Research, decide, build, operate — one team, all four.
The person who writes the spec implements it and runs it in production. With no handoff telephone game, decisions land faster and the reasoning behind them survives. We take on everything from a single question to the architecture of an entire product.
-
01
Product development
Planning, design, implementation and operation of Fable, our unified workspace. We build it as the environment we use every day.
-
02
Technology consulting
From mapping business processes to architecture, technology selection and migration planning — designed by people who will implement it.
-
03
Market and data research
Competitive and technology landscape studies, quantitative and qualitative research, metric design — always with sources and assumptions stated.
-
04
Contract development
Design and implementation of web apps, internal systems and API integrations — including handing over CI and monitoring.
Product
Twelve services, one inbox.
Every service is an adapter on a shared sync engine — incremental sync, recovery from expired tokens and read-state propagation all handled behind one contract.
- Gmail
- Calendar
- Drive
- Slack
- Discord
- LINE
- Signal
- Telegram
- Messenger
- 01
One timeline per person
Messages from the same person stop splitting across services. They line up in a single chronological thread.
- 02
Search across everything
Mail and chat share one index, so a single query covers all of it.
- 03
Sync that does not drop messages
Incremental sync, resync from an invalid cursor and reconnection on token expiry are all standard.
- 04
Passkey authentication
WebAuthn plus Cloudflare Access — two independent boundaries. Knowing the URL is not enough to get in.
How we work
From first conversation to production
- 01 1–2 weeks
Discovery
We map your workflows, the tools in use and where things get stuck. The best time to start is before requirements are fixed.
Problem brief / open questions
- 02 2–4 weeks
Research and design
We test the market and technical assumptions, then settle architecture, stack and migration plan — with the reasoning written down.
Research report / design doc / ADRs
- 03 1–3 months
Implementation
Something running early, refined in weekly review. Types, lint and end-to-end tests are fixed exit criteria.
A production application
- 04 Ongoing
Operations
SLOs and monitoring in place, daily reports on system state, and runbooks written for handover from day one.
Monitoring setup / runbooks
- 05 2–4 weeks
Transfer in house
We share design intent and code conventions, and pair with your team until they can run on their own.
Developer guide / handover training
- 06 Quarterly
Review and reinvest
We look at how the metrics moved and propose a prioritised list of what to work on next.
Quarterly review / improvement plan
Typical requests
What people ask us for
-
PRODUCT
Bring communication scattered across tools into one place
-
CONSULTING
Review whether our current technology choices still hold
-
RESEARCH
Study the market and competitors before we enter
-
DEVELOPMENT
Replace a manual process with a real application
-
AI
Introduce an AI-assisted development practice in house
-
OPERATIONS
Re-examine our cloud architecture and spend
-
SECURITY
Rework authentication and permissions ahead of an audit
-
DATA
Consolidate scattered data and surface the metrics
-
RESEARCH
Compare candidate technologies against our constraints
Engineering culture
Code that fails verification never ships.
Types, lint, end-to-end tests and screenshot review are fixed exit criteria on every task. Specs and the reasoning behind decisions live in the repository, and we split the work with AI agents.
-
The repository is the spec
Docs, planning, tasks and ADRs are the source of truth, so every decision stays traceable.
-
AI agents in the loop
Task selection, implementation, verification and commits are shared with agents. People spend their time on judgement.
-
Verification is automated
Build, types, lint, Playwright and screenshot review are fixed exit criteria.
-
We own operations
SLOs, monitoring dashboards and the daily report bot are part of the design.
-
Types as the first defence
TypeScript strict, no any. Breakage is caught before anything runs.
-
Forward-compatible migrations
Schema changes apply in an order that never breaks existing data, and stay reversible.