> ## 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.

# State schema

> Complete reference for the Noēsis state.json artifact.

The `state.json` artifact captures cognitive state snapshots during execution and at terminal completion. It provides a complete view of what was planned and what happened.

## Schema overview

```json theme={null}
{
  "version": "1.0",
  "state_schema_version": "1.0.0",
  "episode": { ... },
  "goal": { ... },
  "beliefs": [ ... ],
  "plan": { ... },
  "memory": { ... },
  "outcomes": { ... },
  "links": { ... }
}
```

## Root fields

<ResponseField name="version" type="string" required>
  Backwards-compatible identifier. Currently `"1.0"`.
</ResponseField>

<ResponseField name="state_schema_version" type="string" required>
  Semantic version for the schema contract. Currently `"1.0.0"`.
</ResponseField>

<ResponseField name="links" type="object">
  Relative artifact paths for this run (for example `events.jsonl`,
  `learn.jsonl`, `summary.json`, `manifest.json`). Keys vary by lifecycle state.
</ResponseField>

## Episode

Episode metadata and timestamps.

```json theme={null}
{
  "episode": {
    "id": "ep_2024_abc123_s0",
    "seed": 0,
    "tags": {
      "environment": "staging",
      "team": "platform"
    },
    "using": "baseline",
    "started_at": "2024-01-15T10:30:00Z"
  }
}
```

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

<ResponseField name="episode.seed" type="number">
  Seed used for reproducibility.
</ResponseField>

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

<ResponseField name="episode.using" type="string">
  Adapter label used for execution (optional).
</ResponseField>

<ResponseField name="episode.started_at" type="string" required>
  ISO 8601 start timestamp.
</ResponseField>

<ResponseField name="episode.intuition_mode" type="string">
  Intuition posture for the episode (advisory | interventive | hybrid). Runs created
  with older Noēsis versions may omit this field (default advisory).
</ResponseField>

## Artifact links

`links` points to run-local artifacts in the episode directory.

```json theme={null}
{
  "links": {
    "events": "events.jsonl",
    "learn": "learn.jsonl",
    "summary": "summary.json",
    "manifest": "manifest.json"
  }
}
```

<ResponseField name="links.events" type="string">
  Event timeline artifact path.
</ResponseField>

<ResponseField name="links.learn" type="string">
  Learning timeline artifact path.
</ResponseField>

<ResponseField name="links.summary" type="string">
  Final summary artifact path (terminal runs only).
</ResponseField>

<ResponseField name="links.manifest" type="string">
  Final manifest artifact path (terminal runs only).
</ResponseField>

<Info>
  Lifecycle constraint:

  * non-terminal runs (for example approval pauses) persist `links.events` and
    `links.learn`
  * terminal runs additionally persist `links.summary` and `links.manifest`
</Info>

## Goal

The task the agent is pursuing.

```json theme={null}
{
  "goal": {
    "task": "Draft release notes for v1.2.0",
    "type": "task"
  }
}
```

<ResponseField name="goal.task" type="string" required>
  The original task or goal.
</ResponseField>

## Beliefs

Normalized statements the system inferred during execution.

```json theme={null}
{
  "beliefs": [
    {
      "statement": "Version 1.2.0 includes 3 new features",
      "confidence": 0.9,
      "provenance": "changelog_analysis",
      "timestamp": "2024-01-15T10:30:02Z"
    },
    {
      "statement": "Breaking changes require migration guide",
      "confidence": 0.85,
      "provenance": "policy_hint"
    }
  ]
}
```

<ResponseField name="beliefs[].statement" type="string" required>
  The belief statement.
</ResponseField>

<ResponseField name="beliefs[].confidence" type="number" required>
  Confidence in the belief (0-1).
</ResponseField>

<ResponseField name="beliefs[].provenance" type="string" required>
  Source of the belief.
</ResponseField>

<ResponseField name="beliefs[].timestamp" type="string">
  When the belief was recorded.
</ResponseField>

## Plan

Ordered steps describing the execution plan.

```json theme={null}
{
  "plan": {
    "source": "planner.minimal",
    "updated_at": "2024-01-15T10:30:01Z",
    "rationale": "minimal planner",
    "steps": [
      {
        "id": "step_1",
        "kind": "detect",
        "description": "Read changelog entries",
        "status": "done",
        "rationale": "Need to gather raw changelog data",
        "inputs": {
          "file": "CHANGELOG.md"
        },
        "outputs": {
          "entries": 15
        }
      },
      {
        "id": "step_2",
        "kind": "analyze",
        "description": "Categorize changes",
        "status": "done"
      },
      {
        "id": "step_3",
        "kind": "act",
        "description": "Generate release notes",
        "status": "done"
      },
      {
        "id": "step_4",
        "kind": "verify",
        "description": "Validate format",
        "status": "done"
      }
    ]
  }
}
```

<ResponseField name="plan.steps" type="array" required>
  Ordered list of plan steps.
</ResponseField>

<ResponseField name="plan.source" type="string">
  Origin of the plan (for example, `"planner.minimal"` or `"planner.resume"`). When projected from events, this comes from the latest `plan` payload `source` value (with `agent_id` as fallback).
</ResponseField>

<ResponseField name="plan.updated_at" type="string">
  ISO 8601 timestamp of the last plan update. For event-projected plans, this is the timestamp of the latest `plan` event.
</ResponseField>

### Step fields

<ResponseField name="plan.steps[].id" type="string" required>
  Unique step identifier.
</ResponseField>

<ResponseField name="plan.steps[].kind" type="string" required>
  Step kind (controlled vocabulary):

  | Kind      | Purpose               |
  | --------- | --------------------- |
  | `detect`  | Gather information    |
  | `analyze` | Process or categorize |
  | `plan`    | Sub-planning          |
  | `act`     | Execute action        |
  | `verify`  | Check results         |
  | `review`  | Human review point    |
</ResponseField>

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

<ResponseField name="plan.steps[].status" type="string" required>
  Step status (controlled vocabulary):

  | Status    | Meaning                |
  | --------- | ---------------------- |
  | `pending` | Not yet started        |
  | `running` | Currently executing    |
  | `done`    | Completed successfully |
  | `skipped` | Intentionally skipped  |
  | `failed`  | Failed with error      |
  | `vetoed`  | Blocked by policy      |
</ResponseField>

<ResponseField name="plan.steps[].rationale" type="string">
  Explanation for the step.
</ResponseField>

<ResponseField name="plan.steps[].inputs" type="object">
  Inputs provided to the step.
</ResponseField>

<ResponseField name="plan.steps[].outputs" type="object">
  Outputs produced by the step.
</ResponseField>

### Plan reconstruction contract

The runtime can reconstruct `state.plan` from `events.jsonl`:

1. Locate the latest `plan` event.
2. Build steps from `payload.step_records` when present.
3. Fall back to parsing legacy `payload.steps` labels (`<kind>:<description>`) when `step_records` is absent.
4. Apply subsequent `act` events that include both `payload.step_id` and `payload.step_status`.
5. Keep existing step status when no `step_status` evidence exists.

This contract is implemented by `noesis.runtime.plan_projection.project_plan_state(...)`.

## Memory

Persistent facts and scratchpad captured during the run.

```json theme={null}
{
  "memory": {
    "facts": [
      {
        "key": "changelog_format",
        "value": "keep-a-changelog",
        "timestamp": "2024-01-15T10:30:02Z",
        "provenance": "detection"
      },
      {
        "key": "breaking_changes_count",
        "value": 3,
        "timestamp": "2024-01-15T10:30:03Z",
        "provenance": "analysis"
      }
    ],
    "scratchpad": "Found 3 breaking changes to highlight in the migration section"
  }
}
```

<ResponseField name="memory.facts" type="array">
  Normalized facts with timestamps and provenance.
</ResponseField>

<ResponseField name="memory.facts[].key" type="string" required>
  Fact identifier.
</ResponseField>

<ResponseField name="memory.facts[].value" type="any" required>
  Fact value (any JSON type).
</ResponseField>

<ResponseField name="memory.facts[].timestamp" type="string">
  When the fact was recorded.
</ResponseField>

<ResponseField name="memory.facts[].provenance" type="string">
  Source of the fact.
</ResponseField>

<ResponseField name="memory.scratchpad" type="string">
  Free-form notes captured during execution.
</ResponseField>

## Outcomes

Final status, action log, metrics, and artifacts.

```json theme={null}
{
  "outcomes": {
    "status": "ok",
    "actions": [
      {
        "id": "action_1",
        "tool": "changelog_reader",
        "input": "CHANGELOG.md",
        "output": {"entries": 15},
        "timestamp": "2024-01-15T10:30:01Z",
        "duration_ms": 150
      },
      {
        "id": "action_2",
        "tool": "release_notes_generator",
        "input": {"entries": 15, "format": "markdown"},
        "output": {"file": "release_notes.md"},
        "timestamp": "2024-01-15T10:30:03Z",
        "duration_ms": 2500
      }
    ],
    "metrics": {
      "task_score": 0.95,
      "steps_completed": 4,
      "steps_total": 4
    },
    "artifacts": [
      "release_notes.md"
    ],
    "error": null
  }
}
```

<ResponseField name="outcomes.status" type="string" required>
  Final outcome status (controlled vocabulary):

  | Status    | Meaning                |
  | --------- | ---------------------- |
  | `ok`      | Completed successfully |
  | `error`   | Failed with error      |
  | `vetoed`  | Blocked by policy      |
  | `aborted` | Manually stopped       |
  | `partial` | Partially completed    |
  | `pending` | Still running          |
</ResponseField>

<ResponseField name="outcomes.actions" type="array">
  Structured action records (`id`, `kind`, `tool`, `input_excerpt`, `result_status`,
  `step_id`, `provenance`, `result_artifacts`, plus `x-` extensions). The shape
  mirrors `act` event payloads, and runtime emission aligns each action
  `timestamp` to the corresponding `act` event timestamp.
</ResponseField>

<ResponseField name="outcomes.metrics" type="object">
  Outcome metrics (e.g., total duration).
</ResponseField>

## Traceability guarantees

* `episode.started_at` is aligned to the `start` event timestamp and remains
  stable across continuation.
* Whenever `state.json` is persisted, runtime emits
  `phase="runtime"`, `event_type="run.state_projection"` with projection
  evidence for outcomes and links.
* For terminal runs, projection `outcomes` and `links` mirror the final
  persisted `state.json` values.

## Complete example

```json theme={null}
{
  "version": "1.0",
  "state_schema_version": "1.0.0",
  "episode": {
    "id": "ep_2024_abc123_s0",
    "seed": 0,
    "tags": {"team": "platform"},
    "using": "baseline",
    "started_at": "2024-01-15T10:30:00Z"
  },
  "goal": {
    "task": "Draft release notes for v1.2.0",
    "type": "task"
  },
  "beliefs": [
    {
      "statement": "Version 1.2.0 includes 3 new features",
      "confidence": 0.9,
      "provenance": "changelog_analysis"
    }
  ],
  "plan": {
    "source": "direction",
    "updated_at": "2024-01-15T10:30:01Z",
    "steps": [
      {"id": "step_1", "kind": "detect", "description": "Read changelog", "status": "done"},
      {"id": "step_2", "kind": "act", "description": "Generate notes", "status": "done"}
    ]
  },
  "memory": {
    "facts": [
      {"key": "format", "value": "keep-a-changelog", "provenance": "detection"}
    ],
    "scratchpad": "3 breaking changes found"
  },
  "outcomes": {
    "status": "ok",
    "actions": [
      {"id": "action_1", "tool": "reader", "timestamp": "2024-01-15T10:30:01Z"}
    ],
    "metrics": {"task_score": 0.95},
    "artifacts": ["release_notes.md"]
  }
}
```

## Reading state

### Python

```python theme={null}
import noesis as ns

state = ns.state.read("ep_abc123")

print(f"Task: {state['goal']['task']}")
print(f"Status: {state['outcomes']['status']}")
print(f"Steps: {len(state['plan']['steps'])}")
```

### File access

```bash theme={null}
cat .noesis/episodes/ep_abc123/state.json | jq '.outcomes.status'
```

## Policy usage

Policies receive the state snapshot in their `advise` method:

```python theme={null}
class MyPolicy(ns.DirectedIntuition):
    def advise(self, state: dict):
        # Access goal
        task = state["goal"]["task"]
        
        # Access plan
        steps = state["plan"]["steps"]
        
        # Access memory
        facts = state["memory"]["facts"]
        
        # Access outcomes
        actions = state["outcomes"]["actions"]
        
        return None
```

<Warning>
  Policies should treat state as read-only. To modify execution, return hints, interventions, or vetoes through the policy API.
</Warning>

## Next steps

<CardGroup cols={2}>
  <Card title="Summary schema" icon="file" href="/reference/summary">
    Summary artifact reference.
  </Card>

  <Card title="Events schema" icon="list" href="/reference/events">
    Event timeline reference.
  </Card>
</CardGroup>
