# Changelog

This page is the repository's `CHANGELOG.md`, rendered at build time; the current release is 0.2.0. Versions follow Semantic Versioning at `0.x` while OpenContext is in beta, and `1.0.0` is reserved for general availability. The notes are written for developers and use their shorthand: CLI is the command-line tool, MCP is the Model Context Protocol, SDK is a software development kit, OAuth is the sign-in grant a service such as Google issues, SSRF is server-side request forgery (a fetch tricked into reaching an internal address), CI is continuous integration (the checks that run on every push), UI is the user interface, and SSE is server-sent events (the stream the interface watches).

All notable changes to OpenContext are recorded here.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) at
`0.x` while it is in beta: the minor number carries breaking changes, and `1.0.0`
is reserved for general availability. How a release is cut is in
[docs/operations/RELEASE.md](https://github.com/Alec-Merle/OpenContext/blob/main/docs/operations/RELEASE.md).

## [Unreleased]

### Added

- A repeatable security test gate (`npm run test:security`) with an automatically
  discovered route sweep, hostile markdown fixtures, model handoff checks and
  source/policy-hashed evidence retained by CI. See `docs/security/README.md`.
- Required-sign-in health checks now return availability only. Early request
  rejections carry privacy headers, and model callers cannot override the
  configured destination through SDK environment options.

- Native Codex prompt hooks alongside Claude Code hooks. `opencontext context`
  supplies bounded repository and personal graph evidence with one-hop links;
  `diagnose` explains the actual CLI/vault target and each client's installation.
- Settings > AI tools can preview the exact task context locally, with no model
  call. Hook installation and live-client trust are described separately.

- A double-clickable macOS app. `npm run desktop` builds `OpenContext.app` into
  `~/Applications` and puts a shortcut on the Desktop; clicking it finds Node
  (the Finder's PATH has neither nvm nor Homebrew on it), starts the server
  unless OpenContext already answers on the port, waits for `/api/health`, and
  opens the UI in a Chrome app window, or the default browser with
  `--browser default` or when Chrome is not installed. Clicking again while it
  runs skips the boot and opens the window, and failures are a dialog with the
  log rather than a bouncing icon. `open -a OpenContext --args --stop` hands the
  port back. The bundle is generated, not tracked: it bakes in the checkout
  path, the port, and the browser choice, and the icon is drawn from the
  favicon's graph glyph in pure Node, so there is nothing to install first.
- The account chip is present with sign-in off, where it used to be absent: a
  person glyph whose popover says this install trusts whoever reaches it on
  localhost, so there is no account to sign into, and how to turn sign-in on.
- The public site's legal and policy pages (docs/go-live/SITE-COMPLIANCE.md):
  terms, a privacy policy for the website and the local software, a cookie
  policy that explains why there is no consent banner (the site stores
  nothing), a refund policy (nothing is sold), and an accessibility statement
  with measured contrast, all linked from every page's footer and listed
  under a Legal section of `llms.txt`. Who publishes the site (name, location,
  governing law, contact routes) lives in `site/publisher.json` and reaches
  every page through placeholders; `npm run site:build -- --release` refuses
  to build while the contact email is empty (decision D-E).
- `agents.md` at the site root, the agent primer as markdown, and a `Person`
  publisher entity plus `dateModified` in the JSON-LD.
- Site accessibility: a visible focus ring, tables that keep their semantics
  inside a scrollable wrapper with `scope="col"` headers, keyboard-focusable
  code blocks, "Copy code" buttons that announce their result, larger tap
  targets, and reduced-motion support. The site suite now pins these, the
  no-form/no-cookie/no-storage/no-fetch claims of the policies, alt text on
  every image, heading order, and a plain-language rule (an acronym is
  expanded before its first use on every page).

- Area rebaseline (docs/features/area-rebaseline.md): a coverage map that says
  where a repository's knowledge graph is thin (`GET /api/repos/:id/coverage`,
  with `?for=<prompt>` nominating the areas a task's words live in, thinnest
  first, with who cites them, commits since the graph, and the packages they
  import), a deepen job that runs one deep pass per named area without a
  re-survey (`POST /api/repos/:id/deepen`, capped per job like a baseline's
  dives, refused over the cap with the number), registry memory of every
  survey nomination and every area pass, a Coverage card on the project pane,
  and `opencontext coverage` / `opencontext deepen`.
- The recall hook quotes with the files and identifiers an entity cites, names
  the prompt terms no entity mentions, and stops quoting on a single common
  word (calibrated on this repository's graph; the sign-in prompt of AB1/AB2 no
  longer quotes an unrelated decision on "credential").
- AB3 replicated to N=3 (docs/metrics/PLAN.md section 8): the injected arm
  was about a fifth cheaper every time; the blind judge preferred the control
  two of three on completeness, a trade the record names.

- Discoverability: a crawlable public site under `site/` (seven answer-first
  pages, each with a markdown twin, canonical, Open Graph, and JSON-LD),
  generated by `npm run site:build` together with `llms.txt`, `llms-full.txt`,
  and `sitemap.xml`; crawler files (`robots.txt` allowing every documented AI
  crawler by name, `ai.txt`, `humans.txt`, `agents.txt`,
  `.well-known/security.txt`); a GitHub Pages workflow; and the `site` suite.
- The running app answers `GET /llms.txt` (the active vault rendered as an
  llms.txt index, one section per domain, every entity linked through
  `/api/raw`) and `GET /agents.txt` (the agent primer plus the MCP tool list),
  so an agent that only knows the server's address can discover the graph.
  Covered by the `discovery` suite.
- A prepared, not yet published, manifest for the official MCP registry
  (`mcp/server.json`) and package.json metadata (description, keywords,
  repository, homepage). The unscoped npm names `opencontext`,
  `opencontext-cli`, and `opencontext-mcp` are taken by unrelated packages;
  the manifest uses the scoped `@alec-merle/opencontext` pending decision D6.
- `docs/marketing/DISCOVERABILITY.md`: the playbook for becoming the cited
  answer in web search and AI answer engines, what is built, the naming
  collision, the compounding tricks, and the order of operations.

### Changed

- Site copy corrected to what the code does: the distillation cost figure is
  labelled an estimate, the entity scan is listed as its own outbound path
  (its page fetches leave the machine through the address guard), the
  embedding index is "deliberately absent" rather than "on the roadmap", the
  100-item confirmation is scoped to Drive and Gmail, and acronyms are
  expanded on first use.

### Fixed

- `npm run demo` now creates a disposable vault and blocks vault switching, so
  simulator output cannot contaminate the personal vault or its saved choice.
- The live model diagnostic explicitly enables Read and requires a real tool
  call plus an exact random fixture result before reporting success.

- Structured-output turn-limit errors now reach the ingestion fallback even
  when the SDK throws after returning the error result. Failed-pass cost and
  cancellation behavior are preserved.
- Mobile navigation, graph focus/details, file headers and chat now fit phone
  viewports; the chat context graph is optional and appears below the conversation.
- Named graph components survive common-word filtering, linked decision excerpts
  prefer substance to attribution, and missing CLI vaults produce useful errors.
- Dev startup now stops the portable tsx watcher as well as the older npm-bin
  form, preventing stale servers from reclaiming the fixed API port after edits.

## [0.2.0] - 2026-09-02

The production-readiness effort ("Go Live", branch `go-live`), aimed at the local
beta. What it is and its eight gates: [docs/go-live/GO-LIVE.md](https://github.com/Alec-Merle/OpenContext/blob/main/docs/go-live/GO-LIVE.md).
Current status: [docs/go-live/CHECKLIST.md](https://github.com/Alec-Merle/OpenContext/blob/main/docs/go-live/CHECKLIST.md).

### Security

- An HTTP guard in front of every route: a Host allowlist (the loopback forms,
  the bind address, the configured OAuth redirect hosts, and
  `OPENCONTEXT_ALLOWED_HOSTS`) that refuses DNS-rebinding requests, and an
  Origin / Sec-Fetch-Site gate on every state-changing request. A non-loopback
  bind now prints a warning at every boot, and a busy port exits 1 with the fix
  instead of leaving the process listening to nothing.
- Capture fetches connect only to addresses the SSRF guard vetted, with the
  lookup pinned and every redirect re-vetted. The scan agent's WebFetch calls go
  through the same guard, and invoked saved agents are vault-only with no web
  tools.
- Zip-based extractors are bounded before and during inflation (entry count,
  per-entry and total inflated bytes, compression ratio) against decompression
  bombs. Upload limits map to 413/400 sentences with temp-file cleanup.
- `/api/file` and `/api/raw` refuse symlinks and decide forbidden prefixes on the
  real path.
- Google state files (`_state/gdrive.json`, `_state/gmail.json`) are written 0600
  and atomically; a corrupt one is moved aside as `<name>.corrupt-<timestamp>`
  and reported rather than silently reset.
- The privacy deep reviewer can no longer read held originals, findings in
  `_projects/` are redacted, reviewer findings survive a re-audit, discard removes
  staged copies, and classifier truncation is visible instead of silent.

### Added

- **Agent links.** Installing the CLI now also points the repository you installed
  from at this machine's knowledge graph: a managed, marker-delimited block in
  `AGENTS.md`, `CLAUDE.md`, `CODEX.md` and `README.md`, naming the vault, the read
  commands, and that repository's own `_projects/<slug>/` graph, so a coding agent
  finds the graph in the first file it reads. `opencontext link` and
  `opencontext unlink` do it in any other repository. The block is content-keyed:
  the begin marker carries a hash of its own body, so re-running refreshes a stale
  block in place rather than appending a second copy, an old
  `agent-guide >> AGENTS.md` append is adopted into markers, and a block edited by
  hand is reported and left alone. `--check` previews without writing and exits
  non-zero on drift (usable as a CI gate); `--portable` omits machine paths;
  `--file` narrows the set; `unlink` restores the file byte for byte. The installers
  link only inside a git worktree, are guarded so a failure cannot fail an install,
  and honour `OPENCONTEXT_LINK=0` (skip) and `OPENCONTEXT_LINK=<path>` (retarget).
  `RepoInfo.agentLink` reports link state for registered local repositories, and the
  Project pane shows it; the server never writes those files itself.
  See [docs/features/agent-links.md](https://github.com/Alec-Merle/OpenContext/blob/main/docs/features/agent-links.md).
- `npm run setup` (install both packages and build the web app) and
  `npm run doctor`, a free offline prerequisite check covering Node, git, the
  Agent SDK's platform runtime, the web build, `.env`, the visible model
  credential, the vault, and the dev ports. The paid half stays
  `npm run doctor:live`.
- `GET /api/setup/status`: version, Node version, platform, demo mode, the vault
  and where it came from, whether the web build is served, which credential is
  present (presence only), and a `ready` verdict with plain-sentence reasons.
- In-app Anthropic key storage (`PUT`/`DELETE /api/settings/anthropic-key`, mode
  0600, outranks `.env`, no restart needed).
- `GET /api/health` now reports the running version from `package.json`.
- `.env.example` covering every environment variable, `.nvmrc`, `.editorconfig`,
  and `engines.node >= 22` on both packages.
- Continuous integration: `.github/workflows/ci.yml` runs typecheck, the offline
  suite, and the web build on every push and pull request, with the agent
  simulator on and every credential blanked, plus an advisory `npm audit`.
- The root-index audit: `GET /api/index-audit` and `POST /api/index-audit/fix`,
  which repairs the vault's README indexes in one revertible commit.
- Thirteen offline suites: `index-audit`, `harness`, `http-guard`, `file-route`,
  `privacy-routes`, and `onboarding` in wave 1; `chats`, `knowledge-routes`,
  `ingest-paths`, and `core-routes` in wave 2; then `web` (the production build,
  a bundle audit, and the pure web modules under test), `secret-scrub` (sentinel
  credentials seeded into every store and proven absent from every response,
  log, feed entry, vault file, and the packaged CLI tarball), and `agent-link`.
  The offline run is now 46 suites.
- A first-run "Get started" card on the Intake pane for empty vaults: add a
  credential, drop a document, connect a source, point your coding agents at
  the graph - each step with a live done check, gone once the vault has
  entities.
- A favicon, canvas glyphs for agent and skill graph nodes, and vault-scoped
  browser state (a vault switch drops the old vault's remembered chat, project,
  and pane instead of pointing at another vault's ids).
- A React error boundary around every pane
  (`web/src/components/ErrorBoundary.tsx`), so a render exception no longer
  blanks the whole app.
- A placeholder [LICENSE](https://github.com/Alec-Merle/OpenContext/blob/main/LICENSE): a proprietary evaluation license for beta
  invitees, marked in the file as pending the maintainer's decision D-C.
- Documentation: [docs/README.md](https://github.com/Alec-Merle/OpenContext/blob/main/docs/README.md) as the index, the operations
  set ([configuration](https://github.com/Alec-Merle/OpenContext/blob/main/docs/operations/CONFIGURATION.md),
  [runbook](https://github.com/Alec-Merle/OpenContext/blob/main/docs/operations/RUNBOOK.md), [release](https://github.com/Alec-Merle/OpenContext/blob/main/docs/operations/RELEASE.md)),
  the [testing guide](https://github.com/Alec-Merle/OpenContext/blob/main/docs/testing/TESTING.md), the Go Live
  [definition](https://github.com/Alec-Merle/OpenContext/blob/main/docs/go-live/GO-LIVE.md), [gap register](https://github.com/Alec-Merle/OpenContext/blob/main/docs/go-live/GAPS.md),
  [subsystem map](https://github.com/Alec-Merle/OpenContext/blob/main/docs/architecture/SUBSYSTEMS.md), [progress log](https://github.com/Alec-Merle/OpenContext/blob/main/docs/go-live/PROGRESS.md)
  and [checklist](https://github.com/Alec-Merle/OpenContext/blob/main/docs/go-live/CHECKLIST.md), this changelog,
  [CONTRIBUTING.md](https://github.com/Alec-Merle/OpenContext/blob/main/CONTRIBUTING.md), [SECURITY.md](https://github.com/Alec-Merle/OpenContext/blob/main/SECURITY.md), and GitHub
  issue and pull request templates.

### Changed

- The test runner enforces per-suite deadlines (default 600s, `--timeout` to
  change), rejects unknown flags with usage instead of silently running
  everything, gained `--fail-fast`, and reports the slowest suites. A hung suite
  is killed together with every process it spawned.
- Every suite that binds a socket owns a row in one port table (`PORT_SLOTS`)
  with its own environment override for parallel sessions; the `harness` suite
  fails the build on a duplicate port, a duplicate override name, or a listening
  script with no row. `npm run free-ports` reclaims only this project's own
  processes and reports anything else by pid, command, and directory.
- Boot refuses to scaffold a vault into a populated folder that OpenContext did
  not create, unless `OPENCONTEXT_VAULT_ADOPT=1` grants it; a chosen vault that
  has gone missing falls back with a warning and a `missingChoice` status instead
  of being silently recreated; a vault living inside the app checkout is reported
  as such.
- The activity feed's history follows the vault chosen at boot rather than the
  environment default, and the job list resets on a vault switch.
- The re-distillation verdict carries a sentence explaining why a source went
  stale.
- A vault whose entity catalog outgrows the single-shot prompt cap now distills
  against a relevance-filtered subset of the catalog instead of silently falling
  back to the roughly 10x-cost agent loop.
- Gmail gained an "API disabled in Google Cloud" diagnosis, per-account census
  resilience, and one paced runner for every metadata pass. Ghost "unknown
  account" grants are marked and swept, disconnect is refused while a job runs
  on the grant, the census reports a real summary, scan snapshots persist only
  privacy-masked subjects, and Drive detail walks are cached with loose
  shared-with-me files syncable as single-file sources.
- Forge clone URLs are validated against the connection's own host, GitHub
  secondary rate limits read as transient instead of flagging reauth, ssh
  origins fail fast instead of prompting, and repository notes write
  `local_path` home-portable (`~/...`) through the guard and privacy screen so
  a pushed vault leaks no username.
- X bookmark syncs resume without dropping the rest of a capped page, refuse
  overlapping runs, and mark posts imported only when the enqueue succeeded.
- The server sends conservative security headers (a strict app-shell CSP,
  nosniff, no-referrer, frame denial), answers malformed or oversized JSON with
  readable 400/413 sentences, sweeps orphaned upload temp files at boot, exits
  cleanly on an uncaught exception instead of serving in an unknown state,
  validates vault remote URLs before handing them to git, and bounds PDF text
  extraction by pages and wall clock with the truncation narrated. Agent
  invocations get a wall-clock deadline. The privacy events ledger rotates past
  8 MB and reads a bounded tail, and unscreenable documents are counted as
  "not screenable" instead of screened. An `npm audit fix` cleared every high
  finding lockfile-only (three moderates remain in the express body-parser qs
  chain, not reachable without an upstream release - waived for the beta).
- PDFs past 100 pages with a usable text layer distill from that text instead of
  being skipped, and the large-file hold estimates text size per format.
- The CLI's server probe distinguishes down, timeout, and unhealthy, and the MCP
  server answers with the reason when its pinned vault is missing rather than
  reporting an empty graph.

### Fixed

- A frontmatter block-list parser bug.
- `gmail-doctor` read the pre-multi-account state shape, so its grant check never
  ran.
- A Gmail 401 retry now drops the cached token first.
- A "Flag only" privacy rule no longer quarantines the document.

## [0.1.0] - 2026-09-01

The version carried by `package.json` since the project began. It was never
tagged and never released; this entry records what the product was when the Go
Live effort started, so the section above reads as a delta. Dates come from the
**Status** lines in [ROADMAP.md](https://github.com/Alec-Merle/OpenContext/blob/main/ROADMAP.md).

### Added

- **Ingestion and distillation.** Drop a document in and an agent decomposes it
  into a knowledge graph of plain markdown, one entity per file, relationships as
  relative markdown links, agent-maintained README indexes at every level.
  Universal extraction (2026-08-21): sniffing from the bytes, a format registry,
  `_extracted/`, and PDF, Word, Excel, PowerPoint, OpenDocument, EPUB, RTF, HTML,
  email, markdown, CSV, and source code. Single-shot distillation (2026-08-27):
  one toolless model call plus a deterministic writer, roughly 10x cheaper than
  the agent loop, with the loop kept as the automatic fallback. The default model
  is `claude-sonnet-5`, chosen by a three-way bake-off (2026-08-21).
- **Vault versioning and rollback** (2026-08-24): git underneath the vault, one
  commit per operation, a History pane, and undo. Remote push added 2026-08-27.
- **Privacy and security layer** (2026-08-24): deterministic detectors with
  structural validation, a preflight hold before the model reads a document, a
  write-boundary redaction hook, and an audit over the vault. The PDF text-layer
  pass shipped 2026-08-27.
- **Chat.** Server-persisted conversations with citations, checkpoints, and a
  sidebar list (2026-08-21); the context-graph panel and composer amenities
  (2026-08-23); anchored conversations; context economics and the evidence
  surfaces (2026-08-24), with the aggregate Evidence pane added 2026-08-26 and
  rebuilt as a ledger 2026-08-27.
- **Insights** (2026-08-21): a signal engine over the graph plus a fresh-context
  agent whose analysis streams into a review queue.
- **Knowledge graph views** (2026-08-23): the Organize layout engine.
- **Sources.** Google Drive (2026-08-23), Gmail (2026-08-25, later multi-account
  with the financial census), GitHub and GitLab connections (2026-08-24) with
  repository ingestion (2026-08-21), X bookmarks, link and paste capture, and
  assistant-history import for ChatGPT, Claude, and Gemini exports (2026-08-26).
  Every integration uses your own OAuth client or token, read-only scopes, and
  on-demand syncs.
- **Entity web scan** (2026-08-23, extended 2026-08-24): hydrating people and
  organizations from the web, within the same write guard.
- **Coding-agent surface**: the `opencontext` CLI and an MCP server with a
  one-line install (2026-08-26), so an external agent can search, read, traverse,
  and contribute to the vault.
- **Agents and Skills** (2026-08-30): reusable agents built from the vault's own
  patterns, with a review queue, promotion, and invocation.
- **Duplicates**: detection with a source-of-truth sign-off and a dedupe commit.
- **Projects** (2026-09-01): per-repository knowledge graphs under
  `_projects/<slug>/`, pointer metadata on the repository's note, and
  project-scoped chat.
- **Vault search**: `GET /api/search` and a Cmd/Ctrl+K palette.
- **Settings**: in-app vault switching, the OpenRouter model provider as an
  alternative to Anthropic direct, self-set spend budgets, and naming
  conventions.
- **Metrics and the bench harness** (2026-08-29): per-run token and cost
  instrumentation, and `npm run bench` for measured accuracy and cost.
- **Demo mode**: the whole pipeline on a deterministic simulator, no tokens
  spent.
