Latest commit

History

5,289 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

xNet

CInpm: @xnetjs/reactDemo AppLicense: MIT

xNet is a local-first workspace — documents, databases, and canvases that live on your device, sync everywhere, and belong to you. There is no account to create and no server in the middle: data is stored locally, synced peer-to-peer or through a hub you control, and signed with your own keys.

The xNet app: a document open in the workspace, with the explorer sidebar and live sync status

Try it

  • Connect your coding agent — one command, no install:

    npx @xnetjs/cli connect claude-code # or: connect codex

    Claude Code or Codex can then read, search, query, and edit your workspace — read-only until you say otherwise.

  • Open the demo — no signup; sign in with your device's passkey (Touch ID, Face ID, Windows Hello). Demo data lives in your browser, with encrypted backups on our demo hub (10MB, expires after 24 hours of inactivity).

  • Download the desktop app for permanent backups and reliable cross-device sync.

  • Deploy your own hub — an always-on relay and backup node that you run.

Alpha software. The @xnetjs/* packages, desktop app, and hub image all ship today — but APIs, schemas, and wire formats can still change between releases, sometimes without a migration path. Pin your versions, read the changelog before upgrading, and keep a backup you control (.xnetpack export is built in). Package version numbers are not a maturity signal; what is and isn't stable is written down in STABILITY.md.

Your agent, your workspace

Coding agents are first-class users of an xNet workspace — through the filesystem they already know, not a wall of tool definitions. xnet connect installs a ~500-token skill and gives the agent three lanes, cheapest first: the xnet CLI (plain stdout), a scoped vault checkout (Markdown/JSONL files whose edits become schema-validated mutation plans), and a slim MCP server as the no-shell fallback. On a 15-task benchmark the files+CLI surface uses ~0.11x the tokens of a traditional MCP toolset at equal success.

Safety is structural: the server registers read-only by default, writes require an enrolled agent passport or an explicit key, and every change an agent makes lands in the workspace's signed, hash-chained change log — so you can verify what your agent did without trusting it.

Build with it

Everything in xNet is a node, and a schema describes what a node is:

import{defineSchema,text,number,select}from'@xnetjs/data'constInvoiceSchema=defineSchema({name: 'Invoice',namespace: 'xnet://myapp/',document: 'yjs',properties: {title: text({required: true}),amount: number(),status: select({options: [{id: 'draft',name: 'Draft'},{id: 'sent',name: 'Sent'},{id: 'paid',name: 'Paid'}]asconst})}})

React hooks give you live queries, mutations, collaborative rich text, and permissions:

import{useQuery,useMutate,useNode,useIdentity,useCan,useGrants}from'@xnetjs/react'// Structured data — live queries and writesfunctionTaskList(){const{data: tasks, loading }=useQuery(TaskSchema)const{ create, update, remove }=useMutate()return(<ul>{tasks.map((task)=>(<likey={task.id}>{task.title}</li>))}<buttononClick={()=>create(TaskSchema,{title: 'New',status: 'todo'})}>Add</button></ul>)}// Rich text — a synced Y.Doc per nodefunctionPageEditor({ nodeId }: {nodeId: string}){const{data: page, doc, syncStatus, peerCount }=useNode(PageSchema,nodeId)if(!doc)returnnullreturn<RichTextEditorydoc={doc}/>}// Identity and sharing — DIDs, permission checks, delegated grantsfunctionSharingPanel({ nodeId }: {nodeId: string}){const{ did }=useIdentity()const{allowed: canShare}=useCan(nodeId,'share')const{ grant }=useGrants(nodeId)return(<buttondisabled={!canShare}onClick={()=>canShare&&grant({to: 'did:key:z6MkRecipient...',actions: ['read','write']})}>
Share as {did.slice(0,16)}...
</button>)}

Under the hood: SQLite for storage (OPFS in the browser, native on desktop), Yjs CRDTs for rich text, an event-sourced change log for structured data, libp2p + WebRTC for peer-to-peer sync, and DID:key + UCAN for identity and sharing. The deep dives live in the docs.

An open protocol

This repository is one implementation of xNet. The protocol itself is an open standard you can re-implement in any language, over any database, and interoperate: see the normative spec, the conformance suite (golden vectors plus a second-language kernel), and xnet.fyi/docs/protocol. Independent implementations that pass conformance may call themselves "xNet-compatible" (how).

Develop

pnpm install
pnpm --filter xnet-web dev # run the web app
pnpm dev:stories # Storybook component catalog
pnpm build # build all packages
pnpm test# unit tests
pnpm typecheck && pnpm lint

The monorepo at a glance:

  • packages/ — the @xnetjs/* SDK packages, from crypto and storage up through React hooks, editor, views, and canvas
  • apps/ — Electron desktop, web PWA, and Expo mobile
  • site/ — the docs and landing site (Astro + Starlight)
  • tests/ — browser-based integration tests (Playwright)

Learn more

  • Vision — the big picture: micro-to-macro data sovereignty
  • Tradeoffs — why hybrid sync (Yjs + event sourcing)
  • Roadmap — the current six-month execution plan

Project

License

MIT — see LICENSE. The @xnetjs/cloud package is source-available under FSL-1.1-Apache-2.0 (converts to Apache-2.0 two years after each release).

About

Local-first infrastructure and app for user-owned data: offline-first sync, CRDT collaboration, typed schemas, and secure identity/permissions

Topics

Resources

Code of conduct

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

5,289 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

xNet

CInpm: @xnetjs/reactDemo AppLicense: MIT

xNet is a local-first workspace — documents, databases, and canvases that live on your device, sync everywhere, and belong to you. There is no account to create and no server in the middle: data is stored locally, synced peer-to-peer or through a hub you control, and signed with your own keys.

The xNet app: a document open in the workspace, with the explorer sidebar and live sync status

Try it

  • Connect your coding agent — one command, no install:

    npx @xnetjs/cli connect claude-code # or: connect codex

    Claude Code or Codex can then read, search, query, and edit your workspace — read-only until you say otherwise.

  • Open the demo — no signup; sign in with your device's passkey (Touch ID, Face ID, Windows Hello). Demo data lives in your browser, with encrypted backups on our demo hub (10MB, expires after 24 hours of inactivity).

  • Download the desktop app for permanent backups and reliable cross-device sync.

  • Deploy your own hub — an always-on relay and backup node that you run.

Alpha software. The @xnetjs/* packages, desktop app, and hub image all ship today — but APIs, schemas, and wire formats can still change between releases, sometimes without a migration path. Pin your versions, read the changelog before upgrading, and keep a backup you control (.xnetpack export is built in). Package version numbers are not a maturity signal; what is and isn't stable is written down in STABILITY.md.

Your agent, your workspace

Coding agents are first-class users of an xNet workspace — through the filesystem they already know, not a wall of tool definitions. xnet connect installs a ~500-token skill and gives the agent three lanes, cheapest first: the xnet CLI (plain stdout), a scoped vault checkout (Markdown/JSONL files whose edits become schema-validated mutation plans), and a slim MCP server as the no-shell fallback. On a 15-task benchmark the files+CLI surface uses ~0.11x the tokens of a traditional MCP toolset at equal success.

Safety is structural: the server registers read-only by default, writes require an enrolled agent passport or an explicit key, and every change an agent makes lands in the workspace's signed, hash-chained change log — so you can verify what your agent did without trusting it.

Build with it

Everything in xNet is a node, and a schema describes what a node is:

import{defineSchema,text,number,select}from'@xnetjs/data'constInvoiceSchema=defineSchema({name: 'Invoice',namespace: 'xnet://myapp/',document: 'yjs',properties: {title: text({required: true}),amount: number(),status: select({options: [{id: 'draft',name: 'Draft'},{id: 'sent',name: 'Sent'},{id: 'paid',name: 'Paid'}]asconst})}})

React hooks give you live queries, mutations, collaborative rich text, and permissions:

import{useQuery,useMutate,useNode,useIdentity,useCan,useGrants}from'@xnetjs/react'// Structured data — live queries and writesfunctionTaskList(){const{data: tasks, loading }=useQuery(TaskSchema)const{ create, update, remove }=useMutate()return(<ul>{tasks.map((task)=>(<likey={task.id}>{task.title}</li>))}<buttononClick={()=>create(TaskSchema,{title: 'New',status: 'todo'})}>Add</button></ul>)}// Rich text — a synced Y.Doc per nodefunctionPageEditor({ nodeId }: {nodeId: string}){const{data: page, doc, syncStatus, peerCount }=useNode(PageSchema,nodeId)if(!doc)returnnullreturn<RichTextEditorydoc={doc}/>}// Identity and sharing — DIDs, permission checks, delegated grantsfunctionSharingPanel({ nodeId }: {nodeId: string}){const{ did }=useIdentity()const{allowed: canShare}=useCan(nodeId,'share')const{ grant }=useGrants(nodeId)return(<buttondisabled={!canShare}onClick={()=>canShare&&grant({to: 'did:key:z6MkRecipient...',actions: ['read','write']})}>
Share as {did.slice(0,16)}...
</button>)}

Under the hood: SQLite for storage (OPFS in the browser, native on desktop), Yjs CRDTs for rich text, an event-sourced change log for structured data, libp2p + WebRTC for peer-to-peer sync, and DID:key + UCAN for identity and sharing. The deep dives live in the docs.

An open protocol

This repository is one implementation of xNet. The protocol itself is an open standard you can re-implement in any language, over any database, and interoperate: see the normative spec, the conformance suite (golden vectors plus a second-language kernel), and xnet.fyi/docs/protocol. Independent implementations that pass conformance may call themselves "xNet-compatible" (how).

Develop

pnpm install
pnpm --filter xnet-web dev # run the web app
pnpm dev:stories # Storybook component catalog
pnpm build # build all packages
pnpm test# unit tests
pnpm typecheck && pnpm lint

The monorepo at a glance:

  • packages/ — the @xnetjs/* SDK packages, from crypto and storage up through React hooks, editor, views, and canvas
  • apps/ — Electron desktop, web PWA, and Expo mobile
  • site/ — the docs and landing site (Astro + Starlight)
  • tests/ — browser-based integration tests (Playwright)

Learn more

  • Vision — the big picture: micro-to-macro data sovereignty
  • Tradeoffs — why hybrid sync (Yjs + event sourcing)
  • Roadmap — the current six-month execution plan

Project

License

MIT — see LICENSE. The @xnetjs/cloud package is source-available under FSL-1.1-Apache-2.0 (converts to Apache-2.0 two years after each release).

About

Local-first infrastructure and app for user-owned data: offline-first sync, CRDT collaboration, typed schemas, and secure identity/permissions

Topics

Resources

Code of conduct

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

5,289 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

xNet

CInpm: @xnetjs/reactDemo AppLicense: MIT

xNet is a local-first workspace — documents, databases, and canvases that live on your device, sync everywhere, and belong to you. There is no account to create and no server in the middle: data is stored locally, synced peer-to-peer or through a hub you control, and signed with your own keys.

The xNet app: a document open in the workspace, with the explorer sidebar and live sync status

Try it

  • Connect your coding agent — one command, no install:

    npx @xnetjs/cli connect claude-code # or: connect codex

    Claude Code or Codex can then read, search, query, and edit your workspace — read-only until you say otherwise.

  • Open the demo — no signup; sign in with your device's passkey (Touch ID, Face ID, Windows Hello). Demo data lives in your browser, with encrypted backups on our demo hub (10MB, expires after 24 hours of inactivity).

  • Download the desktop app for permanent backups and reliable cross-device sync.

  • Deploy your own hub — an always-on relay and backup node that you run.

Alpha software. The @xnetjs/* packages, desktop app, and hub image all ship today — but APIs, schemas, and wire formats can still change between releases, sometimes without a migration path. Pin your versions, read the changelog before upgrading, and keep a backup you control (.xnetpack export is built in). Package version numbers are not a maturity signal; what is and isn't stable is written down in STABILITY.md.

Your agent, your workspace

Coding agents are first-class users of an xNet workspace — through the filesystem they already know, not a wall of tool definitions. xnet connect installs a ~500-token skill and gives the agent three lanes, cheapest first: the xnet CLI (plain stdout), a scoped vault checkout (Markdown/JSONL files whose edits become schema-validated mutation plans), and a slim MCP server as the no-shell fallback. On a 15-task benchmark the files+CLI surface uses ~0.11x the tokens of a traditional MCP toolset at equal success.

Safety is structural: the server registers read-only by default, writes require an enrolled agent passport or an explicit key, and every change an agent makes lands in the workspace's signed, hash-chained change log — so you can verify what your agent did without trusting it.

Build with it

Everything in xNet is a node, and a schema describes what a node is:

import{defineSchema,text,number,select}from'@xnetjs/data'constInvoiceSchema=defineSchema({name: 'Invoice',namespace: 'xnet://myapp/',document: 'yjs',properties: {title: text({required: true}),amount: number(),status: select({options: [{id: 'draft',name: 'Draft'},{id: 'sent',name: 'Sent'},{id: 'paid',name: 'Paid'}]asconst})}})

React hooks give you live queries, mutations, collaborative rich text, and permissions:

import{useQuery,useMutate,useNode,useIdentity,useCan,useGrants}from'@xnetjs/react'// Structured data — live queries and writesfunctionTaskList(){const{data: tasks, loading }=useQuery(TaskSchema)const{ create, update, remove }=useMutate()return(<ul>{tasks.map((task)=>(<likey={task.id}>{task.title}</li>))}<buttononClick={()=>create(TaskSchema,{title: 'New',status: 'todo'})}>Add</button></ul>)}// Rich text — a synced Y.Doc per nodefunctionPageEditor({ nodeId }: {nodeId: string}){const{data: page, doc, syncStatus, peerCount }=useNode(PageSchema,nodeId)if(!doc)returnnullreturn<RichTextEditorydoc={doc}/>}// Identity and sharing — DIDs, permission checks, delegated grantsfunctionSharingPanel({ nodeId }: {nodeId: string}){const{ did }=useIdentity()const{allowed: canShare}=useCan(nodeId,'share')const{ grant }=useGrants(nodeId)return(<buttondisabled={!canShare}onClick={()=>canShare&&grant({to: 'did:key:z6MkRecipient...',actions: ['read','write']})}>
Share as {did.slice(0,16)}...
</button>)}

Under the hood: SQLite for storage (OPFS in the browser, native on desktop), Yjs CRDTs for rich text, an event-sourced change log for structured data, libp2p + WebRTC for peer-to-peer sync, and DID:key + UCAN for identity and sharing. The deep dives live in the docs.

An open protocol

This repository is one implementation of xNet. The protocol itself is an open standard you can re-implement in any language, over any database, and interoperate: see the normative spec, the conformance suite (golden vectors plus a second-language kernel), and xnet.fyi/docs/protocol. Independent implementations that pass conformance may call themselves "xNet-compatible" (how).

Develop

pnpm install
pnpm --filter xnet-web dev # run the web app
pnpm dev:stories # Storybook component catalog
pnpm build # build all packages
pnpm test# unit tests
pnpm typecheck && pnpm lint

The monorepo at a glance:

  • packages/ — the @xnetjs/* SDK packages, from crypto and storage up through React hooks, editor, views, and canvas
  • apps/ — Electron desktop, web PWA, and Expo mobile
  • site/ — the docs and landing site (Astro + Starlight)
  • tests/ — browser-based integration tests (Playwright)

Learn more

  • Vision — the big picture: micro-to-macro data sovereignty
  • Tradeoffs — why hybrid sync (Yjs + event sourcing)
  • Roadmap — the current six-month execution plan

Project

License

MIT — see LICENSE. The @xnetjs/cloud package is source-available under FSL-1.1-Apache-2.0 (converts to Apache-2.0 two years after each release).

About

Local-first infrastructure and app for user-owned data: offline-first sync, CRDT collaboration, typed schemas, and secure identity/permissions

Topics

Resources

Code of conduct

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

5,289 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

xNet

CInpm: @xnetjs/reactDemo AppLicense: MIT

xNet is a local-first workspace — documents, databases, and canvases that live on your device, sync everywhere, and belong to you. There is no account to create and no server in the middle: data is stored locally, synced peer-to-peer or through a hub you control, and signed with your own keys.

The xNet app: a document open in the workspace, with the explorer sidebar and live sync status

Try it

  • Connect your coding agent — one command, no install:

    npx @xnetjs/cli connect claude-code # or: connect codex

    Claude Code or Codex can then read, search, query, and edit your workspace — read-only until you say otherwise.

  • Open the demo — no signup; sign in with your device's passkey (Touch ID, Face ID, Windows Hello). Demo data lives in your browser, with encrypted backups on our demo hub (10MB, expires after 24 hours of inactivity).

  • Download the desktop app for permanent backups and reliable cross-device sync.

  • Deploy your own hub — an always-on relay and backup node that you run.

Alpha software. The @xnetjs/* packages, desktop app, and hub image all ship today — but APIs, schemas, and wire formats can still change between releases, sometimes without a migration path. Pin your versions, read the changelog before upgrading, and keep a backup you control (.xnetpack export is built in). Package version numbers are not a maturity signal; what is and isn't stable is written down in STABILITY.md.

Your agent, your workspace

Coding agents are first-class users of an xNet workspace — through the filesystem they already know, not a wall of tool definitions. xnet connect installs a ~500-token skill and gives the agent three lanes, cheapest first: the xnet CLI (plain stdout), a scoped vault checkout (Markdown/JSONL files whose edits become schema-validated mutation plans), and a slim MCP server as the no-shell fallback. On a 15-task benchmark the files+CLI surface uses ~0.11x the tokens of a traditional MCP toolset at equal success.

Safety is structural: the server registers read-only by default, writes require an enrolled agent passport or an explicit key, and every change an agent makes lands in the workspace's signed, hash-chained change log — so you can verify what your agent did without trusting it.

Build with it

Everything in xNet is a node, and a schema describes what a node is:

import{defineSchema,text,number,select}from'@xnetjs/data'constInvoiceSchema=defineSchema({name: 'Invoice',namespace: 'xnet://myapp/',document: 'yjs',properties: {title: text({required: true}),amount: number(),status: select({options: [{id: 'draft',name: 'Draft'},{id: 'sent',name: 'Sent'},{id: 'paid',name: 'Paid'}]asconst})}})

React hooks give you live queries, mutations, collaborative rich text, and permissions:

import{useQuery,useMutate,useNode,useIdentity,useCan,useGrants}from'@xnetjs/react'// Structured data — live queries and writesfunctionTaskList(){const{data: tasks, loading }=useQuery(TaskSchema)const{ create, update, remove }=useMutate()return(<ul>{tasks.map((task)=>(<likey={task.id}>{task.title}</li>))}<buttononClick={()=>create(TaskSchema,{title: 'New',status: 'todo'})}>Add</button></ul>)}// Rich text — a synced Y.Doc per nodefunctionPageEditor({ nodeId }: {nodeId: string}){const{data: page, doc, syncStatus, peerCount }=useNode(PageSchema,nodeId)if(!doc)returnnullreturn<RichTextEditorydoc={doc}/>}// Identity and sharing — DIDs, permission checks, delegated grantsfunctionSharingPanel({ nodeId }: {nodeId: string}){const{ did }=useIdentity()const{allowed: canShare}=useCan(nodeId,'share')const{ grant }=useGrants(nodeId)return(<buttondisabled={!canShare}onClick={()=>canShare&&grant({to: 'did:key:z6MkRecipient...',actions: ['read','write']})}>
Share as {did.slice(0,16)}...
</button>)}

Under the hood: SQLite for storage (OPFS in the browser, native on desktop), Yjs CRDTs for rich text, an event-sourced change log for structured data, libp2p + WebRTC for peer-to-peer sync, and DID:key + UCAN for identity and sharing. The deep dives live in the docs.

An open protocol

This repository is one implementation of xNet. The protocol itself is an open standard you can re-implement in any language, over any database, and interoperate: see the normative spec, the conformance suite (golden vectors plus a second-language kernel), and xnet.fyi/docs/protocol. Independent implementations that pass conformance may call themselves "xNet-compatible" (how).

Develop

pnpm install
pnpm --filter xnet-web dev # run the web app
pnpm dev:stories # Storybook component catalog
pnpm build # build all packages
pnpm test# unit tests
pnpm typecheck && pnpm lint

The monorepo at a glance:

  • packages/ — the @xnetjs/* SDK packages, from crypto and storage up through React hooks, editor, views, and canvas
  • apps/ — Electron desktop, web PWA, and Expo mobile
  • site/ — the docs and landing site (Astro + Starlight)
  • tests/ — browser-based integration tests (Playwright)

Learn more

  • Vision — the big picture: micro-to-macro data sovereignty
  • Tradeoffs — why hybrid sync (Yjs + event sourcing)
  • Roadmap — the current six-month execution plan

Project

License

MIT — see LICENSE. The @xnetjs/cloud package is source-available under FSL-1.1-Apache-2.0 (converts to Apache-2.0 two years after each release).

About

Local-first infrastructure and app for user-owned data: offline-first sync, CRDT collaboration, typed schemas, and secure identity/permissions

Topics

Resources

Code of conduct

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

5,289 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

xNet

CInpm: @xnetjs/reactDemo AppLicense: MIT

xNet is a local-first workspace — documents, databases, and canvases that live on your device, sync everywhere, and belong to you. There is no account to create and no server in the middle: data is stored locally, synced peer-to-peer or through a hub you control, and signed with your own keys.

The xNet app: a document open in the workspace, with the explorer sidebar and live sync status

Try it

  • Connect your coding agent — one command, no install:

    npx @xnetjs/cli connect claude-code # or: connect codex

    Claude Code or Codex can then read, search, query, and edit your workspace — read-only until you say otherwise.

  • Open the demo — no signup; sign in with your device's passkey (Touch ID, Face ID, Windows Hello). Demo data lives in your browser, with encrypted backups on our demo hub (10MB, expires after 24 hours of inactivity).

  • Download the desktop app for permanent backups and reliable cross-device sync.

  • Deploy your own hub — an always-on relay and backup node that you run.

Alpha software. The @xnetjs/* packages, desktop app, and hub image all ship today — but APIs, schemas, and wire formats can still change between releases, sometimes without a migration path. Pin your versions, read the changelog before upgrading, and keep a backup you control (.xnetpack export is built in). Package version numbers are not a maturity signal; what is and isn't stable is written down in STABILITY.md.

Your agent, your workspace

Coding agents are first-class users of an xNet workspace — through the filesystem they already know, not a wall of tool definitions. xnet connect installs a ~500-token skill and gives the agent three lanes, cheapest first: the xnet CLI (plain stdout), a scoped vault checkout (Markdown/JSONL files whose edits become schema-validated mutation plans), and a slim MCP server as the no-shell fallback. On a 15-task benchmark the files+CLI surface uses ~0.11x the tokens of a traditional MCP toolset at equal success.

Safety is structural: the server registers read-only by default, writes require an enrolled agent passport or an explicit key, and every change an agent makes lands in the workspace's signed, hash-chained change log — so you can verify what your agent did without trusting it.

Build with it

Everything in xNet is a node, and a schema describes what a node is:

import{defineSchema,text,number,select}from'@xnetjs/data'constInvoiceSchema=defineSchema({name: 'Invoice',namespace: 'xnet://myapp/',document: 'yjs',properties: {title: text({required: true}),amount: number(),status: select({options: [{id: 'draft',name: 'Draft'},{id: 'sent',name: 'Sent'},{id: 'paid',name: 'Paid'}]asconst})}})

React hooks give you live queries, mutations, collaborative rich text, and permissions:

import{useQuery,useMutate,useNode,useIdentity,useCan,useGrants}from'@xnetjs/react'// Structured data — live queries and writesfunctionTaskList(){const{data: tasks, loading }=useQuery(TaskSchema)const{ create, update, remove }=useMutate()return(<ul>{tasks.map((task)=>(<likey={task.id}>{task.title}</li>))}<buttononClick={()=>create(TaskSchema,{title: 'New',status: 'todo'})}>Add</button></ul>)}// Rich text — a synced Y.Doc per nodefunctionPageEditor({ nodeId }: {nodeId: string}){const{data: page, doc, syncStatus, peerCount }=useNode(PageSchema,nodeId)if(!doc)returnnullreturn<RichTextEditorydoc={doc}/>}// Identity and sharing — DIDs, permission checks, delegated grantsfunctionSharingPanel({ nodeId }: {nodeId: string}){const{ did }=useIdentity()const{allowed: canShare}=useCan(nodeId,'share')const{ grant }=useGrants(nodeId)return(<buttondisabled={!canShare}onClick={()=>canShare&&grant({to: 'did:key:z6MkRecipient...',actions: ['read','write']})}>
Share as {did.slice(0,16)}...
</button>)}

Under the hood: SQLite for storage (OPFS in the browser, native on desktop), Yjs CRDTs for rich text, an event-sourced change log for structured data, libp2p + WebRTC for peer-to-peer sync, and DID:key + UCAN for identity and sharing. The deep dives live in the docs.

An open protocol

This repository is one implementation of xNet. The protocol itself is an open standard you can re-implement in any language, over any database, and interoperate: see the normative spec, the conformance suite (golden vectors plus a second-language kernel), and xnet.fyi/docs/protocol. Independent implementations that pass conformance may call themselves "xNet-compatible" (how).

Develop

pnpm install
pnpm --filter xnet-web dev # run the web app
pnpm dev:stories # Storybook component catalog
pnpm build # build all packages
pnpm test# unit tests
pnpm typecheck && pnpm lint

The monorepo at a glance:

  • packages/ — the @xnetjs/* SDK packages, from crypto and storage up through React hooks, editor, views, and canvas
  • apps/ — Electron desktop, web PWA, and Expo mobile
  • site/ — the docs and landing site (Astro + Starlight)
  • tests/ — browser-based integration tests (Playwright)

Learn more

  • Vision — the big picture: micro-to-macro data sovereignty
  • Tradeoffs — why hybrid sync (Yjs + event sourcing)
  • Roadmap — the current six-month execution plan

Project

License

MIT — see LICENSE. The @xnetjs/cloud package is source-available under FSL-1.1-Apache-2.0 (converts to Apache-2.0 two years after each release).

About

Local-first infrastructure and app for user-owned data: offline-first sync, CRDT collaboration, typed schemas, and secure identity/permissions

Topics

Resources

Code of conduct

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

5,289 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

xNet

CInpm: @xnetjs/reactDemo AppLicense: MIT

xNet is a local-first workspace — documents, databases, and canvases that live on your device, sync everywhere, and belong to you. There is no account to create and no server in the middle: data is stored locally, synced peer-to-peer or through a hub you control, and signed with your own keys.

The xNet app: a document open in the workspace, with the explorer sidebar and live sync status

Try it

  • Connect your coding agent — one command, no install:

    npx @xnetjs/cli connect claude-code # or: connect codex

    Claude Code or Codex can then read, search, query, and edit your workspace — read-only until you say otherwise.

  • Open the demo — no signup; sign in with your device's passkey (Touch ID, Face ID, Windows Hello). Demo data lives in your browser, with encrypted backups on our demo hub (10MB, expires after 24 hours of inactivity).

  • Download the desktop app for permanent backups and reliable cross-device sync.

  • Deploy your own hub — an always-on relay and backup node that you run.

Alpha software. The @xnetjs/* packages, desktop app, and hub image all ship today — but APIs, schemas, and wire formats can still change between releases, sometimes without a migration path. Pin your versions, read the changelog before upgrading, and keep a backup you control (.xnetpack export is built in). Package version numbers are not a maturity signal; what is and isn't stable is written down in STABILITY.md.

Your agent, your workspace

Coding agents are first-class users of an xNet workspace — through the filesystem they already know, not a wall of tool definitions. xnet connect installs a ~500-token skill and gives the agent three lanes, cheapest first: the xnet CLI (plain stdout), a scoped vault checkout (Markdown/JSONL files whose edits become schema-validated mutation plans), and a slim MCP server as the no-shell fallback. On a 15-task benchmark the files+CLI surface uses ~0.11x the tokens of a traditional MCP toolset at equal success.

Safety is structural: the server registers read-only by default, writes require an enrolled agent passport or an explicit key, and every change an agent makes lands in the workspace's signed, hash-chained change log — so you can verify what your agent did without trusting it.

Build with it

Everything in xNet is a node, and a schema describes what a node is:

import{defineSchema,text,number,select}from'@xnetjs/data'constInvoiceSchema=defineSchema({name: 'Invoice',namespace: 'xnet://myapp/',document: 'yjs',properties: {title: text({required: true}),amount: number(),status: select({options: [{id: 'draft',name: 'Draft'},{id: 'sent',name: 'Sent'},{id: 'paid',name: 'Paid'}]asconst})}})

React hooks give you live queries, mutations, collaborative rich text, and permissions:

import{useQuery,useMutate,useNode,useIdentity,useCan,useGrants}from'@xnetjs/react'// Structured data — live queries and writesfunctionTaskList(){const{data: tasks, loading }=useQuery(TaskSchema)const{ create, update, remove }=useMutate()return(<ul>{tasks.map((task)=>(<likey={task.id}>{task.title}</li>))}<buttononClick={()=>create(TaskSchema,{title: 'New',status: 'todo'})}>Add</button></ul>)}// Rich text — a synced Y.Doc per nodefunctionPageEditor({ nodeId }: {nodeId: string}){const{data: page, doc, syncStatus, peerCount }=useNode(PageSchema,nodeId)if(!doc)returnnullreturn<RichTextEditorydoc={doc}/>}// Identity and sharing — DIDs, permission checks, delegated grantsfunctionSharingPanel({ nodeId }: {nodeId: string}){const{ did }=useIdentity()const{allowed: canShare}=useCan(nodeId,'share')const{ grant }=useGrants(nodeId)return(<buttondisabled={!canShare}onClick={()=>canShare&&grant({to: 'did:key:z6MkRecipient...',actions: ['read','write']})}>
Share as {did.slice(0,16)}...
</button>)}

Under the hood: SQLite for storage (OPFS in the browser, native on desktop), Yjs CRDTs for rich text, an event-sourced change log for structured data, libp2p + WebRTC for peer-to-peer sync, and DID:key + UCAN for identity and sharing. The deep dives live in the docs.

An open protocol

This repository is one implementation of xNet. The protocol itself is an open standard you can re-implement in any language, over any database, and interoperate: see the normative spec, the conformance suite (golden vectors plus a second-language kernel), and xnet.fyi/docs/protocol. Independent implementations that pass conformance may call themselves "xNet-compatible" (how).

Develop

pnpm install
pnpm --filter xnet-web dev # run the web app
pnpm dev:stories # Storybook component catalog
pnpm build # build all packages
pnpm test# unit tests
pnpm typecheck && pnpm lint

The monorepo at a glance:

  • packages/ — the @xnetjs/* SDK packages, from crypto and storage up through React hooks, editor, views, and canvas
  • apps/ — Electron desktop, web PWA, and Expo mobile
  • site/ — the docs and landing site (Astro + Starlight)
  • tests/ — browser-based integration tests (Playwright)

Learn more

  • Vision — the big picture: micro-to-macro data sovereignty
  • Tradeoffs — why hybrid sync (Yjs + event sourcing)
  • Roadmap — the current six-month execution plan

Project

License

MIT — see LICENSE. The @xnetjs/cloud package is source-available under FSL-1.1-Apache-2.0 (converts to Apache-2.0 two years after each release).

About

Local-first infrastructure and app for user-owned data: offline-first sync, CRDT collaboration, typed schemas, and secure identity/permissions

Topics

Resources

Code of conduct

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

5,289 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

xNet

CInpm: @xnetjs/reactDemo AppLicense: MIT

xNet is a local-first workspace — documents, databases, and canvases that live on your device, sync everywhere, and belong to you. There is no account to create and no server in the middle: data is stored locally, synced peer-to-peer or through a hub you control, and signed with your own keys.

The xNet app: a document open in the workspace, with the explorer sidebar and live sync status

Try it

  • Connect your coding agent — one command, no install:

    npx @xnetjs/cli connect claude-code # or: connect codex

    Claude Code or Codex can then read, search, query, and edit your workspace — read-only until you say otherwise.

  • Open the demo — no signup; sign in with your device's passkey (Touch ID, Face ID, Windows Hello). Demo data lives in your browser, with encrypted backups on our demo hub (10MB, expires after 24 hours of inactivity).

  • Download the desktop app for permanent backups and reliable cross-device sync.

  • Deploy your own hub — an always-on relay and backup node that you run.

Alpha software. The @xnetjs/* packages, desktop app, and hub image all ship today — but APIs, schemas, and wire formats can still change between releases, sometimes without a migration path. Pin your versions, read the changelog before upgrading, and keep a backup you control (.xnetpack export is built in). Package version numbers are not a maturity signal; what is and isn't stable is written down in STABILITY.md.

Your agent, your workspace

Coding agents are first-class users of an xNet workspace — through the filesystem they already know, not a wall of tool definitions. xnet connect installs a ~500-token skill and gives the agent three lanes, cheapest first: the xnet CLI (plain stdout), a scoped vault checkout (Markdown/JSONL files whose edits become schema-validated mutation plans), and a slim MCP server as the no-shell fallback. On a 15-task benchmark the files+CLI surface uses ~0.11x the tokens of a traditional MCP toolset at equal success.

Safety is structural: the server registers read-only by default, writes require an enrolled agent passport or an explicit key, and every change an agent makes lands in the workspace's signed, hash-chained change log — so you can verify what your agent did without trusting it.

Build with it

Everything in xNet is a node, and a schema describes what a node is:

import{defineSchema,text,number,select}from'@xnetjs/data'constInvoiceSchema=defineSchema({name: 'Invoice',namespace: 'xnet://myapp/',document: 'yjs',properties: {title: text({required: true}),amount: number(),status: select({options: [{id: 'draft',name: 'Draft'},{id: 'sent',name: 'Sent'},{id: 'paid',name: 'Paid'}]asconst})}})

React hooks give you live queries, mutations, collaborative rich text, and permissions:

import{useQuery,useMutate,useNode,useIdentity,useCan,useGrants}from'@xnetjs/react'// Structured data — live queries and writesfunctionTaskList(){const{data: tasks, loading }=useQuery(TaskSchema)const{ create, update, remove }=useMutate()return(<ul>{tasks.map((task)=>(<likey={task.id}>{task.title}</li>))}<buttononClick={()=>create(TaskSchema,{title: 'New',status: 'todo'})}>Add</button></ul>)}// Rich text — a synced Y.Doc per nodefunctionPageEditor({ nodeId }: {nodeId: string}){const{data: page, doc, syncStatus, peerCount }=useNode(PageSchema,nodeId)if(!doc)returnnullreturn<RichTextEditorydoc={doc}/>}// Identity and sharing — DIDs, permission checks, delegated grantsfunctionSharingPanel({ nodeId }: {nodeId: string}){const{ did }=useIdentity()const{allowed: canShare}=useCan(nodeId,'share')const{ grant }=useGrants(nodeId)return(<buttondisabled={!canShare}onClick={()=>canShare&&grant({to: 'did:key:z6MkRecipient...',actions: ['read','write']})}>
Share as {did.slice(0,16)}...
</button>)}

Under the hood: SQLite for storage (OPFS in the browser, native on desktop), Yjs CRDTs for rich text, an event-sourced change log for structured data, libp2p + WebRTC for peer-to-peer sync, and DID:key + UCAN for identity and sharing. The deep dives live in the docs.

An open protocol

This repository is one implementation of xNet. The protocol itself is an open standard you can re-implement in any language, over any database, and interoperate: see the normative spec, the conformance suite (golden vectors plus a second-language kernel), and xnet.fyi/docs/protocol. Independent implementations that pass conformance may call themselves "xNet-compatible" (how).

Develop

pnpm install
pnpm --filter xnet-web dev # run the web app
pnpm dev:stories # Storybook component catalog
pnpm build # build all packages
pnpm test# unit tests
pnpm typecheck && pnpm lint

The monorepo at a glance:

  • packages/ — the @xnetjs/* SDK packages, from crypto and storage up through React hooks, editor, views, and canvas
  • apps/ — Electron desktop, web PWA, and Expo mobile
  • site/ — the docs and landing site (Astro + Starlight)
  • tests/ — browser-based integration tests (Playwright)

Learn more

  • Vision — the big picture: micro-to-macro data sovereignty
  • Tradeoffs — why hybrid sync (Yjs + event sourcing)
  • Roadmap — the current six-month execution plan

Project

License

MIT — see LICENSE. The @xnetjs/cloud package is source-available under FSL-1.1-Apache-2.0 (converts to Apache-2.0 two years after each release).

About

Local-first infrastructure and app for user-owned data: offline-first sync, CRDT collaboration, typed schemas, and secure identity/permissions

Topics

Resources

Code of conduct

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

5,289 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

xNet

CInpm: @xnetjs/reactDemo AppLicense: MIT

xNet is a local-first workspace — documents, databases, and canvases that live on your device, sync everywhere, and belong to you. There is no account to create and no server in the middle: data is stored locally, synced peer-to-peer or through a hub you control, and signed with your own keys.

The xNet app: a document open in the workspace, with the explorer sidebar and live sync status

Try it

  • Connect your coding agent — one command, no install:

    npx @xnetjs/cli connect claude-code # or: connect codex

    Claude Code or Codex can then read, search, query, and edit your workspace — read-only until you say otherwise.

  • Open the demo — no signup; sign in with your device's passkey (Touch ID, Face ID, Windows Hello). Demo data lives in your browser, with encrypted backups on our demo hub (10MB, expires after 24 hours of inactivity).

  • Download the desktop app for permanent backups and reliable cross-device sync.

  • Deploy your own hub — an always-on relay and backup node that you run.

Alpha software. The @xnetjs/* packages, desktop app, and hub image all ship today — but APIs, schemas, and wire formats can still change between releases, sometimes without a migration path. Pin your versions, read the changelog before upgrading, and keep a backup you control (.xnetpack export is built in). Package version numbers are not a maturity signal; what is and isn't stable is written down in STABILITY.md.

Your agent, your workspace

Coding agents are first-class users of an xNet workspace — through the filesystem they already know, not a wall of tool definitions. xnet connect installs a ~500-token skill and gives the agent three lanes, cheapest first: the xnet CLI (plain stdout), a scoped vault checkout (Markdown/JSONL files whose edits become schema-validated mutation plans), and a slim MCP server as the no-shell fallback. On a 15-task benchmark the files+CLI surface uses ~0.11x the tokens of a traditional MCP toolset at equal success.

Safety is structural: the server registers read-only by default, writes require an enrolled agent passport or an explicit key, and every change an agent makes lands in the workspace's signed, hash-chained change log — so you can verify what your agent did without trusting it.

Build with it

Everything in xNet is a node, and a schema describes what a node is:

import{defineSchema,text,number,select}from'@xnetjs/data'constInvoiceSchema=defineSchema({name: 'Invoice',namespace: 'xnet://myapp/',document: 'yjs',properties: {title: text({required: true}),amount: number(),status: select({options: [{id: 'draft',name: 'Draft'},{id: 'sent',name: 'Sent'},{id: 'paid',name: 'Paid'}]asconst})}})

React hooks give you live queries, mutations, collaborative rich text, and permissions:

import{useQuery,useMutate,useNode,useIdentity,useCan,useGrants}from'@xnetjs/react'// Structured data — live queries and writesfunctionTaskList(){const{data: tasks, loading }=useQuery(TaskSchema)const{ create, update, remove }=useMutate()return(<ul>{tasks.map((task)=>(<likey={task.id}>{task.title}</li>))}<buttononClick={()=>create(TaskSchema,{title: 'New',status: 'todo'})}>Add</button></ul>)}// Rich text — a synced Y.Doc per nodefunctionPageEditor({ nodeId }: {nodeId: string}){const{data: page, doc, syncStatus, peerCount }=useNode(PageSchema,nodeId)if(!doc)returnnullreturn<RichTextEditorydoc={doc}/>}// Identity and sharing — DIDs, permission checks, delegated grantsfunctionSharingPanel({ nodeId }: {nodeId: string}){const{ did }=useIdentity()const{allowed: canShare}=useCan(nodeId,'share')const{ grant }=useGrants(nodeId)return(<buttondisabled={!canShare}onClick={()=>canShare&&grant({to: 'did:key:z6MkRecipient...',actions: ['read','write']})}>
Share as {did.slice(0,16)}...
</button>)}

Under the hood: SQLite for storage (OPFS in the browser, native on desktop), Yjs CRDTs for rich text, an event-sourced change log for structured data, libp2p + WebRTC for peer-to-peer sync, and DID:key + UCAN for identity and sharing. The deep dives live in the docs.

An open protocol

This repository is one implementation of xNet. The protocol itself is an open standard you can re-implement in any language, over any database, and interoperate: see the normative spec, the conformance suite (golden vectors plus a second-language kernel), and xnet.fyi/docs/protocol. Independent implementations that pass conformance may call themselves "xNet-compatible" (how).

Develop

pnpm install
pnpm --filter xnet-web dev # run the web app
pnpm dev:stories # Storybook component catalog
pnpm build # build all packages
pnpm test# unit tests
pnpm typecheck && pnpm lint

The monorepo at a glance:

  • packages/ — the @xnetjs/* SDK packages, from crypto and storage up through React hooks, editor, views, and canvas
  • apps/ — Electron desktop, web PWA, and Expo mobile
  • site/ — the docs and landing site (Astro + Starlight)
  • tests/ — browser-based integration tests (Playwright)

Learn more

  • Vision — the big picture: micro-to-macro data sovereignty
  • Tradeoffs — why hybrid sync (Yjs + event sourcing)
  • Roadmap — the current six-month execution plan

Project

License

MIT — see LICENSE. The @xnetjs/cloud package is source-available under FSL-1.1-Apache-2.0 (converts to Apache-2.0 two years after each release).

About

Local-first infrastructure and app for user-owned data: offline-first sync, CRDT collaboration, typed schemas, and secure identity/permissions

Topics

Resources

Code of conduct

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages