Task document
How state travels between agents that can't read each other's sessions
No provider can read another's session. Klein Kit carries continuity across handoffs as a structured task document — kept current from native events and injected at each handoff.
interface TaskState {
goal: string;
status: "pending" | "in_progress" | "blocked" | "completed" | "failed";
plan: PlanStep[];
todos: TodoItem[];
decisions: string[];
openQuestions: string[];
filesTouched: FileChange[];
history: HandoffRecord[]; // per-agent history with resumable session ids
}
interface HandoffRecord {
provider: ProviderId;
nativeSessionId?: string; // resume any past leg of the work
role: string;
summary?: string;
startedAt: number;
endedAt?: number;
}Where it comes from
Every session maintains one automatically at session.taskState, folded from events:
turn.startedmovespending → in_progressplan.updated/todo.updatedreplace the plan/todosfile.changedupserts by path (a delete wins; a create survives a later modify)turn.failed/session.errormark itblocked
Workflows create one from the workflow goal and thread it through every step; each handoff event carries the current state.
Using it directly
import { createTaskState, applyEventToTaskState, renderTaskState } from "@klein-kit/core";
const state = createTaskState("Migrate the config loader to zod");
for await (const event of session) {
applyEventToTaskState(state, event);
}
// Deterministic markdown — inject into the next agent's prompt:
const doc = renderTaskState(state);renderTaskState produces sections for the task, status, work so far, plan, todos, decisions, files touched, and open questions — with [x] / [~] / [ ] status markers. It's deterministic, so it diffs cleanly and caches well in prompts.