Skip to main content
Concept · Explanation

Compound learning

Senkani mines your own sessions for patterns and surfaces four artifact types: filter rules, context docs, instruction patches, workflow playbooks. Patterns flow .recurring → .staged → .applied.

The lifecycle

Every session's tool calls, outputs, and retries are logged to the session DB. A daily sweep (lazy — runs at session start) looks at the recurring set and promotes any pattern meeting recurrence ≥ 3 AND confidence ≥ 0.7 (Laplace-smoothed) to .staged. You review staged proposals in the Sprint Review pane or via senkani learn review. Accepted proposals move to .applied; applied artifacts take effect on the next session.

Filter rules (H, H+1)

The post-session waste analyzer notices when output from command X gets repeatedly truncated to its first N lines or has a substring stripped. It proposes a filter rule (head(50), stripMatching("progress")) for future invocations. Regression-gated on real commands.output_preview samples — the proposed rule must not break outputs that previously passed through cleanly.

Context docs (H+2b)

Files read across ≥ 3 distinct sessions become priming documents at .senkani/context/<title>.md, injected into the next session's brief as a one-line "Learned:" section. The body is scanned by SecretDetector on every read and write.

Instruction patches (H+2c) — never auto-apply

Tool hints derived from per-session retry patterns. Example: if the agent consistently retries Read after getting an outline when it wanted full content, an instruction patch proposes tweaking the tool's description to clarify the full: true parameter. Never applied automatically from the daily sweep — Schneier constraint forces explicit senkani learn apply <id>. The rationale: instruction drift is a subtle prompt-injection surface; you want a human in the loop.

Workflow playbooks (H+2c)

Named multi-step recipes mined from ordered tool-call pairs within a 60-second window. Applied at .senkani/playbooks/learned/<title>.md — namespace-isolated from shipped skills so the two don't collide.

Prompt-side artifact gate (V.4 round 1)

Skills, hook prompts, MCP tool descriptions, and brief templates land in their own pre-merge gate — PromptArtifactRegressionGate — distinct from the H+1 RegressionGate that scores filter-rule savings. A candidate body is checked against an EvalCorpus of labeled .mustContain / .mustNotContain / .maxLength requirements. Score is (passing, total, cost); cost is the body's utf8 byte count. The gate accepts when candidate.passing ≥ baseline.passing — equal-passing-with-lower-cost is legal because ReflectiveLearningRun retains a Pareto frontier on (passing↑, cost↓) per artifact kind, persisted at .senkani/learn/pareto/<kind>.json. The Propose-step hook CompoundLearning.runReflectiveLearning is operator-triggered, not auto-fired in runPostSession — round 1 is the scaffold; an LLM-driven mutator and a pre-merge CLI surface arrive in V.4-bis.

Session continuity (W.4 round 1)

Long autonomous sessions hit a hard ceiling: the active context window. ContextSaturationGate is a pure decision (.ok / .warn / .block) that reads tokens_in + tokens_out from agent_trace_event and divides by a configurable budgetTokens (defaults: warn 65 %, block 80 %, 200 000-token active window — the Continuous Claude v4.7 pattern). When the gate blocks, PreCompactHandoffWriter lands a structured handoff card under ~/.senkani/handoffs/<sessionId>.json with openFiles, currentIntent, lastValidation (pulled from validation_results), nextActionHint, and the most-recent trace keys for the pane. Writes are atomic — temp file, fsync, rename — so a crash mid-write never leaves a half-card readable. PreCompactHandoffLoader.load(...) / loadLatest(...) reads the card on the next session start and returns nil for missing / corrupt / future-schema files. Round 1 lands the gate, the writer, and the loader; HookRouter PreCompact wiring + a status-bar saturation chip + senkani doctor --handoff are W.4-bis (operator decision pending — needs a review of which hook payload fields the writer should auto-fill).

Annotation evidence (V.6 round 1)

Operator-tagged verdicts on a skill or KB entity feed Analyze as read-only evidence. Each annotation row carries a target_kind (skill / kb-entity), an inclusive byte range, a verdict (works / fails / note), free-text notes, an authored_by handle, and a V.5 AuthorshipTag. Annotations are append-only — a new verdict supersedes by recency, never by mutation — and they survive an artifact rename via renameAnnotationTarget. AnnotationSignalGenerator.analyze rolls evidence up per (kind, target), classifies each as failing / working / mixed, and bumps compound_learning.annotation.observed + per-class counters during runPostSession. Round 1 stops at evidence — no rule mutation, no auto-staging. Operators' fails calls are ground truth, never silently inferred into a learned rule.

Enrichment via Gemma (H+2a)

Gemma 4 optionally enriches the rationale strings that accompany each proposal, via MLX. The enriched text lives in a dedicated enrichedRationale field — never enters FilterPipeline. This is deliberate: the enrichment improves the human review experience; it doesn't alter the runtime behavior.

Cadence

KB ↔ learning bridge

High-mention entities from the knowledge base boost compound-learning confidence; applied context docs seed KB entity stubs; rolling back a KB entity cascades to invalidate derived context docs. The two systems are not isolated — they're sources for each other.