Beagle
P2P chat, file transfer and calls over the Decent Network. No account, no server, no admin privilege — your identity is a keypair on your own machine, and messages go peer-to-peer.
Beagle is the application. The protocol lives in @decentnetwork/peer (SDK)
and the virtual-LAN layer in @decentnetwork/lan (decentlan, a developer and
operator tool). Beagle iterates fast; those stay boring on purpose.
Run
npm install
npm run build
node dist/cli.js
Then open http://localhost:8766.
--port <n> HTTP port (default 8766)
--host <addr> bind address (default 127.0.0.1)
--config-dir <p> identity/config dir (default ~/.agentnet)
--dora-dir <p> dora roster dir, if this machine runs a dora
Port 8766 rather than decentlan's 8765, so during the transition the old
agentnet ui and Beagle can run side by side on one machine.
Calls (web ↔ Android)
Online WebRTC with the Android app uses Carrier bootstrap TURN, not the tokyo messaging relay. See docs/webrtc-android-interop.md for the failure modes and how the first-call cold-start was fixed.
Status: Phase 1
Beagle picks a backend for its Carrier identity. Exactly one is ever live, because one identity must never run two Carrier peers at once — two peers on the same keypair race on session establishment and corrupt each other's state.
| Backend | Status | Needs root | Virtual LAN |
|---|---|---|---|
daemon — talks to a running decentlan daemon over IPC | shipping | no (the daemon does) | yes |
embedded — Beagle opens its own Peer in-process | Phase 2 | no | no |
Today Beagle requires a decentlan daemon. Phase 2 adds the embedded backend, at which point Beagle runs standalone at ordinary user privilege and decentlan becomes the optional "I also want a virtual LAN" add-on.
Identity is read from ~/.agentnet by default, so a machine already running
decentlan keeps the same userid and the same friends — it is the same node,
not a new one.
Layout
src/
├── cli.ts # the `beagle` binary — argument parsing, startup
├── peer-host.ts # backend abstraction + selection (the split's hinge)
├── ipc.ts # decentlan daemon wire protocol, client side
├── server.ts # local HTTP server: /api/* + serves the UI bundle
├── exits.ts # official exit table (network panel only)
└── desktop/ # the UI itself (JSX, concatenated + esbuild-transpiled)
scripts/build-ui.mjs bundles src/desktop/*.jsx into dist/desktop/app.js.
The UI runs as one concatenated script sharing global scope with React (UMD) —
no CDN, no in-browser Babel.