Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ The managed cloud runs **this same engine**. Cloud adds operations and product c
| --- | --- |
| Docs | [docs.remember.dev](https://docs.remember.dev) |
| Managed product | [remember.dev](https://remember.dev) |
| Release | [v0.13.0](https://github.com/writeitai/remember-stack/releases/tag/v0.13.0) |
| Release | [v0.16.0](https://github.com/writeitai/remember-stack/releases/tag/v0.16.0) |

---

Expand Down
17 changes: 13 additions & 4 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Releasing RememberStack

The `Release` workflow publishes one version to PyPI and GHCR, then creates a GitHub release
containing the Python distributions, the same version-pinned `compose.yaml`, and the example
environment as `default.env.example` (GitHub's public asset name for the source
`.env.example`). It accepts only tags exactly matching `vMAJOR.MINOR.PATCH`.
containing the Python distributions, the same version-pinned `compose.yaml`, the generated
`openapi.json`, and the example environment as `default.env.example` (GitHub's public asset
name for the source `.env.example`). It accepts only tags exactly matching
`vMAJOR.MINOR.PATCH`.

## One-time owner setup

Expand Down Expand Up @@ -105,7 +106,15 @@ Run these checks from a clean machine or temporary directory:
uvx --from rememberstack==0.2.0 remember --version
docker pull ghcr.io/writeitai/remember-stack:0.2.0
gh release download v0.2.0 --repo writeitai/remember-stack \
--pattern compose.yaml --pattern default.env.example
--pattern compose.yaml --pattern default.env.example --pattern openapi.json
found=$(jq -r '.info.version' openapi.json) || {
echo "cannot read openapi.json" >&2
exit 1
}
[ "$found" = "0.2.0" ] || {
echo "openapi.json is version $found, expected 0.2.0" >&2
exit 1
}
cp default.env.example .env
docker compose --env-file .env up --no-build --pull always --detach --wait
curl --fail http://localhost:8000/healthz
Expand Down
2 changes: 1 addition & 1 deletion compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ x-app: &app
# Empty when the caller does not supply it; released images get the tag's
# commit from CI.
REMEMBERSTACK_BUILD_REVISION: ${REMEMBERSTACK_BUILD_REVISION:-}
image: ghcr.io/writeitai/remember-stack:0.15.0
image: ghcr.io/writeitai/remember-stack:0.16.0
environment:
REMEMBERSTACK_DATABASE_URL: postgresql+psycopg://${REMEMBERSTACK_POSTGRES_USER}:${REMEMBERSTACK_POSTGRES_PASSWORD}@postgres:5432/${REMEMBERSTACK_POSTGRES_DB}
REMEMBERSTACK_MINIO_ENDPOINT_URL: http://minio:9000
Expand Down
2 changes: 1 addition & 1 deletion openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -3260,7 +3260,7 @@
},
"info": {
"title": "RememberStack query API",
"version": "0.15.0"
"version": "0.16.0"
},
"openapi": "3.1.0",
"paths": {
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "rememberstack"
version = "0.15.0"
version = "0.16.0"
description = "Open memory infrastructure for AI agents."
readme = "README.md"
requires-python = ">=3.12"
Expand Down
34 changes: 34 additions & 0 deletions scripts/check_release_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def main() -> None:
version = _package_version(root=root)
_validate_semver(version=version)
_validate_compose_pin(root=root, version=version)
_validate_release_docs(root=root, version=version)
_validate_postgres_release(root=root)
if arguments.tag is not None:
_validate_tag(tag=arguments.tag, version=version)
Expand Down Expand Up @@ -78,6 +79,39 @@ def _validate_tag(*, tag: str, version: str) -> None:
raise ValueError(f"release tag must be {expected!r}, found {tag!r}")


def _validate_release_docs(*, root: Path, version: str) -> None:
"""Keep public version claims on the same coordinate as the artifacts."""
image = f"ghcr.io/writeitai/remember-stack:{version}"
markers = {
Path("README.md"): (
f"[v{version}](https://github.com/writeitai/remember-stack/releases/tag/v{version})",
),
Path("website/src/app/docs/getting-started/page.mdx"): (image,),
Path("website/src/app/docs/deployment/page.mdx"): (
f"`v{version}` release",
image,
),
Path("website/src/app/docs/reference/cli/page.mdx"): (
f"# RememberStack {version}",
),
Path("website/src/app/docs/reference/api/page.mdx"): (
f"Release v{version} and later",
f"releases/download/v{version}/openapi.json",
),
Path("website/src/app/docs/project-status/page.mdx"): (
f"releases/tag/v{version}",
f"rememberstack/{version}/",
),
}
for relative_path, expected_markers in markers.items():
document = (root / relative_path).read_text(encoding="utf-8")
for marker in expected_markers:
if marker not in document:
raise ValueError(
f"{relative_path} must contain release coordinate {marker!r}"
)


def _validate_postgres_release(*, root: Path) -> None:
"""Bind Compose to the multi-architecture immutable image publisher."""
dockerfile = (root / "Dockerfile.postgres").read_text(encoding="utf-8")
Expand Down
39 changes: 39 additions & 0 deletions src/tests/packaging/test_release_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@
import sys
import tomllib

import pytest
from scripts.check_release_contract import _validate_release_docs

_RELEASE_DOCS = (
Path("README.md"),
Path("website/src/app/docs/getting-started/page.mdx"),
Path("website/src/app/docs/deployment/page.mdx"),
Path("website/src/app/docs/reference/cli/page.mdx"),
Path("website/src/app/docs/reference/api/page.mdx"),
Path("website/src/app/docs/project-status/page.mdx"),
)


def test_release_contract_matches_package_compose_and_tag() -> None:
"""Accept the current package version, Compose image, and matching tag."""
Expand Down Expand Up @@ -48,6 +60,33 @@ def test_release_contract_rejects_a_mismatched_tag() -> None:
assert f"release tag must be 'v{version}', found '{invalid_tag}'" in result.stderr


def test_release_contract_rejects_a_stale_document_coordinate(tmp_path: Path) -> None:
"""Reject a public document that advertises a different release."""
root = Path(__file__).resolve().parents[3]
version = _project_version(root=root)
for relative_path in _RELEASE_DOCS:
destination = tmp_path / relative_path
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(
(root / relative_path).read_text(encoding="utf-8"), encoding="utf-8"
)

cli_reference = tmp_path / "website/src/app/docs/reference/cli/page.mdx"
cli_reference.write_text(
cli_reference.read_text(encoding="utf-8").replace(
f"# RememberStack {version}", "# RememberStack 0.0.0", 1
),
encoding="utf-8",
)

with pytest.raises(ValueError) as error:
_validate_release_docs(root=tmp_path, version=version)
assert str(error.value) == (
"website/src/app/docs/reference/cli/page.mdx must contain release "
f"coordinate '# RememberStack {version}'"
)


def _project_version(*, root: Path) -> str:
"""Read the package version independently from the release checker process."""
with (root / "pyproject.toml").open("rb") as pyproject:
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions website/src/app/docs/deployment/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ Pre-release volumes created by the older PostgreSQL image are not migrated. For
this disposable quickstart, remove the old stack with
`docker compose down --volumes` before starting a different PostgreSQL 19 prerelease checkout.

`--build` deliberately tests the checked-out source. The public `v0.13.0` release
`--build` deliberately tests the checked-out source. The public `v0.16.0` release
also ships this Compose file pinned to
`ghcr.io/writeitai/remember-stack:0.13.0`; release consumers use
`ghcr.io/writeitai/remember-stack:0.16.0`; release consumers use
`--no-build --pull always` so Compose cannot fall back to a local source build.

Do **not** put cost export on the public query port. When you want HTTP export,
Expand Down
2 changes: 1 addition & 1 deletion website/src/app/docs/getting-started/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ cp .env.example .env
docker compose up --build --detach --wait
```

The Compose file can also pull the public `ghcr.io/writeitai/remember-stack:0.13.0` image. Use `--build` when you want to run local source; use `--no-build --pull always` when you want the released image.
The Compose file can also pull the public `ghcr.io/writeitai/remember-stack:0.16.0` image. Use `--build` when you want to run local source; use `--no-build --pull always` when you want the released image.

Health:

Expand Down
50 changes: 43 additions & 7 deletions website/src/app/docs/project-status/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const metadata = {

# Project Status

Current public release: [`v0.15.0`](https://github.com/writeitai/remember-stack/releases/tag/v0.15.0) on [PyPI](https://pypi.org/project/rememberstack/0.15.0/) and [GHCR](https://github.com/writeitai/remember-stack/pkgs/container/remember-stack).
Current public release: [`v0.16.0`](https://github.com/writeitai/remember-stack/releases/tag/v0.16.0) on [PyPI](https://pypi.org/project/rememberstack/0.16.0/) and [GHCR](https://github.com/writeitai/remember-stack/pkgs/container/remember-stack).

## What ships today

Expand Down Expand Up @@ -156,14 +156,49 @@ Current public release: [`v0.15.0`](https://github.com/writeitai/remember-stack/
The resolver generation moves to `resolver-2026.08g`, so evaluation curves
measured under `08f` are not comparable and a fresh run is required.

## What landed after v0.15.0 (on `main`)
## What landed after v0.15.0 (in v0.16.0)

**Dated events no longer collapse merely because their words match.** The
observation adjudicator now uses each claim's resolved world-time window.
Events with disjoint dates stay distinct unless a date-aware verdict identifies
one occurrence with disputed dates; a dated event also cannot serve as
`evidence` for an undated summary. Recurring same-shaped events therefore
survive as separate facts, and ingestion provenance changes
([#360](https://github.com/writeitai/remember-stack/pull/360)).

**Claim windows have one canonical half-open meaning.** Day, month, quarter,
and year precision cover their complete calendar unit; instants remain
non-empty points; open and unknown bounds stay explicit. `claims_as_of` now
finds a day-precision claim from an intraday or point query, and observation
adjudication uses the same bounds
([#372](https://github.com/writeitai/remember-stack/pull/372)).

**Operators:** migration `p9_26_0047` adds the canonical-bound SQL functions
and the partial expression index used by `claims_as_of`; claim storage is
unchanged. Observation generations roll, so rebuilding changes stored
ingestion provenance, and `claims_as_of` results change under the corrected
window semantics.

**A release now carries the API contract beside the binaries.** The generated
`openapi.json` is attached to the GitHub release, so client generation can pin
the exact schema served by the installed engine rather than following `main`
([#358](https://github.com/writeitai/remember-stack/pull/358)).

**Browser uploads have their own narrow credential.** The signed perimeter now
has `read`, `ingest`, and `write` scopes. `ingest` reaches only `POST /ingest`:
it cannot search, list memory, run operations, or create a connector that keeps
pulling after the browser leaves. Full `write` still reaches ingest. A narrow
credential also cannot assert immutable principal attribution
([#363](https://github.com/writeitai/remember-stack/pull/363),
[#370](https://github.com/writeitai/remember-stack/pull/370)).

**Managed login uses the deployment hostname it receives.** When the token
host advertises a live data-plane hostname, `remember login` derives the query
API URL, so managed users need only `--token-host`. An explicit `--api-url`
still wins for self-hosted and local deployments. A missing hostname asks for
that flag, while a hostname that is not live prints the name and asks the user
to retry; neither refusal replaces an existing credential.
to retry; neither refusal replaces an existing credential
([#371](https://github.com/writeitai/remember-stack/pull/371)).

## What landed after v0.14.0 (in v0.15.0)

Expand Down Expand Up @@ -246,11 +281,12 @@ examined, and the failure looks like the deployment being down.
v16's read surface, answer/judge seats, budgets, and content-before-`Unknown`
guard.

## Document-local exact T0 (current release behavior in v0.13.0)
## Document-local exact T0 (current release behavior)

- Resolver `resolver-2026.08f` can replay an exact canonical-name match at T0
only inside the same document and only after a T4 match established one
unambiguous live binding. Fuzzy T1/T2 signals remain candidate-only.
- Resolver `resolver-2026.08g` can replay an exact canonical-name match at T0
(a behavior introduced in `08f`) only inside the same document and only after
a T4 match established one unambiguous live binding. Fuzzy T1/T2 signals
remain candidate-only.
- The derived binding projection is generation-gated as `document-t0-v1`,
rebuilt before it is enabled for existing deployments, and cleared by normal
lineage deletion and hard forget.
Expand Down
16 changes: 7 additions & 9 deletions website/src/app/docs/reference/api/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,8 @@ the routes a shipped self-host deployment serves — not the cost-export listene
below, which is a separate process, nor connector management, which no shipped
profile composes. The
document is [`openapi.json`](https://github.com/writeitai/remember-stack/blob/main/openapi.json)
at the root of the repository, and releases published from now on attach it as
a release asset of the same name. Releases up to and including v0.15.0 predate
it, so check a release's asset list before pinning one to generate from — the
at the root of the repository. Release v0.16.0 and later attach it as a release
asset of the same name; releases up to and including v0.15.0 predate it. The
repository copy always describes the current `main`.

A deployment does **not** serve the schema itself. `GET /openapi.json` is not a
Expand All @@ -75,14 +74,13 @@ nowhere else.
Generate a typed client the usual way for your language, for example:

```bash
# From the repository, describing current main:
# Pinned to the version you actually run (available from v0.16.0):
curl -fsSL -o openapi.json \
https://raw.githubusercontent.com/writeitai/remember-stack/main/openapi.json
https://github.com/writeitai/remember-stack/releases/download/v0.16.0/openapi.json

# Or, pinned to the version you actually run — check the release's asset
# list first, since releases up to v0.15.0 do not carry it:
# curl -fsSL -o openapi.json \
# https://github.com/writeitai/remember-stack/releases/download/<tag>/openapi.json
# Or, from the repository, describing current main:
curl -fsSL -o openapi.json \
https://raw.githubusercontent.com/writeitai/remember-stack/main/openapi.json

# TypeScript
npx openapi-typescript openapi.json -o src/engine-schema.ts
Expand Down
2 changes: 1 addition & 1 deletion website/src/app/docs/reference/cli/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ in the deployment. One deployment is one trust domain.

```bash
remember --version
# RememberStack 0.15.0
# RememberStack 0.16.0
```

## `remember login` / `remember logout`
Expand Down
Loading