diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 766c0fc..9125d3b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -143,3 +143,77 @@ jobs: generate_release_notes: false draft: true prerelease: true + + auto-release: + name: Push(main) / Auto Release + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: test-merge + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + + - name: Check if already tagged + id: check + run: | + # Skip if this commit already has a stable version tag + for tag in $(git tag --points-at HEAD 2>/dev/null); do + if echo "$tag" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Commit already tagged as $tag, skipping." + exit 0 + fi + done + echo "skip=false" >> "$GITHUB_OUTPUT" + + - name: Setup Bun + if: steps.check.outputs.skip != 'true' + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install dependencies + if: steps.check.outputs.skip != 'true' + run: bun install + + - name: Compute release metadata + if: steps.check.outputs.skip != 'true' + id: meta + run: | + bun run scripts/release-meta.ts --allow-invalid --github-output "$GITHUB_OUTPUT" + + # Squash merges lose individual commit types, so if bump is + # "none" but there are unreleased commits, default to patch. + BUMP=$(grep '^bump=' "$GITHUB_OUTPUT" | cut -d= -f2) + COUNT=$(grep '^commit_count=' "$GITHUB_OUTPUT" | cut -d= -f2) + if [ "$BUMP" = "none" ] && [ "$COUNT" -gt 0 ]; then + echo "Bump was 'none' with $COUNT commits — overriding to 'patch'" + LATEST=$(git tag --list 'v*.*.*' --sort=-version:refname \ + | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1) + if [ -n "$LATEST" ]; then + IFS='.' read -r MAJ MIN PAT <<< "${LATEST#v}" + NEXT="v${MAJ}.${MIN}.$((PAT + 1))" + else + NEXT="v0.1.0" + fi + echo "next_version=${NEXT}" >> "$GITHUB_OUTPUT" + echo "bump=patch" >> "$GITHUB_OUTPUT" + fi + + - name: Create release + if: steps.check.outputs.skip != 'true' && steps.meta.outputs.bump != 'none' + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.meta.outputs.next_version }} + target_commitish: ${{ github.sha }} + name: ${{ steps.meta.outputs.next_version }} + body: ${{ steps.meta.outputs.release_notes }} + generate_release_notes: false + draft: false + prerelease: false diff --git a/CLAUDE.md b/CLAUDE.md index 39aa414..99f56dc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,6 +3,118 @@ Shared memory layer for AI-powered engineering teams. Built on [QMD](https://github.com/tobi/qmd). +## Memory + +You have Smriti. USE IT. + +### Start of Every Session + +Before writing a single line of code, run: + +```bash +smriti recall "[what we're about to work on]" +``` + +Use what comes back. If there's prior context on this topic, it changes how +you approach the work. Don't ignore it. + +### Recognize These Moments — Then Act Immediately + +No permission needed. No asking "should I save this?" Just do it. + +- Someone says "this works" or "let's go with this" +- An approach is chosen after comparing options +- A bug is fixed and the root cause is understood +- A constraint is discovered that will affect future work +- An architectural decision is made + +**WRONG**: Continue the conversation without saving. +**RIGHT**: Write the decision record, ingest it, tag it — then respond. + +### How to Save a Decision + +**Step 1 — Write the record:** + +```bash +cat > /tmp/smriti-note.md << 'EOF' +# [Title] + +## Decision +[One sentence — the actual choice made.] + +## Why +[The reasoning. What was considered. What was ruled out and why.] + +## Context +[What problem this solves. What breaks if someone reverses this later.] +EOF +``` + +**Step 2 — Ingest:** + +```bash +smriti ingest file /tmp/smriti-note.md \ + --title "[Title]" \ + --project smriti +``` + +**Step 3 — Tag:** + +```bash +smriti tag [session-id] [category] +``` + +### Categories + +| What happened | Tag | +|---------------|-----| +| Architecture choice, approach finalized | `decision/technical` | +| Library or tool selected | `decision/tooling` | +| Bug fixed, root cause identified | `bug/fix` | +| Structural design settled | `architecture/design` | +| Feature approach finalized | `feature/implementation` | +| Config or setup figured out | `project/config` | + +### Concrete Example + +User says: *"Okay let's use post-filtering for vector search with filters"* + +**WRONG**: +> "Got it, I'll use post-filtering." + +**RIGHT**: + +```bash +cat > /tmp/smriti-note.md << 'EOF' +# Vector search with filters: post-filter approach + +## Decision +Use post-filter strategy for applying metadata filters to vector search +results, rather than combining sqlite-vec queries with EXISTS subqueries. + +## Why +sqlite-vec's two-step query pattern hangs when combined with Smriti's +EXISTS subqueries on metadata tables. Post-filtering runs vector search +unfiltered (3x overfetch), then filters results against session metadata +in a separate batch lookup — no sqlite-vec changes needed. + +## Context +Affects smriti recall when --project, --category, or --agent flags are +used. Without this, filtered recall loses semantic search entirely and +falls back to BM25 only. +EOF + +smriti ingest file /tmp/smriti-note.md \ + --title "Vector search with filters: post-filter approach" \ + --project smriti + +smriti tag [session-id] decision/technical +``` + +Then respond to the user. + +--- + ## Quick Reference ```bash @@ -104,7 +216,7 @@ get a clean name like `openfga`. 4. Store message/meta/sidecars/costs (store gateway) 5. Aggregate results and continue on per-session errors (orchestrator) -See `INGEST_ARCHITECTURE.md` for details. +See `docs/internal/ingest-architecture.md` for details. ### Search