> ## Documentation Index
> Fetch the complete documentation index at: https://noesis-32c1d602-cursor-technical-documentation-improvements.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Events schema

> Complete reference for Noēsis event types and their payloads.

Events are stored in `events.jsonl` as newline-delimited JSON. Each event represents a phase transition in the cognitive loop.

Current event schema version: `1.3.0` ([JSON schema](/schema/event/1.3.0.json)).

## Integrity contract (`events.jsonl`)

`events.jsonl` is the canonical append-only trace for an episode. Noēsis treats corruption as a hard integrity failure.

* Reads fail closed: malformed records are not skipped.
* `iter_events()` / `read_events()` raise `EventLogIntegrityError` when a line has invalid UTF-8, invalid JSON, or a non-object JSON value.
* Appends are guarded: `write_event()` validates the existing log before writing and rejects append attempts if any existing record is corrupt (including corruption in the middle of the file).

Typical deterministic failures:

* A truncated final line.
* Invalid UTF-8 bytes in any record.
* A malformed JSON record even when later lines are valid.

## Event structure

Every event follows this base structure:

```json theme={null}
{
  "id": "evt_abc123",
  "phase": "plan",
  "agent_id": "meta_planner",
  "payload": { ... },
  "evidence_ids": ["event:observe:1"],
  "metrics": {
    "started_at": "2024-01-15T10:30:00.500Z",
    "completed_at": "2024-01-15T10:30:00.512Z",
    "duration_ms": 12.7
  },
  "caused_by": "evt_xyz789"
}
```

<ResponseField name="id" type="string" required>
  Unique event identifier.
</ResponseField>

<ResponseField name="phase" type="string" required>
  Event phase. Canonical values: `start`, `observe`, `interpret`, `plan`, `direction`, `governance`, `action_candidate`, `act`, `reflect`, `learn`, `runtime`, `terminate`, `insight`, `memory`, `intuition`, `reason`, `error`. Extensions may emit additional phases.
</ResponseField>

<ResponseField name="event_type" type="string">
  Subtype for `phase="runtime"` events (for example `run.interrupt`, `run.checkpoint`, `run.resume`, `run.state_projection`).
</ResponseField>

<ResponseField name="agent_id" type="string">
  Identifier of the component that emitted the event.
</ResponseField>

<ResponseField name="payload" type="object" required>
  Phase-specific payload data.
</ResponseField>

<ResponseField name="evidence_ids" type="array">
  Optional evidence references carried forward into the event record.
</ResponseField>

<ResponseField name="metrics" type="object">
  Timing metrics for the event.

  <Expandable title="Metrics properties">
    <ResponseField name="started_at" type="string">
      ISO 8601 timestamp when the phase started.
    </ResponseField>

    <ResponseField name="completed_at" type="string">
      ISO 8601 timestamp when the phase completed.
    </ResponseField>

    <ResponseField name="duration_ms" type="number">
      Duration in milliseconds.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="caused_by" type="string">
  ID of the event that caused this one (for lineage tracking).
</ResponseField>

## Event phases

Additional phases you may see:

* **start**: episode initialization metadata.
* **intuition**: advisory/intuition policy events.
* **memory**: reads/writes performed by the memory port.
* **insight**: computed insight metrics (alias of events --phase insight).
* **reason**: reasoning traces from the planner.
* **runtime**: lifecycle and projection evidence (`run.*` event types).
* **error**: fatal errors.

### observe

Captures the raw task and context at episode start.

```json theme={null}
{
  "phase": "observe",
  "payload": {
    "task": "Draft release notes for v1.2.0",
    "tags": {
      "priority": "high",
      "team": "platform"
    },
    "timestamp": "2024-01-15T10:30:00Z",
    "context": {
      "changelog_path": "CHANGELOG.md"
    }
  }
}
```

<ResponseField name="payload.task" type="string" required>
  The task or goal for the episode.
</ResponseField>

<ResponseField name="payload.tags" type="object">
  User-provided metadata tags.
</ResponseField>

<ResponseField name="payload.timestamp" type="string" required>
  ISO 8601 timestamp of observation.
</ResponseField>

<ResponseField name="payload.context" type="object">
  Additional context provided with the task.
</ResponseField>

### intuition

Captures advisory/intervention/veto signals before interpretation and planning.

```json theme={null}
{
  "phase": "intuition",
  "payload": {
    "schema_version": "1.1.0",
    "kind": "hint",
    "advice": "Consider chunking the task input before execution.",
    "confidence": 0.6,
    "policy_id": "intuition.heuristic",
    "policy_version": "1.0.0",
    "policy_kind": "rules",
    "rationale": "task_length",
    "evidence_ids": ["event:observe:1"],
    "risk_level": "moderate",
    "salience_signals": ["task_complexity"],
    "strategy_hints": ["retrieve_more", "narrow_scope"],
    "scrutiny_level": "elevated",
    "target": "input",
    "scope": "episode",
    "blocking": false
  },
  "evidence_ids": ["event:observe:1"],
  "caused_by": "observe_event_id"
}
```

<ResponseField name="payload.kind" type="string" required>
  Directive kind: `hint`, `intervention`, `veto`.
</ResponseField>

<ResponseField name="payload.risk_level" type="string">
  Optional risk posture: `low`, `moderate`, `high`, `critical`.
</ResponseField>

<ResponseField name="payload.salience_signals" type="array">
  Optional salience cues: `task_complexity`, `normalization_gap`, `policy_hint`, `safety_boundary`.
</ResponseField>

<ResponseField name="payload.strategy_hints" type="array">
  Optional planning hints: `conservative`, `verify_first`, `retrieve_more`, `narrow_scope`.
</ResponseField>

<ResponseField name="payload.tool_constraints" type="array">
  Optional tool constraints: `no_side_effects`, `read_only`, `require_double_check`.
</ResponseField>

<ResponseField name="payload.scrutiny_level" type="string">
  Optional review level: `normal`, `elevated`, `strict`.
</ResponseField>

### interpret

Summarizes signals extracted from the observed input.

```json theme={null}
{
  "phase": "interpret",
  "payload": {
    "signals": [
      {
        "type": "risk",
        "level": "medium",
        "description": "Production deployment mentioned"
      },
      {
        "type": "constraint",
        "description": "Requires changelog file"
      }
    ],
    "intent": "documentation_generation",
    "policy_id": "SafetyPolicy@1.0"
  }
}
```

<ResponseField name="payload.signals" type="array" required>
  List of detected signals.

  <Expandable title="Signal properties">
    <ResponseField name="type" type="string" required>
      Signal type: `risk`, `constraint`, `opportunity`, `warning`.
    </ResponseField>

    <ResponseField name="level" type="string">
      Signal level: `low`, `medium`, `high`, `critical`.
    </ResponseField>

    <ResponseField name="description" type="string" required>
      Human-readable signal description.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="payload.intent" type="string">
  Classified intent of the task.
</ResponseField>

<ResponseField name="payload.policy_id" type="string">
  Policy that performed interpretation.
</ResponseField>

### plan

Records the selected action steps and projection metadata used to rebuild `state.json`.

```json theme={null}
{
  "phase": "plan",
  "payload": {
    "steps": [
      "detect:Collect context",
      "act:Execute task"
    ],
    "step_records": [
      {
        "id": "step-1",
        "kind": "detect",
        "description": "Collect context",
        "status": "pending"
      },
      {
        "id": "step-2",
        "kind": "act",
        "description": "Execute task",
        "status": "pending"
      }
    ],
    "source": "planner.minimal",
    "rationale": "minimal planner"
  }
}
```

<ResponseField name="payload.steps" type="array" required>
  Compatibility labels in `<kind>:<description>` format. Legacy consumers may rely on this field.
</ResponseField>

<ResponseField name="payload.step_records" type="array">
  Structured plan records used for deterministic plan-state projection.

  <Expandable title="Step record properties">
    <ResponseField name="id" type="string" required>
      Unique step identifier.
    </ResponseField>

    <ResponseField name="kind" type="string" required>
      Step kind: `detect`, `analyze`, `plan`, `act`, `verify`, `review`.
    </ResponseField>

    <ResponseField name="description" type="string" required>
      Human-readable step description.
    </ResponseField>

    <ResponseField name="status" type="string" required>
      Step status: `pending`, `running`, `done`, `skipped`, `failed`, `vetoed`.
    </ResponseField>

    <ResponseField name="depends_on" type="array">
      Optional list of predecessor step IDs.
    </ResponseField>

    <ResponseField name="inputs" type="object">
      Optional structured inputs for the step.
    </ResponseField>

    <ResponseField name="outputs" type="object">
      Optional structured outputs for the step.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="payload.source" type="string">
  Planner source identifier (for example, `planner.minimal`). Runtime-emitted plan events always include this.
</ResponseField>

<ResponseField name="payload.rationale" type="string">
  Optional planner rationale.
</ResponseField>

### direction

Records policy directives (meta mode only).

```json theme={null}
{
  "phase": "direction",
  "payload": {
    "schema_version": "1.2.0",
    "directive_id": "dir_abc123",
    "legacy_directive_id": "11111111-1111-1111-1111-111111111111",
    "steps": ["meta:start", "intuition:risk-review"],
    "status": "applied",
    "reason": "heuristic-adjustment",
    "diff": [
      {
        "key": "plan.steps[0].description",
        "before": "Collect relevant context",
        "after": "Collect relevant context with risk review"
      }
    ],
    "applied": true,
    "policy_id": "planner.meta",
    "policy_version": "1.0.0",
    "policy_kind": "rules",
    "intuition_event_id": "evt_intuition",
    "risk_level": "high",
    "salience_signals": ["policy_hint"],
    "strategy_hints": ["verify_first"],
    "tool_constraints": ["read_only"],
    "scrutiny_level": "strict",
    "evidence_ids": ["event:observe:1"]
  },
  "evidence_ids": ["event:observe:1"],
  "caused_by": "plan_event_id"
}
```

<ResponseField name="payload.schema_version" type="string" required>
  Direction schema version (`1.2.0` at time of writing).
</ResponseField>

<ResponseField name="payload.directive_id" type="string" required>
  Stable directive identifier derived from content.
</ResponseField>

<ResponseField name="payload.legacy_directive_id" type="string">
  Legacy UUID retained for compatibility.
</ResponseField>

<ResponseField name="payload.status" type="string" required>
  Directive status: `applied`, `blocked`, `skipped`.
</ResponseField>

<ResponseField name="payload.diff" type="array">
  Structured mutations with `key`, `before`, `after`.
</ResponseField>

<ResponseField name="payload.reason" type="string" required>
  Why the directive status was produced.
</ResponseField>

<ResponseField name="payload.policy_id" type="string" required>
  Policy that issued the directive (typically `planner.meta`).
</ResponseField>

<ResponseField name="payload.policy_version" type="string" required>
  Policy version for compatibility and replay diagnostics.
</ResponseField>

<ResponseField name="payload.policy_kind" type="string" required>
  Policy kind: `llm`, `rules`, `hybrid`.
</ResponseField>

<ResponseField name="payload.intuition_event_id" type="string">
  When present, links this directive back to the originating intuition event.
</ResponseField>

<ResponseField name="payload.risk_level" type="string">
  Optional steering carry-over: `low`, `moderate`, `high`, `critical`.
</ResponseField>

<ResponseField name="payload.scrutiny_level" type="string">
  Optional steering carry-over: `normal`, `elevated`, `strict`.
</ResponseField>

<ResponseField name="evidence_ids" type="array">
  Evidence propagated from intuition (`payload.evidence_ids` mirrors this when set).
</ResponseField>

### governance

Records governance decisions (meta mode only).

```json theme={null}
{
  "phase": "governance",
  "payload": {
    "governance_id": "gov_def456",
    "decision_id": "dec_789",
    "decision": "allow",
    "rule_id": "rules.allow.default",
    "score": 0.95,
    "policy_id": "governance.rules",
    "policy_version": "1.0.0",
    "policy_kind": "rules",
    "details": {
      "checked_rules": ["rule1", "rule2"],
      "matched_rule": "rule1"
    }
  }
}
```

<ResponseField name="payload.governance_id" type="string" required>
  Unique governance event identifier.
</ResponseField>

<ResponseField name="payload.decision" type="string" required>
  Governance decision: `allow`, `audit`, `veto`.
</ResponseField>

<ResponseField name="payload.rule_id" type="string">
  Rule that determined the decision.
</ResponseField>

<ResponseField name="payload.score" type="number">
  Confidence score for the decision (0-1).
</ResponseField>

<ResponseField name="payload.policy_id" type="string" required>
  Governance policy identifier.
</ResponseField>

<ResponseField name="payload.details" type="object">
  Additional governance details.
</ResponseField>

### act

Logs tool or adapter invocations.

The runtime emits an action projection that is intentionally close to the persisted
`state.json` action record so action outcomes are reconstructible from
`events.jsonl`.

```json theme={null}
{
  "phase": "act",
  "payload": {
    "action_id": "act-2",
    "kind": "adapter",
    "tool": "adapter:core.minimal",
    "input_excerpt": "Execute goal: Draft release notes",
    "outcome": "ok",
    "result_status": "ok",
    "step_id": "step-2",
    "step_status": "done"
  }
}
```

<ResponseField name="payload.action_id" type="string">
  Action record identifier (for example `act-1`).
</ResponseField>

<ResponseField name="payload.kind" type="string">
  Action kind (for example `tool`).
</ResponseField>

<ResponseField name="payload.tool" type="string">
  Tool that was invoked.
</ResponseField>

<ResponseField name="payload.input_excerpt" type="string" required>
  Truncated input for logging.
</ResponseField>

<ResponseField name="payload.outcome" type="string" required>
  Compatibility status field for existing consumers.
</ResponseField>

<ResponseField name="payload.result_status" type="string">
  Canonical action status mirrored from state (`ok`, `error`, `vetoed`, etc.).
</ResponseField>

<ResponseField name="payload.outcome" type="string" required>
  Action outcome value.
</ResponseField>

<ResponseField name="payload.result_status" type="string">
  Canonical action status string from the action record (for example, `ok`).
</ResponseField>

<ResponseField name="payload.step_id" type="string">
  Plan step ID associated with this action.
</ResponseField>

<ResponseField name="payload.step_status" type="string">
  Resulting status for `payload.step_id`. This field is used to project final step status from `act` evidence.
</ResponseField>

<ResponseField name="payload.x-*" type="any">
  Extension keys from the action record. Only `x-` prefixed extension keys are emitted.
</ResponseField>

<Info>
  `outcome` and `result_status` currently carry the same status value. `outcome`
  is retained for compatibility with older consumers.
</Info>

<Info>
  For runtime-emitted actions, `state.json` action timestamps are aligned to the
  event completion time before persistence, so
  `state.outcomes.actions[n].timestamp == act_event.timestamp`.
</Info>

### reflect

Evaluates outcomes against expectations.

```json theme={null}
{
  "phase": "reflect",
  "payload": {
    "success": true,
    "reason": "All planned steps completed successfully",
    "expected_outcomes": ["data_processed", "report_generated"],
    "actual_outcomes": ["data_processed", "report_generated"],
    "issues": [],
    "metrics": {
      "task_score": 0.95,
      "steps_completed": 3,
      "steps_total": 3
    }
  }
}
```

<ResponseField name="payload.success" type="boolean" required>
  Whether the episode succeeded.
</ResponseField>

<ResponseField name="payload.reason" type="string" required>
  Human-readable explanation of the outcome.
</ResponseField>

<ResponseField name="payload.expected_outcomes" type="array">
  List of expected outcomes.
</ResponseField>

<ResponseField name="payload.actual_outcomes" type="array">
  List of actual outcomes.
</ResponseField>

<ResponseField name="payload.issues" type="array">
  List of issues encountered.
</ResponseField>

<ResponseField name="payload.metrics" type="object">
  Evaluation metrics.
</ResponseField>

### learn

Captures learning signals for future episodes. The minimal validator expects the following keys; runners may add extra detail.

```json theme={null}
{
  "phase": "learn",
  "payload": {
    "policy_id": "policy:core.meta",
    "basis": ["rules.veto.danger"],
    "proposal": [],
    "applied": false,
    "scope": "episode"
  }
}
```

<ResponseField name="payload.policy_id" type="string" required>
  Policy that produced the learning signal.
</ResponseField>

<ResponseField name="payload.basis" type="array" required>
  Reasons or evidence that drove the learning update.
</ResponseField>

<ResponseField name="payload.proposal" type="array" required>
  List of proposed updates (may be empty).
</ResponseField>

<ResponseField name="payload.applied" type="boolean" required>
  Whether the proposed updates were applied.
</ResponseField>

<ResponseField name="payload.scope" type="string" required>
  Update scope: `session`, `episode`, `policy`, `global`.
</ResponseField>

### runtime (`run.*`)

Runtime events share `phase="runtime"` and use `event_type` as the stable subtype.
The current lifecycle family includes `run.interrupt`, `run.checkpoint`,
`run.resume`, and `run.state_projection`.

`run.state_projection` is emitted whenever state is persisted so `state.json`
outcome/link fields have explicit event evidence.

```json theme={null}
{
  "phase": "runtime",
  "event_type": "run.state_projection",
  "payload": {
    "kind": "run.state_projection",
    "status": "interrupted",
    "outcomes": {
      "status": "interrupted",
      "summary": "Awaiting approval",
      "metrics": {}
    },
    "links": {
      "events": "events.jsonl",
      "learn": "learn.jsonl"
    }
  },
  "caused_by": "evt_prev123"
}
```

<ResponseField name="payload.kind" type="string" required>
  Always `run.state_projection` for projection evidence records.
</ResponseField>

<ResponseField name="payload.status" type="string" required>
  Mirrors `payload.outcomes.status` for compatibility with existing consumers.
</ResponseField>

<ResponseField name="payload.outcomes" type="object" required>
  Trace-backed projection of persisted state outcome fields: `status`, `summary`,
  and `metrics`.
</ResponseField>

<ResponseField name="payload.links" type="object" required>
  Trace-backed projection of persisted `state.json.links`.

  * Non-terminal runs: `events`, `learn`
  * Terminal runs: `events`, `learn`, `summary`, `manifest`
</ResponseField>

<ResponseField name="caused_by" type="string">
  For runtime lifecycle/projection events, points to the latest prior event in the
  trace when available.
</ResponseField>

### terminate

Marks the end of an episode.

```json theme={null}
{
  "phase": "terminate",
  "payload": {
    "status": "completed",
    "episode_id": "ep_2024_abc123_s0",
    "duration_ms": 5000
  }
}
```

<ResponseField name="payload.status" type="string" required>
  Final status: `completed`, `errored`, `vetoed`, `aborted`.
</ResponseField>

<ResponseField name="payload.episode_id" type="string" required>
  Episode identifier.
</ResponseField>

<ResponseField name="payload.duration_ms" type="number" required>
  Total episode duration in milliseconds.
</ResponseField>

## Phase order (partial)

Current phases: `start`, `observe`, `interpret`, `plan`, `direction`, `governance`, `action_candidate`, `act`, `reflect`, `learn`, `runtime`, `terminate`, `insight`, `memory`, `intuition`, `reason`, `error`.

* Required: `start` kicks off every episode; `terminate` marks completion.
* Typical loop: `observe` → `interpret` → `plan` → (`direction`/`governance` in meta mode) → `act` → `reflect` → (`learn` optionally).
* Optional tail: `insight` and `memory` may emit *after* `terminate` for scoring/persistence.
* Partial order: phases follow the sequence above when present, but not every phase appears in every run.

## Reading events

### CLI

```bash theme={null}
# All events
noesis events ep_abc123

# Filter by phase
noesis events ep_abc123 --phase act

# As JSON
noesis events ep_abc123 -j
```

### Python

```python theme={null}
import noesis as ns
from noesis.trace.events import EventLogIntegrityError

try:
    events = list(ns.events.read("ep_abc123"))
except EventLogIntegrityError as exc:
    corruption = exc.corruption
    print(f"Corrupted trace at line {corruption.line_number}: {corruption.reason}")
    raise

# Filter
act_events = [e for e in events if e["phase"] == "act"]

# Reconstruct lineage
def get_chain(events, event_id):
    chain = []
    current = next((e for e in events if e["id"] == event_id), None)
    while current:
        chain.append(current)
        caused_by = current.get("caused_by")
        current = next((e for e in events if e["id"] == caused_by), None)
    return chain
```

### Troubleshooting: verify plan derivability

Use the runtime projector to confirm `state.json.plan` is derivable from `events.jsonl`.

```python theme={null}
import noesis as ns
from noesis.runtime.plan_projection import project_plan_state

episode_id = "ep_01JH6Z2V9Q2K6Y6N0QZ7K2QW8C"
events = list(ns.events.read(episode_id))
projected = project_plan_state(events)
state = ns.state.read(episode_id)

assert projected is not None
assert projected.to_dict() == state["plan"]
```

If this assertion fails, inspect:

* the latest `plan` payload for `step_records` and `source`
* `act` payload entries for both `step_id` and `step_status`

If this exception is raised, treat the episode trace as untrusted until the underlying `events.jsonl` is repaired or replaced.

## Next steps

<CardGroup cols={2}>
  <Card title="State schema" icon="database" href="/reference/state">
    State artifact reference.
  </Card>

  <Card title="Cognitive loop" icon="arrows-rotate" href="/explanation/cognitive-loop">
    Understanding the phases.
  </Card>
</CardGroup>
