---
title: "Rules & retrieval"
description: "The structured rule store, the rendered context, and task-conditioned retrieval"
icon: "book-marked"
---

Rules are the harness's output: permanent operating constraints the agent writes for itself, learned from its own failures. They live in a structured store, render into the system prompt, and — since v0.6 — carry a full lifecycle and relevance-based injection.

## The rule store

`rules.jsonl` is append-only; the latest record per rule id wins (so retiring or promoting a rule appends an updated record rather than rewriting history). Each rule carries:

| Field | Purpose |
| --- | --- |
| `id`, `created_at` | Identity (`r-` + 10 hex chars) and provenance timestamp. |
| `rule`, `rationale` | The constraint and why it exists — both sanitized on write. |
| `source_notice_id`, `metric` | Provenance: which notice motivated it, which metric it targets. |
| `status` | `candidate` → `active` \| `retired`. See [Rule validation](/harness/closed-loop/rule-validation). |
| `tags` | Retrieval hooks — auto-derived from the source notice (signatures, metric names, signal names, severity) plus any explicit tags. An **untagged rule is global**: always injected. |
| `trial` | Validation bookkeeping: baseline vs. observed breach rates, sessions watched, replay attempts, and the final verdict. |

Guard rails on `add`:

- **Dedup** — a rule whose normalized text matches a live rule returns the existing rule instead of creating a duplicate.
- **Cap** — at `max_active_rules` (default 50, counted over active + candidate) the add fails with a message telling the agent to retire something first. Compaction is agent-driven; nothing is silently evicted.
- **Sanitization** — rule text and rationale pass the trust boundary (`sanitize_text`) before they can ever reach a prompt.

## The rendered context

`harness_rules.md` is a **projection**, regenerated from the store on every change: the packaged template preamble (the self-healing contract and tool table), then the rules:

```markdown
## Learned Mitigations

<!-- ACTIVE RULES — managed by the harness; use the harness rule tools -->

- **r-9772c134b8**: Never call the payment tool twice without first verifying
  the transaction status identifier.
  - rationale: Repeated identical payment call flagged by the reliability eval.
    (added 2026-07-03T05:35:11+00:00, from notice n-20260703T053511-f2019e57)

### Provisional rules (under evaluation)

_The following candidate rules are in force but not yet validated. Treat
them as tentative: apply them, but prefer validated rules when they conflict._

- **r-23b0460306** (candidate): Verify the transaction status before retrying.
  - rationale: ... (added ...; trial: 2/5 sessions observed)
```

Candidates render **always** — a rule must be in force to be measurable — but under a heading that makes their unproven status unmistakable, and the standing protocol tells the agent to prefer validated rules on conflict.

## Task-conditioned retrieval

With more than a handful of rules, injecting all of them dilutes attention and lets a rule learned from one failure mode overfit onto unrelated tasks. With `rule_retrieval=true` (the default), the context renders:

1. **Every global (untagged) rule** — always, exempt from the budget.
2. **The top-`rules_context_topk`** (default 8) tagged rules ranked by lexical relevance to the current **query**: the pending notices' signatures and metric names, plus an optional caller-supplied task hint:

```python
system_prompt = harness.system_context(task_hint="charge a customer payment") + MY_PROMPT
```

3. A one-line note when rules were trimmed, pointing at `harness_rules_search` / `harness_rules_list` — the context stays small while every rule stays reachable.

The scorer is deliberately simple and dependency-free: casefolded word tokens, tag hits weighted double over rule/rationale text hits, normalized by query size, ties broken by recency. `breach:agent_reliability` tokenizes to `breach` + `agent_reliability`, so signatures, metric names, and task words all match naturally.

Behavior at the edges:

- **No signal** (no pending notices, no hint) → everything renders; retrieval never hides rules without a reason.
- **No overlap** → ranking degrades to recency under the same top-k.
- **Candidates** never consume top-k slots — retrieval can't starve a trial.
- `rule_retrieval=false` restores render-everything (the pre-v0.6 behavior).
- The on-disk `harness_rules.md` is always the *full* render; retrieval only shapes the composed prompt.

## Working with rules programmatically

```python
harness.rules.active()                      # validated rules
harness.rules.candidates()                  # rules under trial
harness.rules.search("payment breach")      # ranked (rule, score) pairs
harness.rules.retire("r-9772c134b8", reason="superseded by a broader rule")
harness.rules.effectiveness()               # per-rule notice counts before/after
```

The agent-facing equivalents are `harness_rules_list`, `harness_rules_search`, `harness_rule_retire`, `harness_rule_status`, and `harness_reflect` — see [the toolset](/harness/loop/agent-toolset).
