Note on evolution: The framing of this proposal shifted significantly through the discussion. @janx pushed me to clarify the categorisation — this is not a transaction-DAG L2 or a new ledger, but a UTXO-generation surface. @phroi’s questions about inter-protocol composition helped me separate CellScript’s single-protocol focus from CellFabric’s cross-protocol coordination role. The current structure reflects those clarifications.
One conclusion i currently draw from this discussion is that CellFabric should not be framed as a transaction-DAG L2 or a new ledger. The better category is narrower:
CellFabric should be explored as a UTXO-generation and inter-protocol composition surface for CKB.
In particular, I now see two related but separate problems.
The first problem is individual protocol authoring.
How do we make a single CKB cell protocol easier to write, inspect, compile, and reason about? This is the role I currently see for CellScript. It should make lock/type boundaries, witnesses, receipts, assumptions, and ProofPlan coverage explicit for one protocol.
The second problem is inter-protocol transaction generation.
How do wallets, apps, solvers, and protocol-specific builders coordinate multiple protocols before final CKB settlement? How do they expose intents, conflict surfaces, settlement plans, verifier interfaces, and user-facing receipts without turning the upper layer into a new ledger?
This second problem is what I would now place under the name CellFabric.
CellFabric is a UTXO-generation and inter-protocol composition surface for CKB.
It asks whether wallets, apps, solvers, and protocol-specific builders can share a minimal language for intents, conflict surfaces, receipts, and settlement plans before producing final CKB transactions.
CKB remains the verification and settlement layer. CellFabric lives on the generation side.
So the proposed split is:
CellScript = author and compile individual cell protocols.
CellFabric = coordinate intents and settlement plans across protocols.
CellIntent = a pre-settlement generation object, not a ledger object.
CKB transaction = the final verification and settlement object.
In this framing, CellFabric is not primarily a DAG protocol. A graph may still be useful for indexing dependencies, conflicts, lineage, and bundle history, but the graph is an observability and coordination structure, not the protocol identity.
CellFabric is not trying to make the graph itself into a ledger. It is meant for intent propagation, conflict visibility, solver/builder coordination, deterministic settlement planning, and auditable pre-settlement receipts. Settlement, exits, and disputes should still return to CKB.
A receipt in CellFabric is not finality. A bundle is not a block. An orderer or solver is not the owner of state.
Why CellIntent as the Pre-Settlement Object?
I would not state CellIntent as a hard theorem. It is more of an engineering boundary between user intent and concrete CKB transaction generation.
If the coordination object is a block, the upper layer starts to inherit block-layer questions: who creates blocks, how often, what order exists inside the block, what happens when producers disagree, and whether empty blocks exist. That is not wrong for an execution network, but it is more structure than a UTXO-generation surface needs.
If the coordination object is already a concrete CKB transaction, the design is still possible, but the boundary is awkward. Replacement means rebuilding transactions. Batching means taking apart already-shaped transactions. Matching and solver work need templates, placeholders, partial signatures, or side conventions. Those tools can work, but at that point an intent layer is being rebuilt around the transaction anyway.
CellIntent sits between the two. It is not final enough to be settlement, but it is concrete enough to expose expected cells, app resources, witnesses, signatures, expiry rules, and conflict surfaces. For CellFabric, that seems like the least awkward pre-settlement object.
Proposed Architecture
The architecture is basically a generation pipeline. Users submit CellIntents. A gateway or app-specific builder checks basic validity. A coordination index records dependencies, conflicts, expiry, and lineage. Solvers or orderers select compatible bundles under declared rules. A settlement compiler turns selected bundles into concrete CKB transactions. A tracker follows those transactions on L1.
The important boundary is that a solver/orderer may select and sign a bundle, but the settlement compiler still has to produce real CKB transactions. The receipt is useful for accountability and UX, but it is not a substitute for CKB settlement.
Conflict Model
For cells, the obvious hard conflict is simple: two intents trying to consume the same outpoint cannot both settle. That part fits CKB naturally.
The more interesting problem is protocol-level or app-level conflict. AMM pools, launchpad allocations, order-book levels, registries, auctions, and oracle windows often have shared resources that are not fully captured by the cells a user names at intent time. If the generation layer ignores those resources, the solver/orderer becomes a private matcher that everyone has to trust.
So each protocol or app should expose conflict keys in a deterministic way. A CellIntent can declare the keys it touches, but the app policy should be able to recompute them. If the two do not match, the intent should not be treated as safely orderable.
Ideally, conflict keys should not be arbitrary strings asserted by the intent submitter. They should be recomputable from the protocol’s declared policy, CellScript metadata, or a verifier interface. Otherwise the conflict model becomes another hidden trusted convention.
This is deliberately less clean than pretending conflicts only exist at L1. The whole point of the upper layer is to see likely contention before the final transaction is built.
Coordination Receipt
A Coordination Receipt should be boring and explicit. It means a solver/orderer has selected a bundle under some declared rule and signed that statement. It does not mean the state change is final.
The receipt should contain enough information to audit the coordination statement: bundle id, selected intents, selection rule or version, expiry, coordinator identity, signature, and a commitment to the data needed to inspect the bundle.
It would appear to be something like this struct snippet :
pub struct BundleReceipt {
pub bundle_id: BundleId,
pub orderer_id: OrdererId,
pub ordered_intents: Vec<IntentId>,
pub selector_version: u16,
pub compiler_version: u16,
pub intent_root: [u8; 32],
pub conflict_root: [u8; 32],
pub data_availability_root: [u8; 32],
pub created_at_ms: u64,
pub issued_at_ms: u64,
pub valid_until_ms: u64,
pub non_final: bool,
}
If two orderers make different choices, or the same orderer signs inconsistent receipts, that should be visible. It still does not replace CKB settlement.
Settlement Compiler
The compiler is where the upper-layer object becomes CKB-shaped. It should take an immutable bundle and lower it into concrete CKB transactions. It should not read a live mutable DAG while compiling. It should not depend on the orderer’s private memory. Given the same bundle and compiler configuration, it should produce the same settlement plan.
Practical Scenarios
1, low-latency transfers, CellFabric can give wallets fast feedback while keeping final settlement on CKB. The useful distinction is that a user can see whether an intent is indexed, conflicted, coordination-receipted, submitted, or settled instead of treating all of those states as one vague ‘pending.’
2, launchpads, conflict keys can make allocations visible before settlement. A sale might have keys for the pool, the round, and each user’s allocation. If two claims touch the same allocation key, the conflict is visible before the CKB transaction exists.
3, AMM batching, many swap intents can compete over the same pool. A pool-specific orderer can choose a batch and compile one pool transition back into CKB. The pool is still a CKB cell; the upper layer only coordinates the batch.
4, RFQ or order-book flows, makers can publish constrained intents and solvers can compose them. Replacement and partial matching are much easier before everything is fixed as a concrete transaction.
5, cross-application solving, one bundle might include a mint, transfer, swap, claim, and fee payment. The compiler still has to lower the result into real CKB transactions, so the system does not need an account-style global state machine above CKB.
Observability (intent explorer)
A CellFabric explorer should not just be a block explorer with smaller blocks. The useful view is the coordination graph: where an intent sits, what it conflicts with, which bundle selected it, who signed the receipt, what data the receipt commits to, what settlement plan was produced, and whether the CKB transaction has settled.
The coordination graph is relevant here as an observability structure. It gives users a way to reason about intent ancestry, conflict surfaces, and coordination waypoints. CellFabric should aim for similar graph-native visibility, but with CKB-specific objects: cells, app conflict keys, intent bundles, settlement plans, and L1 status.
Decentralisation Path
I would likely not try to make the first version fully decentralised. Probably wiser to begin with one orderer and prove that the intent format, conflict model, bundle selection, compiler, and direct CKB settlement path work. Then move to a small known orderer set. Only after data availability, auth verification, exit paths, and dispute evidence are more mature does it make sense to discuss open orderer admission, stake, reputation, or quorum rules.
The important thing is not to describe the early system as more trustless than it is. A coordination receipt is not final. Conflicts should be queryable. Settlement lineage should be auditable. Users should keep an L1 path if the orderer fails.
A Few Open Questions
-
How should apps define/expose conflict keys without turning the app compiler into hidden trusted logic?
-
UIUX-wise, what should wallets show before L1 settlement?
-
What is the smallest forced-exit design that is actually useful?
-
What data must be available for a coordination receipt to be meaningful?
-
How can multiple orderers converge without becoming a new consensus layer?
-
Can AMM, launchpad, and order-book workloads stay cell-shaped instead of drifting into account-style global state?
References
- Nervos Talk discussion: CellScript 0.1 - A DSL for Cell-Based Contracts
- Obyte technology overview: A DAG based ledger
- Obyte order providers: Order Providers



