Help us shape the future of Go! Take the 2026 Go Developer Survey

spoke

module
v0.14.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 22, 2026 License: Apache-2.0

README

SPOKE

CI License Version Last commit

中文 · Concepts · Strategy · Contributing

Standardized Programmable Ontology Knowledge Engine — a protocol of JSON Schema wire contracts for narrative KnowledgeEntry data and ops. Independent products exchange consistency-check and context-assembly I/O through these shapes.

Includes:

  • Data-layer schemas: KnowledgeEntry, Relation, SourceAnchor, Finding, AssemblePacket, HostCapabilityManifest, Rule, TimelineEvent, MindState
  • Ops-layer schemas: upsert, extract→promote, relate, check, assemble; optional project / compute under l2-computable
  • Generated TypeScript (@42ch/spoke-schemas) and Rust (spoke-schemas, spoke-operations)
  • Pure lifecycle helpers plus adapter ports and injection orchestration (@42ch/spoke-operations / spoke-operations)
  • Opt-in Connect for signed cross-process interaction (@42ch/spoke-connect / spoke-connect, plus native bindings, including C and C++)
  • Protocol conformance fixtures and reference ToyWorldAdapter (fixtures/toy-world/)

Packages

Published consumer packages share one lockstep SemVer.

Package Registry Role
@42ch/spoke-schemas npm Generated TypeScript wire types — what crosses the wire
@42ch/spoke-operations npm Pure helpers, adapter ports, and orchestration over those types
@42ch/spoke-connect npm Opt-in connect client — identity, hello auth, session core, WebSocket transport
spoke-schemas crates.io Generated Rust wire types
spoke-operations crates.io Pure helpers, adapter ports, and orchestration — parity with @42ch/spoke-operations
spoke-connect crates.io Opt-in connect reference — libp2p transport, session core, uniffi binding surface

Product-specific payloads live under extensions.<namespace> (namespace keys are product-chosen ids). Cross-product functional dialects shared by narrative hosts (lore activation, knowledge packs, assemble placement) live under modules.* — an optional, capability-flagged bag on KnowledgeEntry, AssemblePacket, and TimelineEvent. See Data model.

Install pins and package roles: Package quick-start.

Install

TypeScript (npm)
pnpm add @42ch/spoke-schemas @42ch/spoke-operations
# Pin both to the same lockstep SemVer, e.g. @X.Y.Z

@42ch/spoke-schemas — import generated wire types:

import type {
  KnowledgeEntry,
  TimelineEvent,
  PromoteRequest,
  AssemblePacket,
  HostCapabilityManifest,
} from "@42ch/spoke-schemas";

@42ch/spoke-operations — implement capability-sliced ports on one adapter, then call orchestrate*:

import type { PromoteRequest, UpsertRequest } from "@42ch/spoke-schemas";
import {
  orchestrateUpsert,
  orchestratePromote,
  orchestrateCheck,
  orchestrateAssemble,
  type BaselineAdapter,
} from "@42ch/spoke-operations";

declare const adapter: BaselineAdapter; // product implements BaselineAdapter / FullAdapter
declare const upsertRequest: UpsertRequest;
declare const promoteRequest: PromoteRequest;

async function runBaseline() {
  const upserted = await orchestrateUpsert(adapter, upsertRequest);
  const promoted = await orchestratePromote(adapter, promoteRequest);
}

Optional capabilities use ComputableAdapter / ForkAdapter (or FullAdapter) with orchestrateProject, orchestrateCompute, orchestrateForkCheck, and orchestrateForkAssemble. Pure helpers (validatePromoteRequest, mergeExtensionMaps, buildAssemblePacket, …) remain available for focused gates.

Rust (crates.io)
cargo add spoke-schemas spoke-operations
# Pin both to the same lockstep SemVer, e.g. X.Y.Z
# Cargo.toml
[dependencies]
spoke-schemas = "X.Y.Z"
spoke-operations = "X.Y.Z"

spoke-schemas — wire types from the same JSON Schema SSOT:

use spoke_schemas::{KnowledgeEntry, HostCapabilityManifest, PromoteRequest, TimelineEvent};

spoke-operations — port traits plus orchestrate_* (also re-exports spoke_schemas):

use spoke_operations::{
    orchestrate_promote, orchestrate_upsert, BaselineAdapter,
};
use spoke_operations::spoke_schemas::{PromoteRequest, UpsertRequest};

async fn run_baseline(adapter: &impl BaselineAdapter, upsert: UpsertRequest, promote: PromoteRequest) {
    let _ = orchestrate_upsert(adapter, upsert).await;
    let _ = orchestrate_promote(adapter, promote).await;
}
Connect (optional)

Declare the spoke-connect capability when hosts need signed cross-process interaction (hello, session, invoke, auth envelopes).

TypeScript — npm client with WebSocket transport:

pnpm add @42ch/spoke-connect
# Pin to the same lockstep SemVer as schemas / operations

Rust — crates.io reference with libp2p transport and a uniffi binding surface for other host languages:

cargo add spoke-connect

C and C++ — git-based from the release tag: check out vX.Y.Z and take crates/spoke-connect/bindings/cpp/include/spoke_connect.h (hand-written C ABI header), crates/spoke-connect/bindings/cpp/include/spoke_connect.hpp (C++17 header-only convenience layer), and the committed carrier for your target — crates/spoke-connect/bindings/cpp/native/osx-arm64/libspoke_connect_capi.dylib for macOS arm64 or crates/spoke-connect/bindings/cpp/native/win-x64/spoke_connect_capi.dll for Windows x64. Both carrier libraries are Git LFS objects, so run git lfs install once and git lfs pull in an existing clone before linking.

git clone --branch vX.Y.Z --depth 1 https://github.com/42ch-dev/spoke.git

Connect is multi-language: a language-native TypeScript client on npm, a Rust reference on crates.io (libp2p + uniffi binding surface), and native bindings — registry-backed for C# (GitHub Packages NuGet), Kotlin (GitHub Packages Maven), and Python (PyPI), git-based for Swift, Go, and C/C++ (committed headers and platform carriers). Guides: TypeScript client, native bindings, and Connect from C and C++.

Version and pinning

Pin every consumer surface to the same SemVer (X.Y.Z) on npm and crates.io:

pnpm add @42ch/spoke-schemas@X.Y.Z @42ch/spoke-operations@X.Y.Z
cargo add spoke-schemas@X.Y.Z spoke-operations@X.Y.Z

Annotated git tags vX.Y.Z match that lockstep version. Release notes: CHANGELOG.md and GitHub Releases. Pinning guide: Version & release.

Quick start

Implement the port families for the capabilities you claim on one adapter type, then call orchestrate* from @42ch/spoke-operations (Rust: orchestrate_*).

import type { KnowledgeEntry, PromoteRequest } from "@42ch/spoke-schemas";
import {
  orchestratePromote,
  type BaselineAdapter,
} from "@42ch/spoke-operations";

// Product adapter implements BaselineAdapter.
// Reference FullAdapter: fixtures/toy-world ToyWorldAdapter
declare const adapter: BaselineAdapter;

const candidate: KnowledgeEntry = {
  schema_version: 1,
  entry_id: "kb_01",
  entry_type: "character",
  canonical_name: "Aria",
  status: "provisional",
  body: { summary: "A reluctant scout." },
  extensions: {},
};

const request: PromoteRequest = { candidate };

async function promote() {
  const result = await orchestratePromote(adapter, request);

  if (result.ok) {
    // Confirmed entry persisted through adapter OCC ports
  } else {
    console.error(result.code, result.message);
  }
}

Reference FullAdapter and the committed “Mira at Harbor” graph: fixtures/toy-world/. Step-by-step package path: Package quick-start.

Core concepts

Term In SPOKE
KnowledgeEntry Atomic narrative knowledge unit on the wire (entry_id, entry_type, status, body, extensions)
Relation Directed edge between KnowledgeEntries (or KnowledgeEntry ↔ source)
SourceAnchor Provenance pointer to a manuscript span or external locator
Finding Checker output for consistency, style, or analysis
Rule Declarative constraint input to check (L6)
TimelineEvent First-class temporal object on the when-axis (L5)
MindState First-class temporal mental-state record on the when-axis (L5, optional l5-mind)
AssemblePacket Wire context-assembly payload (slim entries for downstream LLM prompts)
HostCapabilityManifest Host roles, capabilities, and owned namespaces[] for in-process collaboration
Extensions Product-specific bag on every data object (extensions.<namespace>)
Modules Optional cross-product functional-dialect bag on KnowledgeEntry, AssemblePacket, and TimelineEvent (capability-flagged narrative-modules)
Adapter ports Injected read/write surfaces (KnowledgeEntryPort, HostManifestPort, …) that own persistence
Orchestration orchestrate* / orchestrate_* sequences that load scope, apply gates, and persist via ports

Vocabulary and positioning: CONCEPTS.md, STRATEGY.md, and Concepts.

Optional capabilities

Products that need programmable KnowledgeEntry body state may declare l2-computable:

  • body.state — static durable computable values
  • body.computable — dynamic Session-scoped projection
  • TimelineEvent.computable_logs — Moment-scale field-change presentation
  • project / compute ops — init/projection and apply/settle I/O envelopes

Products that need fork-scoped timeline queries may declare l5-fork. Products that exchange cross-product functional dialects (lore activation, knowledge packs, assemble placement / activation trace) may declare narrative-modules: an optional modules (ModuleMap) bag on KnowledgeEntry, AssemblePacket, and TimelineEvent carries these dialects, and adapters round-trip unknown module namespaces verbatim. Domain Profile handbooks define the inner shapes.

Products that interchange "who believes / wants / feels what at time t" may declare l5-mind: an optional MindState temporal record (snapshot / delta over the when-axis) and modules.observation on TimelineEvent.modules. The settled home of mental fields and belief labels is the holder KnowledgeEntry modules.mental / modules.belief (narrative-modules bag); MindState is strictly derivative, never a second authority. Mental-state engines stay product-owned. Opt-in, not spoke-baseline.

Products that need signed cross-process interaction may declare spoke-connect. Composed adapter aliases: BaselineAdapter, ComputableAdapter, ForkAdapter, FullAdapter.

Baseline integrators use core schemas; optional capabilities are opt-in. Detail: Concepts.

Operations

@42ch/spoke-operations / spoke-operations provide pure helpers and port-injected orchestration:

  • Baseline orchestrators: orchestrateUpsert, orchestratePromote, orchestrateRelate, orchestrateCheck, orchestrateAssemble
  • Optional orchestrators: orchestrateProject, orchestrateCompute, orchestrateForkCheck, orchestrateForkAssemble
  • Capability-sliced ports and composed aliases (BaselineAdapter … FullAdapter)
  • Extension and module map merge and round-trip preservation (mergeExtensionMaps / mergeModuleMaps, preserveExtensionMaps / preserveModuleMaps)
  • Finding / KnowledgeEntry status transition helpers
  • Promote acceptance, upsert/relate, and MindState wire-shape validators (validateMindState / validate_mind_state)
  • AssemblePacket builders from KnowledgeEntries
  • Unified SpokeResult / SpokeRejectCode on reject paths

Reference FullAdapter (baseline + l2-computable + l5-fork, including HostCapabilityManifest peers): fixtures/toy-world/ — TypeScript ToyWorldAdapter, Rust crate spoke-fixture-toy-world.

Detail: Orchestrate operations.

Further reading

Topic Guide
Protocol umbrella Protocol
Nine layers and capability levels Concepts
Data objects and open vocabulary Data model
MindState MindState reference
Ops request/response envelopes Ops wire
Operations library behavior Orchestrate operations
Core / modules / extensions Data model
Connect envelopes and bindings Connect
Domain Profiles Domain profiles
JSON Schema SSOT schemas/
Reference adapters and sample graph fixtures/toy-world/

Contributing

Local development, CI gates, and release procedure: CONTRIBUTING.md.

Directories

Path Synopsis
crates
spoke-connect/bindings/go
Package spokeconnect is the integrator-facing Go binding for spoke-connect session core.
Package spokeconnect is the integrator-facing Go binding for spoke-connect session core.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL