# behave-core [← repo](../README.md) The shared observation envelope for BEHAVE. Defines the wire format that `behave-shell` and `behave-text` serialize all behavioral observations into. Every sensor in the BEHAVE ecosystem emits the same `Observation` structure — the domain-specific meaning lives in `primitive` and `value`; the envelope provides identity, provenance, time window, and schema versioning. ## What it provides | Symbol | Type | Description | |---|---|---| | `OBSERVATION_SCHEMA_VERSION` | `int` | Envelope schema version (currently `1`). Bumped when field shapes change; federation gossip receivers reject mismatched versions. | | `Observation` | Pydantic model | One behavioral observation: a single primitive measured over a time window. The core class is registry-agnostic — it does not validate `primitive` or `value` against any specific domain. Use the registry-aware subclasses in `behave-shell` or `behave-text` for full validation. | | `ObservationValue` | `Union[str, int, float, bool, list[str], list[int], list[float], dict]` | Type alias covering all valid value shapes. | | `Window` | Pydantic model | The measurement window: `start_ts` and `end_ts` in epoch seconds. Distinct from `Observation.ts` (the emission time) — a sensor may compute an observation over a past window and emit it later. | ## `Observation` fields | Field | Type | Required | Description | |---|---|---|---| | `primitive` | `str` | ✓ | Fully-qualified primitive path, e.g. `motor.keystroke_cadence` | | `value` | `ObservationValue` | ✓ | The measured value; shape validated by the domain registry | | `confidence` | `float [0,1]` | ✓ | Sensor's confidence in this measurement (not in any attribution verdict) | | `window` | `Window` | ✓ | Measurement time window | | `source` | `str` | ✓ | Canonical sensor identifier, e.g. `behave/sniffer/timing.py` | | `evidence_ref` | `str \| None` | — | Pointer to underlying raw evidence (session tape, pcap). **Never** the evidence itself — see PII note below. | | `identity_ref` | `str \| None` | — | AttackerIdentity UUID if the observation is pre-attributed | | `ts` | `float` | auto | Emission timestamp, epoch seconds | | `id` | `str` | auto | UUID hex for deduplication | | `v` | `int` | auto | Envelope schema version (= `OBSERVATION_SCHEMA_VERSION`) | ## PII discipline (non-negotiable) BEHAVE observations carry **categorical labels, timing aggregates, and hashes only**. They must never carry: - Raw keystroke content or command arguments - Passwords, tokens, session keys, or any authentication material - File contents or payload bytes - Raw message text (especially in `behave-text`) `evidence_ref` is a **pointer** to underlying evidence held elsewhere. Never the evidence itself. ## Install ```bash pip install -e . # or, as a dependency of behave-shell / behave-text: pip install -e ../core/ ``` ## Quickstart ```python from behave_core.spec import Observation, Window, OBSERVATION_SCHEMA_VERSION obs = Observation( primitive="motor.keystroke_cadence", value="bursty", confidence=0.82, window=Window(start_ts=1714000000.0, end_ts=1714003600.0), source="behave/shell-sensor/timing.py", ) print(obs.model_dump_json()) ``` ## Tests ```bash pytest tests/ ``` ## License Code: [GPL-3.0-or-later](../LICENSE)