Skip to content

Add channel stream API, multi-provider config, and Netclaw.Configuration library#16

Merged
Aaronontheweb merged 1 commit into
devfrom
feature/channel-stream-api
Feb 23, 2026
Merged

Add channel stream API, multi-provider config, and Netclaw.Configuration library#16
Aaronontheweb merged 1 commit into
devfrom
feature/channel-stream-api

Conversation

@Aaronontheweb
Copy link
Copy Markdown
Collaborator

Summary

  • Layered channel architecture with Akka.Streams session API — introduces IChannel abstraction, ChannelPipeline with Akka.Streams, ChannelInput/MessageSource types, and refactors ConsoleAdapterConsoleChannel and HeadlessAdapterHeadlessChannel
  • Multi-provider configuration system — replaces single-provider ProviderConfig with named Providers dictionary (credential containers) + Models section with Main/Fallback/Compaction roles. Config loaded from ~/.netclaw/config/netclaw.json + secrets.json overlay + NETCLAW_ env vars
  • Extract Netclaw.Configuration shared library — moves NetclawPaths, SessionConfig, ToolConfig, ISystemPromptProvider, SystemPromptAssembler out of Netclaw.Actors into a new project. Adds IChatClientProvider, ModelRole, SingleClientProvider, IProviderCatalog interfaces
  • LlmSessionActor now uses IChatClientProvider — constructor takes provider instead of raw IChatClient, with separate _compactionClient for memory extraction
  • Configuration reference docs at docs/spec/configuration.md

Test plan

  • All 110 existing tests pass (session, tool, compaction, system prompt tests)
  • 0 Slopwatch violations
  • Single-shot headless mode works against configured provider (~/.netclaw/config/netclaw.json)
  • Build succeeds across all projects in solution

Extract configuration types from Netclaw.Actors into a new
Netclaw.Configuration library. Separate LLM providers (credential
containers) from models (provider + model ID references) with named
roles (Main, Fallback, Compaction).

- Create Netclaw.Configuration project with shared config types:
  NetclawPaths, SessionConfig, ToolConfig, ISystemPromptProvider,
  IChatClientProvider, ModelRole, IProviderCatalog
- Add multi-provider config schema: Providers dict + Models with
  Main/Fallback/Compaction roles in netclaw.json
- Replace single ProviderConfig with ProviderEntry + ModelReference +
  ModelSelection POCOs for IConfiguration binding
- Update LlmSessionActor to accept IChatClientProvider instead of
  IChatClient, enabling separate compaction model
- Add configuration reference documentation at docs/spec/configuration.md
- Layered config: netclaw.json → secrets.json → NETCLAW_* env vars
@Aaronontheweb Aaronontheweb force-pushed the feature/channel-stream-api branch from b355508 to 867df8e Compare February 23, 2026 19:11
@Aaronontheweb Aaronontheweb merged commit 18876b8 into dev Feb 23, 2026
3 checks passed
@Aaronontheweb Aaronontheweb deleted the feature/channel-stream-api branch February 23, 2026 19:24
Aaronontheweb added a commit that referenced this pull request Feb 24, 2026
Update PRDs (001, 004, 009), SPEC-011, and IMPLEMENTATION_PLAN to reflect
the OpenClaw-pattern architecture: persistent daemon (Netclaw.Daemon) with
thin CLI/TUI clients (Netclaw.Cli) connecting via SignalR.

Key changes:
- Two binaries: daemon owns Akka/persistence/tools, CLI is lightweight
- TUI chat becomes pure thin client rendering SessionOutput over SignalR
- CLI commands categorized as offline vs daemon-required
- Daemon management commands: start/stop/status/install/uninstall
- systemd user service registration (no sudo)
- New implementation tasks 1.26-1.31 for the split
- Tasks 1.10-1.12 marked as done (PRs #14, #16, #17)
Aaronontheweb added a commit that referenced this pull request Feb 24, 2026
* Revise architecture to daemon + thin client split

Update PRDs (001, 004, 009), SPEC-011, and IMPLEMENTATION_PLAN to reflect
the OpenClaw-pattern architecture: persistent daemon (Netclaw.Daemon) with
thin CLI/TUI clients (Netclaw.Cli) connecting via SignalR.

Key changes:
- Two binaries: daemon owns Akka/persistence/tools, CLI is lightweight
- TUI chat becomes pure thin client rendering SessionOutput over SignalR
- CLI commands categorized as offline vs daemon-required
- Daemon management commands: start/stop/status/install/uninstall
- systemd user service registration (no sudo)
- New implementation tasks 1.26-1.31 for the split
- Tasks 1.10-1.12 marked as done (PRs #14, #16, #17)

* Split Netclaw.App into Netclaw.Daemon and Netclaw.Cli

Structural split following the daemon + thin client pattern:

- Netclaw.Daemon (netclawd): Web SDK, actor system, SignalR hub,
  config watcher, health endpoint
- Netclaw.Cli (netclaw): CLI routing (chat, -p, init, doctor,
  daemon stub, config stub), TUI, headless channel

Shared types moved to library projects:
- Config POCOs (ProviderEntry, ModelSelection, ModelReference) →
  Netclaw.Configuration
- SessionOutputDto → Netclaw.Actors.Protocol

CLI temporarily keeps full Akka stack in-process with transitional
copies of ChatClientFactory/NetclawChatClientProvider. Task 1.28
refactors to SignalR client and removes Akka dependencies.

* Wire SessionHub to SessionPipeline via SessionRegistry

Replace the stub SessionHub with a functional implementation that
creates sessions, accepts messages, and streams output back to
SignalR callers. SessionRegistry (singleton) owns session state and
uses IHubContext to push output from Akka.Streams callbacks without
requiring a hub instance.

* Add daemon management commands (start, stop, status, install, uninstall)

DaemonManager handles the full lifecycle: binary discovery, detached
process spawning with PID file tracking, graceful SIGTERM shutdown on
Linux/macOS, and systemd user service registration. Windows service
support tracked in #21.

* Fix review issues and update README for daemon architecture

Review fixes:
- CLI port conflict: use port 0 (random) for transitional in-process mode
- SessionHub: call base.OnDisconnectedAsync for framework cleanup
- SessionRegistry: log output delivery errors instead of swallowing,
  guard against duplicate CreateSession per connection, check OfferAsync
  result for queue failures
- DaemonManager: don't redirect stdio (prevents SIGPIPE / pipe deadlock),
  validate process name before SIGTERM to prevent PID recycling kills,
  check kill() return value, proper DateTimeOffset for uptime calc
- Eliminate duplicate NetclawPaths instances in both Program.cs files

README updated to reflect daemon + thin client architecture with CLI
reference documentation.

* Harden daemon session ownership and PID handling

Enforce connection-scoped SignalR sessions with typed IDs, preserve sessions for reconnect, and tighten daemon PID/process validation for safer lifecycle commands. Add targeted tests and daemon PID file ownership to keep status/stop behavior reliable.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant