mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
5973f9b787
Signed-off-by: phernandez <paul@basicmachines.co>
471 lines
19 KiB
Makefile
471 lines
19 KiB
Makefile
# Basic Memory - Modern Command Runner
|
|
|
|
# Install dependencies
|
|
install:
|
|
uv sync
|
|
@echo ""
|
|
@echo "💡 Remember to activate the virtual environment by running: source .venv/bin/activate"
|
|
|
|
# ==============================================================================
|
|
# DATABASE BACKEND TESTING
|
|
# ==============================================================================
|
|
# Basic Memory supports dual database backends (SQLite and Postgres).
|
|
# By default, tests run against SQLite (fast, no dependencies).
|
|
# Set BASIC_MEMORY_TEST_POSTGRES=1 to run against Postgres (uses testcontainers).
|
|
#
|
|
# Quick Start:
|
|
# just test # Run all tests against SQLite (default)
|
|
# just test-sqlite # Run all tests against SQLite
|
|
# just test-postgres # Run all tests against Postgres (testcontainers)
|
|
# just test-unit-sqlite # Run unit tests against SQLite
|
|
# just test-unit-postgres # Run unit tests against Postgres
|
|
# just test-int-sqlite # Run integration tests against SQLite
|
|
# just test-int-postgres # Run integration tests against Postgres
|
|
#
|
|
# CI runs both in parallel for faster feedback.
|
|
# ==============================================================================
|
|
|
|
# Run all tests against SQLite and Postgres
|
|
test: test-sqlite test-postgres
|
|
|
|
# Run all tests against SQLite
|
|
test-sqlite: test-unit-sqlite test-int-sqlite
|
|
|
|
# Run all tests against Postgres (uses testcontainers)
|
|
test-postgres: test-unit-postgres test-int-postgres
|
|
|
|
# Run unit tests against SQLite
|
|
test-unit-sqlite:
|
|
BASIC_MEMORY_ENV=test uv run pytest -p pytest_mock -v --no-cov tests
|
|
|
|
# Run unit tests against Postgres
|
|
test-unit-postgres:
|
|
BASIC_MEMORY_ENV=test BASIC_MEMORY_TEST_POSTGRES=1 uv run pytest -p pytest_mock -v --no-cov tests
|
|
|
|
# Run integration tests against SQLite (excludes semantic benchmarks — use just test-semantic)
|
|
test-int-sqlite:
|
|
BASIC_MEMORY_ENV=test uv run pytest -p pytest_mock -v --no-cov -m "not semantic" test-int
|
|
|
|
# Run integration tests against Postgres
|
|
# Note: Uses timeout due to FastMCP Client + asyncpg cleanup hang (tests pass, process hangs on exit)
|
|
# See: https://github.com/jlowin/fastmcp/issues/1311
|
|
test-int-postgres:
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
# Use gtimeout (macOS/Homebrew) or timeout (Linux)
|
|
TIMEOUT_CMD=$(command -v gtimeout || command -v timeout || echo "")
|
|
if [[ -n "$TIMEOUT_CMD" ]]; then
|
|
$TIMEOUT_CMD --signal=KILL 600 bash -c 'BASIC_MEMORY_ENV=test BASIC_MEMORY_TEST_POSTGRES=1 uv run pytest -p pytest_mock -v --no-cov -m "not semantic" test-int' || test $? -eq 137
|
|
else
|
|
echo "⚠️ No timeout command found, running without timeout..."
|
|
BASIC_MEMORY_ENV=test BASIC_MEMORY_TEST_POSTGRES=1 uv run pytest -p pytest_mock -v --no-cov -m "not semantic" test-int
|
|
fi
|
|
|
|
# Run tests impacted by recent changes (requires pytest-testmon)
|
|
# Pass paths or node ids after `just testmon` to limit the candidate set further.
|
|
testmon *args:
|
|
BASIC_MEMORY_ENV=test uv run pytest -p pytest_mock -v --no-cov --testmon {{args}}
|
|
|
|
# Run MCP smoke test (fast end-to-end loop)
|
|
test-smoke:
|
|
BASIC_MEMORY_ENV=test uv run pytest -p pytest_mock -v --no-cov -m smoke test-int/mcp/test_smoke_integration.py
|
|
|
|
# Fast local loop: lint, format, typecheck, impacted tests via pytest-testmon
|
|
fast-check:
|
|
just fix
|
|
just format
|
|
just typecheck
|
|
just testmon
|
|
|
|
# Reset Postgres test database (drops and recreates schema)
|
|
# Useful when Alembic migration state gets out of sync during development
|
|
# Uses credentials from docker-compose-postgres.yml
|
|
postgres-reset:
|
|
docker exec basic-memory-postgres psql -U ${POSTGRES_USER:-basic_memory_user} -d ${POSTGRES_TEST_DB:-basic_memory_test} -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"
|
|
@echo "✅ Postgres test database reset"
|
|
|
|
# Run Alembic migrations manually against Postgres test database
|
|
# Useful for debugging migration issues
|
|
# Uses credentials from docker-compose-postgres.yml (can override with env vars)
|
|
postgres-migrate:
|
|
@cd src/basic_memory/alembic && \
|
|
BASIC_MEMORY_DATABASE_BACKEND=postgres \
|
|
BASIC_MEMORY_DATABASE_URL=${POSTGRES_TEST_URL:-postgresql+asyncpg://basic_memory_user:dev_password@localhost:5433/basic_memory_test} \
|
|
uv run alembic upgrade head
|
|
@echo "✅ Migrations applied to Postgres test database"
|
|
|
|
# Run Windows-specific tests only (only works on Windows platform)
|
|
# These tests verify Windows-specific database optimizations (locking mode, NullPool)
|
|
# Will be skipped automatically on non-Windows platforms
|
|
test-windows:
|
|
BASIC_MEMORY_ENV=test uv run pytest -p pytest_mock -v --no-cov -m windows tests test-int
|
|
|
|
# Run benchmark tests only (performance testing)
|
|
# These are slow tests that measure sync performance with various file counts
|
|
# Excluded from default test runs to keep CI fast
|
|
test-benchmark:
|
|
BASIC_MEMORY_ENV=test uv run pytest -p pytest_mock -v --no-cov -m benchmark tests test-int
|
|
|
|
# Run semantic search quality benchmarks (all combos)
|
|
test-semantic:
|
|
BASIC_MEMORY_ENV=test uv run pytest -p pytest_mock -v --no-cov -m semantic test-int/semantic/
|
|
|
|
# Run semantic benchmarks with JSON artifact output, then show report
|
|
test-semantic-report:
|
|
BASIC_MEMORY_ENV=test BASIC_MEMORY_BENCHMARK_OUTPUT=.benchmarks/semantic-quality.jsonl uv run pytest -p pytest_mock -v -s --no-cov -m semantic test-int/semantic/
|
|
uv run python test-int/semantic/report.py .benchmarks/semantic-quality.jsonl
|
|
|
|
# Run semantic benchmarks (Postgres combos only)
|
|
test-semantic-postgres:
|
|
BASIC_MEMORY_ENV=test uv run pytest -p pytest_mock -v --no-cov -m semantic -k postgres test-int/semantic/
|
|
|
|
# View semantic benchmark results (rich formatted table)
|
|
# Usage: just semantic-report [--filter-combo sqlite] [--filter-suite paraphrase] [--sort-by avg_latency_ms]
|
|
semantic-report *args:
|
|
uv run python test-int/semantic/report.py .benchmarks/semantic-quality.jsonl {{args}}
|
|
|
|
# Compare two search benchmark JSONL outputs
|
|
# Usage:
|
|
# just benchmark-compare .benchmarks/search-baseline.jsonl .benchmarks/search-candidate.jsonl
|
|
# just benchmark-compare .benchmarks/search-baseline.jsonl .benchmarks/search-candidate.jsonl --format markdown --show-missing
|
|
benchmark-compare baseline candidate *args:
|
|
uv run python test-int/compare_search_benchmarks.py "{{baseline}}" "{{candidate}}" --format table {{args}}
|
|
|
|
# Run all tests including Windows, Postgres, and Benchmarks (for CI/comprehensive testing)
|
|
# Use this before releasing to ensure everything works across all backends and platforms
|
|
test-all:
|
|
BASIC_MEMORY_ENV=test uv run pytest -p pytest_mock -v --no-cov tests test-int
|
|
|
|
# Generate HTML coverage report
|
|
coverage:
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
uv run coverage erase
|
|
|
|
echo "🔎 Coverage (SQLite)..."
|
|
BASIC_MEMORY_ENV=test uv run coverage run --source=basic_memory -m pytest -p pytest_mock -v --no-cov tests test-int
|
|
|
|
echo "🔎 Coverage (Postgres via testcontainers)..."
|
|
# Note: Uses timeout due to FastMCP Client + asyncpg cleanup hang (tests pass, process hangs on exit)
|
|
# See: https://github.com/jlowin/fastmcp/issues/1311
|
|
TIMEOUT_CMD=$(command -v gtimeout || command -v timeout || echo "")
|
|
if [[ -n "$TIMEOUT_CMD" ]]; then
|
|
$TIMEOUT_CMD --signal=KILL 600 bash -c 'BASIC_MEMORY_ENV=test BASIC_MEMORY_TEST_POSTGRES=1 uv run coverage run --source=basic_memory -m pytest -p pytest_mock -v --no-cov -m postgres tests test-int' || test $? -eq 137
|
|
else
|
|
echo "⚠️ No timeout command found, running without timeout..."
|
|
BASIC_MEMORY_ENV=test BASIC_MEMORY_TEST_POSTGRES=1 uv run coverage run --source=basic_memory -m pytest -p pytest_mock -v --no-cov -m postgres tests test-int
|
|
fi
|
|
|
|
echo "🧩 Combining coverage data..."
|
|
uv run coverage combine
|
|
uv run coverage report -m
|
|
uv run coverage html
|
|
echo "Coverage report generated in htmlcov/index.html"
|
|
|
|
# Lint and fix code (calls fix)
|
|
lint: fix
|
|
|
|
# Lint and fix code
|
|
fix:
|
|
uv run ruff check --fix --unsafe-fixes src tests test-int
|
|
|
|
# Type check code (ty)
|
|
typecheck:
|
|
uv run ty check src tests test-int
|
|
|
|
# Type check code (pyright)
|
|
typecheck-pyright:
|
|
uv run pyright
|
|
|
|
# Type check code (ty)
|
|
typecheck-ty:
|
|
just typecheck
|
|
|
|
# Clean build artifacts and cache files
|
|
clean:
|
|
find . -type f -name '*.pyc' -delete
|
|
find . -type d -name '__pycache__' -exec rm -r {} +
|
|
rm -rf installer/build/ installer/dist/ dist/
|
|
rm -f rw.*.dmg .coverage.*
|
|
|
|
# Format code with ruff
|
|
format:
|
|
uv run ruff format .
|
|
|
|
# Run MCP inspector tool
|
|
run-inspector:
|
|
npx @modelcontextprotocol/inspector
|
|
|
|
# Run doctor checks in an isolated temp home/config
|
|
doctor:
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
TMP_HOME=$(mktemp -d)
|
|
TMP_CONFIG=$(mktemp -d)
|
|
HOME="$TMP_HOME" \
|
|
BASIC_MEMORY_ENV=test \
|
|
BASIC_MEMORY_HOME="$TMP_HOME/basic-memory" \
|
|
BASIC_MEMORY_CONFIG_DIR="$TMP_CONFIG" \
|
|
./.venv/bin/python -m basic_memory.cli.main doctor --local
|
|
|
|
# Run an isolated Logfire smoke workflow for local trace inspection
|
|
telemetry-smoke:
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
TMP_HOME=$(mktemp -d)
|
|
TMP_CONFIG=$(mktemp -d)
|
|
TMP_PROJECT=$(mktemp -d)
|
|
export HOME="$TMP_HOME"
|
|
export BASIC_MEMORY_ENV="${BASIC_MEMORY_ENV:-dev}"
|
|
export BASIC_MEMORY_HOME="$TMP_PROJECT/home-root"
|
|
export BASIC_MEMORY_CONFIG_DIR="$TMP_CONFIG"
|
|
export BASIC_MEMORY_NO_PROMOS=1
|
|
export BASIC_MEMORY_LOG_LEVEL="${BASIC_MEMORY_LOG_LEVEL:-INFO}"
|
|
export BASIC_MEMORY_SEMANTIC_SEARCH_ENABLED="${BASIC_MEMORY_SEMANTIC_SEARCH_ENABLED:-false}"
|
|
export BASIC_MEMORY_LOGFIRE_ENABLED="${BASIC_MEMORY_LOGFIRE_ENABLED:-true}"
|
|
export BASIC_MEMORY_LOGFIRE_ENVIRONMENT="${BASIC_MEMORY_LOGFIRE_ENVIRONMENT:-telemetry-smoke}"
|
|
if [[ -z "${BASIC_MEMORY_LOGFIRE_SEND_TO_LOGFIRE:-}" ]]; then
|
|
if [[ -n "${LOGFIRE_TOKEN:-}" ]]; then
|
|
export BASIC_MEMORY_LOGFIRE_SEND_TO_LOGFIRE=true
|
|
else
|
|
export BASIC_MEMORY_LOGFIRE_SEND_TO_LOGFIRE=false
|
|
fi
|
|
fi
|
|
mkdir -p "$BASIC_MEMORY_HOME"
|
|
echo "Telemetry smoke setup:"
|
|
echo " logfire_enabled=$BASIC_MEMORY_LOGFIRE_ENABLED"
|
|
echo " send_to_logfire=$BASIC_MEMORY_LOGFIRE_SEND_TO_LOGFIRE"
|
|
echo " log_level=$BASIC_MEMORY_LOG_LEVEL"
|
|
echo " semantic_search_enabled=$BASIC_MEMORY_SEMANTIC_SEARCH_ENABLED"
|
|
echo " logfire_environment=$BASIC_MEMORY_LOGFIRE_ENVIRONMENT"
|
|
echo " project_path=$TMP_PROJECT"
|
|
./.venv/bin/python -m basic_memory.cli.main project add telemetry-smoke "$TMP_PROJECT" --default --local
|
|
./.venv/bin/python -m basic_memory.cli.main tool write-note --title "Telemetry Smoke" --folder notes --content "hello from smoke" --project telemetry-smoke --local
|
|
./.venv/bin/python -m basic_memory.cli.main tool read-note notes/telemetry-smoke --project telemetry-smoke --local
|
|
./.venv/bin/python -m basic_memory.cli.main tool edit-note notes/telemetry-smoke --operation append --content $'\n\nsmoke edit line' --project telemetry-smoke --local
|
|
./.venv/bin/python -m basic_memory.cli.main tool build-context notes/telemetry-smoke --project telemetry-smoke --local --page-size 5 --max-related 5
|
|
./.venv/bin/python -m basic_memory.cli.main tool search-notes telemetry --project telemetry-smoke --local
|
|
./.venv/bin/python -m basic_memory.cli.main doctor --local
|
|
echo ""
|
|
echo "Telemetry smoke complete."
|
|
echo "Search Logfire for:"
|
|
echo " service_name: basic-memory-cli"
|
|
echo " environment: $BASIC_MEMORY_LOGFIRE_ENVIRONMENT"
|
|
echo " span names: mcp.tool.write_note, mcp.tool.read_note, mcp.tool.edit_note, mcp.tool.build_context, mcp.tool.search_notes, sync.project.run"
|
|
|
|
|
|
# Update all dependencies to latest versions
|
|
update-deps:
|
|
uv sync --upgrade
|
|
|
|
# Run all code quality checks and tests
|
|
check: lint format typecheck test
|
|
|
|
# Run all code quality checks and all test suites, including semantic benchmarks
|
|
check-all: lint format typecheck test test-semantic
|
|
|
|
# Validate every consolidated agent package (Claude Code, Codex, skills, Hermes, OpenClaw)
|
|
package-check: package-check-claude-code package-check-codex package-check-skills package-check-hermes package-check-openclaw
|
|
|
|
# Alias for plugin/package validation during consolidation work
|
|
plugins-check: package-check
|
|
|
|
# Validate the host-native agent harnesses
|
|
agent-harness-check: package-check-claude-code package-check-hermes package-check-openclaw
|
|
|
|
# Claude Code plugin: manifests, bundled skills, bundled agent, and strict plugin validation
|
|
package-check-claude-code:
|
|
just --justfile plugins/claude-code/justfile --working-directory plugins/claude-code check
|
|
|
|
# Codex plugin: manifest, bundled skills, hooks, MCP config, and schemas
|
|
package-check-codex:
|
|
just --justfile plugins/codex/justfile --working-directory plugins/codex check
|
|
|
|
# Shared top-level SKILL.md source
|
|
package-check-skills:
|
|
just --justfile skills/justfile --working-directory skills check
|
|
|
|
# Hermes plugin: native manifest plus hermetic unit test suite
|
|
package-check-hermes:
|
|
just --justfile integrations/hermes/justfile --working-directory integrations/hermes check
|
|
|
|
# OpenClaw plugin: install deps, copy skills, typecheck, lint, build, test, and npm pack dry-run
|
|
package-check-openclaw:
|
|
just --justfile integrations/openclaw/justfile --working-directory integrations/openclaw install
|
|
just --justfile integrations/openclaw/justfile --working-directory integrations/openclaw release-check
|
|
|
|
# Generate Alembic migration with descriptive message
|
|
migration message:
|
|
cd src/basic_memory/alembic && alembic revision --autogenerate -m "{{message}}"
|
|
|
|
# Set the Basic Memory version across release manifests (scope: all | core | packages)
|
|
set-version version scope="all":
|
|
python3 scripts/update_versions.py "{{version}}" --scope "{{scope}}"
|
|
|
|
# Preview a version update without writing (scope: all | core | packages)
|
|
set-version-dry-run version scope="all":
|
|
python3 scripts/update_versions.py "{{version}}" --scope "{{scope}}" --dry-run
|
|
|
|
# Set the version for just the plugin/agent artifacts (plugin, marketplaces, Hermes, OpenClaw)
|
|
set-packages-version version:
|
|
just set-version "{{version}}" packages
|
|
|
|
# Preview a plugin/agent-artifact version update without writing
|
|
set-packages-version-dry-run version:
|
|
just set-version-dry-run "{{version}}" packages
|
|
|
|
# Preview the consolidated manifest version update without changing files
|
|
release-dry-run version:
|
|
just set-version-dry-run "{{version}}"
|
|
|
|
# Create a stable release (e.g., just release v0.13.2)
|
|
release version:
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Validate version format
|
|
if [[ ! "{{version}}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
echo "❌ Invalid version format. Use: v0.13.2"
|
|
exit 1
|
|
fi
|
|
|
|
# Extract version number without 'v' prefix
|
|
VERSION_NUM=$(echo "{{version}}" | sed 's/^v//')
|
|
|
|
echo "🚀 Creating stable release {{version}}"
|
|
|
|
# Pre-flight checks
|
|
echo "📋 Running pre-flight checks..."
|
|
if [[ -n $(git status --porcelain) ]]; then
|
|
echo "❌ Uncommitted changes found. Please commit or stash them first."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ $(git branch --show-current) != "main" ]]; then
|
|
echo "❌ Not on main branch. Switch to main first."
|
|
exit 1
|
|
fi
|
|
|
|
# Check if tag already exists
|
|
if git tag -l "{{version}}" | grep -q "{{version}}"; then
|
|
echo "❌ Tag {{version}} already exists"
|
|
exit 1
|
|
fi
|
|
|
|
# Run quality checks
|
|
echo "🔍 Running lint checks..."
|
|
just lint
|
|
just typecheck
|
|
|
|
# Update all package manifests to the one Basic Memory product version.
|
|
echo "📝 Updating consolidated package versions..."
|
|
just set-version "{{version}}"
|
|
|
|
# Commit version update
|
|
git add \
|
|
src/basic_memory/__init__.py \
|
|
server.json \
|
|
.claude-plugin/marketplace.json \
|
|
plugins/claude-code/.claude-plugin/plugin.json \
|
|
plugins/claude-code/.claude-plugin/marketplace.json \
|
|
integrations/hermes/plugin.yaml \
|
|
integrations/hermes/__init__.py \
|
|
integrations/openclaw/package.json
|
|
git commit -s -m "chore: update version to $VERSION_NUM for {{version}} release"
|
|
|
|
# Create and push tag
|
|
echo "🏷️ Creating tag {{version}}..."
|
|
git tag "{{version}}"
|
|
|
|
echo "📤 Pushing to GitHub..."
|
|
git push origin main
|
|
git push origin "{{version}}"
|
|
|
|
echo "✅ Release {{version}} created successfully!"
|
|
echo "📦 GitHub Actions will build and publish to PyPI"
|
|
echo "🔗 Monitor at: https://github.com/basicmachines-co/basic-memory/actions"
|
|
echo ""
|
|
echo "📝 REMINDER: Post-release tasks:"
|
|
echo " 1. docs.basicmemory.com - Add release notes to src/pages/latest-releases.mdx"
|
|
echo " 2. basicmachines.co - Update version in src/components/sections/hero.tsx"
|
|
echo " 3. MCP Registry - Run: mcp-publisher publish"
|
|
echo " See: .claude/commands/release/release.md for detailed instructions"
|
|
|
|
# Create a beta release (e.g., just beta v0.13.2b1)
|
|
beta version:
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Validate version format (allow beta/rc suffixes)
|
|
if [[ ! "{{version}}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(b[0-9]+|rc[0-9]+)$ ]]; then
|
|
echo "❌ Invalid beta version format. Use: v0.13.2b1 or v0.13.2rc1"
|
|
exit 1
|
|
fi
|
|
|
|
# Extract version number without 'v' prefix
|
|
VERSION_NUM=$(echo "{{version}}" | sed 's/^v//')
|
|
|
|
echo "🧪 Creating beta release {{version}}"
|
|
|
|
# Pre-flight checks
|
|
echo "📋 Running pre-flight checks..."
|
|
if [[ -n $(git status --porcelain) ]]; then
|
|
echo "❌ Uncommitted changes found. Please commit or stash them first."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ $(git branch --show-current) != "main" ]]; then
|
|
echo "❌ Not on main branch. Switch to main first."
|
|
exit 1
|
|
fi
|
|
|
|
# Check if tag already exists
|
|
if git tag -l "{{version}}" | grep -q "{{version}}"; then
|
|
echo "❌ Tag {{version}} already exists"
|
|
exit 1
|
|
fi
|
|
|
|
# Run quality checks
|
|
echo "🔍 Running lint checks..."
|
|
just lint
|
|
just typecheck
|
|
|
|
# Update all package manifests to the one Basic Memory product version.
|
|
echo "📝 Updating consolidated package versions..."
|
|
just set-version "{{version}}"
|
|
|
|
# Commit version update
|
|
git add \
|
|
src/basic_memory/__init__.py \
|
|
server.json \
|
|
.claude-plugin/marketplace.json \
|
|
plugins/claude-code/.claude-plugin/plugin.json \
|
|
plugins/claude-code/.claude-plugin/marketplace.json \
|
|
integrations/hermes/plugin.yaml \
|
|
integrations/hermes/__init__.py \
|
|
integrations/openclaw/package.json
|
|
git commit -s -m "chore: update version to $VERSION_NUM for {{version}} beta release"
|
|
|
|
# Create and push tag
|
|
echo "🏷️ Creating tag {{version}}..."
|
|
git tag "{{version}}"
|
|
|
|
echo "📤 Pushing to GitHub..."
|
|
git push origin main
|
|
git push origin "{{version}}"
|
|
|
|
echo "✅ Beta release {{version}} created successfully!"
|
|
echo "📦 GitHub Actions will build and publish to PyPI as pre-release"
|
|
echo "🔗 Monitor at: https://github.com/basicmachines-co/basic-memory/actions"
|
|
echo "📥 Install with: uv tool install basic-memory --pre"
|
|
echo ""
|
|
echo "📝 REMINDER: For stable releases, update documentation sites:"
|
|
echo " 1. docs.basicmemory.com - Add release notes to src/pages/latest-releases.mdx"
|
|
echo " 2. basicmachines.co - Update version in src/components/sections/hero.tsx"
|
|
echo " See: .claude/commands/release/release.md for detailed instructions"
|
|
|
|
# List all available recipes
|
|
default:
|
|
@just --list
|