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
81 changes: 66 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"
pip install -e ".[dev,langchain]"

- name: Run focused regression suite
env:
Expand All @@ -39,6 +39,8 @@ jobs:
run: |
pytest \
tests/production \
tests/test_embedded_scm.py \
tests/test_langchain_embedded.py \
tests/test_scm_sdk.py \
tests/test_product_runtime_api.py \
tests/test_mcp_contract.py \
Expand Down Expand Up @@ -80,10 +82,51 @@ jobs:
sys.exit(1)
PY

- name: Verify embedded product front door
run: python scripts/check_embedded_front_door.py

postgres-embedded:
name: Embedded PostgreSQL coordination
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: scm_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres -d scm_test"
--health-interval 5s
--health-timeout 5s
--health-retries 10

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip

- name: Install PostgreSQL test dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev,postgres]"

- name: Run multi-process persistence tests
env:
SCM_TEST_POSTGRES_URL: postgresql://postgres:postgres@127.0.0.1:5432/scm_test
LLM_PROVIDER: ""
SCM_EMBEDDING_BACKEND: hash
SCM_AUTO_SLEEP_DISABLE: "1"
run: pytest tests/production/test_postgres_embedded.py -q --tb=short

build:
name: Build distribution artifacts
runs-on: ubuntu-latest
needs: test
needs: [test, postgres-embedded]

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -137,7 +180,8 @@ jobs:
run: |
python -m venv /tmp/scm-wheel
/tmp/scm-wheel/bin/python -m pip install --upgrade pip
/tmp/scm-wheel/bin/pip install dist/scm_memory-*.whl
WHEEL=$(echo dist/scm_memory-*.whl)
/tmp/scm-wheel/bin/pip install "${WHEEL}[langchain]"

- name: Verify installed package data and Python SDK
env:
Expand All @@ -149,24 +193,31 @@ jobs:
cd /tmp
/tmp/scm-wheel/bin/python - <<'PY'
import importlib.resources as resources
from scm import SCMClient, SCMEngine
from scm import SCM

assert SCMClient.__name__ == "SCMClient"
assert SCM.__name__ == "SCM"
assert resources.files("src.core").joinpath("locales/en.json").is_file()
assert resources.files("src.api").joinpath("static/app.html").is_file()

client = SCMClient(user_id="wheel-smoke", base_url="http://localhost:8765/v1")
assert client.user_id == "wheel-smoke"

engine = SCMEngine(session_id="wheel-smoke", sandbox=True, offline=True)
added = engine.add_memory("Alice is allergic to peanuts.")
assert added["ok"] and added["concepts_added"] >= 1
found = engine.search_memory("what should Alice avoid?")
assert found["ok"]
assert engine.sleep("deep")["ok"]
assert engine.wake_summary()["ok"]
with SCM(user_id="wheel-smoke", auto_sleep=False) as memory:
added = memory.add_memory("Alice is allergic to peanuts.")
assert added["ok"] and added["concepts_added"] >= 1
found = memory.search_memory("what should Alice avoid?")
assert found["ok"]
assert memory.sleep("deep")["user_id"] == "wheel-smoke"
assert memory.wake_summary()["ok"]
PY

- name: Verify embedded LangChain outside repo
env:
SCM_DATA_DIR: /tmp/scm-wheel-langchain-data
LLM_PROVIDER: ""
SCM_EMBEDDING_BACKEND: hash
SCM_AUTO_SLEEP_DISABLE: "1"
run: |
cd /tmp
/tmp/scm-wheel/bin/python "$GITHUB_WORKSPACE/scripts/installed_langchain_smoke.py"

- name: Verify CLI and offline quickstart outside repo
env:
SCM_DATA_DIR: /tmp/scm-wheel-data
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,25 @@ jobs:
VERSION="${GITHUB_REF_NAME#v}"
awk "/^## v${VERSION}/{flag=1; next} /^## /{flag=0} flag" CHANGELOG.md > release_notes.md

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Build release assets and checksums
run: |
python -m pip install --upgrade pip
pip install build twine
python -m build --wheel --sdist
twine check dist/*
sha256sum dist/* > SHA256SUMS

- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
body_path: release_notes.md
draft: false
prerelease: false
files: |
dist/*
SHA256SUMS
23 changes: 22 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ Format: each release lists what shipped, why it shipped, what tests verified it,

---

## v1.0.0 - 2026-07-13

**Theme: embedded lifecycle memory for Python and LangChain agents.**

- Added `SCM`, the URL-free Python runtime backed by isolated per-user engines.
- Added LangChain 1.x middleware and `create_scm_agent` with automatic recall,
durable message capture, bounded wake context, and exactly five tools.
- Added lifecycle snapshot v2 with atomic local persistence, optional
encryption, corruption recovery, idempotency, and PostgreSQL coordination.
- Added per-user export, import, hard deletion, process locks, and sleep leases.
- Kept REST, MCP, `SCMEngine`, and the JavaScript REST client compatible as
advanced and remote surfaces.

### Verification

- Embedded direct API and LangChain tests run without an SCM server or URL.
- Local recovery and real PostgreSQL multi-process tests cover lifecycle state,
concurrent writes, and exclusive sleep leases.
- The published paper and reproducibility manifest are linked through DOI
`10.5281/zenodo.21323877`.

## v0.9.2 - 2026-07-09

**Theme: lifecycle behavior parity across public product surfaces.**
Expand Down Expand Up @@ -44,7 +65,7 @@ Format: each release lists what shipped, why it shipped, what tests verified it,

### 2026-05-04 — Paper held until product ready

The paper push to arXiv is **deferred** until the product-ready checklist in [`docs/ROADMAP.md`](docs/ROADMAP.md) is fully green (hosted demo + PyPI + npm publish + demo video + tutorial + lighthouse users + repo public). Reasoning: papers without products fade; products with papers compound. The arXiv submission bundle stays staged at `research/arxiv_submission/` ready for fast turnaround once the gate opens. See [`research/arxiv_submission/DO_NOT_SUBMIT.md`](research/arxiv_submission/DO_NOT_SUBMIT.md).
The paper push to arXiv was **deferred** until the product-ready checklist was green. The current product sequence and release gates are tracked in [`docs/PRODUCT_ADOPTION_PLAN.md`](docs/PRODUCT_ADOPTION_PLAN.md). Reasoning: papers without products fade; products with papers compound.

This inverts the original committed sequence (Build → Paper → Publish → Productize) into (Build → Paper → Productize → Publish). The paper still exists — it just waits for the moment it can convert readers into adopters.

Expand Down
17 changes: 6 additions & 11 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# SCM hosted demo container.
#
# Builds the SCM REST API on Python 3.11 slim. Defaults to Profile A
# (offline-only — heuristic encoder + sentence-transformers MiniLM) so
# the image is self-contained and runs without LLM provider credentials.
# Builds the SCM REST API on Python 3.11 slim. The default image uses offline
# extraction and hash embeddings so it is self-contained and requires no LLM
# provider credentials or model download.
#
# To enable a stronger profile at deploy time:
# docker run -e LLM_PROVIDER=deepseek -e DEEPSEEK_API_KEY=... ...
Expand All @@ -14,7 +14,7 @@

FROM python:3.11-slim AS base

# System deps for sentence-transformers + scientific Python
# Runtime health checks use curl. Build tools cover source-only dependencies.
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
curl \
Expand All @@ -24,6 +24,7 @@ WORKDIR /app

# Layer caching: copy only what pip needs first
COPY pyproject.toml README.md LICENSE ./
COPY scm/ ./scm/
COPY src/ ./src/

# Pre-create the data dir SCM persists to
Expand All @@ -32,15 +33,9 @@ RUN mkdir -p /data && chmod 777 /data
# Install the package + its dependencies
RUN pip install --no-cache-dir -e .

# Pre-fetch the default sentence-transformer model so first request is fast.
# (Skips the cold-start download; ~80 MB added to the image.)
RUN python -c "from sentence_transformers import SentenceTransformer; \
SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')" \
|| echo "sentence-transformer pre-fetch failed; will fall back to hash"

# Reasonable production defaults
ENV SCM_DATA_DIR=/data \
SCM_EMBEDDING_BACKEND=sentence_transformers \
SCM_EMBEDDING_BACKEND=hash \
SCM_AUTO_SLEEP_DISABLE=0 \
SCM_IDLE_THRESHOLD_SEC=300 \
SCM_MCP_SWEEP_INTERVAL_SEC=30 \
Expand Down
Loading
Loading