ive harnessed the harness
klbr docs runtime-v2 HANDOFF.md
10 kB
Markdown
at main

Handoff: continue from the source, not from a blank page #

Read docs/runtime-v2/STATUS.md, HANDOFF.md, and the tests before expanding the scope. The archived v2 plans retain the product direction; they are not evidence of implemented behavior. The uploaded Lucid pack is retained as design/lucid-code-skill-pack-main.tar.gz; the original v2 plan, hook spec and behavior source trace are beside it. Read those contract/skill sources before changing the architecture.

This starter covers parts of plan slices 1, 2, 3 and 3a, plus a narrow local-effect/wait slice of 4 and host-side hook activation from 9. No numbered slice should be marked fully complete.

First task: establish the Rust baseline #

Use the user's actual toolchain/dev environment. Run:

python tools/check_runtime.py --rust --format --report /tmp/klbr-runtime-checks.json

Use --portable-linker when clang/wild are absent. It overrides the original repository configuration for this command only. Do not rewrite the existing flake just to make a temporary machine's linker happy. Do not use a Bash-only invocation in user-facing instructions; the helper launches subprocesses directly and works from Nushell.

Fix compilation, formatting, real integration failures and lockfile resolution before adding features. The producer could not run Cargo, so this is actual work, not ceremonial verification. Record exact Rust, Cargo, Python and linked SQLite versions. The SQLite guard is intentional; validate a fixed runtime rather than weakening the guard. If a dependency needs an update, make it explicit and regenerate Cargo.lock on this machine.

Rust test entrypoints:

  • tests/protocol.rs: shared envelopes, framing failures, IDs, role/output boundaries.
  • tests/store.rs: snapshot hash, source/session dedupe, owner lock, legacy DB refusal, local receipt identity, wait/input ordering, reopen without replay.
  • tests/session.rs: real Rust/Python execution, separate review, fail-closed guards, invalid activation, blocked worker deadlines, admission during blocked hooks, pinned in-flight revisions, independent stop, and terminal shutdown.

Run the workbench example only after these checks. It is a no-network demonstration, not an agent or an interactive client. The Python peer is a test double, and must not be promoted into a production Python orchestrator to sidestep a Rust integration problem.

Next coherent change: daemon-owned session and inbox coordinator #

Add a single-owner registry in the existing daemon. The integration should own one new runtime Store and one SessionRuntime for each active session. Preserve the current one-root agent across local and Discord conversations; a channel is routing provenance, not a new agent by default. Use a separate new runtime database filename and do not open the legacy memory DB through this constructor.

Durably accept authenticated input before acknowledging it. Pass a canonical source dedupe key, source kind, immutable conversation identity, author and receipt timestamps. Admission must not wait for a Python hook. Channels/notifications are wake signals, not the only data. Wire attention.plan only after admission. A failure retains pending work; the basic operator control path never requires a successful policy callback.

Do not call acknowledge_inputs merely because attention was planned or a cell ran. Add a transactional turn/attention-frame record linking the consumed input IDs, routing handles, context epoch and policy revision. Acknowledgement is a consequence of this accepted frame. The current API comment marks this boundary rather than pretending it is implemented.

Provide operator stop and activation/recovery endpoints independently of the model. Protect these endpoints. The library's shutdown is not by itself a complete daemon drain protocol; await accepted host tasks and finish their durable outcomes before exiting the service.

Acceptance: burst inputs during blocked work, cancel/replace a kernel, and still find each accepted input and its disposition. No remote sends in this stage.

Then wire the model loop, scratchpad and the existing client #

Adapt the existing provider boundary instead of copying the old memory/tool coupling. Persist complete provider blocks/tool-call IDs before execution. Use one model-visible Python tool. Ordinary assistant text goes to typed scratchpad records, not automatic speech. Partial stream text remains partial. Preserve the user's scratchpad diagnostics without misrepresenting that text as delivered to a conversation.

local.send already has a host-side durable publication contract. Teach the client to render that lane separately from scratchpad and cell output, using event sequence cursors. A reconnect replays completed durable records; transient token animation can remain lossy. Add protocol adapter tests rather than reexporting provider/storage types into klbr-ipc.

Replace tool-name string matches (wait_and_continue, local_send, restart controls, etc.) in the new loop with explicit outcomes/commands. Do not leave the old tool registry active under the new Python executor. Add model.plan, context.prepare and turn.next when those actual domains exist, with documented failure semantics and editable Python defaults.

Acceptance: scratchpad + cells + one explicit send yields one conversational message; a terminal wait ends code, resumes only from a new wake/model boundary, and consumes no idle inference loop. Persisted provider sequences remain valid after interruption.

Build complete revision editing around the existing activation primitive #

The next SDK work is behavior.draft/publish/activate/rollback and hooks.bind/test/trace, not a new loader. Existing code already snapshots sources and activates host-side candidates. Stage normal source files and tests in a writable draft, retain the base epoch, run trusted fake-effect validation, publish immutable content, then call the existing guarded switch. The agent should be able to edit ordinary hook/skill code without touching Rust.

Do not accept a candidate's own boolean claim that it passed trusted checks. Add environment and component fingerprints so a shared dependency change replaces every affected process role. Keep source-only compatible hook activation separate from workbench replacement.

Expand startup from “fail on corrupt active snapshot” to a persisted last-good recovery path that does not need user hooks to succeed. Expose failed candidate diagnostics and invocation trace references. Do not replay old events solely because a handler revision changed.

Acceptance: the agent edits a hook through the SDK, tests/activates it, keeps a live workbench object, and sees new behavior in the next cell. An in-flight cell remains pinned. A bad candidate or broken active revision remains repairable without model cooperation.

Discord, LCM, then durable jobs/children #

Bring the existing Discord/Twilight transport behind the new domain commands; preserve the social semantics recorded in the design's behavior companion. Add canonical conversations, immutable attention frames, per-effect destinations/reply anchors, and an outbox with honest pending/attempting/confirmed/failed/unknown states. Do not generalize the current local atomic publication into a claim of atomic remote send. Only consume reply state when actual receipt evidence permits it. Keep ambient silence and explicit ignore/reaction decisions.

For LCM, first replace discarded large output with artifact spooling. Then add immutable structured session items, chronological summary coverage, transactional context replacement, lexical retrieval and exact source reads. Maintain provider-valid tool groups. Preserve the difference between a scratchpad draft and a confirmed message across summaries. Compaction must not depend on reflection, embeddings, skill editing, or note-garden reconciliation. The current append-only event table is a useful substrate, not a completed context manager.

For jobs/RLM, add explicit identities, revision/workspace pinning, budgets and completion notifications. Never implement durability by pickling a coroutine or replaying arbitrary cells. Add durable observers only with an atomic acknowledgement/state/proposed-command commit and stable causation/action identities. The current prototype deliberately does not implement generic transforms/observers with vague dictionaries and no durability contract.

Move useful tree-sitter vocabulary into Python skills using maintained Python bindings. Preserve version-bound source/symbol ranges and checked patches rather than recreating each old JSON tool as a Python function. No tree-sitter capability was ported in this starter.

Review/failure work before unattended deployment #

Process groups/cgroups and tracked command ownership are needed before arbitrary subprocess work can be cleaned up reliably. Today only the direct Python child is killed. Add bounded artifact disk use and input/output backpressure, auth on operator APIs, global process and model budgets, current runtime health, hook backlog diagnostics and explicit cleanup policy.

Exercise actual kill/fault windows: SQLite commit-before-notify; local publish-before-reply; wait-before-wake; hook activation during an execution; corrupt active release; truncated control frames; failed artifact writes; a handler catching cancellation; and daemon shutdown with an accepted execution still completing. Verify backups with artifacts/releases before cutover. Keep the old production database and owner stopped, never two live senders.

What was deliberately not done here #

No old production paths were deleted, no key was used, no migration ran against user state, and no existing note was reinterpreted as truth. No Git remote or live beads tool was available in the supplied archive/environment. No commits were pushed or issue IDs invented. Use the repository's actual issue workflow when continuing; this file is an artifact handoff, not a replacement issue database. Source was written anew for this slice, not copied from Prime's implementation. Consult upstream licenses before later borrowing source.