Skip to content

About

2WAY System PoC Design

Resources

Stars

17 stars

Watchers

0 watching

Forks

Repository files navigation

2WAY design repository


Table of Contents


1. 2WAY design repository in short

2WAY is a protocol and backend for software that stays correct without a central authority. It gives apps a local-first foundation for identity, permissions, ordering, storage, and sync, enforced by the system. Each device, user, and app keeps its own keys and history and enforces the same rules. Changes are accepted only if valid, authorized, and structurally sound.

State is a cryptographically verifiable graph, not mutable rows behind an API. Accepted changes form an append-only, ordered history with clear authorship. Sync trusts verification, not transport, timing, or peers.

The proof of concept defines the guarantees: a strict validation pipeline, graph-encoded permissions, replayable audit, and ordering assigned locally and replayable across nodes. Security assumes a hostile network, so every envelope is verified and rejected early if structure, schema, or authorization fail. Privacy is enforced by explicit read scopes, keeping data local by default and sharing only what a node is allowed to see. Incentives are neutral at the protocol layer, and conformance is binary.

This repository defines the protocol, architecture, and invariants that make those guarantees hold. It is a design repo, not an SDK and not a demo. The goal is a system that stays predictable under failure, adversarial input, and long time horizons.

Looking for a more comprehensive read-through? See README-long.md.


2. Why it exists

Most systems tie identity, permissions, ordering, and storage to whoever runs the backend. That makes the operator part of the trust model. If the operator changes rules, gets compromised, shuts down, or makes a mistake, users lose authority over their own history. Federation rarely fixes this. It spreads the same problem across fragile bridges and special cases.

2WAY separates durable structure from transient infrastructure. Identity, ownership, permissions, and history live in a shared, cryptographically verifiable graph that every device, user, and app enforces locally. No server decides what is valid. No relay decides what is authoritative. Software can change, vendors can disappear, and the rules still hold.

Because all state changes are signed, ordered, and append-only, a device does not need to trust uptime or timing. It can go offline, fall behind, or disconnect. When it reconnects, it verifies and replays history until it converges again. Authority comes from keys and structure, not from who stayed online the longest.

The point is not decentralization for its own sake. The point is multi-party software that remains correct when operators fail, infrastructure degrades, or trust assumptions break.


3. Repository guide

This repo is the main design set for the proof of concept. Normative specs live under specs/ and define scope, rules, architecture, object models, security, flows, and acceptance criteria, with PoC goals in specs/07-poc. Lower-numbered spec folders carry higher authority. When conflicts appear, record an ADR in specs/09-decisions so exceptions stay visible. docs-build/ is a non-normative build pack that must stay aligned with the specs.

Folder Focus
specs/00-scope Vocabulary, boundary, assumptions
specs/01-protocol Wire format, object model, rules
specs/02-architecture Managers and services that enforce the protocol
specs/03-data Persistence model and lifecycle
specs/04-interfaces APIs and event surfaces
specs/05-security Threat framing and structural controls
specs/06-flows Bootstrap, sync, recovery, governance flows
specs/07-poc What the proof of concept must demonstrate
specs/08-testing Test categories, conformance, and regression policy
specs/09-decisions Architecture Decision Records
specs/10-appendix / specs/11-examples Reference material
docs-build Build planning and traceability (non-normative)

4. What 2WAY is

2WAY is a protocol and backend that replaces the traditional server as authority over application state. Every node runs the same core system for identity, permissions, ordering, storage, sync, and audit. Because those controls are enforced locally, devices can go offline, keep working, and later reconcile changes without handing authority to a central service.

Applications do not manage storage or trust directly. They define schemas, domain logic, and user interfaces, then operate against a constrained system interface. Apps submit proposed changes and the system validates them. Only changes that satisfy schema rules, ownership, and access control become part of shared state.

At the center is a shared graph: the canonical record of identities, devices, apps, relationships, capabilities, and application objects. Every object has explicit ownership. Every relationship is typed. Each change declares which identity authored it and under which rules it is allowed to exist.

History is append-only and ordered. Once accepted, a change cannot be rewritten or physically removed; visibility suppression happens through Rating objects at read time rather than deletes. Entries reference structure, payload, and ancestry so they can be verified and replayed. Peers exchange signed sequences, then validate them locally. A node accepts only what satisfies its own rules, using the same logic it applies to local changes.

The result is a system where correctness does not depend on transport, uptime, or coordination. State converges because it is verifiable, not because a server says so.


5. Graph, objects, and protocol model

2WAY defines a protocol for how state is created, validated, ordered, and shared. It is centered on a shared graph rather than APIs or databases. The protocol overview provides the high-level structure, with supporting architectural context in the architecture overview and data flow lifecycle.

All application state is represented as graph records with formal object model definitions. The model is small and explicit. Parents anchor identities, devices, apps, and domain objects. Attributes attach typed data to Parents. Edges express relationships, capabilities, and transitions. Ratings capture judgments such as endorsements or trust signals. Identifiers and namespaces remain unambiguous across apps and devices, following Identifiers and namespaces. Access control is not external logic. It is encoded into the same graph using constrained Parents and Attributes, keeping authorization visible, replayable, and verifiable like any other data, as described in the access control model.

Apps are first-class participants in the protocol. Each app has its own namespace, schemas, and portion of the graph. Schemas are defined by apps and stored in the graph itself through the Schema Manager and the shared object model. They specify which object types exist, how they relate, and what values are valid. The protocol does not interpret application meaning. It enforces that meaning structurally and consistently, so every node evaluates the same rules when deciding whether a change is acceptable.

Every proposed change is wrapped in a protocol envelope that specifies the operation records and required identifiers, as defined in Serialization and envelopes. Sync packages add sender identity, domain metadata, and sequence fields for ordering and replay checks. When a node receives an envelope, it validates it locally. Structure is checked first, including object model invariants and app namespace boundaries. Schema rules are then applied to ensure the change fits the app's schema. Access control is evaluated next using graph-encoded permissions. Only if all checks succeed is the change assigned a global order and committed, with failures classified per Errors and failure modes. Canonical error shapes and transport mappings are defined in 04-error-model.md. This pipeline runs across the Graph Manager, Schema Manager, and ACL Manager.

History is append-only and ordered per Sync and consistency. Nodes exchange signed, ordered envelopes rather than mutable state. Each node replays those sequences independently and accepts only the parts that satisfy its local rules. Ordering comes from protocol-defined sequence assignment, not from message arrival or wall-clock time, with storage-level constraints captured in Sequences and ordering. This allows nodes to diverge temporarily, operate offline, and still converge without trusting transport or peers.

For the proof of concept, the graph is persisted in SQLite as a relational store, with durability and layout owned by the Storage Manager and detailed in the data model overview and SQLite layout. SQLite keeps the PoC storage footprint small and predictable, which makes it realistic to run the same graph persistence layer on desktops, servers, and even embedded devices in theory while still supporting transactional ordering and replay. The protocol remains database-agnostic: it assumes only a storage layer that can persist ordered graph state and replay it deterministically, not a specific engine.

The result is a protocol where apps, schemas, identities, permissions, and records all live in the same verifiable structure. The graph is not an internal implementation detail. It is the protocol surface. Everything else, networking, storage engines, frontend frameworks, exists only to move envelopes in and out of that structure.


6. Backend component model

The backend makes the rules real. It is one integrated system that decides what is valid, what is allowed, what order changes land in, and what gets stored. If something fails validation, it never becomes part of state, no matter who sent it or how it arrived. This is the opposite of systems that rely on server-side discretion or relay behavior; authority lives in the enforcement pipeline that every node runs locally.

That is the key difference from architectures built around loose roles like clients, servers, and relays. In those systems, correctness depends on assumptions, relay behavior, server-side logic, or social norms. In 2WAY, authority lives in the protocol enforcement pipeline that every node runs locally. A node does not accept state because a peer says it is fine. It accepts state because it can verify it and it passes the same checks it applies to its own writes.

The backend is built from singleton managers with narrow jobs that form one path for reads and writes, as defined in the Managers overview. The Config Manager loads configuration and rejects unsafe settings. The Auth Manager resolves local sessions into an OperationContext per Operation Context. The Key Manager owns private keys and performs signing and decryption for trusted callers. The App Manager registers apps and app identities. The Schema Manager checks that a change matches the app's declared structure. The ACL Manager checks that the caller has the right to perform it, using the current OperationContext. The Graph Manager is the only place where writes are accepted. It validates object model invariants, assigns a global_seq, and commits through the Storage Manager. The State Manager coordinates ordered sync and package construction from accepted history. The Network Manager admits peers, verifies packages using public keys, encrypts payloads with recipient public keys when required, decrypts via the Key Manager when required, and never changes protocol data. The Event Manager and Log Manager record what happened and why. The Health Manager and DoS Guard Manager keep the node stable and reject load before correctness can be threatened.

Services sit above the managers and provide higher-level behavior. They turn user intent into protocol-compliant operations, expose backend endpoints, and do app-specific aggregation or validation when needed. They do not get special authority. They cannot write around the managers, bypass schema or ACL checks, or touch keys, storage, or sockets directly. They must always call into the same enforcement path with a complete OperationContext as defined in Operation Context.

There are two service classes. System services are always present and cover shared workflows that multiple apps rely on. App services are optional and scoped to one app. They exist for backend-heavy features like indexing or specialized queries, and removing them must not break the core or corrupt state.

The point of this design is that the backend behaves like a kernel. It enforces one coherent model of validity, permission, ordering, and persistence. Everything above it can change, but enforcement does not become optional.


7. Security model

2WAY assumes the network is adversarial and peers can be careless, compromised, or hostile. Security is enforced by protocol structure rather than operator policy. Each device, user, and app holds its own keys and history, and every node verifies incoming changes locally before accepting them per Cryptography and Keys and identity.

All writes, local or remote, use the same envelope path and validation order: structural checks first, then schema rules, then ACL authorization as defined in Serialization and envelopes and the access control model. Ordering is assigned locally and is repeatable, so replayed or reordered input cannot change outcomes per Sync and consistency.

Sybil resistance comes from bounded reach, not global reputation. Identities are key-bound, app namespaces are isolated, and permissions are explicit in the graph, so unknown identities cannot gain broad access without explicit edges or ACL grants per Identifiers and namespaces and the access control model. This limits the blast radius of fake identities and impersonation attempts.

Denial-of-service protection is part of the protocol pipeline, not a bolt-on. The DoS Guard Manager gates admission at the network boundary and can require client puzzles before any payload flows inward, following DoS guard and client puzzles and Network transport requirements. Puzzle difficulty adjusts dynamically to load and abuse signals, and the system fails closed on policy or puzzle failures. Earlier stages reject malformed input without expensive work, and failures are classified consistently by the protocol overview and Errors and failure modes.

Recovery is intentionally simple. Accepted changes are ordered and append-only, and sync packages are signed, so a node can rebuild by replaying history and reapplying the same rules. Unverifiable history is rejected rather than patched or trusted per Sync and consistency.

The protocol does not define social or political choices. Governance models, moderation rules, incentives, and policy meaning live in application schemas and data. The protocol enforces correctness, authorship, and ordering, not policy content.


8. Incentives

2WAY is neutral on economic incentives at the protocol level. The protocol includes Ratings as a first-class object category, and ACL rules can gate actions using app-defined rating or trust thresholds, but those values live in application data and are scoped to the app domain. There is no global reputation score, token, reward scheme, or fee market enforced by the protocol itself. That is intentional.

The core incentive is correctness. Nodes participate because enforcing the protocol locally protects their own state. A node that validates strictly, rejects invalid input, and orders changes correctly ends up with a coherent, auditable history it can rely on. A node that cuts corners gains nothing durable and risks corrupting its own state. This creates a baseline incentive to follow the rules without payments or coordination.

For users, good behavior is the easiest way to keep their own graph usable and their relationships intact. Most value in 2WAY flows through explicit edges and permissions, so bad behavior breaks access, severs collaboration, and makes a user's own history less trusted by the people and apps they want to work with. Good behavior preserves continuity: your device keeps syncing, your records remain accepted, and your peers keep you in their allowed scopes. The balance comes from local enforcement and mutual dependence. You cannot force others to accept bad input, and they cannot be forced to keep sharing with you if you violate rules, so honest participation is the stable path.

Because every device, user, and app keeps its own keys and history, there is no central operator that can extract rent by default. Running a node does not grant control over others, and there is no privileged position to monetize purely by being in the middle.

Abuse resistance is handled structurally rather than economically. Sybil behavior is limited by relationship depth, ACLs, and schema constraints, not by proof-of-work or staking. Flooding the network is discouraged by DoS guards, early rejection, and local resource limits. These mechanisms do not reward good behavior with payouts, but they make bad behavior ineffective and costly in local resources.

Incentives that matter to users and developers live above the protocol, inside applications. Apps can define their own economic models, governance rules, trust signals, or reputation systems as graph data. Markets can encode listings, contracts, escrow, and settlement logic. Communities can encode moderation, membership, and voting. Enterprises can encode approvals, compliance flows, and audit requirements. None of these meanings are hard-coded into 2WAY, but all of them benefit from the same guarantees around identity, ordering, authorship, and replayability.

This separation is intentional. It prevents the protocol from baking in assumptions about value, scarcity, or motivation that may not hold across domains or over time. It also avoids coupling long-term infrastructure correctness to short-term incentive fashions. If an incentive model is flawed, it can be changed at the application level without forking the protocol or rewriting history.

For operators and integrators, the incentive is leverage. By building on 2WAY, they avoid re-implementing identity, permissions, sync, and audit for every system. They gain durability and user trust without having to promise perpetual uptime or benevolent control. Because apps share a common graph model and enforcement rules, they remain interoperable: developers can build on each other's schemas and data without lock-in, and removing one app does not break the system or invalidate the underlying state.

2WAY can also sit alongside existing systems, integrating at the edges while letting legacy apps and new 2WAY-native apps reinforce each other rather than compete for control.

For users, the incentive is autonomy. Their data, history, and authority persist even if an app, vendor, or service disappears. That means you can move between tools without rewriting your identity or losing the context attached to your records. If a front end goes away, your state is still readable and verifiable because it lives in the shared graph, not in that app's private database. You can keep working offline and sync later without having to trust a central operator to arbitrate what is real. Permissions follow the same rules everywhere, so access does not become a negotiation with each new product. Your history remains auditable, so you can trace who did what and when without relying on screenshots or exports. If you want a different interface, you can adopt another app that speaks the same protocol and continue from the same state. The system favors continuity and user control over vendor-specific gatekeeping. Autonomy here is practical: it protects long-term access, reduces lock-in, and lets users choose tools based on fit rather than fear of losing their data.

In short, 2WAY does not try to motivate participation with rewards. It motivates participation by making correct behavior the simplest path, abusive behavior ineffective, and long-term control stay with the people and applications that use the system.


9. Privacy

2WAY treats privacy as a structural property, not as a feature layered on later. The system is designed so nodes only see what they are allowed to see, and only share what they explicitly choose to share. There is no global view of the network, no mandatory data aggregation point, and no requirement to disclose more information than an application's rules demand.

Each node keeps its own full state locally. Data is not pulled into a central service by default, and there is no background process that mirrors complete histories elsewhere. When nodes exchange data, they do so through scoped synchronization. Only the parts of the graph that fall within an allowed domain and pass access checks are included. Objects outside those scopes never leave the device, even if they exist in the same local graph.

Visibility is enforced by the same mechanisms that enforce correctness. Access control rules live in the graph and are evaluated for every read and every sync decision. If an identity does not have permission to read an object, that object is omitted entirely rather than redacted after the fact. This prevents accidental disclosure and makes privacy failures easier to reason about, because absence is explicit rather than inferred.

Identity is decentralized and composable. Users, devices, and apps each have their own keys, and relationships between them are explicit. This allows people to operate across multiple apps or contexts without collapsing everything into a single global profile. Pseudonymous identities can exist alongside real-world ones, and applications can choose how, or whether, to link them. The protocol does not require universal discoverability.

Network privacy is separate from data privacy. Transport can run over Tor or other privacy-preserving networks, but the protocol does not assume the transport layer is trusted or private. Messages are signed so authorship can be verified, and they can be encrypted so contents are not visible to intermediaries. Even if transport metadata leaks, the graph structure limits what meaningful information can be inferred.

Because history is append-only and verifiable, privacy does not depend on secrecy alone. Unauthorized parties cannot rewrite or silently alter records to remove traces or fabricate consent. At the same time, applications can encode expiration, revocation, or visibility rules directly into their schemas to limit how long data remains relevant or accessible. The protocol enforces those rules consistently across nodes.

The result is a system where privacy emerges from local control, explicit sharing, and enforced boundaries. Users do not have to trust a service to handle their data carefully. They can verify what is shared, with whom, and under which rules, because those rules are part of the state itself.


10. Application model and use cases

In 2WAY, an application is not a backend service that owns data. It is a way of working with shared state the system already knows how to protect. That model assumes the protocol-level incentives and privacy boundaries already described: apps inherit correctness-first participation and scoped visibility, rather than reinventing them. From a user's perspective, an app feels local and responsive. You can create, edit, and inspect records on your own device, even when you are offline. When the network is available again, your changes are checked, ordered, and merged with everyone else's in a predictable way. Nothing disappears because a server is down, and nothing silently changes because a service updated its logic.

From a developer's perspective, an app defines what the data means and how people interact with it. You describe the kinds of records the app uses, how they relate, and who is allowed to do what. The system takes care of identity, permissions, history, synchronization, and audit. Instead of writing custom backend logic to keep things consistent, you propose changes through the protocol and let the system decide whether they are valid. If they are accepted on one node, they will be accepted the same way everywhere.

Apps model their domain data with the same graph primitives: Parents (core entities), Attributes (typed fields), Edges (relations), and Ratings (judgments). That makes relationship queries first-class. Degrees-of-separation queries become bounded graph traversals across explicit edges (contacts-of-contacts, delegated access, trust paths), filtered by schema and ACL so results only include readable nodes. App services can build indexes or materialized views for large datasets, but they still evaluate the same rules and cannot manufacture authority.

This makes apps easier to reason about and test. State changes form an ordered history that can be replayed to reconstruct the app at any point in time. Bugs are easier to track because there is a clear record of what happened and why. Multiple frontends or implementations can work with the same app data as long as they follow the same schemas and rules, which means user interfaces can evolve or be replaced without breaking the underlying state.

Because the state already lives locally, queries are fast and dependable. You are not waiting on a central server or a fragile API to answer basic questions. The relevant data flows to your device, and you can read it directly even when the network is slow or missing. This separation is powerful in a decentralized app substrate. It keeps control of data and context on the user side, and it lets people switch apps, change providers, or run their own tools without losing access to their history or their ability to make sense of it.

Moderation and spam control are expressed as state rather than hidden server logic. Blocks, mutes, allowlists, reputation signals, and community votes can live as ratings or edges in the graph. Apps can enforce inbox filters, rate limits, or visibility rules based on those signals, while the DoS Guard protects the protocol surface from abusive traffic. Different communities can tune policies without forking the protocol.

In practice, this model fits domains where history, collaboration, and durability matter. Messaging and chat become collections of explicit conversations, participants, and messages that remain inspectable and trustworthy even when people are offline. Social and publishing tools treat posts, reactions, moderation actions, and discovery paths as part of a shared record rather than hidden server decisions. Marketplaces and service platforms can model listings, offers, agreements, escrow, fulfillment, and reputation as state that all parties can verify and audit. Operational workflows like logistics, access control, or governance can be expressed as sequences of approved changes that remain auditable long after the original software is gone.

Across all of these cases, the common thread is that apps do not have to reinvent trust. Identity, permissions, ordering, and resilience are part of the system below them. That lets developers focus on what their app is for, and lets users keep control over their data and its history, regardless of which app or vendor they are using at the moment.

11. Conformance

2WAY only works if the rules are followed exactly. An implementation either conforms or it does not. Validation, permissions, ordering, and storage must behave the same way in all conditions, including offline use and hostile input. Forbidden behavior must be impossible by design, not merely detected after the fact or left to operator judgment.

All state changes must pass through the same enforcement path. There are no shortcuts, no trusted fast paths, and no exceptions for convenience. If an implementation diverges from the documented behavior, that divergence must be written down as an Architecture Decision Record with clear scope and compensating measures. Without that, the implementation is out of spec, even if it appears to work.


12. Scope boundary and current status

This repository only promises what it states explicitly. Examples are illustrative, not requirements. The proof of concept prioritizes correctness, clarity, and inspectability over polish or performance. Details may evolve over time, but changes are intentional and documented.

Treat this repository as the authoritative description of how the system is meant to behave today. Build against the guarantees it defines, not against assumptions or implied features.


13. How to use this README

This README gives you the mental model. It explains what 2WAY is, why it exists, how the graph and backend work, and what guarantees the system enforces. It does not replace the detailed documents.

Once the overview is clear, move into the numbered folders. The protocol folder defines rules and invariants. The architecture folder explains how those rules are enforced in practice. Any deviation should be recorded as an ADR so the system remains coherent over time.

The key idea to keep in mind is that every node enforces the same structure locally. Collaboration works because correctness is shared, not because authority is centralized.


14. Acknowledgments

Credit to Martti Malmi, a.k.a., Sirius for his work on Iris, formerly Identifi, an MIT-licensed project. When the project was still Identifi and implemented as a fork of the Bitcoin daemon in C++ (originally created by Satoshi Nakamoto and worth a hat-tip here), first seeing it helped shape early ideas about private, user-controlled data layers that go beyond simple broadcast messaging through a minimal object model. Our projects took different paths over the years. That early work still influenced this line of thinking and deserves explicit acknowledgment.

Credit to Nick Szabo for his long-running work on decentralized systems. He also explored social contracts in a way that kept these ideas active for me. His public writing sustained this problem space well before 2WAY existed. His essay Trusted Third Parties Are Security Holes remains a standout reference for its framing of trust boundaries. It is a personal favorite.

Credit to Phil Zimmermann for creating PGP and the Web of Trust model. The way PGP makes trust explicit and composable across social graphs shaped how I think about trust edges, endorsements, and traversal in 2WAY's graph. That lineage helped turn the graph from a storage structure into a verifiable relationship map for endorsements and delegation.

Credit to Robert Hettinga, a.k.a., RAH for his essay The Geodesic Market. It sharpened my understanding of how geodesic networks shift power. It also reframed how I think about coordination. It highlighted resilience as a property of network shape. That framing clarified why topology and path structure matter when you design systems meant to hold up without a central authority.

Credit to Ian Grigg for his work on Financial Cryptography in 7 Layers. His essay on The Ricardian Contract clarified how contractual intent can live alongside cryptographic enforcement. His broader body of writing shaped how I think about layered trust. It also sharpened how I draw the boundary between protocol and policy. Those ideas influenced how this design separates enforceable structure from application meaning.

Credit to Carsten Keutmann for his work on the Digital Trust Protocol. He also shared a practical insight that certain flows get faster and simpler when you treat RAM as scarce. He pairs that with the observation that disk is cheap. That framing helped me see where to favor durable append-first structures instead of memory-heavy shortcuts.

Credit to Adam Back for his work on proof of work with Hashcash. It grounded how I think about resource-based abuse resistance. It also highlighted the trade-offs in making spam expensive at the protocol edge. It made DoS costs feel like a first-class design input.

Credit to Ari Juels for his paper New Client Puzzle Outsourcing Techniques for DoS Resistance. It clarified how to structure puzzles so relays can resist abuse without outsourcing trust. That line of thinking connects directly to the DoS Guard Manager's puzzle flow in this design.

About

2WAY System PoC Design

Resources

Stars

17 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages