Team learning and context packs
Harn can turn repeated team friction into reviewable context packs or promoted workflows. The loop is:
- A workflow or host shim records a structured friction event.
- Repeated events become evidence for a candidate context pack suggestion.
- A human reviews the suggested manifest, privacy notes, and estimated savings.
- Future runs load deterministic context first and ask fewer repeated questions.
This is different from generic memory. A context pack is structured, reviewable, capability-scoped, and measurable. It points at explicit queries, docs, tools, secrets, refresh policy, output slots, and fallback instructions instead of storing raw conversation history.
For repeated action traces that should become deterministic Harn code, use the workflow crystallization loop in Workflow crystallization.
Friction events
Use friction_record(payload, options?) to record repeated pain from Harn workflows
or host integrations. With no configured recorder, the event is stored in the
process-local friction buffer and the workflow keeps running. Set enabled: false
for a deliberate no-op, or pass log_path / HARN_FRICTION_LOG to append JSONL.
friction_record({
kind: "repeated_query",
source: "incident-triage",
actor: "sre",
run_id: "run_checkout_184",
tool: "splunk",
provider: "splunk",
redacted_summary: "Checkout incidents repeatedly need the same error search",
estimated_time_ms: 300000,
estimated_cost_usd: 0.12,
recurrence_hints: ["checkout incident queries"],
trace_id: "trace_01H...",
metadata: {
query: "index=checkout service=api error",
capability: "splunk.search",
secret_ref: "SPLUNK_READ_TOKEN",
output_slot: "splunk_errors",
},
})
Supported event kinds are repeated_query, repeated_clarification, approval_stall,
missing_context, manual_handoff, tool_gap, failed_assumption,
expensive_model_used_for_deterministic_step, and human_hypothesis.
Events intentionally keep redacted_summary as the user-facing text field. Raw
prompts, raw content, and secret-looking metadata are dropped or redacted by the
normalizer.
Context pack manifests
context_pack_manifest(payload) validates a manifest shape. context_pack_manifest_parse(src) accepts TOML or JSON.
version = 1
id = "checkout_incident_context"
name = "Checkout incident context"
description = "Gather deterministic incident triage context before an agent starts."
owner = "sre"
fallback_instructions = "Ask one scoped question if the deterministic context is insufficient."
capabilities = ["splunk.search", "honeycomb.board.read"]
[[triggers]]
kind = "repeated_query"
source = "incident-triage"
match_hint = "checkout incident queries"
[[inputs]]
name = "incident_id"
required = true
[[included_queries]]
id = "splunk_errors"
provider = "splunk"
query = "index=checkout service=api error"
output_slot = "splunk_errors"
[[included_docs]]
id = "runbook"
title = "Checkout incident runbook"
url = "https://notion.example/runbooks/checkout"
[[included_tools]]
name = "honeycomb_board"
capability = "honeycomb.board.read"
purpose = "Open the checkout latency board."
deterministic = true
[refresh_policy]
mode = "on_demand"
stale_after = "24h"
[[secrets]]
name = "SPLUNK_READ_TOKEN"
capability = "splunk.search"
required = true
[[output_slots]]
name = "splunk_errors"
artifact_kind = "context"
Secrets are references to host-managed capabilities, not raw token values.
Suggestions and evals
context_pack_suggestions(events?, options?) groups repeated friction and emits
candidate suggestion artifacts with evidence, example summaries, estimated savings,
risk/privacy notes, and a draft manifest. friction_eval_fixture(fixture) is the
stdlib smoke path for fixture-driven checks.
Eval packs can also run repeated-friction fixtures:
version = 1
id = "team-learning"
[[fixtures]]
id = "incident-friction"
kind = "friction-events"
path = "fixtures/incident-friction.json"
[[cases]]
id = "incident-context-pack"
friction_events = "incident-friction"
rubrics = ["context-pack"]
[[rubrics]]
id = "context-pack"
kind = "friction"
[[rubrics.assertions]]
kind = "context-pack-suggestion"
contains = "incident"
expected = {
min_suggestions = 1,
recommended_artifact = "context_pack",
required_capability = "splunk.search",
}
The fixture should contain either a JSON array of friction events or { "events": [...] }.
Local evaluation stays deterministic and does not call an LLM judge.