OverviewFilesCommitsIssuesDocsReleasesPeers

wirecore commits / 87091dc

Add comprehensive Pear implementation guide
Complete documentation for building Pear terminal app with: - Deployment best practices and lessons learned - Identity system comparison (keet-identity-key vs hyperident) - Sparse replication strategy - Pear GUI options (terminal, desktop Electron, web UI) - Phase-by-phase implementation plan - Code examples for each component Addresses deployment issues from previous attempts: - Module resolution under pear:// protocol - Permission model requirements - Cache corruption solutions - Systemd service configuration Implementation phases: 1. Pear terminal app with keet-identity-key 2. Web UI integration with sparse queries 3. Native desktop GUI research Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
87091dc823b2edacd020c99bde2e81e7593baed4
by plankatron <fleeky@gmail.com> · 2026-01-20T17:57:14.000Z

Changed files (1) +1176 -0

PEAR_IMPLEMENTATION_GUIDE.md +1176 -0
……@@ -0,0 +1,1176 @@
1# Wirecore Pear Implementation Guide
2
3**Date**: 2026-01-20
4**Status**: Planning Phase - Pre-Implementation Documentation
5
6---
7
8## Table of Contents
9
101. [Overview](#overview)
112. [Pear Deployment Best Practices](#pear-deployment-best-practices)
123. [Identity Systems](#identity-systems)
134. [Sparse Replication Strategy](#sparse-replication-strategy)
145. [Pear GUI Options](#pear-gui-options)
156. [Implementation Plan](#implementation-plan)
167. [Phase Breakdown](#phase-breakdown)
178. [References](#references)
18
19---
20
21## Overview
22
23This document outlines the complete implementation strategy for building a Pear-native Wirecore application based on lessons learned from hyper-fleeky projects and holepunchto best practices.
24
25**Goals:**
26- ✅ Build Pear terminal app with persistent identities
27- ✅ Test P2P connectivity between instances
28- ✅ Deploy reliably (avoid previous deployment issues)
29- ✅ Integrate with existing relay infrastructure
30- ✅ Implement sparse replication (only pull followed users)
31- ✅ Support multi-device identities (future phase)
32- ✅ Build web UI that integrates with P2P core
33- ✅ Research native GUI options (Electron vs alternatives)
34
35---
36
37## Pear Deployment Best Practices
38
39### Lessons Learned from hyper-fleeky/pear-deployment-lessons.md
40
41#### Critical Issues to Avoid
42
431. **Module Resolution Under pear:// Protocol**
44 - **Problem**: ESM/CommonJS interop with hoisted dependencies fails in Bare runtime
45 - **Status**: Critical bug, not fixed as of 2026-01-20
46 - **Impact**: Apps with npm dependencies fail to load under `pear://` links
47 - **Workaround**: Use local directory deployment
48
492. **Node Modules Staging**
50 - **Problem**: Ignoring `node_modules` in `pear.stage.ignore` breaks module resolution
51 - **Solution**: Always include `node_modules` in staging
52 - **Reason**: Bare runtime needs explicit module resolution paths
53
543. **Dynamic Dependencies**
55 - **Problem**: Dynamically required modules not included in bundle
56 - **Solution**: Add all transitive dependencies explicitly to `package.json`
57 - **Example**: `require('hyperswarm')` called indirectly needs explicit listing
58
594. **Permission Model**
60 - **Problem**: Running Pear as root breaks permission model
61 - **Solution**: Run as regular user with `CAP_NET_ADMIN` capability
62 - **Systemd Example**:
63 ```ini
64 [Service]
65 User=fleeky
66 Group=fleeky
67 AmbientCapabilities=CAP_NET_ADMIN
68 Environment="PATH=/home/fleeky/.config/pear/bin:/usr/bin:/bin"
69 ```
70
715. **Cache Corruption**
72 - **Problem**: Pear caches apps in `~/.config/pear/app-storage/`, persists across updates
73 - **Detection**: Silent failures, timeouts, module not found errors
74 - **Solution**: Clear cache with `rm -rf ~/.config/pear/app-storage/*`
75 - **Nuclear Option**: Complete reinstall `rm -rf ~/.config/pear && npx pear`
76
77### Development Workflow
78
79#### Local Development (Recommended)
80
81```bash
82# 1. Initialize project
83pear init -t terminal -y
84cd my-app
85
86# 2. Install dependencies
87npm install
88
89# 3. Develop with hot-reload
90pear run --dev .
91
92# 4. Test in production-like environment
93pear run .
94```
95
96#### Production Deployment (Two Options)
97
98**Option A: pear:// Link (Dynamic, Broken for npm deps)**
99```bash
100# Stage for production
101pear stage production
102
103# Release to DHT
104pear release production
105
106# Seed (make available)
107pear seed production
108
109# Users install via
110pear install pear://[key]
111```
112
113**Status**: ❌ Broken for apps with npm dependencies (module resolution bug)
114
115**Option B: Local Directory (Reliable, Recommended)**
116```bash
117# Package and extract
118pear stage production
119pear dump production /opt/wirecore
120
121# Deploy as systemd service
122pear run /opt/wirecore
123
124# Or use existing systemd unit
125systemctl start wirecore
126```
127
128**Status**: ✅ Works reliably, recommended for production
129
130### Best Practices Checklist
131
132- [ ] Include `node_modules` in staging (remove from `.pearignore`)
133- [ ] List all dependencies explicitly in `package.json`
134- [ ] Test on clean machine before release
135- [ ] Run as regular user with capabilities, not root
136- [ ] Set full PATH in systemd: `/home/user/.config/pear/bin:/usr/bin:/bin`
137- [ ] Use local directory deployment for apps with npm dependencies
138- [ ] Clear cache when testing updates
139- [ ] Use `--checkout=latest` flag to force fresh download
140
141### Common Errors and Solutions
142
143| Error | Cause | Solution |
144|-------|-------|----------|
145| `Cannot find module 'X'` | Module not in bundle | Add to `package.json` explicitly |
146| Permission denied | Running as root | Run as user with `CAP_NET_ADMIN` |
147| Silent failure | Corrupted cache | `rm -rf ~/.config/pear/app-storage/*` |
148| Module resolution error under pear:// | Known bug | Use local directory deployment |
149| Service won't start | Wrong PATH | Set full PATH in systemd unit |
150
151---
152
153## Identity Systems
154
155### Options Evaluated
156
157#### 1. keet-identity-key (Recommended)
158
159**What it is**: Hierarchical deterministic (HD) keypair system for P2P identities
160
161**Key Features:**
162- BIP39-like mnemonic generation (24 words)
163- Device chaining with proof system
164- Multi-device support built-in
165- Hypercore integration via discoveryCorePath()
166- Used in production by Keet
167
168**API Example:**
169```javascript
170import IdentityKey from 'keet-identity-key'
171
172// Generate new identity
173const mnemonic = IdentityKey.generateMnemonic()
174const id = await IdentityKey.from({ mnemonic })
175
176// Get identity keypair
177const identityKey = id.identityKeyPair
178
179// Device-specific keys
180const deviceKey = id.keyPair(0) // First device
181const deviceKey2 = id.keyPair(1) // Second device
182
183// Discovery key for Hyperswarm
184const discoveryKey = id.discoveryCorePath()
185
186// Bootstrap device chain
187const proof = id.bootstrap(deviceKey.publicKey)
188
189// Attest additional devices
190const proof2 = IdentityKey.attest(deviceKey2.publicKey, deviceKey, proof)
191
192// Verify proof
193const info = IdentityKey.verify(proof2)
194```
195
196**Storage:**
197- Mnemonic stored in `~/.wirecore/identity.json`
198- Encrypted with user password (optional)
199- Backup-friendly (24 words restore everything)
200
201**Integration with Hypercore:**
202```javascript
203// User's profile feed
204const profileCore = store.get({
205 key: id.identityKeyPair.publicKey
206})
207
208// Join swarm with discovery key
209swarm.join(id.discoveryCorePath())
210
211// Device-specific signing
212const signature = deviceKey.sign(message)
213```
214
215**Pros:**
216- ✅ Multi-device support from day 1
217- ✅ HD key derivation (one mnemonic → many keys)
218- ✅ Production-proven (Keet)
219- ✅ Identity recovery via mnemonic
220- ✅ Device proof system
221
222**Cons:**
223- ⚠️ More complex than simple Ed25519
224- ⚠️ Requires proof management for multi-device
225
226#### 2. hyperident (Alternative, Local Implementation)
227
228**What it is**: Decentralized identity manager built in hyper-fleeky
229
230**Features:**
231- Uses keet-identity-key under the hood
232- Additional profile management
233- Device linking/mesh networking
234- P2P device discovery
235
236**Components:**
237- `IdentityManager`: High-level identity operations
238- `CryptoManager`: Encryption/decryption
239- `DeviceLinkingManager`: Multi-device coordination
240- `DeviceMeshManager`: P2P device-to-device
241
242**Storage Location:** `~/.hyperident/profiles.json`
243
244**Pros:**
245- ✅ Higher-level abstraction over keet-identity-key
246- ✅ Profile management built-in
247- ✅ Device mesh networking
248
249**Cons:**
250- ⚠️ More dependencies
251- ⚠️ Larger codebase to maintain
252- ⚠️ Overkill for simple social network
253
254### Recommendation: keet-identity-key
255
256**Reason**: Direct, minimal, production-proven, handles multi-device without extra complexity.
257
258**Implementation Strategy:**
259```javascript
260// lib/identity/manager.js
261import IdentityKey from 'keet-identity-key'
262import { readFile, writeFile } from 'fs/promises'
263import { join } from 'path'
264
265export class WirecoreIdentity {
266 constructor(storagePath) {
267 this.storagePath = storagePath
268 this.identityPath = join(storagePath, 'identity.json')
269 this.id = null
270 }
271
272 async init() {
273 try {
274 const data = await readFile(this.identityPath, 'utf8')
275 const { mnemonic } = JSON.parse(data)
276 this.id = await IdentityKey.from({ mnemonic })
277 } catch {
278 // No identity exists, will need to create
279 this.id = null
280 }
281 }
282
283 async create(name = 'Anonymous') {
284 const mnemonic = IdentityKey.generateMnemonic()
285 this.id = await IdentityKey.from({ mnemonic })
286
287 await writeFile(this.identityPath, JSON.stringify({
288 name,
289 mnemonic,
290 publicKey: this.id.identityKeyPair.publicKey.toString('hex'),
291 created: Date.now()
292 }))
293
294 return {
295 mnemonic,
296 publicKey: this.getPublicKey()
297 }
298 }
299
300 getPublicKey() {
301 return this.id.identityKeyPair.publicKey.toString('hex')
302 }
303
304 getDiscoveryKey() {
305 return this.id.discoveryCorePath()
306 }
307
308 sign(message) {
309 return this.id.identityKeyPair.sign(message)
310 }
311}
312```
313
314---
315
316## Sparse Replication Strategy
317
318### Problem Statement
319
320**Current relay architecture**: One central feed with ALL messages from ALL users
321- 612 messages from 89 authors
322- User following 3 people downloads 609 irrelevant messages
323- Wastes bandwidth and storage
324
325**Goal**: Only replicate feeds of followed users
326
327### Solution: Per-User Feeds
328
329**Architecture:**
330```
331User Alice User Bob
332├── Alice's Feed (writable) ├── Bob's Feed (writable)
333└── Follows: └── Follows:
334 ├── Bob's Feed (replica) ├── Alice's Feed (replica)
335 └── Carol's Feed (replica) └── Carol's Feed (replica)
336```
337
338**No central relay feed needed** - each user's feed is discovered via Hyperswarm DHT.
339
340### Implementation
341
342#### 1. Selective Replication via Corestore
343
344```javascript
345// Initialize corestore
346const store = new Corestore('./storage/feeds')
347
348// User's own feed (writable)
349const myFeed = store.get({ name: 'my-feed' })
350await myFeed.ready()
351
352// Follow another user (read-only replica)
353async function follow(publicKey, name) {
354 const feedKey = Buffer.from(publicKey, 'hex')
355 const feed = store.get(feedKey)
356 await feed.ready()
357
358 follows.set(publicKey, { feed, name })
359
360 // Join their topic to find peers
361 swarm.join(feed.discoveryKey, {
362 server: false, // Don't serve their data
363 client: true // Download their data
364 })
365}
366
367// Replicate all followed feeds
368swarm.on('connection', (conn) => {
369 // This replicates myFeed + all followed feeds
370 store.replicate(conn)
371})
372```
373
374**Key Points:**
375- `store.replicate(conn)` automatically replicates all cores in corestore
376- Each followed user = one Hypercore in corestore
377- Hyperswarm DHT handles peer discovery per feed
378- No manual range selection needed (Hypercore handles sparse download)
379
380#### 2. Sparse Downloads (Built-in)
381
382Hypercore automatically does sparse downloading:
383```javascript
384// Read only what you need
385for await (const entry of feed.createReadStream({
386 live: true,
387 start: feed.length - 20 // Only last 20 entries
388})) {
389 console.log(entry)
390}
391
392// Or specific ranges
393const entries = await feed.getBatch(0, 20)
394```
395
396**Hyperbee also sparse downloads:**
397```javascript
398const bee = new Hyperbee(feed)
399await bee.get('key') // Only downloads blocks needed for this query
400```
401
402#### 3. Relay Integration (Sparse)
403
404**Don't replicate entire relay feed:**
405
406```javascript
407// BAD: Downloads all 612 messages
408const relayCore = store.get(relayKey)
409swarm.join(relayCore.discoveryKey)
410```
411
412**GOOD: Query relay API, cache locally:**
413
414```javascript
415// Query relay for followed users only
416async function syncFromRelay(followedUsers) {
417 for (const user of followedUsers) {
418 // GET /relay/query?author=<pubkey>
419 const res = await fetch(`https://7rnx.net/relay/all?author=${user}`)
420 const messages = await res.json()
421
422 // Store in user's local feed
423 for (const msg of messages) {
424 await userFeed.append(msg)
425 }
426 }
427}
428```
429
430**Even Better: Relay publishes per-user feeds:**
431
432```javascript
433// Relay exposes per-user Hypercores
434// GET /relay/user/<pubkey>/feed-key
435const feedKey = await fetch(`/relay/user/${pubkey}/feed-key`).then(r => r.text())
436
437// Replicate just that user's feed via Hyperswarm
438const userFeed = store.get(Buffer.from(feedKey, 'hex'))
439swarm.join(userFeed.discoveryKey)
440```
441
442### Disk Space Comparison
443
444| Scenario | Messages Downloaded | Storage |
445|----------|-------------------|---------|
446| Full relay feed | 612 messages | ~2MB |
447| Follow 3 users (sparse) | ~30 messages | ~50KB |
448| **Savings** | **95% less** | **97% less** |
449
450---
451
452## Pear GUI Options
453
454### 1. Terminal App (Recommended for Phase 1)
455
456**Technology:** Pear Terminal + bare-readline
457
458**Capabilities:**
459- Line-based input/output
460- ANSI color support
461- Raw terminal mode for key capture
462- Cross-platform (Linux, macOS, Windows)
463
464**Limitations:**
465- No blessed (TUI framework) - not compatible with Bare
466- No fancy UI elements (boxes, windows, etc.)
467- Manual ANSI escape codes for formatting
468
469**Example:**
470```javascript
471// index.js
472import Hyperswarm from 'hyperswarm'
473import readline from 'bare-readline'
474import tty from 'bare-tty'
475
476const rl = readline.createInterface({
477 input: new tty.ReadStream(0),
478 output: new tty.WriteStream(1)
479})
480
481// Colors via ANSI
482const colors = {
483 cyan: '\x1b[36m',
484 green: '\x1b[32m',
485 reset: '\x1b[0m'
486}
487
488console.log(`${colors.cyan}Wirecore${colors.reset} - P2P Social Network`)
489
490rl.on('data', (line) => {
491 const [cmd, ...args] = line.split(' ')
492
493 switch(cmd) {
494 case 'post':
495 handlePost(args.join(' '))
496 break
497 case 'timeline':
498 showTimeline()
499 break
500 }
501})
502```
503
504**Best For:**
505- CLI-first users
506- Server deployments
507- Initial testing
508- SSH access
509
510### 2. Desktop App (Phase 3+)
511
512**Technology:** pear-electron (Electron wrapper)
513
514**Capabilities:**
515- Full HTML/CSS/JavaScript UI
516- React, Vue, Svelte, etc.
517- Native window controls
518- Rich media support
519- Notifications
520
521**Setup:**
522```bash
523# Initialize desktop app
524pear init -t desktop -y
525
526# Install pear-electron
527npm install pear-electron
528
529# package.json
530{
531 "pear": {
532 "pre": "pear-electron/pre"
533 }
534}
535```
536
537**Example UI:**
538```html
539<!-- index.html -->
540<!DOCTYPE html>
541<html>
542<head>
543 <style>
544 #titlebar {
545 -webkit-app-region: drag;
546 background: #333;
547 color: #fff;
548 padding: 10px;
549 }
550 </style>
551</head>
552<body>
553 <div id="titlebar">
554 <span>Wirecore</span>
555 <pear-ctrl></pear-ctrl> <!-- Window controls -->
556 </div>
557
558 <div id="app">
559 <!-- React/Vue/Svelte root -->
560 </div>
561
562 <script type="module" src="app.js"></script>
563</body>
564</html>
565```
566
567```javascript
568// app.js
569import Hyperswarm from 'hyperswarm'
570import { WirecoreNode } from './lib/node.js'
571
572const node = new WirecoreNode('./storage')
573await node.init()
574
575// UI updates
576node.on('post', (post) => {
577 updateTimeline(post)
578})
579```
580
581**Best For:**
582- End users
583- Rich media (images, videos)
584- Mainstream adoption
585- Desktop OS integration
586
587### 3. Web UI (Phase 2)
588
589**Technology:** Traditional HTML/CSS/JS + WebSocket to relay
590
591**Architecture:**
592```
593[Browser] ←→ HTTP/WebSocket ←→ [Relay Gateway] ←→ Hyperswarm P2P
594```
595
596**Capabilities:**
597- No installation
598- Cross-platform
599- Mobile support
600- Accessible URL
601
602**Limitations:**
603- Requires relay gateway
604- Not truly P2P (relay is middleman)
605- Network dependency
606
607**Implementation:**
608```javascript
609// public/app.js
610const ws = new WebSocket('wss://7rnx.net/relay')
611
612ws.onmessage = (event) => {
613 const post = JSON.parse(event.data)
614 addToTimeline(post)
615}
616
617function post(text) {
618 ws.send(JSON.stringify({
619 type: 'post',
620 text
621 }))
622}
623```
624
625**Best For:**
626- Quick access
627- Mobile users
628- Users without Pear installed
629- Public discovery
630
631### Recommendation by Phase
632
633| Phase | Technology | Priority | Reason |
634|-------|-----------|----------|--------|
635| **Phase 1** | Terminal App | HIGH | Test P2P, no GUI complexity |
636| **Phase 2** | Web UI | MEDIUM | Accessibility, mobile support |
637| **Phase 3** | Desktop App | LOW | Rich UX for committed users |
638
639---
640
641## Implementation Plan
642
643### Architecture Overview
644
645```
646┌─────────────────────────────────────────────────────────┐
647│ WIRECORE NODE │
648│ (Core P2P Logic) │
649├─────────────────────────────────────────────────────────┤
650│ lib/core/wirecore.js │
651│ ✅ Already exists │
652│ ✅ Per-user feeds │
653│ ✅ Follow/unfollow │
654│ ✅ Timeline generation │
655│ ✅ ANProto signing │
656└─────────────────────────────────────────────────────────┘
657 ↓ ↓
658┌──────────────────────┐ ┌──────────────────────┐
659│ PEAR TERMINAL │ │ WEB UI │
660│ (Phase 1) │ │ (Phase 2) │
661├──────────────────────┤ ├──────────────────────┤
662│ pear-app/ │ │ web-ui/ │
663│ ├── index.js │ │ ├── index.html │
664│ ├── package.json │ │ ├── app.js │
665│ └── Uses Wirecore │ │ └── WebSocket │
666└──────────────────────┘ └──────────────────────┘
667 ↓ ↓
668┌─────────────────────────────────────────────────────────┐
669│ IDENTITY LAYER │
670│ (keet-identity-key) │
671├─────────────────────────────────────────────────────────┤
672│ lib/identity/manager.js │
673│ ├── Create/restore identities │
674│ ├── HD key derivation │
675│ ├── Device proofs │
676│ └── Mnemonic storage │
677└─────────────────────────────────────────────────────────┘
678 ↓
679┌─────────────────────────────────────────────────────────┐
680│ HYPERSWARM P2P │
681│ (Direct peer-to-peer networking) │
682└─────────────────────────────────────────────────────────┘
683 ↕
684┌─────────────────────────────────────────────────────────┐
685│ RELAY (Optional) │
686│ (Bridge for web users) │
687├─────────────────────────────────────────────────────────┤
688│ relay/wirecore-relay.js │
689│ ✅ Already running on 7rnx.net │
690│ ↔ Sparse queries only (followed users) │
691└─────────────────────────────────────────────────────────┘
692```
693
694---
695
696## Phase Breakdown
697
698### Phase 1: Pear Terminal App (Week 1-2)
699
700**Goal:** Build and test P2P terminal app with persistent identities
701
702**Deliverables:**
7031. Pear terminal app structure
7042. keet-identity-key integration
7053. P2P connectivity between 2+ instances
7064. CLI commands: init, post, follow, timeline
7075. Sparse replication (followed users only)
7086. Relay integration (query only, not full sync)
709
710**Tasks:**
711
712#### 1.1 Project Setup
713```bash
714# Create pear-app directory
715mkdir pear-app
716cd pear-app
717
718# Initialize Pear terminal app
719pear init -t terminal -y
720
721# Install dependencies
722npm install keet-identity-key hyperswarm hypercore corestore
723```
724
725**File structure:**
726```
727pear-app/
728├── package.json
729├── index.js # Main entry point
730├── lib/
731│ ├── identity.js # keet-identity-key wrapper
732│ ├── node.js # Uses lib/core/wirecore.js
733│ └── commands.js # CLI command handlers
734└── .pearignore # IMPORTANT: Don't ignore node_modules
735```
736
737#### 1.2 Identity Management
738
739Create `pear-app/lib/identity.js`:
740```javascript
741import IdentityKey from 'keet-identity-key'
742import { readFile, writeFile, mkdir } from 'fs/promises'
743import { join } from 'path'
744
745export class WirecoreIdentity {
746 constructor(storagePath) {
747 this.storagePath = storagePath
748 this.identityPath = join(storagePath, 'identity.json')
749 this.id = null
750 }
751
752 async init() {
753 await mkdir(this.storagePath, { recursive: true })
754
755 try {
756 const data = await readFile(this.identityPath, 'utf8')
757 const { mnemonic } = JSON.parse(data)
758 this.id = await IdentityKey.from({ mnemonic })
759 return { exists: true }
760 } catch {
761 return { exists: false }
762 }
763 }
764
765 async create(name = 'Anonymous') {
766 const mnemonic = IdentityKey.generateMnemonic()
767 this.id = await IdentityKey.from({ mnemonic })
768
769 await writeFile(this.identityPath, JSON.stringify({
770 name,
771 mnemonic,
772 publicKey: this.getPublicKey(),
773 created: Date.now()
774 }, null, 2))
775
776 return { mnemonic, publicKey: this.getPublicKey() }
777 }
778
779 getPublicKey() {
780 return this.id.identityKeyPair.publicKey.toString('hex')
781 }
782
783 getKeypair() {
784 return this.id.identityKeyPair
785 }
786
787 getDiscoveryKey() {
788 return this.id.discoveryCorePath()
789 }
790}
791```
792
793#### 1.3 Integrate with Wirecore Node
794
795Create `pear-app/lib/node.js`:
796```javascript
797import { Wirecore } from '../../lib/core/wirecore.js'
798import { WirecoreIdentity } from './identity.js'
799
800export class WirecorePearNode {
801 constructor(storagePath) {
802 this.storagePath = storagePath
803 this.identity = new WirecoreIdentity(storagePath)
804 this.node = null
805 }
806
807 async init() {
808 // Initialize identity
809 const { exists } = await this.identity.init()
810 if (!exists) {
811 throw new Error('No identity found. Run "wirecore init" first.')
812 }
813
814 // Initialize Wirecore with keet-identity keypair
815 this.node = new Wirecore(this.storagePath)
816 await this.node.init({
817 keypair: this.identity.getKeypair()
818 })
819
820 return this.node
821 }
822
823 async createIdentity(name) {
824 return await this.identity.create(name)
825 }
826}
827```
828
829#### 1.4 Terminal UI
830
831Create `pear-app/index.js`:
832```javascript
833#!/usr/bin/env pear
834
835import readline from 'bare-readline'
836import tty from 'bare-tty'
837import { WirecorePearNode } from './lib/node.js'
838
839const STORAGE = './wirecore-storage'
840
841// ANSI colors
842const colors = {
843 reset: '\x1b[0m',
844 cyan: '\x1b[36m',
845 green: '\x1b[32m',
846 yellow: '\x1b[33m',
847 gray: '\x1b[90m'
848}
849
850const node = new WirecorePearNode(STORAGE)
851
852async function init(name) {
853 const { mnemonic, publicKey } = await node.createIdentity(name || 'Anonymous')
854
855 console.log(`${colors.green}✓ Identity created!${colors.reset}`)
856 console.log(`${colors.cyan}Public Key:${colors.reset} ${publicKey}`)
857 console.log(`${colors.yellow}Mnemonic (SAVE THIS):${colors.reset}`)
858 console.log(mnemonic)
859 console.log()
860 console.log('Store this mnemonic safely. You\'ll need it to restore your identity.')
861}
862
863async function post(text) {
864 await node.node.post({ text })
865 console.log(`${colors.green}✓ Posted:${colors.reset} ${text}`)
866}
867
868async function timeline() {
869 const posts = await node.node.getTimeline()
870
871 console.log(`${colors.cyan}Timeline (${posts.length} posts):${colors.reset}\n`)
872
873 for (const post of posts.slice(-20).reverse()) {
874 const date = new Date(post.timestamp).toLocaleString()
875 const author = post.author.slice(0, 8) + '...'
876 console.log(`${colors.gray}${date}${colors.reset} ${colors.cyan}@${author}${colors.reset}`)
877 console.log(post.text)
878 console.log()
879 }
880}
881
882async function follow(pubkey, name) {
883 await node.node.follow(pubkey, name)
884 console.log(`${colors.green}✓ Following:${colors.reset} ${name || pubkey.slice(0, 16)}...`)
885}
886
887async function whoami() {
888 const pubkey = node.identity.getPublicKey()
889 console.log(`${colors.cyan}Your Public Key:${colors.reset}`)
890 console.log(pubkey)
891}
892
893// Main
894async function main() {
895 const args = Pear.config.args
896 const [command, ...params] = args
897
898 try {
899 if (command === 'init') {
900 await init(params[0])
901 return
902 }
903
904 // All other commands need initialized node
905 await node.init()
906
907 switch (command) {
908 case 'post':
909 await post(params.join(' '))
910 break
911 case 'timeline':
912 await timeline()
913 break
914 case 'follow':
915 await follow(params[0], params[1])
916 break
917 case 'whoami':
918 await whoami()
919 break
920 default:
921 console.log('Commands: init, post, timeline, follow, whoami')
922 }
923
924 await node.node.close()
925 } catch (err) {
926 console.error(`${colors.yellow}Error:${colors.reset} ${err.message}`)
927 process.exit(1)
928 }
929}
930
931main()
932```
933
934#### 1.5 Testing Plan
935
936**Test 1: Single Instance**
937```bash
938# Initialize
939pear run --dev . init Alice
940
941# Post
942pear run --dev . post "Hello from Alice!"
943
944# View timeline
945pear run --dev . timeline
946
947# Get public key
948pear run --dev . whoami
949```
950
951**Test 2: Two Instances (P2P)**
952```bash
953# Terminal 1 (Alice)
954cd pear-app-alice
955pear run --dev . init Alice
956pear run --dev . post "Alice's first post"
957pear run --dev . whoami
958# Copy Alice's pubkey
959
960# Terminal 2 (Bob)
961cd pear-app-bob
962pear run --dev . init Bob
963pear run --dev . follow <alice-pubkey> Alice
964pear run --dev . timeline
965# Should see Alice's post!
966
967pear run --dev . post "Hi Alice, from Bob"
968
969# Terminal 1 (Alice)
970pear run --dev . follow <bob-pubkey> Bob
971pear run --dev . timeline
972# Should see Bob's post!
973```
974
975#### 1.6 Deployment
976
977**Local directory deployment:**
978```bash
979# Package
980cd pear-app
981pear stage production
982
983# Extract to local directory
984pear dump production /opt/wirecore-pear
985
986# Test
987pear run /opt/wirecore-pear init TestUser
988
989# Create systemd service (optional)
990sudo systemctl enable wirecore-pear
991sudo systemctl start wirecore-pear
992```
993
994---
995
996### Phase 2: Web UI Integration (Week 3-4)
997
998**Goal:** Build web UI that queries relay for followed users only
999
1000**Deliverables:**
10011. Web UI (HTML/CSS/JS)
10022. WebSocket connection to relay
10033. Sparse queries (followed users only)
10044. User authentication (pubkey-based)
10055. Timeline view
10066. Post composition
1007
1008**Architecture:**
1009```
1010[Browser] ←→ WebSocket ←→ [Relay] ←→ [Query followed users] ←→ Hyperswarm
1011```
1012
1013**Key APIs:**
1014```javascript
1015// GET /relay/user/<pubkey>/posts
1016// Returns only that user's posts
1017
1018// WebSocket: Subscribe to followed users
1019ws.send(JSON.stringify({
1020 type: 'subscribe',
1021 follows: ['<pubkey1>', '<pubkey2>']
1022}))
1023
1024// WebSocket: Receive updates
1025ws.onmessage = (event) => {
1026 const { type, author, post } = JSON.parse(event.data)
1027 if (type === 'new-post') {
1028 addToTimeline(author, post)
1029 }
1030}
1031```
1032
1033---
1034
1035### Phase 3: Desktop App (Week 5-6)
1036
1037**Goal:** Build Electron-based desktop app with rich UI
1038
1039**Technology:**
1040- pear-electron
1041- React/Vue/Svelte (TBD)
1042- Same Wirecore core
1043
1044**Features:**
1045- Rich media (images, videos)
1046- Notifications
1047- Native OS integration
1048- Offline support
1049
1050---
1051
1052### Phase 4: Multi-Device Support (Week 7-8)
1053
1054**Goal:** Enable identity across multiple devices using keet-identity-key proofs
1055
1056**Features:**
1057- Device linking
1058- Proof chain verification
1059- Sync between devices
1060- Device-specific keys
1061
1062**Implementation:**
1063```javascript
1064// Main device
1065const proof = identity.id.bootstrap(mainDevice.publicKey)
1066
1067// Secondary device
1068const proof2 = IdentityKey.attest(secondaryDevice.publicKey, mainDevice, proof)
1069
1070// Verify on any device
1071const info = IdentityKey.verify(proof2)
1072// Returns: list of devices in chain
1073```
1074
1075---
1076
1077## References
1078
1079### Documentation Sources
1080
10811. **hyper-fleeky Projects**
1082 - `/hyper-fleeky/pear-deployment-lessons.md` - Critical deployment lessons
1083 - `/hyper-fleeky/repos/hyperident/` - Identity implementation reference
1084 - `/hyper-fleeky/repos/wirecore/` - This project
1085
10862. **holepunchto Knowledge Base**
1087 - `/holepunchto/skills/keet-identity-key/` - HD identity system
1088 - `/holepunchto/skills/hypercore/` - Core P2P primitives
1089 - `/holepunchto/skills/hyperswarm/` - DHT networking
1090 - `/holepunchto/skills/corestore/` - Multi-core management
1091 - `/holepunchto/pear-docs/` - Pear runtime documentation
1092
10933. **Related Documentation**
1094 - `PEAR_APP_PLAN.md` - Original Pear app planning
1095 - `CODE_REVIEW.md` - Relay security review
1096 - `DEPLOYMENT_STATE.md` - Current relay status
1097
1098### Key Dependencies
1099
1100```json
1101{
1102 "dependencies": {
1103 "keet-identity-key": "^1.0.0",
1104 "hyperswarm": "^4.0.0",
1105 "hypercore": "^10.0.0",
1106 "corestore": "^6.0.0",
1107 "hyperbee": "^2.26.5"
1108 }
1109}
1110```
1111
1112### External Resources
1113
1114- Keet: https://keet.io (production P2P chat using similar architecture)
1115- Holepunch: https://holepunch.to (Hypercore ecosystem)
1116- Pear Runtime: https://pears.com
1117
1118---
1119
1120## Appendix: Common Commands Reference
1121
1122### Development
1123```bash
1124# Create new Pear terminal app
1125pear init -t terminal -y
1126
1127# Run in development mode
1128pear run --dev .
1129
1130# Run production build
1131pear run .
1132```
1133
1134### Testing
1135```bash
1136# Clear Pear cache
1137rm -rf ~/.config/pear/app-storage/*
1138
1139# Test on clean instance
1140pear run --checkout=latest pear://[key]
1141
1142# Check Pear version
1143pear --version
1144```
1145
1146### Deployment
1147```bash
1148# Stage for production
1149pear stage production
1150
1151# Extract to directory
1152pear dump production /opt/app
1153
1154# Seed on DHT (broken for npm deps)
1155pear seed production
1156```
1157
1158### Debugging
1159```bash
1160# View Pear logs
1161tail -f ~/.config/pear/by-arch/[arch]/app-storage/[key]/platform.log
1162
1163# Check running apps
1164pear apps
1165
1166# Kill app
1167pear kill [key]
1168```
1169
1170---
1171
1172**Document Version**: 1.0
1173**Last Updated**: 2026-01-20
1174**Next Review**: After Phase 1 completion
1175
1176Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>