# Beagle

P2P chat, file transfer and calls over the [Decent Network](https://github.com/0xli/decentlan).
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

```bash
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](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.
