---
schema_id: session
schema_version: 2
applies_to: aiwiki/sessions/**/*.md
filename_pattern: "{date}-{session_id_short}.md"
hard_cap_lines: 400
soft_target_lines: [40, 200]
required_frontmatter:
  schema_id: { type: string, equals: session }
  schema_version: { type: integer }
  status: { type: enum, values: [active, done, abandoned] }
  date_start: { type: date }
  date_end: { type: date, optional: true }
  focus: { type: string }
  session_id: { type: string, optional: true }
  last_commit: { type: string, optional: true }
required_sections: []
optional_sections:
  - "## Checkpoints"
  - "## Files touched"
  - "## Decisions made"
  - "## Gotchas surfaced"
  - "## Open questions"
  - "## Next steps"
section_order: strict
citation_rule: required-in-files-touched-when-present
maintained_by: lazy-on-first-event
---

# Schema: session (per-session handoff)

## Purpose

A session file is the **handoff artifact** for one Claude session — what events fired during the session (PreCompact, /dream, /wrap) and what knowledge the session produced (files touched, decisions, gotchas, open questions, next steps). The page answers two questions for a future session:

1. **What is the immediate recovery state?** — read `## Checkpoints` for in-session events the post-compact agent (or next session) needs to act on.
2. **What happened and where do I pick up?** — read the index-of-links sections (`## Files touched`, `## Decisions made`, etc.).

**Two patterns mixed in one file by design:**

- `## Checkpoints` is **event-log style** (append-only, chronological). Pre-compact and other hook-driven events write here. Each entry is timestamped and may include a recovery directive that the next agent should act on.
- The other sections are **index of links** (curated, written by `/wrap` or `harden`). No prose paragraphs, no narrative — just links to ADRs, gotchas, raw notes. Future sessions follow the links to the actual artifacts.

## How it's maintained

**Lazy creation.** Session files are NOT created at SessionStart (that would produce empty noise for trivial 30-second sessions). Instead, the first writer creates the file:

| Writer | Triggers create? | Section written |
|---|---|---|
| `hooks/scripts/pre-compact.sh` | yes | `## Checkpoints` (appends event with recovery directive) |
| `/wrap` command | yes | `## Files touched`, `## Decisions made`, `## Gotchas surfaced`, `## Open questions`, `## Next steps` (filled by agent, user confirms) |
| `support-dream` skill | yes | `## Checkpoints` (appends dream-fired event with `dream_id`) |
| `harden` skill (Phase 5) | yes | All sections (codify-time session capture, similar to /wrap) |

`SessionStart` does NOT create the file — it READS the latest existing session file and surfaces a one-line summary to the agent, plus any unconsumed `## Checkpoints` directives.

## File location and naming

- Path: `aiwiki/sessions/{date}-{session_id_short}.md`
- Date: ISO format (`YYYY-MM-DD`) — date the session STARTED
- `session_id_short`: first 7 hex chars of Claude Code's session UUID (read from the hook payload on stdin). Functions like a git sha7 — short enough for filenames, long enough to disambiguate.

Examples: `2026-05-18-7e8a3f2.md`, `2026-05-19-a1b2c3d.md`.

If multiple sessions start on the same date, the short-id keeps them distinct. If a session spans a date boundary (rare — sessions don't usually run >24h), the date_end frontmatter captures it.

The companion file `aiwiki/sessions/INDEX.md` (if present) is a sortable table of sessions; dream's session-refinement step appends a row when consolidating.

## Required frontmatter

| Field | Type | Notes |
|---|---|---|
| `schema_id` | string | Must equal `session` |
| `schema_version` | integer | `2` (was `1` in v6.1.0; v2 adds `session_id` field and `## Checkpoints` section) |
| `status` | enum | `active` (in progress) / `done` (handed off via /wrap) / `abandoned` (orphaned — pruned by dream) |
| `date_start` | ISO date | When the session began (first event triggered file creation) |
| `date_end` | ISO date (optional) | When /wrap fired or SessionEnd hook closed the file; null while active |
| `focus` | string | What this session is about — initially "unset" if file was created by pre-compact before /wrap fired; updated by /wrap |
| `session_id` | string (optional) | Full Claude session UUID. Pre-compact writes the short form into the filename; the full ID lives here for traceability. |
| `last_commit` | string (optional) | SHA of the last commit during this session |

## Optional sections

All sections are optional individually; at least one must be present (an empty session file is meaningless).

| Section | Style | Writer |
|---|---|---|
| `## Checkpoints` | Event log (append-only) | `pre-compact.sh`, `support-dream` skill |
| `## Files touched` | Index of links (with citations) | `/wrap`, `harden` |
| `## Decisions made` | Index of links to ADRs | `/wrap`, `harden` |
| `## Gotchas surfaced` | Index of links to gotchas | `/wrap`, `harden` |
| `## Open questions` | Index of links to raw notes | `/wrap`, `harden` |
| `## Next steps` | Bullet list | `/wrap`; dream refines |

If `## Checkpoints` is present, it MUST be first (before the index sections).

## Section: ## Checkpoints (event log)

Append-only chronological list of in-session events. Each entry is a `###` subsection.

**Entry shape:**

```markdown
### PreCompact at 2026-05-18T14:23:00Z

Active work: feature/wire-dream
Manifest: .forge/work/feature/wire-dream/manifest.yaml

Phase status (from manifest):
```yaml
status: in-progress
artifacts.prototype.locked_at: 2026-05-17T11:00:00Z
artifacts.codify.locked_at: ~
```

**Dream directive (unconsumed):**

- Scope: `aiwiki/raw/`, recently-touched typed pages
- Trigger: pre-compact, context ~85%
- Action: invoke `support-dream` skill before resuming other work

---
```

**Marking consumed.** After the agent acts on a `Dream directive (unconsumed)` entry, it changes the entry's bold-header from `**Dream directive (unconsumed):**` to `**Dream directive (consumed at {ISO-timestamp}):**`. The `session-start.sh` hook counts active directives by matching the exact `(unconsumed):` header — flipping the header is what makes the count accurate. Appending a separate "Status: consumed" line is wrong because it leaves the unconsumed-marked header still grep-matchable; the next session-start will surface the directive as a HARD-INTERRUPT again (dogfood-validated 2026-05-18).

## Section: ## Files touched (index of links)

Bullet list. Each entry cites the file with `file:line@<sha7>` (or `path` if file-level). LINT auto-fills `@<sha7>` on first save.

## Sections: ## Decisions made / ## Gotchas surfaced / ## Open questions

Bullet lists. Each entry is a link to a typed wiki page (ADR, gotcha, raw note). No `@<sha7>` needed for wiki-internal links.

## Section: ## Next steps

Bullet list. What the next session should do. Dream's session-refinement step (if it runs) may rewrite this section as it learns more about the work's state.

## Line caps

- Hard cap: 400 lines (raised from 200 in v1; `## Checkpoints` event log grows over a long session)
- Soft target: 40-200 lines
- A session file >200 lines that hasn't been touched by /wrap is probably pre-compact-heavy and ready for /wrap consolidation
- A session file >400 lines fails LINT — run `/wrap` to consolidate, OR `/dream` to refine the file

## Citation rules

- `## Files touched`: each line MUST cite `file:line@<sha7>` (or `path`)
- Other sections link to typed wiki pages (no `@<sha7>` needed for wiki-internal links)
- `## Checkpoints` entries don't require citations — they're event records, not knowledge claims
- LINT auto-fills missing code citations on first save

## Skeleton

```markdown
---
schema_id: session
schema_version: 2
status: active
date_start: 2026-05-18
session_id: 7e8a3f2-9a4b-4c8d-b1e2-f5a6c7d8e9f0
focus: unset
last_commit: ~
---

## Checkpoints

### PreCompact at 2026-05-18T14:23:00Z

Active work: feature/wire-dream
Manifest: .forge/work/feature/wire-dream/manifest.yaml

Phase status (from manifest):
```yaml
status: in-progress
artifacts.prototype.locked_at: 2026-05-17T11:00:00Z
```

**Dream directive (unconsumed):**
- Scope: `aiwiki/raw/`, recently-touched typed pages
- Trigger: pre-compact, context ~85%
- Action: invoke `support-dream` skill before resuming other work
- Status: unconsumed

---

## Files touched

(filled by /wrap)

## Decisions made

(filled by /wrap)

## Gotchas surfaced

(filled by /wrap)

## Open questions

(filled by /wrap)

## Next steps

(filled by /wrap)
```

## Migration from v1

v1 session files (no `## Checkpoints`, no `session_id`) parse cleanly under v2 (all v2 sections are optional). LINT will surface "no `session_id`" as advisory, not blocking. Manual migration: add `session_id: ~` to frontmatter and bump `schema_version: 2`; or just leave v1 files and let dream consolidate them at next refinement pass.
