Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
ffc9e16
prototype cli interface for managing koi nodes
lukvmil Sep 9, 2025
469f3bf
reorganizing for dependency injection
lukvmil Sep 18, 2025
73010a3
factored effector (for now), added new providers for list of knowledg…
lukvmil Sep 18, 2025
ecf26e0
set up knowledge and event worker threads, continuing to experiment w…
lukvmil Sep 22, 2025
7ff30e6
factored out dependency injector, done manually with NodeAssembler an…
lukvmil Sep 23, 2025
8c7530c
updated effector, removed deprecated flush queue function calls. (pre…
lukvmil Sep 23, 2025
353398d
prototype interested RID types handler and configuration
lukvmil Sep 23, 2025
48ae6ff
factored out handshake into its own component, updated examples, adde…
lukvmil Sep 30, 2025
5ae8948
bug fixes, and decreased max wait time for demo
lukvmil Oct 1, 2025
42df538
added better conditions for determining when no coordinator is known,…
lukvmil Oct 1, 2025
cd0672c
Merge pull request #19 from BlockScience/cli
lukvmil Oct 6, 2025
6a93b38
updated docs, bumped version to 1.2.0-beta.1
lukvmil Oct 6, 2025
382355c
set up structlog, moving towards better logging practices
lukvmil Oct 7, 2025
864061d
refactoring and rearranging, removed behaviors and moved logic into l…
lukvmil Oct 9, 2025
774d7b1
factored out action context for now, finally added support for "limit…
lukvmil Oct 14, 2025
405a7db
working on a better dependency injection system, moved around some de…
lukvmil Oct 15, 2025
5aed08c
figured out clean unified design for assembler and blueprints, works …
lukvmil Oct 16, 2025
ab4eb0c
refined node assembler, parses through all base classes in reverse or…
lukvmil Oct 16, 2025
7edec90
attempt to refactor config system. separate subsystem ConfigLoader ha…
lukvmil Oct 21, 2025
5a64a92
restructuring and renaming, queues and buffer use 'push' instead of r…
lukvmil Oct 22, 2025
82ba5c6
moved config system into a node component, removed old logging system…
lukvmil Oct 31, 2025
8174bad
updated typing and error logging, added LNAV config file for koi-net …
lukvmil Nov 7, 2025
f915e03
removed cli tools, moving to 'cli' branch, won't be a part of v1.2
lukvmil Nov 7, 2025
e934ba2
fixing coordinator catch up, no longer tries to query partial nodes o…
lukvmil Nov 7, 2025
09d3962
removed cli entrypoint
lukvmil Nov 7, 2025
e07e6aa
moved catch up function in lifecycle to a sync manager component, dec…
lukvmil Nov 13, 2025
592dd2a
cleaned up knowledge handler class, added doc strings to assembler
lukvmil Nov 14, 2025
a35f12c
pass on config modules - improved logging and docs
lukvmil Nov 14, 2025
15004ca
update documentation, logging, organization from entry point components
lukvmil Nov 14, 2025
8c8b40a
cleaning up network methods, documentation and small code improvement…
lukvmil Nov 16, 2025
e942374
updated docstrings and cleaned up code in processor modules
lukvmil Nov 16, 2025
87dbfa7
updated documentation for protocol and worker modules
lukvmil Nov 17, 2025
ac4fb83
generalized poll event buffer, to event buffer including timing featu…
lukvmil Nov 18, 2025
56fe7e3
removed unused default effector actions, renamed secure to secure man…
lukvmil Nov 18, 2025
3857f10
refactored effector to work similar to the processing pipeline, accep…
lukvmil Nov 18, 2025
aae753f
hacked type annotation return from node assembler to give a better dy…
lukvmil Nov 18, 2025
ac3e70f
version bump, tentative release -> beta.4
lukvmil Nov 19, 2025
65cd216
spun out config proxy class from config loader, renamed config cls to…
lukvmil Nov 19, 2025
c454822
config_cls -> config_schema, switched assembler functions back to cha…
lukvmil Nov 20, 2025
4420ef2
automated component build order via kahn's algorithm on dependency gr…
lukvmil Nov 20, 2025
74adad4
version bump -> 1.2.0-beta.6, moved cycle detection to another branch
lukvmil Nov 20, 2025
7fd41c2
moved start stop logic into worker classes
lukvmil Nov 20, 2025
38624ce
factoring out lifecycle component, instead the node container object …
lukvmil Dec 2, 2025
7f9f76d
fully factored out lifecycle component, refactored assembly mechanism…
lukvmil Dec 2, 2025
ffba7f2
moved assembler, component, container, and consts to shared build mod…
lukvmil Dec 3, 2025
1e0e116
moved handshaker, profile monitor (renamed from self start), and sync…
lukvmil Dec 3, 2025
dc79547
cleaning up, added get_logger method in log system, may have componen…
lukvmil Dec 3, 2025
366b692
version bump -> 1.2.0-beta.7
lukvmil Dec 3, 2025
3ccd599
renamed assembly artifact -> build artifact, added a new comp_order d…
lukvmil Dec 3, 2025
425b18b
readded access log to uvicorn, added more specific typehints for full…
lukvmil Dec 3, 2025
a71b531
updated log system, achieved compatibility with uvicorn logs includin…
lukvmil Dec 3, 2025
f197a8e
version bump -> 1.2.0-beta.9
lukvmil Dec 3, 2025
ea35e67
handshaker bug fix, handshakes when there aren't any neighbors
lukvmil Dec 3, 2025
7c2408f
version bump [FULL RELEASE] -> v1.2.0
lukvmil Dec 3, 2025
e1eb4f7
Merge branch 'main' into dev
lukvmil Dec 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
rid-lib
__pycache__
*.json
*.pem
*.yaml
*.ndjson*
venv
.env
prototypes
.vscode
dist/
docs/
*.ndjson
tests/
.rid_cache/
*.ndjson
88 changes: 40 additions & 48 deletions examples/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,65 +1,53 @@
import logging
from rich.logging import RichHandler
from pydantic import Field
from rid_lib.types import KoiNetNode, KoiNetEdge
from koi_net.config import NodeConfig, KoiNetConfig
from koi_net.protocol.node import NodeProfile, NodeProvides, NodeType
from koi_net import NodeInterface
from koi_net.context import HandlerContext
from koi_net.processor.handler import HandlerType
import structlog
from koi_net.config.full_node import (
FullNodeConfig,
ServerConfig,
KoiNetConfig,
NodeProfile,
NodeProvides
)
from koi_net.core import FullNode
from koi_net.processor.context import HandlerContext
from koi_net.processor.handler import HandlerType, KnowledgeHandler
from koi_net.processor.knowledge_object import KnowledgeObject
from koi_net.protocol.event import Event, EventType
from koi_net.protocol.edge import EdgeType, generate_edge_bundle

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[RichHandler()]
)
log = structlog.stdlib.get_logger()

logging.getLogger("koi_net").setLevel(logging.DEBUG)
logger = logging.getLogger(__name__)

class CoordinatorConfig(NodeConfig):
koi_net: KoiNetConfig = Field(default_factory = lambda:
KoiNetConfig(
node_name="coordinator",
node_profile=NodeProfile(
node_type=NodeType.FULL,
provides=NodeProvides(
event=[KoiNetNode, KoiNetEdge],
state=[KoiNetNode, KoiNetEdge]
)
),
cache_directory_path=".coordinator_rid_cache",
event_queues_path="coordinator_event_queues.json",
private_key_pem_path="coordinator_priv_key.pem"
)
class CoordinatorConfig(FullNodeConfig):
server: ServerConfig = ServerConfig(port=8080)
koi_net: KoiNetConfig = KoiNetConfig(
node_name="coordinator",
node_profile=NodeProfile(
provides=NodeProvides(
event=[KoiNetNode, KoiNetEdge],
state=[KoiNetNode, KoiNetEdge]
)
),
rid_types_of_interest=[KoiNetNode, KoiNetEdge]
)

node = NodeInterface(
config=CoordinatorConfig.load_from_yaml("coordinator_config.yaml"),
use_kobj_processor_thread=True
)

@node.processor.pipeline.register_handler(HandlerType.Network, rid_types=[KoiNetNode])
@KnowledgeHandler.create(
HandlerType.Network,
rid_types=[KoiNetNode])
def handshake_handler(ctx: HandlerContext, kobj: KnowledgeObject):
logger.info("Handling node handshake")
log.info("Handling node handshake")

# only respond if node declares itself as NEW
if kobj.event_type != EventType.NEW:
return

logger.info("Sharing this node's bundle with peer")
identity_bundle = ctx.effector.deref(ctx.identity.rid)
ctx.event_queue.push_event_to(
log.info("Sharing this node's bundle with peer")
identity_bundle = ctx.cache.read(ctx.identity.rid)
ctx.event_queue.push(
event=Event.from_bundle(EventType.NEW, identity_bundle),
node=kobj.rid,
flush=True
target=kobj.rid
)

logger.info("Proposing new edge")
log.info("Proposing new edge")
# defer handling of proposed edge

edge_bundle = generate_edge_bundle(
Expand All @@ -69,8 +57,12 @@ def handshake_handler(ctx: HandlerContext, kobj: KnowledgeObject):
rid_types=[KoiNetNode, KoiNetEdge]
)

ctx.handle(rid=edge_bundle.rid, event_type=EventType.FORGET)
ctx.handle(bundle=edge_bundle)

ctx.kobj_queue.push(rid=edge_bundle.rid, event_type=EventType.FORGET)
ctx.kobj_queue.push(bundle=edge_bundle)

class CoordinatorNode(FullNode):
config_schema = CoordinatorConfig
knowledge_handlers = FullNode.knowledge_handlers + [handshake_handler]

if __name__ == "__main__":
node.server.run()
CoordinatorNode().run()
40 changes: 9 additions & 31 deletions examples/partial.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,15 @@
import logging
from pydantic import Field
from rich.logging import RichHandler
from koi_net import NodeInterface
from koi_net.protocol.node import NodeProfile, NodeType
from koi_net.config import NodeConfig, KoiNetConfig
from koi_net.config.partial_node import PartialNodeConfig, KoiNetConfig, NodeProfile
from koi_net.core import PartialNode

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[RichHandler()]
)

logging.getLogger("koi_net").setLevel(logging.DEBUG)
logger = logging.getLogger(__name__)


class PartialNodeConfig(NodeConfig):
koi_net: KoiNetConfig = Field(default_factory = lambda:
KoiNetConfig(
node_name="partial",
node_profile=NodeProfile(
node_type=NodeType.PARTIAL
),
cache_directory_path=".partial_rid_cache",
event_queues_path="partial_event_queues.json",
private_key_pem_path="partial_priv_key.pem"
)
class MyPartialNodeConfig(PartialNodeConfig):
koi_net: KoiNetConfig = KoiNetConfig(
node_name="partial",
node_profile=NodeProfile()
)

node = NodeInterface(
config=PartialNodeConfig.load_from_yaml("partial_config.yaml")
)
class MyPartialNode(PartialNode):
config_schema = MyPartialNodeConfig

if __name__ == "__main__":
node.poller.run()
MyPartialNode().run()
79 changes: 79 additions & 0 deletions koi-net.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
{
"$schema": "https://lnav.org/schemas/format-v1.schema.json",
"koi_net_json_log": {
"title": "KOI-net node logs",
"description": "Detailed logs of node and network behavior",
"file-type": "json",
"body-field": "event",
"level-field": "",
"timestamp-field": "timestamp",
"hide-extra": true,
"line-format": [
{
"field": "timestamp",
"auto-width": true,
"timestamp-format": "%Y-%m-%d %H:%M:%S"
},
" ",
{
"field": "level",
"auto-width": true,
"prefix": "[",
"suffix": "]"
},
" ",
{
"field": "module",
"min-width": 15,
"max-width": 15,
"overflow": "dot-dot",
"align": "right"
},
" - ",
{
"field": "event"
}
],
"value": {
"level": {
"kind": "string"
},
"event": {
"kind": "string"
},
"module": {
"kind": "string"
}
},
"highlights": {
"debug": {
"pattern": "\\[(debug) *\\]",
"color": "Blue"
},
"info": {
"pattern": "\\[(info) *\\]",
"color": "Green"
},
"warning": {
"pattern": "\\[(warning) *\\]",
"color": "Yellow"
},
"error": {
"pattern": "\\[(error|critical) *\\]",
"color": "Red"
},
"timestamp": {
"pattern": "(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})",
"color": "Grey"
},
"obj_name": {
"pattern": "<([a-zA-Z.]+)",
"color": "Purple"
},
"quotations": {
"pattern": "(['\"][^']*['\"])",
"color": "Green"
}
}
}
}
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "koi-net"
version = "1.1.0"
version = "1.2.0"
description = "Implementation of KOI-net protocol in Python"
authors = [
{name = "Luke Miller", email = "luke@block.science"}
Expand All @@ -23,6 +23,7 @@ dependencies = [
"fastapi>=0.115.12",
"uvicorn>=0.34.2",
"rich>=14.1.0",
"structlog>=25.4.0",
]

[project.optional-dependencies]
Expand Down
9 changes: 0 additions & 9 deletions requirements.txt

This file was deleted.

16 changes: 16 additions & 0 deletions schemas/bundle.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"title": "Bundle",
"type": "object",
"properties": {
"manifest": {
"$ref": "./manifest.schema.json"
},
"contents": {
"type": "object"
}
},
"required": [
"manifest",
"contents"
]
}
32 changes: 32 additions & 0 deletions schemas/bundles_payload.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"title": "Bundles Payload",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "bundles_payload"
},
"bundles": {
"type": "array",
"items": {
"$ref": "./bundle.schema.json"
}
},
"not_found": {
"type": "array",
"items": {
"type": "string"
}
},
"deferred": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"type",
"bundles"
]
}
49 changes: 49 additions & 0 deletions schemas/edge_profile.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"$defs": {
"EdgeStatus": {
"title": "Edge Status",
"type": "string",
"enum": [
"PROPOSED",
"APPROVED"
]
},
"EdgeType": {
"title": "Edge Type",
"type": "string",
"enum": [
"WEBHOOK",
"POLL"
]
}
},
"title": "Edge Profile",
"type": "object",
"properties": {
"source": {
"type": "string"
},
"target": {
"type": "string"
},
"edge_type": {
"$ref": "#/$defs/EdgeType"
},
"status": {
"$ref": "#/$defs/EdgeStatus"
},
"rid_types": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"source",
"target",
"edge_type",
"status",
"rid_types"
]
}
Loading