255 lines
11 KiB
Markdown
255 lines
11 KiB
Markdown
# Flying Jib
|
||
|
||
**Fully decentralized peer-to-peer Minecraft** — no master servers, ever.
|
||
|
||
NOTE: THIS REPO IS NOT YET READY TO BE USED! THIS NOTICE WILL BE REMOVED WHEN TESTING MAY HAPPEN
|
||
|
||
Flying Jib is a **Bare/Pear** application that runs [Flying Squid](https://github.com/PrismarineJS/flying-squid) **inside Bare** (via [`bare-node-runtime`](https://github.com/holepunchto/bare-node-runtime)), bound only to **`127.0.0.1`**. Friends join through encrypted [Holepunch](https://holepunch.to) tunnels. Worlds stay private (capability invites) or enroll into a federated **mesh** of linked regions with border migration and inventory handoff.
|
||
|
||
| | |
|
||
|--|--|
|
||
| **Version** | 0.1.0 |
|
||
| **License** | [Apache-2.0](./LICENSE) |
|
||
| **Runtime** | Bare / Pear only — **end users do not install Node.js** ([ADR-0013](./agent/ADRs/0013-bare-pear-only-runtime-and-distribution.md)) |
|
||
| **Product shell** | **Pear desktop GUI** primary ([ADR-0014](./agent/ADRs/0014-pear-desktop-gui-primary.md)); Bare CLI secondary |
|
||
| **Default MC** | Flying Squid **1.21.1** (Java Edition) |
|
||
| **Status** | Phases 1–5 core; Phase 6 Pear GUI in progress |
|
||
|
||
> **Living truth:** [living_docs/CURRENT_STATUS.md](./living_docs/CURRENT_STATUS.md) · [living_docs/ROADMAP.md](./living_docs/ROADMAP.md)
|
||
|
||
---
|
||
|
||
## Why “Flying Jib”?
|
||
|
||
A flying jib is a sail that works **with** the main sail — not above it as a master. Each peer runs its own local server; the mesh is coordination among equals, never a company-operated game server.
|
||
|
||
---
|
||
|
||
## What works today
|
||
|
||
| Area | Status |
|
||
|------|--------|
|
||
| Pear desktop GUI (`npm start` / `pear run`) | Scaffolded (host / join / worlds MVP) |
|
||
| Local Flying Squid on `127.0.0.1` | Working |
|
||
| Private worlds (`host` / `join` HyperDHT tunnel + `fj1.` invites) | Working |
|
||
| Invite TTL (default **7 days**), role hint, mint / rotate / revoke | Working |
|
||
| Side-channel chat + presence (`/peers`) | Working |
|
||
| Mesh registry (Autobase), border migrate, inventory handoff (anti-dupe) | Working |
|
||
| Soft-reconnect banners / stable localhost port on migrate | Working |
|
||
| Standalone CLI binary (~**151 MiB** default prune; ~**98 MiB** minimal) | Working |
|
||
| Gitea rolling release (`RELEASE_TOKEN`) + GitHub integrate CI | Wired |
|
||
| Threat model + playtest runbook | Written |
|
||
| Automated tests | `npm test` |
|
||
|
||
**Not done yet:** live Pear seed with real multisig keys, full GUI, enforced viewer ACL, two-machine Java playtest sign-off.
|
||
|
||
---
|
||
|
||
## Architecture (one paragraph)
|
||
|
||
Java Edition always connects to **localhost**. The Bare app owns Squid’s lifecycle and a **HyperDHT** byte-pipe tunnel for remote peers (capability header on the stream). Mesh membership uses **Autobase + Hyperbee**; borders use **session migration** and inventory handoff — not a global voxel CRDT. Runtime is **Bare + pear-runtime** only. Stack: Hyperswarm, HyperDHT, Protomux, Corestore, Flying Squid / Prismarine.
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
Java[Java Edition] --> Local["127.0.0.1:port"]
|
||
Local --> Squid["Flying Squid in Bare"]
|
||
Squid <-->|"HyperDHT tunnel Noise"| Peers["Remote peers<br/>same architecture"]
|
||
```
|
||
|
||
Deep dive: [living_docs/ARCHITECTURE_OVERVIEW.md](./living_docs/ARCHITECTURE_OVERVIEW.md) · [developer_docs/ARCHITECTURE.md](./developer_docs/ARCHITECTURE.md)
|
||
|
||
---
|
||
|
||
## Quick start (developers)
|
||
|
||
```sh
|
||
git clone <this-repo>
|
||
cd flying-jib
|
||
npm install
|
||
|
||
# Primary — Pear desktop GUI
|
||
npm start # pear run -d .
|
||
|
||
# Secondary — Bare CLI
|
||
npm run start:cli -- create home
|
||
npm run start:cli -- host home --port 25565 --name Alice
|
||
# → fj1.… invite; Java Edition → 127.0.0.1:25565
|
||
|
||
npm run start:cli -- --storage /tmp/fj-b join 'fj1.…' --name Bob
|
||
```
|
||
|
||
### Mesh border (two regions)
|
||
|
||
```sh
|
||
BARE=./node_modules/bare-runtime/bin/bare
|
||
|
||
# Host A — create mesh + enroll bounds
|
||
$BARE bin.mjs --storage /tmp/fj-a host west --mesh \
|
||
--min-x 0 --max-x 99 --min-z 0 --max-z 99 \
|
||
--mc-name Steve --name Alice
|
||
|
||
# Host B — join mesh invite + enroll adjacent region
|
||
$BARE bin.mjs --storage /tmp/fj-b host east --mesh-invite 'fj1.…' \
|
||
--min-x 100 --max-x 199 --min-z 0 --max-z 99 \
|
||
--mc-name Alex --name Bob
|
||
```
|
||
|
||
Guest joins a world invite; crossing the border kicks with reconnect instructions, retargets the tunnel, and applies inventory handoff. Manual scenarios: [developer_docs/PLAYTEST.md](./developer_docs/PLAYTEST.md).
|
||
|
||
---
|
||
|
||
## CLI reference
|
||
|
||
Global flags: `--storage <dir>`, `--version` / `-v`, `--help` / `-h`.
|
||
|
||
| Command | Purpose |
|
||
|---------|---------|
|
||
| `create <name>` | Create a local world under storage |
|
||
| `list` | List worlds |
|
||
| `start <name>` | Local Squid only (no P2P share) |
|
||
| `host <name>` | Squid + HyperDHT share; print `fj1.` invite |
|
||
| `join <invite>` | Guest tunnel to a private world |
|
||
| `invite <name>` | Mint invite without starting Squid (default TTL 7d) |
|
||
| `rotate-cap <name>` | New tunnel capability — **invalidates** outstanding invites |
|
||
| `revoke <name> <cap-or-invite>` | Audit fingerprint on local revoke ledger |
|
||
| `status` | Storage path, worlds, meshes |
|
||
| `mesh-create` / `mesh-open` / `mesh-admit` / `mesh-enroll` / `mesh-list` | Mesh registry CLI |
|
||
|
||
**Useful `host` / `invite` flags:** `--ttl 24h`, `--no-expire`, `--role player|viewer`, `--mesh`, `--mesh-invite`, `--mc-name`, `--name` (chat display).
|
||
|
||
Invites are **secrets**. Prefer short TTL for events; after a leak run `rotate-cap` then mint a new invite. Details: [user_docs/INVITES_AND_CAPABILITIES.md](./user_docs/INVITES_AND_CAPABILITIES.md).
|
||
|
||
---
|
||
|
||
## Standalone binary (no Node on PATH)
|
||
|
||
```sh
|
||
npm run make:standalone # current host → out/flying-jib-<host>/flying-jib
|
||
npm run make:standalone:all # all supported 64-bit hosts
|
||
npm run size:report # artifact sizes + prune guidance
|
||
|
||
# Slimmer pack (default MC version only)
|
||
FJ_MC_DATA_MINIMAL=1 npm run make:standalone
|
||
|
||
# Smoke without system Node
|
||
env -i PATH=/usr/bin:/bin HOME="$HOME" TMPDIR=/tmp \
|
||
./out/flying-jib-darwin-arm64/flying-jib --storage /tmp/fj-smoke create demo
|
||
```
|
||
|
||
| Pack mode | Approx size (darwin-arm64) |
|
||
|-----------|----------------------------|
|
||
| Unpruned (full PC + bedrock `minecraft-data`) | ~498 MiB |
|
||
| Default prune (Squid PC versions, no bedrock) | **~151 MiB** |
|
||
| Minimal (`FJ_MC_DATA_MINIMAL=1` → 1.21.1) | **~98 MiB** |
|
||
|
||
Packer: `scripts/bare-standalone.cjs` (peardock-style `bare-pack` + imports). Release notes: [developer_docs/BUILD_AND_RELEASE.md](./developer_docs/BUILD_AND_RELEASE.md).
|
||
|
||
---
|
||
|
||
## Tests & quality gates
|
||
|
||
```sh
|
||
npm test # brittle-node, full suite
|
||
npm run test:bare # when bare test runner is available
|
||
npm run docs:check # scaffold paths present
|
||
npm run pear:check # Pear OTA config structure (placeholders OK)
|
||
npm run pear:check:strict
|
||
npm run license:check # ADR-0012: no AGPL/SSPL/holesail
|
||
```
|
||
|
||
CI (`.github/workflows/integrate.yml`): unit tests + docs + pear/license checks, then standalone matrix (`linux-x64`, `linux-arm64` pack, `darwin-arm64`, `win32-x64`) with create/list smoke where native.
|
||
|
||
---
|
||
|
||
## Non-negotiables
|
||
|
||
1. **No** central/master game servers or company matchmaking control planes
|
||
2. Minecraft TCP **only** on `127.0.0.1` (bind-guard + tests)
|
||
3. **Bare/Pear only** — no system Node for the product; no Node child for Squid
|
||
4. CI product: **single standalone executables** + Pear stage/seed OTA
|
||
5. Documentation updated with every significant change
|
||
6. ADRs before architecture / protocol / security model changes
|
||
7. **Apache-2.0** — no AGPL hard dependencies (in-house HyperDHT tunnel, not Holesail)
|
||
|
||
See [agent/RULES.md](./agent/RULES.md) and [agent/SECURITY.md](./agent/SECURITY.md).
|
||
|
||
---
|
||
|
||
## Roadmap (summary)
|
||
|
||
| Phase | Focus | Status |
|
||
|-------|--------|--------|
|
||
| 0 | Research, ADRs, docs/agent scaffold | **Done** |
|
||
| 1 | Bare shell + Squid on loopback | **Core done** (graceful stop polish open) |
|
||
| 2 | Private worlds via HyperDHT + `fj1.` | **Core done** (two-machine Java playtest open) |
|
||
| 3 | Presence + side-channel chat | **CLI done** (GUI planned) |
|
||
| 4 | Mesh registry + border migrate + handoff | **Core done** |
|
||
| 5 | Security, standalone CI, Pear OTA, polish | **In progress** |
|
||
|
||
Full checklist: [living_docs/ROADMAP.md](./living_docs/ROADMAP.md).
|
||
|
||
---
|
||
|
||
## Documentation map
|
||
|
||
| Tree | Audience |
|
||
|------|----------|
|
||
| [living_docs/](./living_docs/) | **Current truth** — status, roadmap, progress, changelog, open questions |
|
||
| [user_docs/](./user_docs/) | Players — getting started, private worlds, invites, mesh, FAQ |
|
||
| [developer_docs/](./developer_docs/) | Contributors — setup, architecture, protocol, modules, testing, playtest, release |
|
||
| [agent/](./agent/) | Humans & AI — rules, workflow, security, ADRs |
|
||
|
||
**Recommended reading order**
|
||
|
||
1. [living_docs/CURRENT_STATUS.md](./living_docs/CURRENT_STATUS.md)
|
||
2. [user_docs/GETTING_STARTED.md](./user_docs/GETTING_STARTED.md) / [PRIVATE_WORLDS.md](./user_docs/PRIVATE_WORLDS.md)
|
||
3. [agent/ADRs/0013-bare-pear-only-runtime-and-distribution.md](./agent/ADRs/0013-bare-pear-only-runtime-and-distribution.md)
|
||
4. [developer_docs/PROTOCOL.md](./developer_docs/PROTOCOL.md) · [PLAYTEST.md](./developer_docs/PLAYTEST.md)
|
||
5. [developer_docs/security/THREAT_MODEL.md](./developer_docs/security/THREAT_MODEL.md)
|
||
|
||
---
|
||
|
||
## Project layout (high level)
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
Root[flying-jib]
|
||
Root --> Bin["bin.mjs — CLI Bare"]
|
||
Root --> App["app.js — lifecycle"]
|
||
Root --> Lib["lib/ — tunnel invite mesh handoff"]
|
||
Root --> Plugins["plugins/ — bind-guard mesh-border"]
|
||
Root --> Scripts["scripts/ — pack prune checks"]
|
||
Root --> Test[test/]
|
||
Root --> Living[living_docs/]
|
||
Root --> Dev[developer_docs/]
|
||
Root --> User[user_docs/]
|
||
Root --> Agent[agent/]
|
||
```
|
||
|
||
---
|
||
|
||
## Security snapshot
|
||
|
||
- Invites (`fj1.…`), tunnel seeds, and caps are **secrets** — do not commit them or paste them into public logs
|
||
- Default invite lifetime: **7 days**; `rotate-cap` invalidates outstanding private invites
|
||
- Minecraft is never intentionally exposed on `0.0.0.0`
|
||
- Dependency license gate: `npm run license:check`
|
||
- Threat model: [developer_docs/security/THREAT_MODEL.md](./developer_docs/security/THREAT_MODEL.md)
|
||
|
||
---
|
||
|
||
## Contributing
|
||
|
||
1. Read [agent/RULES.md](./agent/RULES.md) and [agent/WORKFLOW.md](./agent/WORKFLOW.md)
|
||
2. Prefer small PRs with tests + doc updates in the **same** change ([agent/DOCUMENTATION_POLICY.md](./agent/DOCUMENTATION_POLICY.md))
|
||
3. Architecture changes need an ADR under [agent/ADRs/](./agent/ADRs/)
|
||
4. Setup details: [developer_docs/SETUP.md](./developer_docs/SETUP.md) · [CONTRIBUTING.md](./developer_docs/CONTRIBUTING.md)
|
||
|
||
---
|
||
|
||
## License
|
||
|
||
[Apache License 2.0](./LICENSE)
|
||
|
||
Flying Squid and Prismarine remain under their upstream licenses; Holepunch modules under theirs. This project does **not** hard-depend on AGPL networking stacks (e.g. Holesail).
|