Skip to content

feat(swarm): node identity bootstrap + node_identity_get tool (#76)#81

Merged
Dewinator merged 3 commits into
mainfrom
agent/issue-76-2026-04-27T19-23-37-671Z
Apr 27, 2026
Merged

feat(swarm): node identity bootstrap + node_identity_get tool (#76)#81
Dewinator merged 3 commits into
mainfrom
agent/issue-76-2026-04-27T19-23-37-671Z

Conversation

@Dewinator

Copy link
Copy Markdown
Owner

Closes #76 — Swarm Phase 1b.

Summary

  • New scripts/init-node-identity.mjs: idempotent Ed25519 keypair bootstrap. Privkey lands in ~/.mycelium/node.key (mode 0600, 0700 directory); pubkey + derived node_id go into the nodes self-row.
  • New MCP tool node_identity_get: read-only, returns { node_id, pubkey_b64, display_name, created_at }.
  • node_id follows docs/SWARM_SPEC.md §3.5 exactly: base58btc(multihash(sha2-256, pubkey_raw)) → 46-char Qm… string.

Research summary

  • Inspected the existing MCP-tool pattern (tools/identity.ts, tools/soul.ts) and copied the read-only getSelfModel shape for the new tool.
  • node:crypto already supports Ed25519 (generateKeyPairSync('ed25519')); existing services/crypto.ts uses the same SPKI-tail pattern to extract the raw 32-byte pubkey, so I reused it.
  • The wire-format formula was already pinned in docs/SWARM_SPEC.md (merged in a50444a); the migration spec from Swarm Phase 1a: migration 070 — node_identity table (file only, do NOT run) #75 is in supabase/migrations/070_node_identity.sql (merged in 3cce198). PR feat(swarm): migration 070 — nodes table for cryptographic identity (#75) #79 (which includes the contract test) is still open but the schema needed by this PR is already on main.
  • Encoded base58btc by hand (no extra dep) with explicit leading-zero handling — pinned by tests against the canonical 2NEpo7TZRRrLZSi2U 'Hello World!' vector.

What this does NOT do

  • No SQL is executed. Migration 070 must be applied to the database manually before the bootstrap script can live-run; the script will fail with a clear PostgREST error if the nodes table is missing.
  • No display_name heuristic — the bootstrap optionally honours MYCELIUM_NODE_DISPLAY_NAME, otherwise leaves the field NULL.
  • No automatic call from setup.sh/install.sh — wiring the bootstrap into the installer is a follow-up.
  • No use of the new identity by any other tool (advertisements, signed lessons, peer discovery) — those are later swarm phases.

Constitution affirmation

Touches Pillar 1 (Decentralized) and Pillar 6 (Cyber security). Reinforced, not weakened:

  • Pillar 1: identity is generated and owned locally; no central registry consulted.
  • Pillar 6: the privkey never reaches the database, lives in a chmod-600 file inside a chmod-700 directory, and bootstrap refuses to regenerate when DB state is inconsistent (would otherwise orphan every signature ever produced under the original key).
  • No other pillar weakened — pairing/breeding/swarm-economics surfaces untouched.

Test plan

  • cd mcp-server && npm test — 271 tests pass, including 12 new ones in node-identity.test.ts:
    • base58btc encoding (empty buffer, leading-zero rule, canonical 'Hello World!' vector)
    • computeNodeId rejects non-32-byte input, is deterministic, distinguishes inputs, produces a 46-char Qm…, matches the spec formula
    • bootstrap idempotency: first run inserts, second run is a no-op, refusal-on-inconsistent-state, deterministic re-derivation from existing privkey
  • Live-test (after migration 070 is applied to a real Supabase): cd mcp-server && npm run build && node scripts/init-node-identity.mjs — verify (a) ~/.mycelium/node.key is created with 0600, (b) nodes table has exactly one is_self=true row, (c) running again prints node_id already initialized: … and inserts nothing, (d) calling node_identity_get from any MCP client returns the same node_id.

Dewinator and others added 3 commits April 27, 2026 20:36
Spec-only first phase of the Mycelium Swarm Foundation Plan v1. Defines
spec versioning, JCS (RFC 8785) over Ed25519 for signatures, the four
wire types (Lesson, HubAnchor, NodeAdvertisement, TrustEdge), four
HTTP/JSON endpoints, and uniform rejection rules. No code, no migrations.

Restates the three unverletzlichen Designprinzipien (Souveränität,
Generalisierung-vor-Sharing, Diversität) at the top so all later phases
implement against the same contract and the same constraints.

Closes the Phase-0 deliverable of issue #74.
)

Swarm Phase 1a: schema-only migration that creates the `nodes` table
holding this mycelium node's public key and node_id (multihash of the
pubkey), plus any peers we will later learn about. The PRIVATE key is
deliberately NOT a column — it lives outside the database in a
chmod-600 file at ~/.mycelium/node.key (Verfassung pillar 1,
Souveränität).

Includes a partial UNIQUE index `nodes_only_one_self ON nodes ((1))
WHERE is_self` that enforces "at most one row may carry is_self=true",
and a sibling TS contract test (`migration-070-node-identity.test.ts`)
that pins the canonical SQL: column types, defaults, and the partial
predicate. The test reads the raw SQL — it does not run the migration.

Out of scope: keypair-generation script and the `node_identity_get`
MCP tool (both phase 1b, separate issue); signature service (phase 2).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Swarm Phase 1b. Builds on migration 070 (#75 / nodes table) by giving
the node a way to (a) generate its Ed25519 keypair on first run and
(b) expose the resulting identity over MCP.

Wire format follows docs/SWARM_SPEC.md §3.5 exactly:
  node_id = base58btc(multihash(sha2-256, pubkey_raw))

The privkey lives in ~/.mycelium/node.key with mode 0600 inside a 0700
directory; it never enters the database. Bootstrap is idempotent and
refuses to act when the DB has a self row but the privkey file is
missing — that combination is unrecoverable signing-state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Dewinator Dewinator added the agent-opened Opened by the autonomy loop label Apr 27, 2026
@Dewinator Dewinator merged commit 1bfef41 into main Apr 27, 2026
@Dewinator Dewinator deleted the agent/issue-76-2026-04-27T19-23-37-671Z branch April 27, 2026 20:19
Dewinator added a commit that referenced this pull request Apr 29, 2026
Updates the stale "spec-only" header (phases 0–3 have all merged via
PRs #79/#81/#82/#85/#89/#91/#92) and pins each phase to its issue +
merged commit so a reader can tell at a glance which sections are wired
on `main` vs. still paper.

Phases 4–9 are deliberately listed as "_not yet issued_" — the project's
current priority is *Gehirn perfektionieren* per CLAUDE.md § Roadmap
(Reed 2026-04-26), and the wire contract is frozen at v1.0 so an
independent implementer can build a phase-3-equivalent peer today.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dewinator added a commit that referenced this pull request Apr 29, 2026
The cryptographic foundation of the swarm (SWARM_SPEC v1, Ed25519
signing, JCS canonicalization, wire-validator, .well-known discovery,
peer/signed-record storage — PRs #78,#79,#81,#82,#85,#89,#91,#92) was
landing on main while the README/MANIFESTO still claimed
"pairing/swarm/federation deferred". This commit fixes that mismatch.

README (EN+DE):
- new "Swarm — federation in flight" section with merged-PR table
  and a "what is next" subsection pointing to the swarm label
- Roadmap rewritten: phase 4-5 from "deferred" to "Phase 1 shipped"
- existing /.well-known/mycelium-node block folded into the new section
- promo video as a clickable poster near the top, served from a
  v0.4-swarm-phase-1 GitHub release asset (14 MB H.264 1080p)

MANIFESTO (EN+DE):
- "What is built today" split into brain core + Swarm Phase 1
- aspirational Tailscale+mTLS / mutual-pairing claims removed; those
  pieces remain on archive/swarm-deferred as historical reference
- "What is not built yet" sharpened to the social layer (verification,
  reputation, banishment-by-consensus, Sybil resistance) plus
  micro-transactions

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-opened Opened by the autonomy loop

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Swarm Phase 1b: scripts/init-node-identity.mjs + node_identity_get MCP tool

1 participant