Fragno: full-stack encapsulation
Some say that abstractions are no longer needed. I say that abstraction compresses moving parts into precise concepts so we can reason about them. AI can generate code faster, but without strong abstractions this leads to ensloppification.
One of the strongest forms of abstraction is encapsulation. This is the reason why we have libraries.
But libraries are limited. They integrate on only one side of the boundary, frontend or backend. Not to even mention the data layer. Fragno is changing that.
But before we explain that, please tell me what you'd like to know about:
What is full-stack library made of?
- Server-side API routes- Handle secure operations, API keys, and network orchestration close to the backend.
- Client-side reactive hooks- Expose stateful UI primitives that keep the integration ergonomic in the app shell.
- A database schema- Persist durable feature data so behavior survives sessions and deployments.
These three components make it so that a library can do much more: it can now dictate the entire user experience, a real vertical slice. This gives the author the opportunity to embed taste into the library.
Compare this to traditional libraries that only provide backend functions. The integrator still needs to create routes, define hooks, wire them up, and store data if needed.
Take as an example Vercel's aisdk. A clear example of a library that has to span both the frontend and the backend. The user interaction on the frontend is the heart of the experience, while the backend holds API keys and handles function calling. Contrast that to theopenai library, which only provides the backend functionality and leaves the user to do the rest.
But even the aisdk library is limited. It provides backend and frontend, but does not include the data layer. As such, they don't provide a way to store conversations, or have persistent LLM memory.
Fragno proposes a different unit of composition: the Fragment. A Fragment is a portable full-stack library slice that carries its own transport surface, optional schema, and client integration. Instead of teaching the developer to rebuild the same feature boundary in three places, it treats that boundary as one authored object.
Well, anything. But these are some examples from the Fragno ecosystem.
Pi Agents
Pi is the minimal agent runtime. With our fragment, you get durable agent sessions with easy tool calling and session management from the frontend.
View fragmentForms
Create forms using the form builder, and track submissions from your own backoffice or database.
View fragmentWorkflows
Package long-running orchestration with routes, durable state, and client controls together, so workflow behavior stays consistent across frameworks.
View fragmentBut that is not all, we have fragments for: Stripe Billing, Telegram Bots, Resend Email, GitHub Apps, and S3 Uploads.
View all fragmentsFragno is a full set of primitives: it contains handlers for all popular full-stack frameworks, as well as database integrations for popular ORMs and SQL databases.
Below you'll find some examples of how fragments are constructed and used in production.
This is from our backoffice. A Pi agent is defined with a system prompt, a model, and tools. The fragment creates durable workflow-backed sessions, so agent state survives restarts and tool calls are replayed rather than re-executed. The React client gets typed hooks for sessions and messages with zero glue code.
import { createPi, createPiFragment, defineAgent } from "@fragno-dev/pi-fragment";import { createWorkflowsFragment } from "@fragno-dev/workflows";const pi = createPi() .agent( defineAgent("support-agent", { systemPrompt: "You are a helpful support agent.", model, tools: ["bash"], }), ) .tool("bash", async ({ session }) => { const fs = await getSessionFs(session.id); return createBashTool(fs, session.id); }) .build();// Fragment = server routes + DB schema + client hooks in one objectconst workflowsFragment = createWorkflowsFragment( { workflows: pi.workflows, runtime: defaultFragnoRuntime }, { databaseAdapter: adapter, mountRoute: "/api/workflows" },);export const piFragment = createPiFragment( pi.config, { databaseAdapter: adapter, mountRoute: "/api/pi" }, { workflows: workflowsFragment.services },);import { createPiFragmentClient } from "@fragno-dev/pi-fragment/react";const pi = createPiFragmentClient({ mountRoute: "/api/pi" });// Typed hooks — derived from the fragment definitionconst { data: sessions } = pi.useSessions();const createSession = pi.useCreateSession();const sendMessage = pi.useSendMessage();// Create a session, send a message — the fragment handles the restconst session = await createSession.mutate({ body: { agent: "support-agent", title: "Customer issue" },});await sendMessage.mutate({ path: { sessionId: session.id }, body: { text: "Summarize the bug report and propose next steps." },});For users, integration should be as frictionless as possible. For a library that spans the backend and frontend, the following is enough:
import type { Route } from "./+types/example-fragment";import { createExampleFragmentInstance } from "@/lib/example-fragment-server";export async function loader({ request }: Route.LoaderArgs) { return await createExampleFragmentInstance().handler(request);}export async function action({ request }: Route.ActionArgs) { return await createExampleFragmentInstance().handler(request);}Fragments that use the optional database layer require slightly more boilerplate. By default, Fragno will use a local SQLite file to store the data. However, you can use any SQL database by providing a database adapter.
Users decide how they want to integrate. They can use Fragno directly to migrate their database, or alternatively the Fragno CLI can be used to generate a database schema in the user's preferred ORM.
Mount the same fragment across modern full-stack frameworks with shared server and client contracts.
Authoring libraries on top of Fragno
Fragno takes inspiration from industry-leading frameworks such as Hono to provide features typically expected from a backend router framework.
End-to-end type safety
Keep input, output, client hooks, and database schema typed from route handlers to UI usage.
Frontend state management
Compose reactive stores and invalidation behavior as part of your library so users get ergonomic state. Based on Nano Stores.
Streaming support
Model long-running and incremental responses with NDJSON streams while preserving typed client-side consumption.
Middleware support
Let integrators add auth and cross-cutting behavior while preserving your fragment contract and runtime semantics.
Letting third-party libraries write to an app's database is a delicate thing. Fragno's data layer is very opinionated. This makes it slightly more complicated for authors, but this gives users the safety they need.
Things that are not supported:
- Interactive transactions- Long-lived, interactive transactions can hold locks unpredictably in user-owned environments, so Fragno has two-phased transactions with optimistic concurrency control instead.
- Arbitrary joins- Arbitrary joins make query performance characteristics unpredictable, so Fragno only supports simple left joins.
In some way, Fragno is the most opinionated ORM. This is necessary to provide safety, consistency, and compatibility with several ORMs and databases. These are some features that Fragno does support:
- Atomicity- Reads and writes run as one retryable unit using optimistic concurrency checks instead of lock-heavy interactive transactions.
- Durable Hooks- Side effects are persisted in-transaction and dispatched after commit with retries and scheduled execution support. This makes interacting with third-party services reliable as well as ingesting webhooks from external systems.
- Cursor-based pagination- List endpoints page through stable index cursors, keeping large datasets efficient without offset drift. This works great with client-side state management. Pages are kept in memory to make pagination feel seamless.
- Testing with real database- Fragment tests run against real adapters so schema behavior, migrations, and hooks are validated end-to-end.
Instead of interactive transactions that hold locks, Fragno uses a retrieve → mutate pattern. Services read first, then schedule mutations. The .check() call pins version numbers — on conflict the entire transaction retries automatically with exponential backoff.
markFileDeleted({ provider, fileKey }: FileByKeyInput) { return this.serviceTx(uploadSchema) .retrieve((uow) => uow.findFirst("file", (b) => b.whereIndex("idx_file_provider_key", (eb) => eb.and( eb("provider", "=", provider), eb("key", "=", fileKey), )), ), ) .mutate(({ uow, retrieveResult: [file] }) => { if (!file) throw new Error("FILE_NOT_FOUND"); if (file.status === "deleted") return file; // .check() pins the row version — retries on conflict uow.update("file", file.id, (b) => b.set({ status: "deleted", updatedAt: uow.now(), deletedAt: uow.now() }).check(), ); // Persisted in the same transaction. See Durable Hooks tab uow.triggerHook("onFileDeleted", { ...buildFileHookPayload(file) }); return { ...file, status: "deleted" }; }) .build();}handler: async function ({ input }, { json }) { const data = await input.valid(); await this.handlerTx() .withServiceCalls(() => [ services.markFileDeleted({ provider: data.provider, fileKey: data.key }), ]) .execute(); return json({ ok: true });}Fragments that use the data layer work with the ORMs and databases your app already relies on.
Why all of this matters
Before Fragno, libraries did the bare minimum.
Now, developers of platforms such as Stripe, Telegram, and Resend can build opinionated, tasteful integration libraries that are not just wrappers around the API, but own the entire integration surface. The developers that know the platform best can ship libraries that own the entire integration surface: webhook ingestion, state persistence, and surfacing information to the end user.
Start building using agent skills
Fragno ships Agent Skills that teach your AI coding assistant how to integrate or author fragments. Install a skill once and your agent knows the conventions, APIs, and best practices.
For users
Integrate existing fragments into your app. The skill includes a list of first-party fragments, to make installing them easy.
npx skills add https://github.com/rejot-dev/fragno --skill fragnoFor authors
Build your own fragments. The skill teaches your agent how to scaffold a package, define routes and hooks, set up code-splitting, and export framework clients.
npx skills add https://github.com/rejot-dev/fragno --skill fragno-authorOur Fragno Claw-like agent
This site and our internal Claw-like agent tooling run on the same fragment primitives outlined on this page. We believe that the only way to build truly good software is by dogfooding it every day.
Stay tuned for more updates on our "Claw".
This website contains the full documentation for Fragno, including the user and author guides, reference, and API documentation.
Occasional email for new essays and releases. Source and chat live below.