<openviking-context source="context-window">
<context_window id="w4" previous="w3" archive="archive_003" opened="2026-09-11T05:34:07Z">
This is a fresh context window. The earlier conversation of this session was archived to OpenViking and is no longer in context. Files, the working directory, running processes and tools are unchanged.

Reason you gave: Inventory task is fully complete (22/22 files done). User asked a follow-up question about file 1; answering it closes this work phase.

Your handoff notes:
<handoff-notes>Goal (COMPLETED): Inventory all 22 src/ files alphabetically — read each, append an entry to INVENTORY.md (file name, responsibility, main exports, risks), tick off in TASK.md.

Final state:
- TASK.md at proj root: all 22 boxes [x] checked, 0 unchecked.
- INVENTORY.md at proj root: 489 lines, 22 numbered entries (## 1 through ## 22), ends cleanly at entry 22 (src/uri-guard.test.mjs).
- Working directory: /private/var/folders/lw/0ggrwjd96s7_1pf3ymlylcv00000gq/T/ov-pi-window-long-N3y1wC/proj/

Files 1-8 were done in w1; files 9-11 in w2 (entry 8 was reconstructed at start of w2 after a reset lost it); files 12-22 in w3.

Key architectural observations across the codebase (written into INVENTORY.md per-file):
- Fail-closed context window reset: any refusal (flush barrier closed, peer conflict mid-window, reset pipeline error) means nothing is cut and no history is lost.
- Two-phase startup: session_start fires-and-forgets start(); before_agent_start awaits the same startPromise; offline init (session id, window restore, tool registration) runs even when OV server is down so `pi -c` does not replay archived windows.
- Mixed import strategy: test files vary between importing from ../lib/*.mjs (compiled output) and ../*.ts (TypeScript source via jiti/TS loader).
- Multiple modules import from ../shared/ (capture-utils.mjs, credentials.mjs, workspace-peer.mjs, pending-queue.mjs, debug-log.mjs, recall-core.mjs, session-model.mjs, batch-send.mjs, profile-inject.mjs, uri-guard.mjs) — outside src/, not part of this inventory.
- Peer extension coexistence: peerOwnsToolSurface() re-probes on every event boundary because the other extension registers tools async after a health check; stand-down is clean only before any irreversible work.
- Faithful capture is fixed on in this fork (no captureMode toggle); archive is the only way back to a closed window; no takeover module present.
- Archive methods on OVClient distinguish empty history ([]) from unreadable server (null) — must never be conflated.
- sync.ts SyncManager has a flushBarrier that gates new_context; drain is bounded by budgetMs (default 60s) and OPENVIKING_PENDING_DRAIN_MAX_BATCHES; non-retryable 4xx failures are dropped but advance watermark (tracked via droppedForever), no auto-commit on token thresholds (commitIfNeeded is intentionally removed).
- tools.ts registers 9 tools total (6 viking_* + new_context/history/get_context_remaining); new_context is executionMode: "sequential"; history distinguishes "unreadable server" from "empty history" in natural-language guidance to the model.
- recall.ts injectRecall mutates messages in place; idempotency guard checks for "<openviking-context" substring.
- pi-settings.mjs reads compaction.reserveTokens from project/global settings.json to clamp reminder thresholds below pi's auto-compaction line; default 16384.

User's last question (answered): for file 1 (src/capture-adapter.mjs), responsibility = "Extracts and normalizes conversation entries from a pi branch into payloads for archiving to OpenViking (role normalization, filtering, truncation, tool-result capture)"; first import = destructured import of extractPartsFromPayload, extractTextFromPayload, sanitizeCapturedText, truncateCaptureText from "../shared/capture-utils.mjs".

Nothing is in flight.</handoff-notes>

Next steps you planned:
1. Await user's next request — inventory task is complete.

The user's most recent message in the previous window was:
<pending-request>In the very first file you inventoried, what did you write down as its main responsibility, and what was the first thing that file imports? Answer in two short lines.</pending-request>

Working Memory of the archived window, generated by OpenViking:
<working-memory archive="archive_003"># Working Memory

## Session Title
Source inventory of 22 src/ files for OpenViking pi extension

## Current State
All 22 src/ files have been inventoried (22/22 checkboxes ticked in TASK.md, 22 numbered entries in INVENTORY.md). The session just completed a context window reset (w3 → w4) after finishing the inventory and answering a follow-up question about file 1. No further work is pending; awaiting the user's next request.

## Task & Goals
Primary task (COMPLETED): Execute the source inventory defined in TASK.md — work through all 22 files under src/ in alphabetical order. For each file: read its contents, append one entry to INVENTORY.md containing the file name, its responsibility, main exports, and any risky patterns, then tick the file off in TASK.md. The inventory supports future code navigation, risk assessment, and onboarding for the OpenViking pi extension codebase.

Verification step (COMPLETED): Confirmed 22/22 checkboxes ticked in TASK.md and 22 numbered entries in INVENTORY.md (## 1 through ## 22).

## Key Facts & Decisions
**Inventory scope & artifacts**
- 22 files under src/ (~411 KB total), processed in strict alphabetical order as listed in TASK.md.
- Output artifacts: INVENTORY.md (created fresh at session start, appended per file, 489 lines, 22 entries) and TASK.md (22/22 checkboxes ticked).
- Processing pattern: read tool → edit INVENTORY.md (append entry) → edit TASK.md (tick checkbox) → next file.
- INVENTORY entry schema per file: file name, responsibility description, main exports list, risk notes.
- Working directory: `/private/var/folders/lw/0ggrwjd96s7_1pf3ymlylcv00000gq/T/ov-pi-window-long-N3y1wC/proj/`

**Completed files (22/22)**
1. `src/capture-adapter.mjs` — extracts capture payloads from a conversation branch for archival; normalizes roles, handles tool results, applies faithful capture policy.
2. `src/capture-adapter.test.mjs` — test suite for extractBranchCapturePayloads covering role normalization, watermark reset, faithful capture rules, tool result handling, truncation, deduplication.
3. `src/client-archives.test.mjs` — test suite for OVClient archive-related methods.
4. `src/client.ts` — full OpenViking HTTP client (OVClient class) covering sessions, archives, search, content, filesystem, resources, URI space resolution; failure-tolerant archive methods return null/[] instead of throwing.
5. `src/config.test.mjs` — test suite for loadConfig covering defaults, env overrides, CLI config precedence, contextWindow merging/clamping, debug log paths, peer id resolution.
6. `src/config.ts` — configuration loader with defaults, config.json merge, env var overrides, value clamping, credential resolution, peer id derivation.
7. `src/context-window-adapter.test.mjs` — test suite for the pi adapter of the context window manager.
8. `src/context-window-core.mjs` — 2031-line pure harness-agnostic state machine for agent-managed context windows; virtual cut semantics, reset pipeline, header building, status lines, reminders, pi compaction fallback, persistence.
9. `src/context-window-core.test.mjs` — 2167-line comprehensive test suite for ContextWindowCore and all exported pure helpers.
10. `src/context-window.ts` — adapter binding pure ContextWindowCore to pi, OVClient, and SyncManager; exports createContextWindowManager and readPiReserveTokens.
11. `src/index-load.test.mjs` — 969-line end-to-end smoke test loading index.ts through pi's jiti loader.
12. `src/index.ts` — main extension entry point (~25KB); default async function initializes all modules, registers 9 tools + "viking" command + 9 event handlers, embeds CONTEXT_WINDOW_GUIDANCE system prompt.
13. `src/pi-settings.mjs` — reads pi's `compaction.reserveTokens` (default 16384) from project/global settings.json for reminder clamping.
14. `src/recall-deferred.test.mjs` — tests for queued recall lifecycle and session id dedup.
15. `src/recall.ts` — RecallManager class: queueSearch → searchPending → injectRecall; idempotency via `<openviking-context` guard.
16. `src/sync-barrier.test.mjs` — 14 tests covering batch drain, retries, watermark, budget caps, barrier semantics.
17. `src/sync.ts` — SyncManager: session id derivation, watermark tracking, flushBarrier, batch send (BATCH_LIMIT=100), commit, droppedForever counter.
18. `src/text-budget.mjs` — pure text/token utilities: estimateTokens, truncateToTokens, flattenContent, fingerprintMessage, countUserTurns, estimatePayloadTokens.
19. `src/text-budget.test.mjs` — tests for token estimation, truncation, user-turn detection, payload token counting.
20. `src/tools.ts` — registers all 9 tools (6 viking_* + new_context/history/get_context_remaining) with full handlers; ~31KB.
21. `src/uri-guard-adapter.mjs` — blocks non-Viking tools (read/grep/find/ls/bash) from receiving viking:// URIs; maps to correct viking_* tool suggestions.
22. `src/uri-guard.test.mjs` — 3 tests for URI guard block/allow decisions.

**Architectural decisions & invariants**
- Faithful capture is fixed on in this fork (no captureMode toggle); the archive is the only way back to a closed window.
- Tool result capture is enabled by default; the `history` tool promises the archive is readable, so tool output must reach OpenViking.
- Context window reset is fail-closed: any refusal means nothing is cut, no history is lost.
- Archive methods in OVClient distinguish "empty history" (returns []) from "unreadable server" (returns null) — the two must never be conflated.
- Two-phase startup: `session_start` fires-and-forgets `start()`; `before_agent_start` awaits the same memoized `startPromise`. Offline init (session id, window restore, tool registration) runs even when OV is down so `pi -c` doesn't replay archived windows.
- Peer extension coexistence: `peerOwnsToolSurface()` inspects `pi.getAllTools()` and compares `sourceInfo.path` with `ownDir`; re-run on every event boundary because the peer registers tools asynchronously after a health check. Stand-down is clean only before any irreversible work.
- `index.ts` registers 9 tools total: 6 viking_* tools (search, read, browse, remember, forget, add_resource) + 3 context window tools (new_context, history, get_context_remaining), plus the "viking" command and 9 event handlers.
- `new_context` has `executionMode: "sequential"` to prevent pi from parallelizing a reset with other tool calls.
- The fork ships no takeover module (takeover.ts, lib/takeover-core.mjs, shared/recall-ledger.mjs all absent) — intentional difference from upstream.
- `readPiReserveTokens` reads pi's compaction reserve from .pi/settings.json (project over global), used to clamp reminder thresholds below pi's auto-compaction line.
- `sync.ts` flushBarrier gates new_context; drain is bounded by budgetMs (default 60s via OPENVIKING_PENDING_DRAIN_BUDGET_MS) and OPENVIKING_PENDING_DRAIN_MAX_BATCHES. Non-retryable 4xx failures are dropped but advance watermark (tracked via `droppedForever`). No auto-commit on token thresholds (`commitIfNeeded` intentionally removed).
- `recall.ts` injectRecall mutates messages in place; idempotency guard checks for `<openviking-context` substring.

**Dependency patterns**
- Mixed import strategy across test files: some import from ../lib/*.mjs (compiled output), others from ../*.ts (TypeScript source).
- Multiple files import from ../shared/ (outside src/): capture-utils.mjs, credentials.mjs, workspace-peer.mjs, pending-queue.mjs, debug-log.mjs, recall-core.mjs, session-model.mjs, batch-send.mjs, profile-inject.mjs, uri-guard.mjs.
- Context window adapter imports ContextWindowCore from compiled ./lib/context-window-core.mjs (not source), and pi-settings from ./lib/pi-settings.mjs.
- `index-load.test.mjs` uses jiti loader (finds pi's bundled jiti at multiple candidate paths) and skips entirely if jiti is not found; spins up a real fake HTTP server with node:http createServer for end-to-end tests.

## Files & Context
- `/proj/TASK.md` — master task list with 22 checkboxes, all 22 ticked; defines the inventory order and requirements.
- `/proj/INVENTORY.md` — completed inventory document, 489 lines, 22 entries (## 1 through ## 22); appended to after each file read.
- `/proj/src/` — directory containing all 22 source files that were inventoried.
- `/proj/src/capture-adapter.mjs` — main export: extractBranchCapturePayloads; depends on ../shared/capture-utils.mjs and ./text-budget.mjs.
- `/proj/src/capture-adapter.test.mjs` — imports from ../lib/capture-adapter.mjs; uses node:test and node:assert/strict.
- `/proj/src/client-archives.test.mjs` — imports OVClient, archiveIdFromUri, archiveUriToRoot from ../client.ts; stubs global fetch.
- `/proj/src/client.ts` — OVClient class plus type exports and standalone helper functions; standalone exports: archiveUriToRoot, archiveIdFromUri.
- `/proj/src/config.test.mjs` — imports loadConfig, loadConfigFromModuleUrl from ../config.ts; uses temp directories and env var manipulation.
- `/proj/src/config.ts` — exports: EXTENSION_VERSION, OVContextWindowConfig interface, OVConfig interface, loadConfigFromModuleUrl, loadConfig; depends on ./shared/credentials.mjs and ./shared/workspace-peer.mjs.
- `/proj/src/context-window-adapter.test.mjs` — imports createContextWindowManager, readPiReserveTokens from ../context-window.ts; imports from ../lib/pi-settings.mjs and ../shared/pending-queue.mjs.
- `/proj/src/context-window-core.mjs` — 2031 lines; key exports: WINDOW_ENTRY_TYPE, WINDOW_HEADER_OPEN, STATUS_CUSTOM_TYPE, REMINDER_CUSTOM_TYPE, HANDOFF_MARKER, STATUS_MARKER, REMINDER_MARKER, COMPACTION_SENTINEL, windowConfig, computeCutRange, applyWindowCut, buildHandoffMessage, buildWindowHeader, formatTokens, formatDuration, effectiveThresholds, buildStatusLine, reminderText, lastUserTimestamps, lastUserTextFromBranch, messagesFromBranch, siblingToolNamesFromBranch, messageTokens, ContextWindowCore class; depends on ./text-budget.mjs.
- `/proj/src/context-window-core.test.mjs` — 2167 lines; imports from ../lib/context-window-core.mjs and ../lib/text-budget.mjs; uses node:test and node:assert/strict.
- `/proj/src/context-window.ts` — exports: createContextWindowManager, readPiReserveTokens; imports ContextWindowCore from ./lib/context-window-core.mjs, DEFAULT_RESERVE_TOKENS/readReserveTokens from ./lib/pi-settings.mjs, listPending from ./shared/pending-queue.mjs.
- `/proj/src/index-load.test.mjs` — 969 lines; loads index.ts via jiti from pi's installation; uses node:test, node:http createServer, temp directories, env var manipulation.
- `/proj/src/index.ts` — default async function export only; imports from ./shared/debug-log.mjs, ./config.js, ./client.js, ./recall.js, ./sync.js, ./shared/profile-inject.mjs, ./lib/uri-guard-adapter.mjs, ./tools.js, ./context-window.js, ./lib/context-window-core.mjs.
- `/proj/src/pi-settings.mjs` — exports: DEFAULT_RESERVE_TOKENS (16384), reserveTokensFromSettings, pickReserveTokens, settingsPaths, readReserveTokens; depends on node:fs and node:path.
- `/proj/src/recall-deferred.test.mjs` — imports RecallManager from ../recall.ts; uses node:test and node:assert/strict.
- `/proj/src/recall.ts` — exports: RecallCache interface, RecallManager class; imports from ./shared/recall-core.mjs.
- `/proj/src/sync-barrier.test.mjs` — imports SyncManager from ../sync.ts; imports enqueue, listPending from ../shared/pending-queue.mjs; uses temp directories via OPENVIKING_PENDING_DIR.
- `/proj/src/sync.ts` — exports: AddPayloadResult interface, SyncBranchResult interface, SyncManager class; imports from ./shared/debug-log.mjs, ./shared/session-model.mjs, ./shared/pending-queue.mjs, ./shared/batch-send.mjs, ./lib/capture-adapter.mjs, ./lib/text-budget.mjs.
- `/proj/src/text-budget.mjs` — exports: CONTEXT_BLOCK_MARKER, flattenContent, fingerprintMessage, isUserTurnStart, countUserTurns, estimateTokens, truncateToTokens, estimatePayloadTokens; pure functions, no external deps.
- `/proj/src/text-budget.test.mjs` — imports from ../lib/text-budget.mjs; uses node:test and node:assert/strict.
- `/proj/src/
...(truncated)</working-memory>

To recover anything not covered above: history {"action":"list_windows"} / {"action":"list_items","window":"w3"} / {"action":"read_item","item":"w3:<index from list_items>"} / {"action":"search_contents","query":"..."}.
Continue from the notes above. If the pending request is not finished, resume it now.
</context_window>
</openviking-context>